Deprecate AppListPreference and AppListPrefWithSettings

- Convert ManageAssist into DashboardFragment
- Convert default assist pref to DefaultAppPickerFragment
- Add PreferenceController for each pref
- Add tests

Bug: 35203386
Test: make RunSettingsRoboTests

Change-Id: I0350a06cae7457809fb261e2d8ec99eda80cc50a
This commit is contained in:
Fan Zhang
2017-02-16 15:00:53 -08:00
parent aba2c95ae0
commit dfce62c507
39 changed files with 1787 additions and 946 deletions

View File

@@ -1,212 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.settings.applications;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.os.Bundle;
import android.os.Handler;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import com.android.internal.app.AssistUtils;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.gestures.AssistGestureFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.voice.VoiceInputListPreference;
/**
* Settings screen to manage everything about assist.
*/
public class ManageAssist extends SettingsPreferenceFragment
implements Preference.OnPreferenceChangeListener {
private static final String KEY_DEFAULT_ASSIST = "default_assist";
private static final String KEY_ASSIST_GESTURE = "gesture_assist";
private static final String KEY_CONTEXT = "context";
private static final String KEY_SCREENSHOT = "screenshot";
private static final String KEY_VOICE_INPUT = "voice_input_settings";
private static final String KEY_FLASH = "flash";
private DefaultAssistPreference mDefaultAssitPref;
private SwitchPreference mContextPref;
private SwitchPreference mScreenshotPref;
private SwitchPreference mFlashPref;
private VoiceInputListPreference mVoiceInputPref;
private Handler mHandler = new Handler();
private Preference mAssistGesturePref;
private AssistGestureFeatureProvider mAssistGestureFeatureProvider;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.manage_assist);
mDefaultAssitPref = (DefaultAssistPreference) findPreference(KEY_DEFAULT_ASSIST);
mDefaultAssitPref.setOnPreferenceChangeListener(this);
mAssistGesturePref = findPreference(KEY_ASSIST_GESTURE);
mAssistGestureFeatureProvider =
FeatureFactory.getFactory(getContext()).getAssistGestureFeatureProvider();
mContextPref = (SwitchPreference) findPreference(KEY_CONTEXT);
mContextPref.setChecked(Settings.Secure.getInt(getContentResolver(),
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1) != 0);
mContextPref.setOnPreferenceChangeListener(this);
mScreenshotPref = (SwitchPreference) findPreference(KEY_SCREENSHOT);
mScreenshotPref.setOnPreferenceChangeListener(this);
mFlashPref = (SwitchPreference) findPreference(KEY_FLASH);
mFlashPref.setOnPreferenceChangeListener(this);
mFooterPreferenceMixin.createFooterPreference()
.setTitle(R.string.assist_footer);
mVoiceInputPref = (VoiceInputListPreference) findPreference(KEY_VOICE_INPUT);
updateUi();
}
@Override
public int getMetricsCategory() {
return MetricsEvent.APPLICATIONS_MANAGE_ASSIST;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == mContextPref) {
Settings.Secure.putInt(getContentResolver(), Settings.Secure.ASSIST_STRUCTURE_ENABLED,
(boolean) newValue ? 1 : 0);
mHandler.post(() -> {
guardFlashPref();
});
return true;
}
if (preference == mScreenshotPref) {
Settings.Secure.putInt(getContentResolver(), Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
(boolean) newValue ? 1 : 0);
return true;
}
if (preference == mFlashPref) {
Settings.Secure.putInt(getContentResolver(), Settings.Secure.ASSIST_DISCLOSURE_ENABLED,
(boolean) newValue ? 1 : 0);
return true;
}
if (preference == mDefaultAssitPref) {
String newAssitPackage = (String)newValue;
if (newAssitPackage == null ||
newAssitPackage.contentEquals(DefaultAssistPreference.ITEM_NONE_VALUE)) {
setDefaultAssist(DefaultAssistPreference.ITEM_NONE_VALUE);
return false;
}
final String currentPackage = mDefaultAssitPref.getValue();
if (currentPackage == null || !newAssitPackage.contentEquals(currentPackage)) {
confirmNewAssist(newAssitPackage);
}
return false;
}
return false;
}
private void guardFlashPref() {
ComponentName assistant = mDefaultAssitPref.getCurrentAssist();
boolean isContextChecked = mContextPref.isChecked();
boolean willShowFlash = AssistUtils.shouldDisclose(getContext(), assistant);
boolean isSystemAssistant = AssistUtils.isPreinstalledAssistant(getContext(), assistant);
mFlashPref.setEnabled(isContextChecked && isSystemAssistant);
mFlashPref.setChecked(willShowFlash);
}
private void updateUi() {
mDefaultAssitPref.refreshAssistApps();
mVoiceInputPref.refreshVoiceInputs();
final ComponentName currentAssist = mDefaultAssitPref.getCurrentAssist();
final boolean hasAssistant = currentAssist != null;
if (hasAssistant) {
getPreferenceScreen().addPreference(mContextPref);
getPreferenceScreen().addPreference(mScreenshotPref);
} else {
getPreferenceScreen().removePreference(mContextPref);
getPreferenceScreen().removePreference(mScreenshotPref);
getPreferenceScreen().removePreference(mFlashPref);
}
if (hasAssistant && mAssistGestureFeatureProvider.isSupported(getContext())) {
getPreferenceScreen().addPreference(mAssistGesturePref);
} else {
getPreferenceScreen().removePreference(mAssistGesturePref);
}
if (hasAssistant && AssistUtils.allowDisablingAssistDisclosure(getContext())) {
getPreferenceScreen().addPreference(mFlashPref);
} else {
getPreferenceScreen().removePreference(mFlashPref);
}
if (isCurrentAssistVoiceService()) {
getPreferenceScreen().removePreference(mVoiceInputPref);
} else {
getPreferenceScreen().addPreference(mVoiceInputPref);
mVoiceInputPref.setAssistRestrict(currentAssist);
}
guardFlashPref();
}
private boolean isCurrentAssistVoiceService() {
ComponentName currentAssist = mDefaultAssitPref.getCurrentAssist();
ComponentName activeService = mVoiceInputPref.getCurrentService();
return currentAssist == null && activeService == null ||
currentAssist != null && currentAssist.equals(activeService);
}
private void confirmNewAssist(final String newAssitPackage) {
final int selected = mDefaultAssitPref.findIndexOfValue(newAssitPackage);
final CharSequence appLabel = mDefaultAssitPref.getEntries()[selected];
final String title = getString(R.string.assistant_security_warning_title, appLabel);
final String message = getString(R.string.assistant_security_warning, appLabel);
final DialogInterface.OnClickListener onAgree = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
setDefaultAssist(newAssitPackage);
}
};
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle(title)
.setMessage(message)
.setCancelable(true)
.setPositiveButton(R.string.assistant_security_warning_agree, onAgree)
.setNegativeButton(R.string.assistant_security_warning_disagree, null);
AlertDialog dialog = builder.create();
dialog.show();
}
private void setDefaultAssist(String assistPackage) {
mDefaultAssitPref.setValue(assistPackage);
updateUi();
}
}

View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications.assist;
import android.content.Context;
import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.TwoStatePreference;
import com.android.internal.app.AssistUtils;
import com.android.settings.core.PreferenceController;
import com.android.settings.core.lifecycle.Lifecycle;
import com.android.settings.core.lifecycle.LifecycleObserver;
import com.android.settings.core.lifecycle.events.OnPause;
import com.android.settings.core.lifecycle.events.OnResume;
import java.util.Arrays;
import java.util.List;
public class AssistContextPreferenceController extends PreferenceController
implements Preference.OnPreferenceChangeListener, LifecycleObserver, OnResume, OnPause {
private static final String KEY_CONTEXT = "context";
private final AssistUtils mAssistUtils;
private final SettingObserver mSettingObserver;
private Preference mPreference;
private PreferenceScreen mScreen;
public AssistContextPreferenceController(Context context, Lifecycle lifecycle) {
super(context);
mAssistUtils = new AssistUtils(context);
mSettingObserver = new SettingObserver();
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public boolean isAvailable() {
return mAssistUtils.getAssistComponentForUser(UserHandle.myUserId()) != null;
}
@Override
public String getPreferenceKey() {
return KEY_CONTEXT;
}
@Override
public void displayPreference(PreferenceScreen screen) {
mScreen = screen;
mPreference = screen.findPreference(getPreferenceKey());
super.displayPreference(screen);
}
@Override
public void onResume() {
mSettingObserver.register(mContext.getContentResolver(), true);
updatePreference();
}
@Override
public void updateState(Preference preference) {
updatePreference();
}
@Override
public void onPause() {
mSettingObserver.register(mContext.getContentResolver(), false);
}
private void updatePreference() {
if (mPreference == null || !(mPreference instanceof TwoStatePreference)) {
return;
}
if (isAvailable()) {
if (mScreen.findPreference(getPreferenceKey()) == null) {
// add it if it's not on scree
mScreen.addPreference(mPreference);
}
} else {
mScreen.removePreference(mPreference);
}
((TwoStatePreference) mPreference).setChecked(isChecked(mContext));
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ASSIST_STRUCTURE_ENABLED,
(boolean) newValue ? 1 : 0);
return true;
}
static boolean isChecked(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1) != 0;
}
class SettingObserver extends AssistSettingObserver {
private final Uri URI =
Settings.Secure.getUriFor(Settings.Secure.ASSIST_STRUCTURE_ENABLED);
@Override
protected List<Uri> getSettingUris() {
return Arrays.asList(URI);
}
@Override
public void onSettingChange() {
updatePreference();
}
}
}

View File

@@ -0,0 +1,158 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications.assist;
import android.content.ComponentName;
import android.content.Context;
import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.TwoStatePreference;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.AssistUtils;
import com.android.settings.core.PreferenceController;
import com.android.settings.core.lifecycle.Lifecycle;
import com.android.settings.core.lifecycle.LifecycleObserver;
import com.android.settings.core.lifecycle.events.OnPause;
import com.android.settings.core.lifecycle.events.OnResume;
import java.util.Arrays;
import java.util.List;
public class AssistFlashScreenPreferenceController extends PreferenceController
implements Preference.OnPreferenceChangeListener, LifecycleObserver, OnResume, OnPause {
private static final String KEY_FLASH = "flash";
private final AssistUtils mAssistUtils;
private final SettingObserver mSettingObserver;
private PreferenceScreen mScreen;
private Preference mPreference;
public AssistFlashScreenPreferenceController(Context context, Lifecycle lifecycle) {
super(context);
mAssistUtils = new AssistUtils(context);
mSettingObserver = new SettingObserver();
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public boolean isAvailable() {
return getCurrentAssist() != null && allowDisablingAssistDisclosure();
}
@Override
public String getPreferenceKey() {
return KEY_FLASH;
}
@Override
public void displayPreference(PreferenceScreen screen) {
mScreen = screen;
mPreference = screen.findPreference(getPreferenceKey());
super.displayPreference(screen);
}
@Override
public void onResume() {
mSettingObserver.register(mContext.getContentResolver(), true);
updatePreference();
}
@Override
public void updateState(Preference preference) {
updatePreference();
}
@Override
public void onPause() {
mSettingObserver.register(mContext.getContentResolver(), false);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ASSIST_DISCLOSURE_ENABLED,
(boolean) newValue ? 1 : 0);
return true;
}
private void updatePreference() {
if (mPreference == null || !(mPreference instanceof TwoStatePreference)) {
return;
}
if (isAvailable()) {
if (mScreen.findPreference(getPreferenceKey()) == null) {
// add it if it's not on scree
mScreen.addPreference(mPreference);
}
} else {
mScreen.removePreference(mPreference);
}
ComponentName assistant = getCurrentAssist();
boolean isContextChecked = AssistContextPreferenceController.isChecked(mContext);
mPreference.setEnabled(isContextChecked && isPreInstalledAssistant(assistant));
((TwoStatePreference) mPreference).setChecked(willShowFlash(assistant));
}
@VisibleForTesting
boolean willShowFlash(ComponentName assistant) {
return AssistUtils.shouldDisclose(mContext, assistant);
}
@VisibleForTesting
boolean isPreInstalledAssistant(ComponentName assistant) {
return AssistUtils.isPreinstalledAssistant(mContext, assistant);
}
@VisibleForTesting
boolean allowDisablingAssistDisclosure() {
return AssistUtils.allowDisablingAssistDisclosure(mContext);
}
private ComponentName getCurrentAssist() {
return mAssistUtils.getAssistComponentForUser(UserHandle.myUserId());
}
class SettingObserver extends AssistSettingObserver {
private final Uri URI =
Settings.Secure.getUriFor(Settings.Secure.ASSIST_DISCLOSURE_ENABLED);
private final Uri CONTEXT_URI =
Settings.Secure.getUriFor(Settings.Secure.ASSIST_STRUCTURE_ENABLED);
@Override
protected List<Uri> getSettingUris() {
return Arrays.asList(URI, CONTEXT_URI);
}
@Override
public void onSettingChange() {
updatePreference();
}
}
}

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications.assist;
import android.content.Context;
import android.net.Uri;
import android.os.UserHandle;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.support.v7.preference.TwoStatePreference;
import com.android.internal.app.AssistUtils;
import com.android.settings.core.PreferenceController;
import com.android.settings.core.lifecycle.Lifecycle;
import com.android.settings.core.lifecycle.LifecycleObserver;
import com.android.settings.core.lifecycle.events.OnPause;
import com.android.settings.core.lifecycle.events.OnResume;
import java.util.Arrays;
import java.util.List;
public class AssistScreenshotPreferenceController extends PreferenceController
implements Preference.OnPreferenceChangeListener, LifecycleObserver, OnResume, OnPause {
private static final String KEY_SCREENSHOT = "screenshot";
private final AssistUtils mAssistUtils;
private final SettingObserver mSettingObserver;
private PreferenceScreen mScreen;
private Preference mPreference;
public AssistScreenshotPreferenceController(Context context, Lifecycle lifecycle) {
super(context);
mAssistUtils = new AssistUtils(context);
mSettingObserver = new SettingObserver();
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public boolean isAvailable() {
return mAssistUtils.getAssistComponentForUser(UserHandle.myUserId()) != null;
}
@Override
public void displayPreference(PreferenceScreen screen) {
mScreen = screen;
mPreference = screen.findPreference(getPreferenceKey());
super.displayPreference(screen);
}
@Override
public String getPreferenceKey() {
return KEY_SCREENSHOT;
}
@Override
public void onResume() {
mSettingObserver.register(mContext.getContentResolver(), true);
updatePreference();
}
@Override
public void updateState(Preference preference) {
updatePreference();
}
@Override
public void onPause() {
mSettingObserver.register(mContext.getContentResolver(), false);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
(boolean) newValue ? 1 : 0);
return true;
}
private void updatePreference() {
if (mPreference == null || !(mPreference instanceof TwoStatePreference)) {
return;
}
if (isAvailable()) {
if (mScreen.findPreference(getPreferenceKey()) == null) {
// add it if it's not on scree
mScreen.addPreference(mPreference);
}
} else {
mScreen.removePreference(mPreference);
}
final boolean checked = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1) != 0;
((TwoStatePreference) mPreference).setChecked(checked);
final boolean contextChecked = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1) != 0;
mPreference.setEnabled(contextChecked);
}
class SettingObserver extends AssistSettingObserver {
private final Uri URI =
Settings.Secure.getUriFor(Settings.Secure.ASSIST_SCREENSHOT_ENABLED);
private final Uri CONTEXT_URI =
Settings.Secure.getUriFor(Settings.Secure.ASSIST_STRUCTURE_ENABLED);
@Override
protected List<Uri> getSettingUris() {
return Arrays.asList(URI, CONTEXT_URI);
}
@Override
public void onSettingChange() {
updatePreference();
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications.assist;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import java.util.List;
public abstract class AssistSettingObserver extends ContentObserver {
private final Uri ASSIST_URI =
Settings.Secure.getUriFor(Settings.Secure.ASSISTANT);
public AssistSettingObserver() {
super(new Handler());
}
public void register(ContentResolver cr, boolean register) {
if (register) {
cr.registerContentObserver(ASSIST_URI, false, this);
final List<Uri> settingUri = getSettingUris();
if (settingUri != null) {
for (Uri uri : settingUri)
cr.registerContentObserver(uri, false, this);
}
} else {
cr.unregisterContentObserver(this);
}
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
boolean shouldUpdatePreference = false;
final List<Uri> settingUri = getSettingUris();
if (ASSIST_URI.equals(uri) || (settingUri != null && settingUri.contains(uri))) {
shouldUpdatePreference = true;
}
if (shouldUpdatePreference) {
onSettingChange();
}
}
protected abstract List<Uri> getSettingUris();
public abstract void onSettingChange();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -11,49 +11,105 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
* limitations under the License.
*/
package com.android.settings.applications;
package com.android.settings.applications.assist;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
import android.speech.RecognitionService;
import android.util.AttributeSet;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.app.AssistUtils;
import com.android.settings.AppListPreferenceWithSettings;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
import com.android.settings.applications.defaultapps.DefaultAppInfo;
import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
import java.util.ArrayList;
import java.util.List;
public class DefaultAssistPreference extends AppListPreferenceWithSettings {
private static final String TAG = DefaultAssistPreference.class.getSimpleName();
public class DefaultAssistPicker extends DefaultAppPickerFragment {
private static final String TAG = "DefaultAssistPicker";
private static final Intent ASSIST_SERVICE_PROBE =
new Intent(VoiceInteractionService.SERVICE_INTERFACE);
private static final Intent ASSIST_ACTIVITY_PROBE =
new Intent(Intent.ACTION_ASSIST);
private final List<Info> mAvailableAssistants = new ArrayList<>();
private final AssistUtils mAssistUtils;
private AssistUtils mAssistUtils;
public DefaultAssistPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setShowItemNone(true);
setDialogTitle(R.string.choose_assist_title);
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DEFAULT_ASSIST_PICKER;
}
@Override
protected boolean shouldShowItemNone() {
return true;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mAssistUtils = new AssistUtils(context);
}
@Override
protected boolean persistString(String value) {
final Info info = findAssistantByPackageName(value);
protected List<DefaultAppInfo> getCandidates() {
mAvailableAssistants.clear();
addAssistServices();
addAssistActivities();
final List<String> packages = new ArrayList<>();
final List<DefaultAppInfo> candidates = new ArrayList<>();
for (Info info : mAvailableAssistants) {
final String packageName = info.component.getPackageName();
if (packages.contains(packageName)) {
// A service appears before an activity thus overrides it if from the same package.
continue;
}
packages.add(packageName);
candidates.add(new DefaultAppInfo(mUserId, info.component));
}
return candidates;
}
@Override
protected String getDefaultAppKey() {
final ComponentName cn = getCurrentAssist();
if (cn != null) {
return new DefaultAppInfo(mUserId, cn).getKey();
}
return null;
}
@Override
protected String getConfirmationMessage(DefaultAppInfo appInfo) {
if (appInfo == null) {
return null;
}
return getContext().getString(R.string.assistant_security_warning,
appInfo.loadLabel(mPm.getPackageManager()));
}
@Override
protected boolean setDefaultAppKey(String key) {
if (TextUtils.isEmpty(key)) {
setAssistNone();
return true;
}
ComponentName cn = ComponentName.unflattenFromString(key);
final Info info = findAssistantByPackageName(cn.getPackageName());
if (info == null) {
setAssistNone();
return true;
@@ -67,20 +123,60 @@ public class DefaultAssistPreference extends AppListPreferenceWithSettings {
return true;
}
public ComponentName getCurrentAssist() {
return mAssistUtils.getAssistComponentForUser(mUserId);
}
private void addAssistServices() {
final PackageManager pm = mPm.getPackageManager();
final List<ResolveInfo> services = pm.queryIntentServices(
ASSIST_SERVICE_PROBE, PackageManager.GET_META_DATA);
for (ResolveInfo resolveInfo : services) {
VoiceInteractionServiceInfo voiceInteractionServiceInfo =
new VoiceInteractionServiceInfo(pm, resolveInfo.serviceInfo);
if (!voiceInteractionServiceInfo.getSupportsAssist()) {
continue;
}
mAvailableAssistants.add(new Info(
new ComponentName(resolveInfo.serviceInfo.packageName,
resolveInfo.serviceInfo.name),
voiceInteractionServiceInfo));
}
}
private void addAssistActivities() {
final PackageManager pm = mPm.getPackageManager();
final List<ResolveInfo> activities = pm.queryIntentActivities(
ASSIST_ACTIVITY_PROBE, PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo resolveInfo : activities) {
mAvailableAssistants.add(new Info(
new ComponentName(resolveInfo.activityInfo.packageName,
resolveInfo.activityInfo.name)));
}
}
private Info findAssistantByPackageName(String packageName) {
for (Info info : mAvailableAssistants) {
if (TextUtils.equals(info.component.getPackageName(), packageName)) {
return info;
}
}
return null;
}
private void setAssistNone() {
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.ASSISTANT, ITEM_NONE_VALUE);
Settings.Secure.ASSISTANT, "");
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.VOICE_INTERACTION_SERVICE, "");
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer());
setSummary(getContext().getText(R.string.default_assist_none));
setSettingsComponent(null);
}
private void setAssistService(Info serviceInfo) {
final String serviceComponentName = serviceInfo.component.flattenToShortString();
final String serviceComponentName = serviceInfo.component.
flattenToShortString();
final String serviceRecognizerName = new ComponentName(
serviceInfo.component.getPackageName(),
serviceInfo.voiceInteractionServiceInfo.getRecognitionService())
@@ -92,13 +188,6 @@ public class DefaultAssistPreference extends AppListPreferenceWithSettings {
Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName);
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName);
setSummary(getEntry());
final String settingsActivity =
serviceInfo.voiceInteractionServiceInfo.getSettingsActivity();
setSettingsComponent(settingsActivity == null ?
null :
new ComponentName(serviceInfo.component.getPackageName(), settingsActivity));
}
private void setAssistActivity(Info activityInfo) {
@@ -108,13 +197,10 @@ public class DefaultAssistPreference extends AppListPreferenceWithSettings {
Settings.Secure.VOICE_INTERACTION_SERVICE, "");
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer());
setSummary(getEntry());
setSettingsComponent(null);
}
private String getDefaultRecognizer() {
ResolveInfo resolveInfo = getContext().getPackageManager().resolveService(
final ResolveInfo resolveInfo = mPm.getPackageManager().resolveService(
new Intent(RecognitionService.SERVICE_INTERFACE),
PackageManager.GET_META_DATA);
if (resolveInfo == null || resolveInfo.serviceInfo == null) {
@@ -126,76 +212,7 @@ public class DefaultAssistPreference extends AppListPreferenceWithSettings {
resolveInfo.serviceInfo.name).flattenToShortString();
}
private Info findAssistantByPackageName(String packageName) {
for (int i = 0; i < mAvailableAssistants.size(); ++i) {
Info info = mAvailableAssistants.get(i);
if (info.component.getPackageName().equals(packageName)) {
return info;
}
}
return null;
}
private void addAssistServices() {
PackageManager pm = getContext().getPackageManager();
List<ResolveInfo> services = pm.queryIntentServices(
new Intent(VoiceInteractionService.SERVICE_INTERFACE),
PackageManager.GET_META_DATA);
for (int i = 0; i < services.size(); ++i) {
ResolveInfo resolveInfo = services.get(i);
VoiceInteractionServiceInfo voiceInteractionServiceInfo =
new VoiceInteractionServiceInfo(pm, resolveInfo.serviceInfo);
if (!voiceInteractionServiceInfo.getSupportsAssist()) {
continue;
}
mAvailableAssistants.add(new Info(
new ComponentName(resolveInfo.serviceInfo.packageName,
resolveInfo.serviceInfo.name),
voiceInteractionServiceInfo));
}
}
private void addAssistActivities() {
PackageManager pm = getContext().getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(
new Intent(Intent.ACTION_ASSIST),
PackageManager.MATCH_DEFAULT_ONLY);
for (int i = 0; i < activities.size(); ++i) {
ResolveInfo resolveInfo = activities.get(i);
mAvailableAssistants.add(new Info(
new ComponentName(resolveInfo.activityInfo.packageName,
resolveInfo.activityInfo.name)));
}
}
public ComponentName getCurrentAssist() {
return mAssistUtils.getAssistComponentForUser(UserHandle.myUserId());
}
public void refreshAssistApps() {
mAvailableAssistants.clear();
addAssistServices();
addAssistActivities();
List<String> packages = new ArrayList<>();
for (int i = 0; i < mAvailableAssistants.size(); ++i) {
String packageName = mAvailableAssistants.get(i).component.getPackageName();
if (packages.contains(packageName)) {
// A service appears before an activity thus overrides it if from the same package.
continue;
}
packages.add(packageName);
}
ComponentName currentAssist = getCurrentAssist();
setPackageNames(packages.toArray(new String[packages.size()]),
currentAssist == null ? null : currentAssist.getPackageName());
}
private static class Info {
static class Info {
public final ComponentName component;
public final VoiceInteractionServiceInfo voiceInteractionServiceInfo;

View File

@@ -0,0 +1,88 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications.assist;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
import com.android.internal.app.AssistUtils;
import com.android.settings.applications.defaultapps.DefaultAppInfo;
import com.android.settings.applications.defaultapps.DefaultAppPreferenceController;
import java.util.List;
public class DefaultAssistPreferenceController extends DefaultAppPreferenceController {
private static final String KEY_DEFAULT_ASSIST = "default_assist";
private AssistUtils mAssistUtils;
public DefaultAssistPreferenceController(Context context) {
super(context);
mAssistUtils = new AssistUtils(context);
}
@Override
protected Intent getSettingIntent(DefaultAppInfo info) {
final ComponentName cn = mAssistUtils.getAssistComponentForUser(mUserId);
if (cn == null) {
return null;
}
final Intent probe = new Intent(VoiceInteractionService.SERVICE_INTERFACE)
.setPackage(cn.getPackageName());
final PackageManager pm = mPackageManager.getPackageManager();
final List<ResolveInfo> services = pm.queryIntentServices(probe, PackageManager
.GET_META_DATA);
if (services == null || services.isEmpty()) {
return null;
}
final ResolveInfo resolveInfo = services.get(0);
final VoiceInteractionServiceInfo voiceInfo =
new VoiceInteractionServiceInfo(pm, resolveInfo.serviceInfo);
if (!voiceInfo.getSupportsAssist()) {
return null;
}
final String activity = voiceInfo.getSettingsActivity();
return new Intent(Intent.ACTION_MAIN)
.setComponent(new ComponentName(cn.getPackageName(), activity));
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return KEY_DEFAULT_ASSIST;
}
@Override
protected DefaultAppInfo getDefaultAppInfo() {
final ComponentName cn = mAssistUtils.getAssistComponentForUser(mUserId);
if (cn == null) {
return null;
}
return new DefaultAppInfo(mUserId, cn);
}
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications.assist;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.provider.Settings;
import android.text.TextUtils;
import com.android.internal.app.AssistUtils;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.applications.defaultapps.DefaultAppInfo;
import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
import java.util.ArrayList;
import java.util.List;
public class DefaultVoiceInputPicker extends DefaultAppPickerFragment {
private VoiceInputHelper mHelper;
private AssistUtils mAssistUtils;
private String mAssistRestrict;
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.DEFAULT_VOICE_INPUT_PICKER;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mAssistUtils = new AssistUtils(context);
mHelper = new VoiceInputHelper(context);
mHelper.buildUi();
final ComponentName assist = getCurrentAssist();
if (isCurrentAssistVoiceService(assist, getCurrentService(mHelper))) {
mAssistRestrict = assist.flattenToShortString();
}
}
@Override
protected List<VoiceInputDefaultAppInfo> getCandidates() {
final List<VoiceInputDefaultAppInfo> candidates = new ArrayList<>();
boolean hasEnabled = true;
for (VoiceInputHelper.InteractionInfo info : mHelper.mAvailableInteractionInfos) {
final boolean enabled = TextUtils.equals(info.key, mAssistRestrict);
hasEnabled |= enabled;
candidates.add(new VoiceInputDefaultAppInfo(mUserId, info, enabled));
}
final boolean assistIsService = !hasEnabled;
for (VoiceInputHelper.RecognizerInfo info : mHelper.mAvailableRecognizerInfos) {
final boolean enabled = !assistIsService;
candidates.add(new VoiceInputDefaultAppInfo(mUserId, info, enabled));
}
return candidates;
}
@Override
protected String getDefaultAppKey() {
final ComponentName currentService = getCurrentService(mHelper);
if (currentService == null) {
return null;
}
return currentService.flattenToShortString();
}
@Override
protected boolean setDefaultAppKey(String value) {
for (VoiceInputHelper.InteractionInfo info : mHelper.mAvailableInteractionInfos) {
if (TextUtils.equals(value, info.key)) {
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.VOICE_INTERACTION_SERVICE, value);
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.VOICE_RECOGNITION_SERVICE,
new ComponentName(info.service.packageName,
info.serviceInfo.getRecognitionService())
.flattenToShortString());
return true;
}
}
for (VoiceInputHelper.RecognizerInfo info : mHelper.mAvailableRecognizerInfos) {
if (TextUtils.equals(value, info.key)) {
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.VOICE_INTERACTION_SERVICE, "");
Settings.Secure.putString(getContext().getContentResolver(),
Settings.Secure.VOICE_RECOGNITION_SERVICE, value);
return true;
}
}
return true;
}
public static ComponentName getCurrentService(VoiceInputHelper helper) {
if (helper.mCurrentVoiceInteraction != null) {
return helper.mCurrentVoiceInteraction;
} else if (helper.mCurrentRecognizer != null) {
return helper.mCurrentRecognizer;
} else {
return null;
}
}
private ComponentName getCurrentAssist() {
return mAssistUtils.getAssistComponentForUser(mUserId);
}
public static boolean isCurrentAssistVoiceService(ComponentName currentAssist,
ComponentName currentVoiceService) {
return currentAssist == null && currentVoiceService == null ||
currentAssist != null && currentAssist.equals(currentVoiceService);
}
public static class VoiceInputDefaultAppInfo extends DefaultAppInfo {
public VoiceInputHelper.BaseInfo mInfo;
public VoiceInputDefaultAppInfo(int userId, VoiceInputHelper.BaseInfo info,
boolean enabled) {
super(userId, info.componentName, null /* summary */, enabled);
mInfo = info;
}
@Override
public String getKey() {
return mInfo.key;
}
@Override
public CharSequence loadLabel(PackageManager pm) {
if (mInfo instanceof VoiceInputHelper.InteractionInfo) {
return mInfo.appLabel;
} else {
return mInfo.label;
}
}
public Intent getSettingIntent() {
if (mInfo.settings == null) {
return null;
}
return new Intent(Intent.ACTION_MAIN).setComponent(mInfo.settings);
}
}
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications.assist;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import com.android.internal.app.AssistUtils;
import com.android.settings.applications.defaultapps.DefaultAppInfo;
import com.android.settings.applications.defaultapps.DefaultAppPreferenceController;
import com.android.settings.core.lifecycle.Lifecycle;
import com.android.settings.core.lifecycle.LifecycleObserver;
import com.android.settings.core.lifecycle.events.OnPause;
import com.android.settings.core.lifecycle.events.OnResume;
import java.util.List;
public class DefaultVoiceInputPreferenceController extends DefaultAppPreferenceController
implements LifecycleObserver, OnResume, OnPause {
private static final String KEY_VOICE_INPUT = "voice_input_settings";
private VoiceInputHelper mHelper;
private AssistUtils mAssistUtils;
private PreferenceScreen mScreen;
private Preference mPreference;
private SettingObserver mSettingObserver;
public DefaultVoiceInputPreferenceController(Context context, Lifecycle lifecycle) {
super(context);
mSettingObserver = new SettingObserver();
mAssistUtils = new AssistUtils(context);
mHelper = new VoiceInputHelper(context);
mHelper.buildUi();
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public boolean isAvailable() {
// If current assist is also voice service, don't show voice preference.
final ComponentName currentVoiceService =
DefaultVoiceInputPicker.getCurrentService(mHelper);
final ComponentName currentAssist =
mAssistUtils.getAssistComponentForUser(mUserId);
return !DefaultVoiceInputPicker.isCurrentAssistVoiceService(
currentAssist, currentVoiceService);
}
@Override
public String getPreferenceKey() {
return KEY_VOICE_INPUT;
}
@Override
public void displayPreference(PreferenceScreen screen) {
mScreen = screen;
mPreference = screen.findPreference(getPreferenceKey());
super.displayPreference(screen);
}
@Override
public void onResume() {
mSettingObserver.register(mContext.getContentResolver(), true);
updatePreference();
}
@Override
public void updateState(Preference preference) {
super.updateState(mPreference);
updatePreference();
}
@Override
public void onPause() {
mSettingObserver.register(mContext.getContentResolver(), false);
}
@Override
protected DefaultAppInfo getDefaultAppInfo() {
final String defaultKey = getDefaultAppKey();
if (defaultKey == null) {
return null;
}
for (VoiceInputHelper.InteractionInfo info : mHelper.mAvailableInteractionInfos) {
if (TextUtils.equals(defaultKey, info.key)) {
return new DefaultVoiceInputPicker.VoiceInputDefaultAppInfo(
mUserId, info, true /* enabled */);
}
}
for (VoiceInputHelper.RecognizerInfo info : mHelper.mAvailableRecognizerInfos) {
if (TextUtils.equals(defaultKey, info.key)) {
return new DefaultVoiceInputPicker.VoiceInputDefaultAppInfo(
mUserId, info, true /* enabled */);
}
}
return null;
}
@Override
protected Intent getSettingIntent(DefaultAppInfo info) {
final DefaultAppInfo appInfo = getDefaultAppInfo();
if (appInfo == null
|| !(appInfo instanceof DefaultVoiceInputPicker.VoiceInputDefaultAppInfo)) {
return null;
}
return ((DefaultVoiceInputPicker.VoiceInputDefaultAppInfo) appInfo).getSettingIntent();
}
private void updatePreference() {
if (mPreference == null) {
return;
}
mHelper.buildUi();
if (isAvailable()) {
if (mScreen.findPreference(getPreferenceKey()) == null) {
// add it if it's not on scree
mScreen.addPreference(mPreference);
}
} else {
mScreen.removePreference(mPreference);
}
}
private String getDefaultAppKey() {
final ComponentName currentService = DefaultVoiceInputPicker.getCurrentService(mHelper);
if (currentService == null) {
return null;
}
return currentService.flattenToShortString();
}
class SettingObserver extends AssistSettingObserver {
@Override
protected List<Uri> getSettingUris() {
return null;
}
@Override
public void onSettingChange() {
updatePreference();
}
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications.assist;
import android.content.Context;
import com.android.settings.core.PreferenceController;
import com.android.settings.gestures.AssistGestureFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
public class GestureAssistPreferenceController extends PreferenceController {
private static final String KEY_ASSIST_GESTURE = "gesture_assist";
private AssistGestureFeatureProvider mFeatureProvider;
public GestureAssistPreferenceController(Context context) {
super(context);
mFeatureProvider = FeatureFactory.getFactory(context)
.getAssistGestureFeatureProvider();
}
@Override
public boolean isAvailable() {
return mFeatureProvider.isSupported(mContext);
}
@Override
public String getPreferenceKey() {
return KEY_ASSIST_GESTURE;
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications.assist;
import android.content.Context;
import android.provider.SearchIndexableResource;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.core.PreferenceController;
import com.android.settings.core.lifecycle.Lifecycle;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Settings screen to manage everything about assist.
*/
public class ManageAssist extends DashboardFragment {
private static final String TAG = "ManageAssist";
@Override
protected String getLogTag() {
return TAG;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.manage_assist;
}
@Override
protected List<PreferenceController> getPreferenceControllers(Context context) {
final Lifecycle lifecycle = getLifecycle();
final List<PreferenceController> controllers = new ArrayList<>();
controllers.add(new DefaultAssistPreferenceController(context));
controllers.add(new GestureAssistPreferenceController(context));
controllers.add(new AssistContextPreferenceController(context, lifecycle));
controllers.add(new AssistScreenshotPreferenceController(context, lifecycle));
controllers.add(new AssistFlashScreenPreferenceController(context, lifecycle));
controllers.add(new DefaultVoiceInputPreferenceController(context, lifecycle));
return controllers;
}
@Override
public int getMetricsCategory() {
return MetricsEvent.APPLICATIONS_MANAGE_ASSIST;
}
@Override
public void onResume() {
super.onResume();
mFooterPreferenceMixin.createFooterPreference()
.setTitle(R.string.assist_footer);
}
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
boolean enabled) {
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.manage_assist;
return Arrays.asList(sir);
}
@Override
public List<String> getNonIndexableKeys(Context context) {
List<String> result = new ArrayList<>();
new DefaultAssistPreferenceController(context).updateNonIndexableKeys(result);
new GestureAssistPreferenceController(context).updateNonIndexableKeys(result);
new AssistContextPreferenceController(context, null)
.updateNonIndexableKeys(result);
new AssistScreenshotPreferenceController(context, null)
.updateNonIndexableKeys(result);
new AssistFlashScreenPreferenceController(context, null)
.updateNonIndexableKeys(result);
new DefaultVoiceInputPreferenceController(context, null)
.updateNonIndexableKeys(result);
return result;
}
};
}

View File

@@ -0,0 +1,206 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.applications.assist;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.provider.Settings;
import android.service.voice.VoiceInteractionService;
import android.service.voice.VoiceInteractionServiceInfo;
import android.speech.RecognitionService;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public final class VoiceInputHelper {
static final String TAG = "VoiceInputHelper";
final Context mContext;
final List<ResolveInfo> mAvailableVoiceInteractions;
final List<ResolveInfo> mAvailableRecognition;
static public class BaseInfo implements Comparable {
public final ServiceInfo service;
public final ComponentName componentName;
public final String key;
public final ComponentName settings;
public final CharSequence label;
public final String labelStr;
public final CharSequence appLabel;
public BaseInfo(PackageManager pm, ServiceInfo _service, String _settings) {
service = _service;
componentName = new ComponentName(_service.packageName, _service.name);
key = componentName.flattenToShortString();
settings = _settings != null
? new ComponentName(_service.packageName, _settings) : null;
label = _service.loadLabel(pm);
labelStr = label.toString();
appLabel = _service.applicationInfo.loadLabel(pm);
}
@Override
public int compareTo(Object another) {
return labelStr.compareTo(((BaseInfo) another).labelStr);
}
}
static public class InteractionInfo extends BaseInfo {
public final VoiceInteractionServiceInfo serviceInfo;
public InteractionInfo(PackageManager pm, VoiceInteractionServiceInfo _service) {
super(pm, _service.getServiceInfo(), _service.getSettingsActivity());
serviceInfo = _service;
}
}
static public class RecognizerInfo extends BaseInfo {
public RecognizerInfo(PackageManager pm, ServiceInfo _service, String _settings) {
super(pm, _service, _settings);
}
}
final ArrayList<InteractionInfo> mAvailableInteractionInfos = new ArrayList<>();
final ArrayList<RecognizerInfo> mAvailableRecognizerInfos = new ArrayList<>();
ComponentName mCurrentVoiceInteraction;
ComponentName mCurrentRecognizer;
public VoiceInputHelper(Context context) {
mContext = context;
mAvailableVoiceInteractions = mContext.getPackageManager().queryIntentServices(
new Intent(VoiceInteractionService.SERVICE_INTERFACE),
PackageManager.GET_META_DATA);
mAvailableRecognition = mContext.getPackageManager().queryIntentServices(
new Intent(RecognitionService.SERVICE_INTERFACE),
PackageManager.GET_META_DATA);
}
public void buildUi() {
// Get the currently selected interactor from the secure setting.
String currentSetting = Settings.Secure.getString(
mContext.getContentResolver(), Settings.Secure.VOICE_INTERACTION_SERVICE);
if (currentSetting != null && !currentSetting.isEmpty()) {
mCurrentVoiceInteraction = ComponentName.unflattenFromString(currentSetting);
} else {
mCurrentVoiceInteraction = null;
}
ArraySet<ComponentName> interactorRecognizers = new ArraySet<>();
// Iterate through all the available interactors and load up their info to show
// in the preference.
int size = mAvailableVoiceInteractions.size();
for (int i = 0; i < size; i++) {
ResolveInfo resolveInfo = mAvailableVoiceInteractions.get(i);
VoiceInteractionServiceInfo info = new VoiceInteractionServiceInfo(
mContext.getPackageManager(), resolveInfo.serviceInfo);
if (info.getParseError() != null) {
Log.w("VoiceInteractionService", "Error in VoiceInteractionService "
+ resolveInfo.serviceInfo.packageName + "/"
+ resolveInfo.serviceInfo.name + ": " + info.getParseError());
continue;
}
mAvailableInteractionInfos.add(new InteractionInfo(mContext.getPackageManager(), info));
interactorRecognizers.add(new ComponentName(resolveInfo.serviceInfo.packageName,
info.getRecognitionService()));
}
Collections.sort(mAvailableInteractionInfos);
// Get the currently selected recognizer from the secure setting.
currentSetting = Settings.Secure.getString(
mContext.getContentResolver(), Settings.Secure.VOICE_RECOGNITION_SERVICE);
if (currentSetting != null && !currentSetting.isEmpty()) {
mCurrentRecognizer = ComponentName.unflattenFromString(currentSetting);
} else {
mCurrentRecognizer = null;
}
// Iterate through all the available recognizers and load up their info to show
// in the preference.
size = mAvailableRecognition.size();
for (int i = 0; i < size; i++) {
ResolveInfo resolveInfo = mAvailableRecognition.get(i);
ComponentName comp = new ComponentName(resolveInfo.serviceInfo.packageName,
resolveInfo.serviceInfo.name);
if (interactorRecognizers.contains(comp)) {
//continue;
}
ServiceInfo si = resolveInfo.serviceInfo;
XmlResourceParser parser = null;
String settingsActivity = null;
try {
parser = si.loadXmlMetaData(mContext.getPackageManager(),
RecognitionService.SERVICE_META_DATA);
if (parser == null) {
throw new XmlPullParserException("No " + RecognitionService.SERVICE_META_DATA +
" meta-data for " + si.packageName);
}
Resources res = mContext.getPackageManager().getResourcesForApplication(
si.applicationInfo);
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
}
String nodeName = parser.getName();
if (!"recognition-service".equals(nodeName)) {
throw new XmlPullParserException(
"Meta-data does not start with recognition-service tag");
}
TypedArray array = res.obtainAttributes(attrs,
com.android.internal.R.styleable.RecognitionService);
settingsActivity = array.getString(
com.android.internal.R.styleable.RecognitionService_settingsActivity);
array.recycle();
} catch (XmlPullParserException e) {
Log.e(TAG, "error parsing recognition service meta-data", e);
} catch (IOException e) {
Log.e(TAG, "error parsing recognition service meta-data", e);
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "error parsing recognition service meta-data", e);
} finally {
if (parser != null) parser.close();
}
mAvailableRecognizerInfos.add(new RecognizerInfo(mContext.getPackageManager(),
resolveInfo.serviceInfo, settingsActivity));
}
Collections.sort(mAvailableRecognizerInfos);
}
}

View File

@@ -37,13 +37,23 @@ public class DefaultAppInfo {
public final String summary;
// Description for why this item is disabled, if null, the item is enabled.
public final String disabledDescription;
public final boolean enabled;
public DefaultAppInfo(int uid, ComponentName cn) {
this(uid, cn, null /* summary */);
}
public DefaultAppInfo(int uid, ComponentName cn, String summary) {
this(uid, cn, summary, true /* enabled */);
}
public DefaultAppInfo(int uid, ComponentName cn, String summary, boolean enabled) {
packageItemInfo = null;
userId = uid;
componentName = cn;
this.summary = summary;
this.disabledDescription = null;
this.enabled = enabled;
}
public DefaultAppInfo(PackageItemInfo info, String description) {
@@ -52,6 +62,7 @@ public class DefaultAppInfo {
componentName = null;
summary = null;
this.disabledDescription = description;
enabled = true;
}
public DefaultAppInfo(PackageItemInfo info) {

View File

@@ -97,7 +97,7 @@ public abstract class DefaultAppPickerFragment extends InstrumentedPreferenceFra
@VisibleForTesting
public void updateCandidates() {
mCandidates.clear();
final List<DefaultAppInfo> candidateList = getCandidates();
final List<? extends DefaultAppInfo> candidateList = getCandidates();
if (candidateList != null) {
for (DefaultAppInfo info : candidateList) {
mCandidates.put(info.getKey(), info);
@@ -134,6 +134,7 @@ public abstract class DefaultAppPickerFragment extends InstrumentedPreferenceFra
pref.setEnabled(false);
pref.setSummary(app.getValue().disabledDescription);
}
pref.setEnabled(info.enabled);
pref.setOnClickListener(this);
screen.addPreference(pref);
}
@@ -200,14 +201,15 @@ public abstract class DefaultAppPickerFragment extends InstrumentedPreferenceFra
return null;
}
protected abstract List<DefaultAppInfo> getCandidates();
protected abstract List<? extends DefaultAppInfo> getCandidates();
protected abstract String getDefaultAppKey();
protected abstract boolean setDefaultAppKey(String key);
// Called after the user tries to select an item.
protected void onSelectionPerformed(boolean success) {}
protected void onSelectionPerformed(boolean success) {
}
protected String getConfirmationMessage(DefaultAppInfo appInfo) {
return null;

View File

@@ -54,7 +54,7 @@ public class DefaultAutoFillPicker extends DefaultAppPickerFragment {
.queryIntentServices(AUTO_FILL_PROBE, PackageManager.GET_META_DATA);
for (ResolveInfo info : resolveInfos) {
candidates.add(new DefaultAppInfo(mUserId, new ComponentName(
info.serviceInfo.packageName, info.serviceInfo.name), null /* summary */));
info.serviceInfo.packageName, info.serviceInfo.name)));
}
return candidates;
}

View File

@@ -55,7 +55,7 @@ public class DefaultAutoFillPreferenceController extends DefaultAppPreferenceCon
DefaultAutoFillPicker.SETTING);
if (!TextUtils.isEmpty(flattenComponent)) {
DefaultAppInfo appInfo = new DefaultAppInfo(
mUserId, ComponentName.unflattenFromString(flattenComponent), null /*summary*/);
mUserId, ComponentName.unflattenFromString(flattenComponent));
return appInfo;
}
return null;

View File

@@ -75,7 +75,7 @@ public class DefaultHomePreferenceController extends DefaultAppPreferenceControl
final ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
final ComponentName currentDefaultHome = mPackageManager.getHomeActivities(homeActivities);
return new DefaultAppInfo(mUserId, currentDefaultHome, null /* summary */);
return new DefaultAppInfo(mUserId, currentDefaultHome);
}
private String getOnlyAppLabel() {

View File

@@ -76,7 +76,7 @@ public class DefaultNotificationAssistantPicker extends DefaultAppPickerFragment
}
candidates.add(new DefaultAppInfo(
mUserId, new ComponentName(info.packageName, info.name), null /* summary */));
mUserId, new ComponentName(info.packageName, info.name)));
}
return candidates;
}

View File

@@ -47,7 +47,7 @@ public class DefaultSmsPreferenceController extends DefaultAppPreferenceControll
protected DefaultAppInfo getDefaultAppInfo() {
final ComponentName app = SmsApplication.getDefaultSmsApplication(mContext, true);
if (app != null) {
return new DefaultAppInfo(mUserId, app, null /* summary */);
return new DefaultAppInfo(mUserId, app);
}
return null;
}