From 8946e64f280e804db6c65d07894d41e724f4dc61 Mon Sep 17 00:00:00 2001 From: Daniel Norman Date: Thu, 19 Oct 2023 01:07:48 +0000 Subject: [PATCH] Adds 'App info' button on accessibility service + activity pages. This launches the existing app info page for the a11y feature's owning package. Features without a valid component (framework features) do not have this button. This is also not shown in Setup Wizard which does not support the App Info page. This helps users find more info about the app that provided an accessibility feature. Screenshot: https://screenshot.googleplex.com/B9FXLoomxFjLBv8.png Flag: accessibility com.android.settings.flags.accessibility_show_app_info_button Bug: 277378550 Test: atest ToggleFeaturePreferenceFragmentTest (robotest) Test: Open and interact with the button, ensure it opens the app info page for the correct app. Change-Id: I2041c09077ce5fadc72117dc0c72409dd33ef60b --- ...gs_accessibility_flag_declarations.aconfig | 13 ++++ .../ToggleFeaturePreferenceFragment.java | 50 ++++++++++++++- .../ToggleFeaturePreferenceFragmentTest.java | 61 +++++++++++++++++++ 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/aconfig/settings_accessibility_flag_declarations.aconfig b/aconfig/settings_accessibility_flag_declarations.aconfig index 9a24399aea5..4363bfc7c0b 100644 --- a/aconfig/settings_accessibility_flag_declarations.aconfig +++ b/aconfig/settings_accessibility_flag_declarations.aconfig @@ -1,8 +1,21 @@ package: "com.android.settings.flags" +# NOTE: Keep alphabetized to help limit merge conflicts from multiple simultaneous editors. + +# NOTE: All Settings flags share the same Flags class, so prefix our +# flags with 'accessibility' to prevent naming collision. + +flag { + name: "accessibility_show_app_info_button" + namespace: "accessibility" + description: "Shows an 'app info' button on non-framework a11y Service and Activity pages." + bug: "277378550" +} + flag { name: "separate_accessibility_vibration_settings_fragments" namespace: "accessibility" description: "Splits VibrationSettings into two fragments, one per XML resource" bug: "289967175" } + diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java index 7f6254439e3..3dc0b477e77 100644 --- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java @@ -47,6 +47,7 @@ import android.widget.CheckBox; import android.widget.ImageView; import android.widget.Switch; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; @@ -58,6 +59,7 @@ import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType; import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType; import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.flags.Flags; import com.android.settings.utils.LocaleUtils; import com.android.settings.widget.SettingsMainSwitchBar; import com.android.settings.widget.SettingsMainSwitchPreference; @@ -188,6 +190,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment initGeneralCategory(); initShortcutPreference(); initSettingsPreference(); + initAppInfoPreference(); initHtmlTextPreference(); initFooterPreference(); @@ -208,7 +211,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment public Dialog onCreateDialog(int dialogId) { switch (dialogId) { case DialogEnums.EDIT_SHORTCUT: - final int dialogType = WizardManagerHelper.isAnySetupWizard(getIntent()) + final int dialogType = isAnySetupWizard() ? DialogType.EDIT_SHORTCUT_GENERIC_SUW : DialogType.EDIT_SHORTCUT_GENERIC; mDialog = AccessibilityDialogUtils.showEditShortcutDialog( getPrefContext(), dialogType, getShortcutTitle(), @@ -216,7 +219,7 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment setupEditShortcutDialog(mDialog); return mDialog; case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL: - if (WizardManagerHelper.isAnySetupWizard(getIntent())) { + if (isAnySetupWizard()) { mDialog = AccessibilityGestureNavigationTutorial .createAccessibilityTutorialDialogForSetupWizard( getPrefContext(), getUserShortcutTypes(), @@ -541,6 +544,44 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment generalCategory.addPreference(mSettingsPreference); } + @VisibleForTesting + @Nullable + Preference createAppInfoPreference() { + if (!Flags.accessibilityShowAppInfoButton()) { + return null; + } + // App Info is not available in Setup Wizard. + if (isAnySetupWizard()) { + return null; + } + // Only show the button for pages with valid component package names. + if (mComponentName == null) { + return null; + } + final String packageName = mComponentName.getPackageName(); + final PackageManager packageManager = getPrefContext().getPackageManager(); + if (!packageManager.isPackageAvailable(packageName)) { + return null; + } + + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + packageName)); + + final Preference appInfoPreference = new Preference(getPrefContext()); + appInfoPreference.setTitle(getString(R.string.application_info_label)); + appInfoPreference.setIconSpaceReserved(false); + appInfoPreference.setIntent(intent); + return appInfoPreference; + } + + private void initAppInfoPreference() { + final Preference appInfoPreference = createAppInfoPreference(); + if (appInfoPreference != null) { + final PreferenceCategory generalCategory = findPreference(KEY_GENERAL_CATEGORY); + generalCategory.addPreference(appInfoPreference); + } + } + private void initHtmlTextPreference() { if (TextUtils.isEmpty(mHtmlDescription)) { return; @@ -902,4 +943,9 @@ public abstract class ToggleFeaturePreferenceFragment extends DashboardFragment } return null; } + + @VisibleForTesting + boolean isAnySetupWizard() { + return WizardManagerHelper.isAnySetupWizard(getIntent()); + } } diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java index de305a6a177..66211a2baba 100644 --- a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java @@ -32,7 +32,12 @@ import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; import android.os.Bundle; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; @@ -42,6 +47,7 @@ import android.widget.PopupWindow; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.FragmentActivity; +import androidx.preference.Preference; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; @@ -50,10 +56,12 @@ import com.android.settings.R; import com.android.settings.accessibility.AccessibilityDialogUtils.DialogType; import com.android.settings.accessibility.AccessibilityUtil.QuickSettingsTooltipType; import com.android.settings.accessibility.AccessibilityUtil.UserShortcutType; +import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.ShadowFragment; import com.android.settingslib.widget.TopIntroPreference; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -74,6 +82,9 @@ import org.robolectric.shadows.ShadowApplication; }) public class ToggleFeaturePreferenceFragmentTest { + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + private static final String PLACEHOLDER_PACKAGE_NAME = "com.placeholder.example"; private static final String PLACEHOLDER_CLASS_NAME = PLACEHOLDER_PACKAGE_NAME + ".placeholder"; private static final ComponentName PLACEHOLDER_COMPONENT_NAME = new ComponentName( @@ -105,6 +116,8 @@ public class ToggleFeaturePreferenceFragmentTest { private FragmentActivity mActivity; @Mock private ContentResolver mContentResolver; + @Mock + private PackageManager mPackageManager; @Before public void setUpTestFragment() { @@ -116,6 +129,7 @@ public class ToggleFeaturePreferenceFragmentTest { when(mFragment.getContext()).thenReturn(mContext); when(mFragment.getActivity()).thenReturn(mActivity); when(mActivity.getContentResolver()).thenReturn(mContentResolver); + when(mContext.getPackageManager()).thenReturn(mPackageManager); final PreferenceScreen screen = spy(new PreferenceScreen(mContext, null)); when(screen.getPreferenceManager()).thenReturn(mPreferenceManager); doReturn(screen).when(mFragment).getPreferenceScreen(); @@ -317,6 +331,53 @@ public class ToggleFeaturePreferenceFragmentTest { assertThat(mFragment.getPreferenceScreen().getPreferenceCount()).isEqualTo(0); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) + public void createAppInfoPreference_withValidComponentName() { + when(mPackageManager.isPackageAvailable(PLACEHOLDER_PACKAGE_NAME)).thenReturn(true); + mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; + + final Preference preference = mFragment.createAppInfoPreference(); + + assertThat(preference).isNotNull(); + final Intent appInfoIntent = preference.getIntent(); + assertThat(appInfoIntent.getAction()) + .isEqualTo(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + assertThat(appInfoIntent.getDataString()).isEqualTo("package:" + PLACEHOLDER_PACKAGE_NAME); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) + public void createAppInfoPreference_noComponentName_shouldBeNull() { + mFragment.mComponentName = null; + + final Preference preference = mFragment.createAppInfoPreference(); + + assertThat(preference).isNull(); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) + public void createAppInfoPreference_withUnavailablePackage_shouldBeNull() { + when(mPackageManager.isPackageAvailable(PLACEHOLDER_PACKAGE_NAME)).thenReturn(false); + mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; + + final Preference preference = mFragment.createAppInfoPreference(); + + assertThat(preference).isNull(); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ACCESSIBILITY_SHOW_APP_INFO_BUTTON) + public void createAppInfoPreference_inSetupWizard_shouldBeNull() { + when(mFragment.isAnySetupWizard()).thenReturn(true); + mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME; + + final Preference preference = mFragment.createAppInfoPreference(); + + assertThat(preference).isNull(); + } + @Test public void createFooterPreference_shouldSetAsExpectedValue() { mFragment.createFooterPreference(mFragment.getPreferenceScreen(),