From d3af193384ed4aa68dc3275f882b78c15e540aad Mon Sep 17 00:00:00 2001 From: Lorenzo Lucena Maguire Date: Mon, 18 Nov 2024 07:11:26 +0000 Subject: [PATCH] Support wallet launch in Double Tap Power Gesture Settings Modify Double Tap Power Gesture Settings screen to be able to set the gesture to launch the wallet. If the feature flag is disabled, the Double Tap Power Gesture Settings screen defaults to the current screen ("Quickly open camera"), which only provides the option to open the camera upon detecting the gesture. If the feature flag is enabled, the Double Tap Power Gesture Settings screen defaults to the new "Double Tap Power Button" screen, which provides the option to open the camera, the wallet, or neither upon detecting the gesture. Android Settings Feature Request: b/380287172 Bug: 378131008 Test: manual tested screen alternates based on feature flag Test: atest DoubleTapPowerSettingsTest Test: atest DoubleTapPowerPreferenceControllerTest Test: atest DoubleTapPowerToOpenCameraPreferenceControllerTest FLAG: android.service.quickaccesswallet.launch_wallet_option_on_power_double_tap Change-Id: I1fc05ab3cfee2e86a80a1756655c368aae16747c --- res/values/strings.xml | 17 ++ res/xml/double_tap_power_settings.xml | 44 +++++ res/xml/gestures.xml | 2 +- .../DoubleTapPowerPreferenceController.java | 54 ++++-- .../gestures/DoubleTapPowerSettings.java | 24 ++- ...oubleTapPowerPreferenceControllerTest.java | 159 +++++++++++++++++- .../gestures/DoubleTapPowerSettingsTest.java | 34 +++- 7 files changed, 306 insertions(+), 28 deletions(-) create mode 100644 res/xml/double_tap_power_settings.xml diff --git a/res/values/strings.xml b/res/values/strings.xml index 525de4796a0..ebd6d60ef55 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -11158,6 +11158,23 @@ To quickly open camera, press the power button twice. Works from any screen. + + Double tap power button + + %1$s / %2$s + + Use double tap + + Double Tap Power Button + + Open Camera + + Access Camera + + Open Wallet + + Access Wallet + Flip camera for selfie diff --git a/res/xml/double_tap_power_settings.xml b/res/xml/double_tap_power_settings.xml new file mode 100644 index 00000000000..cf4a2f60217 --- /dev/null +++ b/res/xml/double_tap_power_settings.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + diff --git a/res/xml/gestures.xml b/res/xml/gestures.xml index 035c7f7c801..bfb359ae804 100644 --- a/res/xml/gestures.xml +++ b/res/xml/gestures.xml @@ -29,7 +29,7 @@ diff --git a/src/com/android/settings/gestures/DoubleTapPowerPreferenceController.java b/src/com/android/settings/gestures/DoubleTapPowerPreferenceController.java index 86c955ba55b..686d64cf1f5 100644 --- a/src/com/android/settings/gestures/DoubleTapPowerPreferenceController.java +++ b/src/com/android/settings/gestures/DoubleTapPowerPreferenceController.java @@ -23,6 +23,8 @@ import android.content.SharedPreferences; import android.provider.Settings; import androidx.annotation.NonNull; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; @@ -39,8 +41,12 @@ public class DoubleTapPowerPreferenceController extends BasePreferenceController } private static boolean isGestureAvailable(@NonNull Context context) { - return context.getResources() - .getBoolean(com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled); + if (!android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap()) { + return context.getResources() + .getBoolean( + com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled); + } + return DoubleTapPowerSettingsUtils.isDoubleTapPowerButtonGestureAvailable(context); } @Override @@ -48,18 +54,42 @@ public class DoubleTapPowerPreferenceController extends BasePreferenceController return isGestureAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } + @Override + public void displayPreference(@NonNull PreferenceScreen screen) { + if (!android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap()) { + final Preference preference = screen.findPreference(getPreferenceKey()); + if (preference != null) { + preference.setTitle(R.string.double_tap_power_for_camera_title); + } + } + super.displayPreference(screen); + } + @Override @NonNull public CharSequence getSummary() { - final boolean isCameraDoubleTapPowerGestureEnabled = - Settings.Secure.getInt( - mContext.getContentResolver(), - CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, - DoubleTapPowerToOpenCameraPreferenceController.ON) - == DoubleTapPowerToOpenCameraPreferenceController.ON; - return mContext.getText( - isCameraDoubleTapPowerGestureEnabled - ? R.string.gesture_setting_on - : R.string.gesture_setting_off); + if (!android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap()) { + final boolean isCameraDoubleTapPowerGestureEnabled = + Settings.Secure.getInt( + mContext.getContentResolver(), + CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, + DoubleTapPowerToOpenCameraPreferenceController.ON) + == DoubleTapPowerToOpenCameraPreferenceController.ON; + return mContext.getText( + isCameraDoubleTapPowerGestureEnabled + ? R.string.gesture_setting_on + : R.string.gesture_setting_off); + } + if (DoubleTapPowerSettingsUtils.isDoubleTapPowerButtonGestureEnabled(mContext)) { + final CharSequence onString = + mContext.getText(com.android.settings.R.string.gesture_setting_on); + final CharSequence actionString = + DoubleTapPowerSettingsUtils.isDoubleTapPowerButtonGestureForCameraLaunchEnabled( + mContext) + ? mContext.getText(R.string.double_tap_power_camera_action_summary) + : mContext.getText(R.string.double_tap_power_wallet_action_summary); + return mContext.getString(R.string.double_tap_power_summary, onString, actionString); + } + return mContext.getText(com.android.settings.R.string.gesture_setting_off); } } diff --git a/src/com/android/settings/gestures/DoubleTapPowerSettings.java b/src/com/android/settings/gestures/DoubleTapPowerSettings.java index 75140ed8c31..076f23fa660 100644 --- a/src/com/android/settings/gestures/DoubleTapPowerSettings.java +++ b/src/com/android/settings/gestures/DoubleTapPowerSettings.java @@ -19,6 +19,9 @@ package com.android.settings.gestures; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.SharedPreferences; +import android.provider.SearchIndexableResource; + +import androidx.annotation.NonNull; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; @@ -27,6 +30,8 @@ import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.search.SearchIndexable; +import java.util.List; + @SearchIndexable public class DoubleTapPowerSettings extends DashboardFragment { @@ -56,9 +61,24 @@ public class DoubleTapPowerSettings extends DashboardFragment { @Override protected int getPreferenceScreenResId() { - return R.xml.double_tap_power_to_open_camera_settings; + return android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap() + ? R.xml.double_tap_power_settings + : R.xml.double_tap_power_to_open_camera_settings; } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.double_tap_power_to_open_camera_settings); + new BaseSearchIndexProvider() { + @Override + @NonNull + public List getXmlResourcesToIndex( + @NonNull Context context, boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = + android.service.quickaccesswallet.Flags + .launchWalletOptionOnPowerDoubleTap() + ? R.xml.double_tap_power_settings + : R.xml.double_tap_power_to_open_camera_settings; + return List.of(sir); + } + }; } diff --git a/tests/robotests/src/com/android/settings/gestures/DoubleTapPowerPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/DoubleTapPowerPreferenceControllerTest.java index 873eeda6c5c..17b03f355bf 100644 --- a/tests/robotests/src/com/android/settings/gestures/DoubleTapPowerPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/gestures/DoubleTapPowerPreferenceControllerTest.java @@ -17,6 +17,7 @@ package com.android.settings.gestures; import static android.provider.Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED; +import static android.provider.Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED; import static com.android.settings.gestures.DoubleTapPowerPreferenceController.isSuggestionComplete; import static com.android.settings.gestures.DoubleTapPowerToOpenCameraPreferenceController.OFF; @@ -24,18 +25,29 @@ import static com.android.settings.gestures.DoubleTapPowerToOpenCameraPreference import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; +import android.service.quickaccesswallet.Flags; import android.text.TextUtils; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + import com.android.settings.R; import com.android.settings.dashboard.suggestions.SuggestionFeatureProviderImpl; import com.android.settings.testutils.shadow.SettingsShadowResources; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -46,16 +58,22 @@ import org.robolectric.annotation.Config; @Config(shadows = SettingsShadowResources.class) public class DoubleTapPowerPreferenceControllerTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private Context mContext; private ContentResolver mContentResolver; private DoubleTapPowerPreferenceController mController; + private Preference mPreference; + private PreferenceScreen mScreen; private static final String KEY_DOUBLE_TAP_POWER = "gesture_double_tap_power"; @Before public void setUp() { - mContext = RuntimeEnvironment.application; + mContext = RuntimeEnvironment.getApplication(); mContentResolver = mContext.getContentResolver(); mController = new DoubleTapPowerPreferenceController(mContext, KEY_DOUBLE_TAP_POWER); + mPreference = new Preference(mContext); + mScreen = mock(PreferenceScreen.class); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); } @After @@ -64,7 +82,26 @@ public class DoubleTapPowerPreferenceControllerTest { } @Test - public void isAvailable_configIsTrue_shouldReturnTrue() { + @EnableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void isAvailable_flagEnabled_configIsTrue_returnsTrue() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_doubleTapPowerGestureEnabled, Boolean.TRUE); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void isAvailable_flagEnabled_configIsFalse_returnsFalse() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_doubleTapPowerGestureEnabled, Boolean.FALSE); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + @DisableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void isAvailable_flagDisabled_configIsTrue_returnsTrue() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled, Boolean.TRUE); @@ -73,7 +110,8 @@ public class DoubleTapPowerPreferenceControllerTest { } @Test - public void isAvailable_configIsFalse_shouldReturnFalse() { + @DisableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void isAvailable_flagDisabled_configIsFalse_returnsFalse() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled, Boolean.FALSE); @@ -82,7 +120,42 @@ public class DoubleTapPowerPreferenceControllerTest { } @Test - public void isSuggestionCompleted_doubleTapPower_trueWhenNotAvailable() { + @EnableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void isSuggestionCompleted_enableFlag_doubleTapPower_trueWhenNotAvailable() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_doubleTapPowerGestureEnabled, false); + + assertThat(isSuggestionComplete(mContext, null /* prefs */)).isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void isSuggestionCompleted_enableFlag_doubleTapPower_falseWhenNotVisited() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_doubleTapPowerGestureEnabled, true); + // No stored value in shared preferences if not visited yet. + final SharedPreferences prefs = + new SuggestionFeatureProviderImpl().getSharedPrefs(mContext); + + assertThat(isSuggestionComplete(mContext, prefs)).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void isSuggestionCompleted_enableFlag_doubleTapPower_trueWhenVisited() { + SettingsShadowResources.overrideResource( + com.android.internal.R.bool.config_doubleTapPowerGestureEnabled, true); + // No stored value in shared preferences if not visited yet. + final SharedPreferences prefs = + new SuggestionFeatureProviderImpl().getSharedPrefs(mContext); + prefs.edit().putBoolean(DoubleTapPowerSettings.PREF_KEY_SUGGESTION_COMPLETE, true).commit(); + + assertThat(isSuggestionComplete(mContext, prefs)).isTrue(); + } + + @Test + @DisableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void isSuggestionCompleted_disableFlag_doubleTapPower_trueWhenNotAvailable() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled, false); @@ -90,7 +163,8 @@ public class DoubleTapPowerPreferenceControllerTest { } @Test - public void isSuggestionCompleted_doubleTapPower_falseWhenNotVisited() { + @DisableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void isSuggestionCompleted_disableFlag_doubleTapPower_falseWhenNotVisited() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled, true); // No stored value in shared preferences if not visited yet. @@ -101,7 +175,8 @@ public class DoubleTapPowerPreferenceControllerTest { } @Test - public void isSuggestionCompleted_doubleTapPower_trueWhenVisited() { + @DisableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void isSuggestionCompleted_disableFlag_doubleTapPower_trueWhenVisited() { SettingsShadowResources.overrideResource( com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled, true); // No stored value in shared preferences if not visited yet. @@ -113,7 +188,20 @@ public class DoubleTapPowerPreferenceControllerTest { } @Test - public void getSummary_doubleTapPowerEnabled_returnsOn() { + @DisableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void displayPreference_flagDisabled_doubleTapPowerLegacyTitleIsDisplayed() { + mController.displayPreference(mScreen); + + assertThat( + TextUtils.equals( + mPreference.getTitle(), + mContext.getText(R.string.double_tap_power_for_camera_title))) + .isTrue(); + } + + @Test + @DisableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void getSummary_flagDisabled_doubleTapPowerEnabled_returnsOn() { // Set the setting to be enabled. Settings.Secure.putInt(mContentResolver, CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, ON); @@ -125,14 +213,67 @@ public class DoubleTapPowerPreferenceControllerTest { } @Test - public void getSummary_doubleTapPowerDisabled_returnsOff() { + @DisableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void getSummary_flagDisabled_doubleTapPowerDisabled_returnsOff() { // Set the setting to be disabled. Settings.Secure.putInt(mContentResolver, CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, OFF); assertThat( TextUtils.equals( mController.getSummary(), - mContext.getText(R.string.gesture_setting_on))) + mContext.getText(R.string.gesture_setting_off))) + .isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void getSummary_flagEnabled_doubleTapPowerDisabled_returnsOff() { + // Set the setting to be disabled. + Settings.Secure.putInt( + mContentResolver, DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED, 0 /* OFF */); + + assertThat( + TextUtils.equals( + mController.getSummary(), + mContext.getText(R.string.gesture_setting_off))) + .isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void getSummary_flagEnabled_doubleTapPowerEnabled_cameraTargetAction_returnsSummary() { + // Set the setting to be enabled. + Settings.Secure.putInt( + mContentResolver, DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED, 1 /* ON */); + DoubleTapPowerSettingsUtils.setDoubleTapPowerButtonForCameraLaunch(mContext); + + assertThat( + TextUtils.equals( + mController.getSummary(), + mContext.getString( + R.string.double_tap_power_summary, + mContext.getText(R.string.gesture_setting_on), + mContext.getText( + R.string.double_tap_power_camera_action_summary)))) + .isTrue(); + } + + @Test + @EnableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void getSummary_flagEnabled_doubleTapPowerEnabled_walletTargetAction_returnsSummary() { + // Set the setting to be enabled. + Settings.Secure.putInt( + mContentResolver, DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED, 1 /* ON */); + DoubleTapPowerSettingsUtils.setDoubleTapPowerButtonForWalletLaunch(mContext); + + assertThat( + TextUtils.equals( + mController.getSummary(), + mContext.getString( + R.string.double_tap_power_summary, + mContext.getText(R.string.gesture_setting_on), + mContext.getText( + R.string.double_tap_power_wallet_action_summary)))) .isTrue(); } } diff --git a/tests/robotests/src/com/android/settings/gestures/DoubleTapPowerSettingsTest.java b/tests/robotests/src/com/android/settings/gestures/DoubleTapPowerSettingsTest.java index 10e2565b345..7d4f52e67a2 100644 --- a/tests/robotests/src/com/android/settings/gestures/DoubleTapPowerSettingsTest.java +++ b/tests/robotests/src/com/android/settings/gestures/DoubleTapPowerSettingsTest.java @@ -18,11 +18,16 @@ package com.android.settings.gestures; import static com.google.common.truth.Truth.assertThat; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.SearchIndexableResource; +import android.service.quickaccesswallet.Flags; import com.android.settings.R; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -33,6 +38,7 @@ import java.util.List; @RunWith(RobolectricTestRunner.class) public class DoubleTapPowerSettingsTest { + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private DoubleTapPowerSettings mSettings; @Before @@ -41,18 +47,38 @@ public class DoubleTapPowerSettingsTest { } @Test - public void getPreferenceResId_returnsResId() { + @EnableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void getPreferenceScreenResId_flagEnabled_returnsFlagEnabledResId() { + assertThat(mSettings.getPreferenceScreenResId()).isEqualTo(R.xml.double_tap_power_settings); + } + + @Test + @DisableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void getPreferenceScreenResId_flagDisabled_returnsFlagDisabledResId() { assertThat(mSettings.getPreferenceScreenResId()) .isEqualTo(R.xml.double_tap_power_to_open_camera_settings); } @Test - public void testSearchIndexProvider_shouldIndexResource() { + @EnableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testSearchIndexProvider_flagEnabled_shouldIndexFlagEnabledResource() { final List indexRes = DoubleTapPowerSettings.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex( - RuntimeEnvironment.application, true /* enabled */); + RuntimeEnvironment.getApplication(), true /* enabled */); assertThat(indexRes).isNotNull(); - assertThat(indexRes.get(0).xmlResId).isEqualTo(mSettings.getPreferenceScreenResId()); + assertThat(indexRes.get(0).xmlResId).isEqualTo(R.xml.double_tap_power_settings); + } + + @Test + @DisableFlags(Flags.FLAG_LAUNCH_WALLET_OPTION_ON_POWER_DOUBLE_TAP) + public void testSearchIndexProvider_flagDisabled_shouldIndexFlagDisabledResource() { + final List indexRes = + DoubleTapPowerSettings.SEARCH_INDEX_DATA_PROVIDER.getXmlResourcesToIndex( + RuntimeEnvironment.getApplication(), true /* enabled */); + + assertThat(indexRes).isNotNull(); + assertThat(indexRes.get(0).xmlResId) + .isEqualTo(R.xml.double_tap_power_to_open_camera_settings); } }