Home | History | Annotate | Download | only in applications
      1 /*
      2  * Copyright (C) 2015 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;
     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.os.UserHandle;
     25 import android.provider.Settings;
     26 import android.service.voice.VoiceInteractionService;
     27 import android.service.voice.VoiceInteractionServiceInfo;
     28 import android.speech.RecognitionService;
     29 import android.util.AttributeSet;
     30 import android.util.Log;
     31 
     32 import com.android.internal.app.AssistUtils;
     33 import com.android.settings.AppListPreferenceWithSettings;
     34 import com.android.settings.R;
     35 
     36 import java.util.ArrayList;
     37 import java.util.List;
     38 
     39 public class DefaultAssistPreference extends AppListPreferenceWithSettings {
     40 
     41     private static final String TAG = DefaultAssistPreference.class.getSimpleName();
     42 
     43     private final List<Info> mAvailableAssistants = new ArrayList<>();
     44 
     45     private final AssistUtils mAssistUtils;
     46 
     47     public DefaultAssistPreference(Context context, AttributeSet attrs) {
     48         super(context, attrs);
     49         setShowItemNone(true);
     50         setDialogTitle(R.string.choose_assist_title);
     51         mAssistUtils = new AssistUtils(context);
     52     }
     53 
     54     @Override
     55     protected boolean persistString(String value) {
     56         final Info info = findAssistantByPackageName(value);
     57         if (info == null) {
     58             setAssistNone();
     59             return true;
     60         }
     61 
     62         if (info.isVoiceInteractionService()) {
     63             setAssistService(info);
     64         } else {
     65             setAssistActivity(info);
     66         }
     67         return true;
     68     }
     69 
     70     private void setAssistNone() {
     71         Settings.Secure.putString(getContext().getContentResolver(),
     72                 Settings.Secure.ASSISTANT, ITEM_NONE_VALUE);
     73         Settings.Secure.putString(getContext().getContentResolver(),
     74                 Settings.Secure.VOICE_INTERACTION_SERVICE, "");
     75         Settings.Secure.putString(getContext().getContentResolver(),
     76                 Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer());
     77 
     78         setSummary(getContext().getText(R.string.default_assist_none));
     79         setSettingsComponent(null);
     80     }
     81 
     82     private void setAssistService(Info serviceInfo) {
     83         final String serviceComponentName = serviceInfo.component.flattenToShortString();
     84         final String serviceRecognizerName = new ComponentName(
     85                 serviceInfo.component.getPackageName(),
     86                 serviceInfo.voiceInteractionServiceInfo.getRecognitionService())
     87                 .flattenToShortString();
     88 
     89         Settings.Secure.putString(getContext().getContentResolver(),
     90                 Settings.Secure.ASSISTANT, serviceComponentName);
     91         Settings.Secure.putString(getContext().getContentResolver(),
     92                 Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName);
     93         Settings.Secure.putString(getContext().getContentResolver(),
     94                 Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName);
     95 
     96         setSummary(getEntry());
     97         final String settingsActivity =
     98                 serviceInfo.voiceInteractionServiceInfo.getSettingsActivity();
     99         setSettingsComponent(settingsActivity == null ?
    100                 null :
    101                 new ComponentName(serviceInfo.component.getPackageName(), settingsActivity));
    102     }
    103 
    104     private void setAssistActivity(Info activityInfo) {
    105         Settings.Secure.putString(getContext().getContentResolver(),
    106                 Settings.Secure.ASSISTANT, activityInfo.component.flattenToShortString());
    107         Settings.Secure.putString(getContext().getContentResolver(),
    108                 Settings.Secure.VOICE_INTERACTION_SERVICE, "");
    109         Settings.Secure.putString(getContext().getContentResolver(),
    110                 Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer());
    111 
    112         setSummary(getEntry());
    113         setSettingsComponent(null);
    114     }
    115 
    116     private String getDefaultRecognizer() {
    117         ResolveInfo resolveInfo = getContext().getPackageManager().resolveService(
    118                 new Intent(RecognitionService.SERVICE_INTERFACE),
    119                 PackageManager.GET_META_DATA);
    120         if (resolveInfo == null || resolveInfo.serviceInfo == null) {
    121             Log.w(TAG, "Unable to resolve default voice recognition service.");
    122             return "";
    123         }
    124 
    125         return new ComponentName(resolveInfo.serviceInfo.packageName,
    126                 resolveInfo.serviceInfo.name).flattenToShortString();
    127     }
    128 
    129     private Info findAssistantByPackageName(String packageName) {
    130         for (int i = 0; i < mAvailableAssistants.size(); ++i) {
    131             Info info = mAvailableAssistants.get(i);
    132             if (info.component.getPackageName().equals(packageName)) {
    133                 return info;
    134             }
    135         }
    136         return null;
    137     }
    138 
    139     private void addAssistServices() {
    140         PackageManager pm = getContext().getPackageManager();
    141 
    142         List<ResolveInfo> services = pm.queryIntentServices(
    143                 new Intent(VoiceInteractionService.SERVICE_INTERFACE),
    144                 PackageManager.GET_META_DATA);
    145         for (int i = 0; i < services.size(); ++i) {
    146             ResolveInfo resolveInfo = services.get(i);
    147             VoiceInteractionServiceInfo voiceInteractionServiceInfo =
    148                     new VoiceInteractionServiceInfo(pm, resolveInfo.serviceInfo);
    149             if (!voiceInteractionServiceInfo.getSupportsAssist()) {
    150                 continue;
    151             }
    152 
    153             mAvailableAssistants.add(new Info(
    154                     new ComponentName(resolveInfo.serviceInfo.packageName,
    155                                       resolveInfo.serviceInfo.name),
    156                     voiceInteractionServiceInfo));
    157         }
    158     }
    159 
    160     private void addAssistActivities() {
    161         PackageManager pm = getContext().getPackageManager();
    162 
    163         List<ResolveInfo> activities = pm.queryIntentActivities(
    164                 new Intent(Intent.ACTION_ASSIST),
    165                 PackageManager.MATCH_DEFAULT_ONLY);
    166         for (int i = 0; i < activities.size(); ++i) {
    167             ResolveInfo resolveInfo = activities.get(i);
    168             mAvailableAssistants.add(new Info(
    169                     new ComponentName(resolveInfo.activityInfo.packageName,
    170                                       resolveInfo.activityInfo.name)));
    171         }
    172     }
    173 
    174     public ComponentName getCurrentAssist() {
    175         return mAssistUtils.getAssistComponentForUser(UserHandle.myUserId());
    176     }
    177 
    178     public void refreshAssistApps() {
    179         mAvailableAssistants.clear();
    180         addAssistServices();
    181         addAssistActivities();
    182 
    183         List<String> packages = new ArrayList<>();
    184         for (int i = 0; i < mAvailableAssistants.size(); ++i) {
    185             String packageName = mAvailableAssistants.get(i).component.getPackageName();
    186             if (packages.contains(packageName)) {
    187                 // A service appears before an activity thus overrides it if from the same package.
    188                 continue;
    189             }
    190             packages.add(packageName);
    191         }
    192 
    193         ComponentName currentAssist = getCurrentAssist();
    194         setPackageNames(packages.toArray(new String[packages.size()]),
    195                 currentAssist == null ? null : currentAssist.getPackageName());
    196     }
    197 
    198     private static class Info {
    199         public final ComponentName component;
    200         public final VoiceInteractionServiceInfo voiceInteractionServiceInfo;
    201 
    202         Info(ComponentName component) {
    203             this.component = component;
    204             this.voiceInteractionServiceInfo = null;
    205         }
    206 
    207         Info(ComponentName component, VoiceInteractionServiceInfo voiceInteractionServiceInfo) {
    208             this.component = component;
    209             this.voiceInteractionServiceInfo = voiceInteractionServiceInfo;
    210         }
    211 
    212         public boolean isVoiceInteractionService() {
    213             return voiceInteractionServiceInfo != null;
    214         }
    215     }
    216 }
    217