diff --git a/res/values/strings.xml b/res/values/strings.xml index 4be267fec4a..e971356192f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4095,8 +4095,14 @@ When magnification is turned on, use the Accessibility button at the bottom of the screen to quickly magnify.\n\nTo zoom, tap the Accessibility button, then tap anywhere on the screen.\n\n\nTo zoom temporarily, tap the Accessibility button, then touch & hold anywhere on the screen.\n\n\nYou can’t zoom in on the keyboard or navigation bar. The Accessibility button is set to %1$s. To use magnification, touch & hold the Accessibility button, then select magnification. - + Accessibility shortcut + + Shortcut service + + Allow from lock screen + + When the shortcut is on, you can press both volume buttons for 3 seconds to start an accessibility feature. High contrast text @@ -4280,6 +4286,9 @@ No services installed + + No service selected + No description provided. diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml index 065ead127e1..48e11afe336 100644 --- a/res/xml/accessibility_settings.xml +++ b/res/xml/accessibility_settings.xml @@ -18,8 +18,9 @@ android:title="@string/accessibility_settings" android:persistent="true"> - + + + + + + + \ No newline at end of file diff --git a/src/com/android/settings/accessibility/AccessibilityServiceWarning.java b/src/com/android/settings/accessibility/AccessibilityServiceWarning.java index 3a84d742c0f..71cafbad651 100644 --- a/src/com/android/settings/accessibility/AccessibilityServiceWarning.java +++ b/src/com/android/settings/accessibility/AccessibilityServiceWarning.java @@ -78,9 +78,16 @@ public class AccessibilityServiceWarning { return StorageManager.isNonDefaultBlockEncrypted(); } - private static View createEnableDialogContentView(Activity parentActivity, + /** + * Get a content View for a dialog to confirm that they want to enable a service. + * + * @param context A valid context + * @param info The info about a service + * @return A content view suitable for viewing + */ + private static View createEnableDialogContentView(Context context, AccessibilityServiceInfo info) { - LayoutInflater inflater = (LayoutInflater) parentActivity.getSystemService( + LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE); View content = inflater.inflate(R.layout.enable_accessibility_service_dialog_content, @@ -89,8 +96,8 @@ public class AccessibilityServiceWarning { TextView encryptionWarningView = (TextView) content.findViewById( R.id.encryption_warning); if (isFullDiskEncrypted()) { - String text = parentActivity.getString(R.string.enable_service_encryption_warning, - info.getResolveInfo().loadLabel(parentActivity.getPackageManager())); + String text = context.getString(R.string.enable_service_encryption_warning, + info.getResolveInfo().loadLabel(context.getPackageManager())); encryptionWarningView.setText(text); encryptionWarningView.setVisibility(View.VISIBLE); } else { @@ -99,8 +106,8 @@ public class AccessibilityServiceWarning { TextView capabilitiesHeaderView = (TextView) content.findViewById( R.id.capabilities_header); - capabilitiesHeaderView.setText(parentActivity.getString(R.string.capabilities_list_title, - info.getResolveInfo().loadLabel(parentActivity.getPackageManager()))); + capabilitiesHeaderView.setText(context.getString(R.string.capabilities_list_title, + info.getResolveInfo().loadLabel(context.getPackageManager()))); LinearLayout capabilitiesView = (LinearLayout) content.findViewById(R.id.capabilities); @@ -110,21 +117,21 @@ public class AccessibilityServiceWarning { ImageView imageView = (ImageView) capabilityView.findViewById( com.android.internal.R.id.perm_icon); - imageView.setImageDrawable(parentActivity.getDrawable( + imageView.setImageDrawable(context.getDrawable( com.android.internal.R.drawable.ic_text_dot)); TextView labelView = (TextView) capabilityView.findViewById( com.android.internal.R.id.permission_group); - labelView.setText(parentActivity.getString( + labelView.setText(context.getString( R.string.capability_title_receiveAccessibilityEvents)); TextView descriptionView = (TextView) capabilityView.findViewById( com.android.internal.R.id.permission_list); descriptionView.setText( - parentActivity.getString(R.string.capability_desc_receiveAccessibilityEvents)); + context.getString(R.string.capability_desc_receiveAccessibilityEvents)); List capabilities = - info.getCapabilityInfos(parentActivity); + info.getCapabilityInfos(context); capabilitiesView.addView(capabilityView); @@ -138,16 +145,16 @@ public class AccessibilityServiceWarning { imageView = (ImageView) capabilityView.findViewById( com.android.internal.R.id.perm_icon); - imageView.setImageDrawable(parentActivity.getDrawable( + imageView.setImageDrawable(context.getDrawable( com.android.internal.R.drawable.ic_text_dot)); labelView = (TextView) capabilityView.findViewById( com.android.internal.R.id.permission_group); - labelView.setText(parentActivity.getString(capability.titleResId)); + labelView.setText(context.getString(capability.titleResId)); descriptionView = (TextView) capabilityView.findViewById( com.android.internal.R.id.permission_list); - descriptionView.setText(parentActivity.getString(capability.descResId)); + descriptionView.setText(context.getString(capability.descResId)); capabilitiesView.addView(capabilityView); } diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index 9b2c85327bb..5e791ae6b9f 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -17,11 +17,9 @@ package com.android.settings.accessibility; import android.accessibilityservice.AccessibilityServiceInfo; -import android.app.Dialog; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; import android.content.Context; -import android.content.DialogInterface; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.res.Resources; @@ -130,9 +128,6 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements // presentation. private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000; - // ID for dialog that confirms shortcut capabilities - private static final int DIALOG_ID_ADD_SHORTCUT_WARNING = 1; - private final Map mLongPressTimeoutValueToTitleMap = new HashMap<>(); private final Handler mHandler = new Handler(); @@ -205,7 +200,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements private Preference mDisplayMagnificationPreferenceScreen; private Preference mFontSizePreferenceScreen; private Preference mAutoclickPreferenceScreen; - private ListPreference mAccessibilityShortcutPreference; + private Preference mAccessibilityShortcutPreferenceScreen; private Preference mDisplayDaltonizerPreferenceScreen; private SwitchPreference mToggleInversionPreference; @@ -264,9 +259,6 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements } else if (mToggleInversionPreference == preference) { handleToggleInversionPreferenceChange((Boolean) newValue); return true; - } else if (mAccessibilityShortcutPreference == preference) { - handleAccessibilityShortcutPreferenceChange((String) newValue); - return true; } return false; } @@ -283,58 +275,6 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, (checked ? 1 : 0)); } - private void handleAccessibilityShortcutPreferenceChange(String serviceComponentName) { - // When assigning a service to the shortcut the user must explicitly agree to the same - // capabilities that are present if the service were being enabled. - // No need if clearing the setting or the service is already enabled. - if (TextUtils.isEmpty(serviceComponentName) - || AccessibilityUtils.getEnabledServicesFromSettings(getActivity()) - .contains(ComponentName.unflattenFromString(serviceComponentName))) { - Settings.Secure.putString(getContentResolver(), - Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, serviceComponentName); - updateAccessibilityShortcut(); - return; - } - if (!serviceComponentName.equals(mAccessibilityShortcutPreference.getValue())) { - showDialog(DIALOG_ID_ADD_SHORTCUT_WARNING); - } - } - - @Override - public Dialog onCreateDialog(int dialogId) { - switch (dialogId) { - case DIALOG_ID_ADD_SHORTCUT_WARNING: { - DialogInterface.OnClickListener listener = - (DialogInterface dialogInterface, int buttonId) -> { - if (buttonId == DialogInterface.BUTTON_POSITIVE) { - Settings.Secure.putString(getContentResolver(), - Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, - mAccessibilityShortcutPreference.getValue()); - } - updateAccessibilityShortcut(); - }; - AccessibilityServiceInfo info = AccessibilityManager.getInstance(getActivity()) - .getInstalledServiceInfoWithComponentName( - ComponentName.unflattenFromString( - mAccessibilityShortcutPreference.getValue())); - if (info == null) { - return null; - } - return AccessibilityServiceWarning - .createCapabilitiesDialog(getActivity(), info, listener); - } - default: { - throw new IllegalArgumentException(); - } - } - } - - @Override - public int getDialogMetricsCategory(int dialogId) { - // The only dialog is the one that confirms the properties for the accessibility shortcut - return MetricsEvent.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE; - } - @Override public boolean onPreferenceTreeClick(Preference preference) { if (mToggleHighTextContrastPreference == preference) { @@ -458,9 +398,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements mDisplayDaltonizerPreferenceScreen = findPreference(DISPLAY_DALTONIZER_PREFERENCE_SCREEN); // Accessibility shortcut - mAccessibilityShortcutPreference = - (ListPreference) findPreference(ACCESSIBILITY_SHORTCUT_PREFERENCE); - mAccessibilityShortcutPreference.setOnPreferenceChangeListener(this); + mAccessibilityShortcutPreferenceScreen = findPreference(ACCESSIBILITY_SHORTCUT_PREFERENCE); } private void updateAllPreferences() { @@ -651,7 +589,7 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements updateAutoclickSummary(mAutoclickPreferenceScreen); - updateAccessibilityShortcut(); + updateAccessibilityShortcut(mAccessibilityShortcutPreferenceScreen); } private void updateFeatureSummary(String prefKey, Preference pref) { @@ -700,35 +638,21 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements mToggleMasterMonoPreference.setChecked(masterMono); } - private void updateAccessibilityShortcut() { - String currentShortcutNameString = - AccessibilityUtils.getShortcutTargetServiceComponentNameString(getActivity(), - UserHandle.myUserId()); - final PackageManager pm = getPackageManager(); - final AccessibilityManager accessibilityManager = getActivity() - .getSystemService(AccessibilityManager.class); - final List installedServices = - accessibilityManager.getInstalledAccessibilityServiceList(); - final int numInstalledServices = installedServices.size(); - - CharSequence[] entries = new CharSequence[numInstalledServices + 1]; - CharSequence[] entryValues = new CharSequence[numInstalledServices + 1]; - int currentSettingIndex = numInstalledServices; - for (int i = 0; i < numInstalledServices; i++) { - AccessibilityServiceInfo installedService = installedServices.get(i); - entries[i] = installedService.getResolveInfo().loadLabel(pm); - entryValues[i] = installedService.getComponentName().flattenToShortString(); - if (installedService.getId().equals(currentShortcutNameString)) { - currentSettingIndex = i; - } + private void updateAccessibilityShortcut(Preference preference) { + if (AccessibilityManager.getInstance(getActivity()) + .getInstalledAccessibilityServiceList().isEmpty()) { + mAccessibilityShortcutPreferenceScreen + .setSummary(getString(R.string.accessibility_no_services_installed)); + mAccessibilityShortcutPreferenceScreen.setEnabled(false); + } else { + mAccessibilityShortcutPreferenceScreen.setEnabled(true); + boolean shortcutEnabled = + AccessibilityUtils.isShortcutEnabled(getContext(), UserHandle.myUserId()); + CharSequence summary = shortcutEnabled + ? AccessibilityShortcutPreferenceFragment.getServiceName(getContext()) + : getString(R.string.accessibility_feature_state_off); + mAccessibilityShortcutPreferenceScreen.setSummary(summary); } - entries[numInstalledServices] = - getString(com.android.internal.R.string.disable_accessibility_shortcut); - entryValues[numInstalledServices] = ""; - mAccessibilityShortcutPreference.setEntryValues(entryValues); - mAccessibilityShortcutPreference.setEntries(entries); - mAccessibilityShortcutPreference.setSummary(entries[currentSettingIndex]); - mAccessibilityShortcutPreference.setValueIndex(currentSettingIndex); } public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java new file mode 100644 index 00000000000..6ed06da768f --- /dev/null +++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java @@ -0,0 +1,140 @@ +/* + * 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.accessibility; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.os.Bundle; +import android.os.UserHandle; +import android.provider.Settings; +import android.support.v14.preference.SwitchPreference; +import android.support.v7.preference.Preference; +import android.text.TextUtils; +import android.view.accessibility.AccessibilityManager; +import android.widget.Switch; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settingslib.accessibility.AccessibilityUtils; + +/** + * Settings page for accessibility shortcut + */ +public class AccessibilityShortcutPreferenceFragment extends ToggleFeaturePreferenceFragment + implements Indexable { + + public static final String SHORTCUT_SERVICE_KEY = "accessibility_shortcut_service"; + public static final String ON_LOCK_SCREEN_KEY = "accessibility_shortcut_on_lock_screen"; + // ID for dialog that confirms shortcut capabilities + private static final int DIALOG_ID_ADD_SHORTCUT_WARNING = 1; + + private Preference mServicePreference; + private SwitchPreference mOnLockScreenSwitchPreference; + private String mSelectedServiceComponentNameString; + + @Override + public int getMetricsCategory() { + return MetricsEvent.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.accessibility_shortcut_settings); + mServicePreference = findPreference(SHORTCUT_SERVICE_KEY); + mOnLockScreenSwitchPreference = (SwitchPreference) findPreference(ON_LOCK_SCREEN_KEY); + mOnLockScreenSwitchPreference.setOnPreferenceChangeListener((Preference p, Object o) -> { + Settings.Secure.putInt(getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, + ((Boolean) o) ? 1 : 0); + return true; + }); + mFooterPreferenceMixin.createFooterPreference() + .setTitle(R.string.accessibility_shortcut_description); + } + + @Override + public void onResume() { + super.onResume(); + updatePreferences(); + } + + @Override + protected void onInstallSwitchBarToggleSwitch() { + super.onInstallSwitchBarToggleSwitch(); + mSwitchBar.addOnSwitchChangeListener((Switch switchView, boolean enabled) -> { + onPreferenceToggled(Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, enabled); + }); + } + + @Override + protected void onPreferenceToggled(String preferenceKey, boolean enabled) { + Settings.Secure.putInt(getContentResolver(), preferenceKey, enabled ? 1 : 0); + } + + private void updatePreferences() { + ContentResolver cr = getContentResolver(); + boolean isEnabled = Settings.Secure + .getInt(cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 1) == 1; + mToggleSwitch.setChecked(isEnabled); + CharSequence serviceName = getServiceName(getContext()); + mServicePreference.setSummary(serviceName); + mOnLockScreenSwitchPreference.setChecked(Settings.Secure.getInt( + cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, 1) == 1); + if (TextUtils.equals(serviceName, getString(R.string.accessibility_no_service_selected))) { + // If there's no service configured, enabling the shortcut will have no effect + // It should already be disabled, but force the switch to off just in case + mToggleSwitch.setChecked(false); + mToggleSwitch.setEnabled(false); + mSwitchBar.setEnabled(false); + } else { + mToggleSwitch.setEnabled(true); + mSwitchBar.setEnabled(true); + } + } + + /** + * Get the user-visible name of the service currently selected for the shortcut. + * + * @param context The current context + * @return The name of the service or a string saying that none is selected. + */ + public static CharSequence getServiceName(Context context) { + ComponentName shortcutServiceName = ComponentName.unflattenFromString( + AccessibilityUtils.getShortcutTargetServiceComponentNameString( + context, UserHandle.myUserId())); + AccessibilityServiceInfo shortcutServiceInfo = AccessibilityManager.getInstance(context) + .getInstalledServiceInfoWithComponentName(shortcutServiceName); + if (shortcutServiceInfo != null) { + return shortcutServiceInfo.getResolveInfo().loadLabel(context.getPackageManager()); + } + return context.getString(R.string.accessibility_no_service_selected); + } + + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + // This fragment is for details of the shortcut. Only the shortcut itself needs + // to be indexed. + protected boolean isPageSearchEnabled(Context context) { + return false; + } + }; +} diff --git a/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java b/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java new file mode 100644 index 00000000000..8b6d52a5677 --- /dev/null +++ b/src/com/android/settings/accessibility/ShortcutServicePickerFragment.java @@ -0,0 +1,157 @@ +/* + * 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.accessibility; + +import android.accessibilityservice.AccessibilityServiceInfo; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.app.Fragment; +import android.content.ComponentName; +import android.content.DialogInterface; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.os.Bundle; +import android.os.UserHandle; +import android.provider.Settings; +import android.support.v7.preference.Preference; +import android.text.TextUtils; +import android.view.accessibility.AccessibilityManager; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.DialogCreatable; +import com.android.settings.applications.defaultapps.DefaultAppInfo; +import com.android.settings.applications.defaultapps.DefaultAppPickerFragment; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import com.android.settings.widget.RadioButtonPreference; +import com.android.settingslib.accessibility.AccessibilityUtils; + +import java.util.ArrayList; +import java.util.List; + +/** + * Fragment for picking accessibility shortcut service + */ +public class ShortcutServicePickerFragment extends DefaultAppPickerFragment { + + @Override + public int getMetricsCategory() { + return MetricsEvent.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE; + } + + @Override + protected List getCandidates() { + final AccessibilityManager accessibilityManager = getContext() + .getSystemService(AccessibilityManager.class); + final List installedServices = + accessibilityManager.getInstalledAccessibilityServiceList(); + final int numInstalledServices = installedServices.size(); + + List candidates = new ArrayList<>(numInstalledServices); + for (int i = 0; i < numInstalledServices; i++) { + AccessibilityServiceInfo installedServiceInfo = installedServices.get(i); + candidates.add(new DefaultAppInfo(mPm, + UserHandle.myUserId(), + installedServiceInfo.getComponentName(), + installedServiceInfo.loadSummary(mPm.getPackageManager()), + true /* enabled */)); + } + + return candidates; + } + + @Override + protected String getDefaultKey() { + String shortcutServiceString = AccessibilityUtils + .getShortcutTargetServiceComponentNameString(getContext(), UserHandle.myUserId()); + if (shortcutServiceString != null) { + ComponentName shortcutName = ComponentName.unflattenFromString(shortcutServiceString); + if (shortcutName != null) { + return shortcutName.flattenToString(); + } + } + return null; + } + + @Override + protected boolean setDefaultKey(String key) { + Settings.Secure.putString(getContext().getContentResolver(), + Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, key); + return true; + } + + @Override + public void onRadioButtonClicked(RadioButtonPreference selected) { + final String selectedKey = selected.getKey(); + + final Activity activity = getActivity(); + if (TextUtils.isEmpty(selectedKey)) { + super.onRadioButtonClicked(selected); + } else if (activity != null) { + final DialogFragment fragment = ConfirmationDialogFragment.newInstance( + this, selectedKey); + fragment.show(activity.getFragmentManager(), ConfirmationDialogFragment.TAG); + } + } + + private void onServiceConfirmed(String serviceKey) { + onRadioButtonConfirmed(serviceKey); + } + + public static class ConfirmationDialogFragment extends InstrumentedDialogFragment + implements DialogInterface.OnClickListener { + private static final String EXTRA_KEY = "extra_key"; + private static final String TAG = "ConfirmationDialogFragment"; + + public static ConfirmationDialogFragment newInstance(ShortcutServicePickerFragment parent, + String key) { + final ConfirmationDialogFragment fragment = new ConfirmationDialogFragment(); + final Bundle argument = new Bundle(); + argument.putString(EXTRA_KEY, key); + fragment.setArguments(argument); + fragment.setTargetFragment(parent, 0); + return fragment; + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final Bundle bundle = getArguments(); + final String key = bundle.getString(EXTRA_KEY); + final ComponentName serviceComponentName = ComponentName.unflattenFromString(key); + final AccessibilityManager accessibilityManager = getActivity() + .getSystemService(AccessibilityManager.class); + AccessibilityServiceInfo info = accessibilityManager + .getInstalledServiceInfoWithComponentName(serviceComponentName); + return AccessibilityServiceWarning.createCapabilitiesDialog(getActivity(), info, this); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + final Fragment fragment = getTargetFragment(); + if (fragment instanceof DefaultAppPickerFragment) { + final Bundle bundle = getArguments(); + ((ShortcutServicePickerFragment) fragment).onServiceConfirmed( + bundle.getString(EXTRA_KEY)); + } + } + } +} diff --git a/src/com/android/settings/applications/defaultapps/DefaultAppInfo.java b/src/com/android/settings/applications/defaultapps/DefaultAppInfo.java index e99b106dfab..b40943ff54a 100644 --- a/src/com/android/settings/applications/defaultapps/DefaultAppInfo.java +++ b/src/com/android/settings/applications/defaultapps/DefaultAppInfo.java @@ -20,6 +20,7 @@ import android.app.AppGlobals; import android.content.ComponentName; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; @@ -76,16 +77,15 @@ public class DefaultAppInfo extends RadioButtonPickerFragment.CandidateInfo { public CharSequence loadLabel() { if (componentName != null) { try { - final ActivityInfo actInfo = AppGlobals.getPackageManager().getActivityInfo( - componentName, 0, userId); - if (actInfo != null) { - return actInfo.loadLabel(mPm.getPackageManager()); + final ComponentInfo componentInfo = getComponentInfo(); + if (componentInfo != null) { + return componentInfo.loadLabel(mPm.getPackageManager()); } else { final ApplicationInfo appInfo = mPm.getApplicationInfoAsUser( componentName.getPackageName(), 0, userId); return appInfo.loadLabel(mPm.getPackageManager()); } - } catch (RemoteException | PackageManager.NameNotFoundException e) { + } catch (PackageManager.NameNotFoundException e) { return null; } } else if (packageItemInfo != null) { @@ -100,16 +100,15 @@ public class DefaultAppInfo extends RadioButtonPickerFragment.CandidateInfo { public Drawable loadIcon() { if (componentName != null) { try { - final ActivityInfo actInfo = AppGlobals.getPackageManager().getActivityInfo( - componentName, 0, userId); - if (actInfo != null) { - return actInfo.loadIcon(mPm.getPackageManager()); + final ComponentInfo componentInfo = getComponentInfo(); + if (componentInfo != null) { + return componentInfo.loadIcon(mPm.getPackageManager()); } else { final ApplicationInfo appInfo = mPm.getApplicationInfoAsUser( componentName.getPackageName(), 0, userId); return appInfo.loadIcon(mPm.getPackageManager()); } - } catch (RemoteException | PackageManager.NameNotFoundException e) { + } catch (PackageManager.NameNotFoundException e) { return null; } } @@ -130,4 +129,18 @@ public class DefaultAppInfo extends RadioButtonPickerFragment.CandidateInfo { return null; } } + + private ComponentInfo getComponentInfo() { + try { + ComponentInfo componentInfo = AppGlobals.getPackageManager().getActivityInfo( + componentName, 0, userId); + if (componentInfo == null) { + componentInfo = AppGlobals.getPackageManager().getServiceInfo( + componentName, 0, userId); + } + return componentInfo; + } catch (RemoteException e) { + return null; + } + } } diff --git a/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragment.java b/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragment.java index d08ac992b35..98557ee86e2 100644 --- a/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragment.java +++ b/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragment.java @@ -61,7 +61,6 @@ public abstract class DefaultAppPickerFragment extends RadioButtonPickerFragment } } - @Override public void bindPreferenceExtra(RadioButtonPreference pref, String key, CandidateInfo info, String defaultKey, String systemDefaultKey) { diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index 8b1983434d0..aca6a157cb1 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -30,6 +30,7 @@ import com.android.settings.R; import com.android.settings.ScreenPinningSettings; import com.android.settings.SecuritySettings; import com.android.settings.accessibility.AccessibilitySettings; +import com.android.settings.accessibility.AccessibilityShortcutPreferenceFragment; import com.android.settings.accessibility.MagnificationPreferenceFragment; import com.android.settings.accounts.UserAndAccountDashboardFragment; import com.android.settings.applications.AdvancedAppSettings; @@ -176,6 +177,8 @@ public final class SearchIndexableResources { R.drawable.ic_settings_security); addIndex(MagnificationPreferenceFragment.class, NO_DATA_RES_ID, R.drawable.ic_settings_accessibility); + addIndex(AccessibilityShortcutPreferenceFragment.class, NO_DATA_RES_ID, + R.drawable.ic_settings_accessibility); } private SearchIndexableResources() { diff --git a/tests/robotests/src/com/android/settings/accessibility/ShortcutServicePickerFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ShortcutServicePickerFragmentTest.java new file mode 100644 index 00000000000..9161f06e9e8 --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/ShortcutServicePickerFragmentTest.java @@ -0,0 +1,83 @@ +/* + * 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.accessibility; + +import android.app.Activity; +import android.content.Context; +import android.os.UserManager; + +import android.test.mock.MockContentResolver; +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; +import com.android.settings.applications.PackageManagerWrapper; +import com.android.settings.testutils.FakeFeatureFactory; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; +import org.robolectric.annotation.Config; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class ShortcutServicePickerFragmentTest { + + private static final String TEST_SERVICE_KEY_1 = "abc/123"; + private static final String TEST_SERVICE_KEY_2 = "abcd/1234"; + + private static final String SUMMARY_1 = "summary1"; + private static final String SUMMARY_2 = "summary2"; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Activity mActivity; + @Mock + private UserManager mUserManager; + @Mock + private PackageManagerWrapper mPackageManager; + + private ShortcutServicePickerFragment mFragment; + private MockContentResolver mContentResolver; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + FakeFeatureFactory.setupForTest(mActivity); + when(mActivity.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); + + mFragment = spy(new ShortcutServicePickerFragment()); + mFragment.onAttach((Context) mActivity); + + doReturn(RuntimeEnvironment.application).when(mFragment).getContext(); + } + + @Test + public void setAndGetDefaultAppKey_shouldUpdateDefaultAppKey() { + assertThat(mFragment.setDefaultKey(TEST_SERVICE_KEY_1)).isTrue(); + assertThat(mFragment.getDefaultKey()).isEqualTo(TEST_SERVICE_KEY_1); + } +} +