• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.applications.assist;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.PackageManager;
23 import android.content.pm.ResolveInfo;
24 import android.provider.Settings;
25 import android.service.voice.VoiceInteractionService;
26 import android.service.voice.VoiceInteractionServiceInfo;
27 import android.speech.RecognitionService;
28 import android.text.TextUtils;
29 import android.util.Log;
30 
31 import com.android.internal.app.AssistUtils;
32 import com.android.internal.logging.nano.MetricsProto;
33 import com.android.settings.R;
34 import com.android.settings.applications.defaultapps.DefaultAppInfo;
35 import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
36 
37 import java.util.ArrayList;
38 import java.util.List;
39 
40 public class DefaultAssistPicker extends DefaultAppPickerFragment {
41 
42     private static final String TAG = "DefaultAssistPicker";
43     private static final Intent ASSIST_SERVICE_PROBE =
44             new Intent(VoiceInteractionService.SERVICE_INTERFACE);
45     private static final Intent ASSIST_ACTIVITY_PROBE =
46             new Intent(Intent.ACTION_ASSIST);
47     private final List<Info> mAvailableAssistants = new ArrayList<>();
48 
49     private AssistUtils mAssistUtils;
50 
51     @Override
getMetricsCategory()52     public int getMetricsCategory() {
53         return MetricsProto.MetricsEvent.DEFAULT_ASSIST_PICKER;
54     }
55 
56     @Override
shouldShowItemNone()57     protected boolean shouldShowItemNone() {
58         return true;
59     }
60 
61     @Override
onAttach(Context context)62     public void onAttach(Context context) {
63         super.onAttach(context);
64         mAssistUtils = new AssistUtils(context);
65     }
66 
67     @Override
getCandidates()68     protected List<DefaultAppInfo> getCandidates() {
69         mAvailableAssistants.clear();
70         addAssistServices();
71         addAssistActivities();
72 
73         final List<String> packages = new ArrayList<>();
74         final List<DefaultAppInfo> candidates = new ArrayList<>();
75         for (Info info : mAvailableAssistants) {
76             final String packageName = info.component.getPackageName();
77             if (packages.contains(packageName)) {
78                 // A service appears before an activity thus overrides it if from the same package.
79                 continue;
80             }
81             packages.add(packageName);
82             candidates.add(new DefaultAppInfo(mPm, mUserId, info.component));
83         }
84         return candidates;
85     }
86 
87     @Override
getDefaultKey()88     protected String getDefaultKey() {
89         final ComponentName cn = getCurrentAssist();
90         if (cn != null) {
91             return new DefaultAppInfo(mPm, mUserId, cn).getKey();
92         }
93         return null;
94     }
95 
96     @Override
getConfirmationMessage(CandidateInfo appInfo)97     protected String getConfirmationMessage(CandidateInfo appInfo) {
98         if (appInfo == null) {
99             return null;
100         }
101         return getContext().getString(R.string.assistant_security_warning, appInfo.loadLabel());
102     }
103 
104     @Override
setDefaultKey(String key)105     protected boolean setDefaultKey(String key) {
106         if (TextUtils.isEmpty(key)) {
107             setAssistNone();
108             return true;
109         }
110         ComponentName cn = ComponentName.unflattenFromString(key);
111         final Info info = findAssistantByPackageName(cn.getPackageName());
112         if (info == null) {
113             setAssistNone();
114             return true;
115         }
116 
117         if (info.isVoiceInteractionService()) {
118             setAssistService(info);
119         } else {
120             setAssistActivity(info);
121         }
122         return true;
123     }
124 
getCurrentAssist()125     public ComponentName getCurrentAssist() {
126         return mAssistUtils.getAssistComponentForUser(mUserId);
127     }
128 
addAssistServices()129     private void addAssistServices() {
130         final PackageManager pm = mPm.getPackageManager();
131         final List<ResolveInfo> services = pm.queryIntentServices(
132                 ASSIST_SERVICE_PROBE, PackageManager.GET_META_DATA);
133         for (ResolveInfo resolveInfo : services) {
134             VoiceInteractionServiceInfo voiceInteractionServiceInfo =
135                     new VoiceInteractionServiceInfo(pm, resolveInfo.serviceInfo);
136             if (!voiceInteractionServiceInfo.getSupportsAssist()) {
137                 continue;
138             }
139 
140             mAvailableAssistants.add(new Info(
141                     new ComponentName(resolveInfo.serviceInfo.packageName,
142                             resolveInfo.serviceInfo.name),
143                     voiceInteractionServiceInfo));
144         }
145     }
146 
addAssistActivities()147     private void addAssistActivities() {
148         final PackageManager pm = mPm.getPackageManager();
149         final List<ResolveInfo> activities = pm.queryIntentActivities(
150                 ASSIST_ACTIVITY_PROBE, PackageManager.MATCH_DEFAULT_ONLY);
151         for (ResolveInfo resolveInfo : activities) {
152             mAvailableAssistants.add(new Info(
153                     new ComponentName(resolveInfo.activityInfo.packageName,
154                             resolveInfo.activityInfo.name)));
155         }
156     }
157 
findAssistantByPackageName(String packageName)158     private Info findAssistantByPackageName(String packageName) {
159         for (Info info : mAvailableAssistants) {
160             if (TextUtils.equals(info.component.getPackageName(), packageName)) {
161                 return info;
162             }
163         }
164         return null;
165     }
166 
setAssistNone()167     private void setAssistNone() {
168         Settings.Secure.putString(getContext().getContentResolver(),
169                 Settings.Secure.ASSISTANT, "");
170         Settings.Secure.putString(getContext().getContentResolver(),
171                 Settings.Secure.VOICE_INTERACTION_SERVICE, "");
172         Settings.Secure.putString(getContext().getContentResolver(),
173                 Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer());
174     }
175 
setAssistService(Info serviceInfo)176     private void setAssistService(Info serviceInfo) {
177         final String serviceComponentName = serviceInfo.component.
178                 flattenToShortString();
179         final String serviceRecognizerName = new ComponentName(
180                 serviceInfo.component.getPackageName(),
181                 serviceInfo.voiceInteractionServiceInfo.getRecognitionService())
182                 .flattenToShortString();
183 
184         Settings.Secure.putString(getContext().getContentResolver(),
185                 Settings.Secure.ASSISTANT, serviceComponentName);
186         Settings.Secure.putString(getContext().getContentResolver(),
187                 Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName);
188         Settings.Secure.putString(getContext().getContentResolver(),
189                 Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName);
190     }
191 
setAssistActivity(Info activityInfo)192     private void setAssistActivity(Info activityInfo) {
193         Settings.Secure.putString(getContext().getContentResolver(),
194                 Settings.Secure.ASSISTANT, activityInfo.component.flattenToShortString());
195         Settings.Secure.putString(getContext().getContentResolver(),
196                 Settings.Secure.VOICE_INTERACTION_SERVICE, "");
197         Settings.Secure.putString(getContext().getContentResolver(),
198                 Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer());
199     }
200 
getDefaultRecognizer()201     private String getDefaultRecognizer() {
202         final ResolveInfo resolveInfo = mPm.getPackageManager().resolveService(
203                 new Intent(RecognitionService.SERVICE_INTERFACE),
204                 PackageManager.GET_META_DATA);
205         if (resolveInfo == null || resolveInfo.serviceInfo == null) {
206             Log.w(TAG, "Unable to resolve default voice recognition service.");
207             return "";
208         }
209 
210         return new ComponentName(resolveInfo.serviceInfo.packageName,
211                 resolveInfo.serviceInfo.name).flattenToShortString();
212     }
213 
214     static class Info {
215         public final ComponentName component;
216         public final VoiceInteractionServiceInfo voiceInteractionServiceInfo;
217 
Info(ComponentName component)218         Info(ComponentName component) {
219             this.component = component;
220             this.voiceInteractionServiceInfo = null;
221         }
222 
Info(ComponentName component, VoiceInteractionServiceInfo voiceInteractionServiceInfo)223         Info(ComponentName component, VoiceInteractionServiceInfo voiceInteractionServiceInfo) {
224             this.component = component;
225             this.voiceInteractionServiceInfo = voiceInteractionServiceInfo;
226         }
227 
isVoiceInteractionService()228         public boolean isVoiceInteractionService() {
229             return voiceInteractionServiceInfo != null;
230         }
231     }
232 }
233