Loading services/core/java/com/android/server/GestureLauncherService.java +206 −24 Original line number Diff line number Diff line Loading @@ -16,9 +16,13 @@ package com.android.server; import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap; import static com.android.internal.R.integer.config_defaultMinEmergencyGestureTapDurationMillis; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.PendingIntent; import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; Loading @@ -33,6 +37,7 @@ import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; import android.os.Bundle; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.WakeLock; Loading @@ -41,10 +46,12 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.service.quickaccesswallet.QuickAccessWalletClient; import android.util.MutableBoolean; import android.util.Slog; import android.view.KeyEvent; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEvent; Loading @@ -70,7 +77,7 @@ public class GestureLauncherService extends SystemService { * Time in milliseconds in which the power button must be pressed twice so it will be considered * as a camera launch. */ @VisibleForTesting static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300; @VisibleForTesting static final long POWER_DOUBLE_TAP_MAX_TIME_MS = 300; /** Loading Loading @@ -100,10 +107,23 @@ public class GestureLauncherService extends SystemService { @VisibleForTesting static final int EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX = 5000; /** * Number of taps required to launch camera shortcut. */ private static final int CAMERA_POWER_TAP_COUNT_THRESHOLD = 2; /** Indicates camera should be launched on power double tap. */ @VisibleForTesting static final int LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER = 0; /** Indicates wallet should be launched on power double tap. */ @VisibleForTesting static final int LAUNCH_WALLET_ON_DOUBLE_TAP_POWER = 1; /** Number of taps required to launch the double tap shortcut (either camera or wallet). */ public static final int DOUBLE_POWER_TAP_COUNT_THRESHOLD = 2; /** Bundle to send with PendingIntent to grant background activity start privileges. */ private static final Bundle GRANT_BACKGROUND_START_PRIVILEGES = ActivityOptions.makeBasic() .setPendingIntentBackgroundActivityStartMode( ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS) .toBundle(); private final QuickAccessWalletClient mQuickAccessWalletClient; /** The listener that receives the gesture event. */ private final GestureEventListener mGestureListener = new GestureEventListener(); Loading Loading @@ -158,6 +178,9 @@ public class GestureLauncherService extends SystemService { */ private boolean mCameraDoubleTapPowerEnabled; /** Whether wallet double tap power button gesture is currently enabled. */ private boolean mWalletDoubleTapPowerEnabled; /** * Whether emergency gesture is currently enabled */ Loading Loading @@ -204,15 +227,17 @@ public class GestureLauncherService extends SystemService { } } public GestureLauncherService(Context context) { this(context, new MetricsLogger(), new UiEventLoggerImpl()); this(context, new MetricsLogger(), QuickAccessWalletClient.create(context), new UiEventLoggerImpl()); } @VisibleForTesting GestureLauncherService(Context context, MetricsLogger metricsLogger, UiEventLogger uiEventLogger) { QuickAccessWalletClient quickAccessWalletClient, UiEventLogger uiEventLogger) { super(context); mContext = context; mMetricsLogger = metricsLogger; mQuickAccessWalletClient = quickAccessWalletClient; mUiEventLogger = uiEventLogger; } Loading @@ -237,6 +262,9 @@ public class GestureLauncherService extends SystemService { "GestureLauncherService"); updateCameraRegistered(); updateCameraDoubleTapPowerEnabled(); if (launchWalletOptionOnPowerDoubleTap()) { updateWalletDoubleTapPowerEnabled(); } updateEmergencyGestureEnabled(); updateEmergencyGesturePowerButtonCooldownPeriodMs(); Loading @@ -250,12 +278,24 @@ public class GestureLauncherService extends SystemService { } private void registerContentObservers() { if (launchWalletOptionOnPowerDoubleTap()) { mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor( Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED), false, mSettingObserver, mUserId); mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor( Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE), false, mSettingObserver, mUserId); } else { mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.CAMERA_GESTURE_DISABLED), false, mSettingObserver, mUserId); mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED), Settings.Secure.getUriFor( Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED), false, mSettingObserver, mUserId); } mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED), false, mSettingObserver, mUserId); Loading Loading @@ -291,6 +331,14 @@ public class GestureLauncherService extends SystemService { } } @VisibleForTesting void updateWalletDoubleTapPowerEnabled() { boolean enabled = isWalletDoubleTapPowerSettingEnabled(mContext, mUserId); synchronized (this) { mWalletDoubleTapPowerEnabled = enabled; } } @VisibleForTesting void updateEmergencyGestureEnabled() { boolean enabled = isEmergencyGestureSettingEnabled(mContext, mUserId); Loading Loading @@ -418,11 +466,35 @@ public class GestureLauncherService extends SystemService { Settings.Secure.CAMERA_GESTURE_DISABLED, 0, userId) == 0); } /** Checks if camera should be launched on double press of the power button. */ public static boolean isCameraDoubleTapPowerSettingEnabled(Context context, int userId) { return isCameraDoubleTapPowerEnabled(context.getResources()) boolean res; if (launchWalletOptionOnPowerDoubleTap()) { res = isDoubleTapPowerGestureSettingEnabled(context, userId) && getDoubleTapPowerGestureAction(context, userId) == LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER; } else { // These are legacy settings that will be deprecated once the option to launch both // wallet and camera has been created. res = isCameraDoubleTapPowerEnabled(context.getResources()) && (Settings.Secure.getIntForUser(context.getContentResolver(), Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0); } return res; } /** Checks if wallet should be launched on double tap of the power button. */ public static boolean isWalletDoubleTapPowerSettingEnabled(Context context, int userId) { if (!launchWalletOptionOnPowerDoubleTap()) { return false; } return isDoubleTapPowerGestureSettingEnabled(context, userId) && getDoubleTapPowerGestureAction(context, userId) == LAUNCH_WALLET_ON_DOUBLE_TAP_POWER; } public static boolean isCameraLiftTriggerSettingEnabled(Context context, int userId) { return isCameraLiftTriggerEnabled(context.getResources()) Loading @@ -441,6 +513,28 @@ public class GestureLauncherService extends SystemService { isDefaultEmergencyGestureEnabled(context.getResources()) ? 1 : 0, userId) != 0; } private static int getDoubleTapPowerGestureAction(Context context, int userId) { return Settings.Secure.getIntForUser( context.getContentResolver(), Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE, LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER, userId); } /** Whether the shortcut to launch app on power double press is enabled. */ private static boolean isDoubleTapPowerGestureSettingEnabled(Context context, int userId) { return Settings.Secure.getIntForUser( context.getContentResolver(), Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED, isDoubleTapConfigEnabled(context.getResources()) ? 1 : 0, userId) == 1; } private static boolean isDoubleTapConfigEnabled(Resources resources) { return resources.getBoolean(R.bool.config_doubleTapPowerGestureEnabled); } /** * Gets power button cooldown period in milliseconds after emergency gesture is triggered. The * value is capped at a maximum Loading Loading @@ -494,12 +588,19 @@ public class GestureLauncherService extends SystemService { * Whether GestureLauncherService should be enabled according to system properties. */ public static boolean isGestureLauncherEnabled(Resources resources) { return isCameraLaunchEnabled(resources) || isCameraDoubleTapPowerEnabled(resources) boolean res = isCameraLaunchEnabled(resources) || isCameraLiftTriggerEnabled(resources) || isEmergencyGestureEnabled(resources); if (launchWalletOptionOnPowerDoubleTap()) { res |= isDoubleTapConfigEnabled(resources); } else { res |= isCameraDoubleTapPowerEnabled(resources); } return res; } /** * Attempts to intercept power key down event by detecting certain gesture patterns * Loading Loading @@ -530,6 +631,7 @@ public class GestureLauncherService extends SystemService { return false; } boolean launchCamera = false; boolean launchWallet = false; boolean launchEmergencyGesture = false; boolean intercept = false; long powerTapInterval; Loading @@ -541,7 +643,7 @@ public class GestureLauncherService extends SystemService { mFirstPowerDown = event.getEventTime(); mPowerButtonConsecutiveTaps = 1; mPowerButtonSlowConsecutiveTaps = 1; } else if (powerTapInterval >= CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) { } else if (powerTapInterval >= POWER_DOUBLE_TAP_MAX_TIME_MS) { // Tap too slow for shortcuts mFirstPowerDown = event.getEventTime(); mPowerButtonConsecutiveTaps = 1; Loading Loading @@ -586,10 +688,16 @@ public class GestureLauncherService extends SystemService { } } if (mCameraDoubleTapPowerEnabled && powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS && mPowerButtonConsecutiveTaps == CAMERA_POWER_TAP_COUNT_THRESHOLD) { && powerTapInterval < POWER_DOUBLE_TAP_MAX_TIME_MS && mPowerButtonConsecutiveTaps == DOUBLE_POWER_TAP_COUNT_THRESHOLD) { launchCamera = true; intercept = interactive; } else if (launchWalletOptionOnPowerDoubleTap() && mWalletDoubleTapPowerEnabled && powerTapInterval < POWER_DOUBLE_TAP_MAX_TIME_MS && mPowerButtonConsecutiveTaps == DOUBLE_POWER_TAP_COUNT_THRESHOLD) { launchWallet = true; intercept = interactive; } } if (mPowerButtonConsecutiveTaps > 1 || mPowerButtonSlowConsecutiveTaps > 1) { Loading @@ -608,6 +716,10 @@ public class GestureLauncherService extends SystemService { (int) powerTapInterval); mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER); } } else if (launchWallet) { Slog.i(TAG, "Power button double tap gesture detected, launching wallet. Interval=" + powerTapInterval + "ms"); launchWallet = sendGestureTargetActivityPendingIntent(); } else if (launchEmergencyGesture) { Slog.i(TAG, "Emergency gesture detected, launching."); launchEmergencyGesture = handleEmergencyGesture(); Loading @@ -623,11 +735,75 @@ public class GestureLauncherService extends SystemService { mPowerButtonSlowConsecutiveTaps); mMetricsLogger.histogram("power_double_tap_interval", (int) powerTapInterval); outLaunched.value = launchCamera || launchEmergencyGesture; outLaunched.value = launchCamera || launchEmergencyGesture || launchWallet; // Intercept power key event if the press is part of a gesture (camera, eGesture) and the // user has completed setup. return intercept && isUserSetupComplete(); } /** * Fetches and sends gestureTargetActivityPendingIntent from QuickAccessWallet, which is a * specific activity that QuickAccessWalletService has defined to be launch on detection of the * power button gesture. */ private boolean sendGestureTargetActivityPendingIntent() { boolean userSetupComplete = isUserSetupComplete(); if (mQuickAccessWalletClient == null || !mQuickAccessWalletClient.isWalletServiceAvailable()) { Slog.w(TAG, "QuickAccessWalletService is not available, ignoring wallet gesture."); return false; } if (!userSetupComplete) { if (DBG) { Slog.d(TAG, "userSetupComplete = false, ignoring wallet gesture."); } return false; } if (DBG) { Slog.d(TAG, "userSetupComplete = true, performing wallet gesture."); } mQuickAccessWalletClient.getGestureTargetActivityPendingIntent( getContext().getMainExecutor(), gesturePendingIntent -> { if (gesturePendingIntent == null) { Slog.d(TAG, "getGestureTargetActivityPendingIntent is null."); sendFallbackPendingIntent(); return; } sendPendingIntentWithBackgroundStartPrivileges(gesturePendingIntent); }); return true; } /** * If gestureTargetActivityPendingIntent is null, this method is invoked to start the activity * that QuickAccessWalletService has defined to host the Wallet view, which is typically the * home screen of the Wallet application. */ private void sendFallbackPendingIntent() { mQuickAccessWalletClient.getWalletPendingIntent( getContext().getMainExecutor(), walletPendingIntent -> { if (walletPendingIntent == null) { Slog.w(TAG, "getWalletPendingIntent returns null. Not launching " + "anything for wallet."); return; } sendPendingIntentWithBackgroundStartPrivileges(walletPendingIntent); }); } private void sendPendingIntentWithBackgroundStartPrivileges(PendingIntent pendingIntent) { try { pendingIntent.send(GRANT_BACKGROUND_START_PRIVILEGES); } catch (PendingIntent.CanceledException e) { Slog.e(TAG, "PendingIntent was canceled", e); } } /** * @return true if camera was launched, false otherwise. */ Loading Loading @@ -709,6 +885,9 @@ public class GestureLauncherService extends SystemService { registerContentObservers(); updateCameraRegistered(); updateCameraDoubleTapPowerEnabled(); if (launchWalletOptionOnPowerDoubleTap()) { updateWalletDoubleTapPowerEnabled(); } updateEmergencyGestureEnabled(); updateEmergencyGesturePowerButtonCooldownPeriodMs(); } Loading @@ -720,6 +899,9 @@ public class GestureLauncherService extends SystemService { if (userId == mUserId) { updateCameraRegistered(); updateCameraDoubleTapPowerEnabled(); if (launchWalletOptionOnPowerDoubleTap()) { updateWalletDoubleTapPowerEnabled(); } updateEmergencyGestureEnabled(); updateEmergencyGesturePowerButtonCooldownPeriodMs(); } Loading services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java +463 −86 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/GestureLauncherService.java +206 −24 Original line number Diff line number Diff line Loading @@ -16,9 +16,13 @@ package com.android.server; import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap; import static com.android.internal.R.integer.config_defaultMinEmergencyGestureTapDurationMillis; import android.app.ActivityManager; import android.app.ActivityOptions; import android.app.PendingIntent; import android.app.StatusBarManager; import android.content.BroadcastReceiver; import android.content.Context; Loading @@ -33,6 +37,7 @@ import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.hardware.TriggerEvent; import android.hardware.TriggerEventListener; import android.os.Bundle; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager.WakeLock; Loading @@ -41,10 +46,12 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.service.quickaccesswallet.QuickAccessWalletClient; import android.util.MutableBoolean; import android.util.Slog; import android.view.KeyEvent; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.UiEvent; Loading @@ -70,7 +77,7 @@ public class GestureLauncherService extends SystemService { * Time in milliseconds in which the power button must be pressed twice so it will be considered * as a camera launch. */ @VisibleForTesting static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300; @VisibleForTesting static final long POWER_DOUBLE_TAP_MAX_TIME_MS = 300; /** Loading Loading @@ -100,10 +107,23 @@ public class GestureLauncherService extends SystemService { @VisibleForTesting static final int EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX = 5000; /** * Number of taps required to launch camera shortcut. */ private static final int CAMERA_POWER_TAP_COUNT_THRESHOLD = 2; /** Indicates camera should be launched on power double tap. */ @VisibleForTesting static final int LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER = 0; /** Indicates wallet should be launched on power double tap. */ @VisibleForTesting static final int LAUNCH_WALLET_ON_DOUBLE_TAP_POWER = 1; /** Number of taps required to launch the double tap shortcut (either camera or wallet). */ public static final int DOUBLE_POWER_TAP_COUNT_THRESHOLD = 2; /** Bundle to send with PendingIntent to grant background activity start privileges. */ private static final Bundle GRANT_BACKGROUND_START_PRIVILEGES = ActivityOptions.makeBasic() .setPendingIntentBackgroundActivityStartMode( ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS) .toBundle(); private final QuickAccessWalletClient mQuickAccessWalletClient; /** The listener that receives the gesture event. */ private final GestureEventListener mGestureListener = new GestureEventListener(); Loading Loading @@ -158,6 +178,9 @@ public class GestureLauncherService extends SystemService { */ private boolean mCameraDoubleTapPowerEnabled; /** Whether wallet double tap power button gesture is currently enabled. */ private boolean mWalletDoubleTapPowerEnabled; /** * Whether emergency gesture is currently enabled */ Loading Loading @@ -204,15 +227,17 @@ public class GestureLauncherService extends SystemService { } } public GestureLauncherService(Context context) { this(context, new MetricsLogger(), new UiEventLoggerImpl()); this(context, new MetricsLogger(), QuickAccessWalletClient.create(context), new UiEventLoggerImpl()); } @VisibleForTesting GestureLauncherService(Context context, MetricsLogger metricsLogger, UiEventLogger uiEventLogger) { QuickAccessWalletClient quickAccessWalletClient, UiEventLogger uiEventLogger) { super(context); mContext = context; mMetricsLogger = metricsLogger; mQuickAccessWalletClient = quickAccessWalletClient; mUiEventLogger = uiEventLogger; } Loading @@ -237,6 +262,9 @@ public class GestureLauncherService extends SystemService { "GestureLauncherService"); updateCameraRegistered(); updateCameraDoubleTapPowerEnabled(); if (launchWalletOptionOnPowerDoubleTap()) { updateWalletDoubleTapPowerEnabled(); } updateEmergencyGestureEnabled(); updateEmergencyGesturePowerButtonCooldownPeriodMs(); Loading @@ -250,12 +278,24 @@ public class GestureLauncherService extends SystemService { } private void registerContentObservers() { if (launchWalletOptionOnPowerDoubleTap()) { mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor( Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED), false, mSettingObserver, mUserId); mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor( Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE), false, mSettingObserver, mUserId); } else { mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.CAMERA_GESTURE_DISABLED), false, mSettingObserver, mUserId); mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED), Settings.Secure.getUriFor( Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED), false, mSettingObserver, mUserId); } mContext.getContentResolver().registerContentObserver( Settings.Secure.getUriFor(Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED), false, mSettingObserver, mUserId); Loading Loading @@ -291,6 +331,14 @@ public class GestureLauncherService extends SystemService { } } @VisibleForTesting void updateWalletDoubleTapPowerEnabled() { boolean enabled = isWalletDoubleTapPowerSettingEnabled(mContext, mUserId); synchronized (this) { mWalletDoubleTapPowerEnabled = enabled; } } @VisibleForTesting void updateEmergencyGestureEnabled() { boolean enabled = isEmergencyGestureSettingEnabled(mContext, mUserId); Loading Loading @@ -418,11 +466,35 @@ public class GestureLauncherService extends SystemService { Settings.Secure.CAMERA_GESTURE_DISABLED, 0, userId) == 0); } /** Checks if camera should be launched on double press of the power button. */ public static boolean isCameraDoubleTapPowerSettingEnabled(Context context, int userId) { return isCameraDoubleTapPowerEnabled(context.getResources()) boolean res; if (launchWalletOptionOnPowerDoubleTap()) { res = isDoubleTapPowerGestureSettingEnabled(context, userId) && getDoubleTapPowerGestureAction(context, userId) == LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER; } else { // These are legacy settings that will be deprecated once the option to launch both // wallet and camera has been created. res = isCameraDoubleTapPowerEnabled(context.getResources()) && (Settings.Secure.getIntForUser(context.getContentResolver(), Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0); } return res; } /** Checks if wallet should be launched on double tap of the power button. */ public static boolean isWalletDoubleTapPowerSettingEnabled(Context context, int userId) { if (!launchWalletOptionOnPowerDoubleTap()) { return false; } return isDoubleTapPowerGestureSettingEnabled(context, userId) && getDoubleTapPowerGestureAction(context, userId) == LAUNCH_WALLET_ON_DOUBLE_TAP_POWER; } public static boolean isCameraLiftTriggerSettingEnabled(Context context, int userId) { return isCameraLiftTriggerEnabled(context.getResources()) Loading @@ -441,6 +513,28 @@ public class GestureLauncherService extends SystemService { isDefaultEmergencyGestureEnabled(context.getResources()) ? 1 : 0, userId) != 0; } private static int getDoubleTapPowerGestureAction(Context context, int userId) { return Settings.Secure.getIntForUser( context.getContentResolver(), Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE, LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER, userId); } /** Whether the shortcut to launch app on power double press is enabled. */ private static boolean isDoubleTapPowerGestureSettingEnabled(Context context, int userId) { return Settings.Secure.getIntForUser( context.getContentResolver(), Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED, isDoubleTapConfigEnabled(context.getResources()) ? 1 : 0, userId) == 1; } private static boolean isDoubleTapConfigEnabled(Resources resources) { return resources.getBoolean(R.bool.config_doubleTapPowerGestureEnabled); } /** * Gets power button cooldown period in milliseconds after emergency gesture is triggered. The * value is capped at a maximum Loading Loading @@ -494,12 +588,19 @@ public class GestureLauncherService extends SystemService { * Whether GestureLauncherService should be enabled according to system properties. */ public static boolean isGestureLauncherEnabled(Resources resources) { return isCameraLaunchEnabled(resources) || isCameraDoubleTapPowerEnabled(resources) boolean res = isCameraLaunchEnabled(resources) || isCameraLiftTriggerEnabled(resources) || isEmergencyGestureEnabled(resources); if (launchWalletOptionOnPowerDoubleTap()) { res |= isDoubleTapConfigEnabled(resources); } else { res |= isCameraDoubleTapPowerEnabled(resources); } return res; } /** * Attempts to intercept power key down event by detecting certain gesture patterns * Loading Loading @@ -530,6 +631,7 @@ public class GestureLauncherService extends SystemService { return false; } boolean launchCamera = false; boolean launchWallet = false; boolean launchEmergencyGesture = false; boolean intercept = false; long powerTapInterval; Loading @@ -541,7 +643,7 @@ public class GestureLauncherService extends SystemService { mFirstPowerDown = event.getEventTime(); mPowerButtonConsecutiveTaps = 1; mPowerButtonSlowConsecutiveTaps = 1; } else if (powerTapInterval >= CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) { } else if (powerTapInterval >= POWER_DOUBLE_TAP_MAX_TIME_MS) { // Tap too slow for shortcuts mFirstPowerDown = event.getEventTime(); mPowerButtonConsecutiveTaps = 1; Loading Loading @@ -586,10 +688,16 @@ public class GestureLauncherService extends SystemService { } } if (mCameraDoubleTapPowerEnabled && powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS && mPowerButtonConsecutiveTaps == CAMERA_POWER_TAP_COUNT_THRESHOLD) { && powerTapInterval < POWER_DOUBLE_TAP_MAX_TIME_MS && mPowerButtonConsecutiveTaps == DOUBLE_POWER_TAP_COUNT_THRESHOLD) { launchCamera = true; intercept = interactive; } else if (launchWalletOptionOnPowerDoubleTap() && mWalletDoubleTapPowerEnabled && powerTapInterval < POWER_DOUBLE_TAP_MAX_TIME_MS && mPowerButtonConsecutiveTaps == DOUBLE_POWER_TAP_COUNT_THRESHOLD) { launchWallet = true; intercept = interactive; } } if (mPowerButtonConsecutiveTaps > 1 || mPowerButtonSlowConsecutiveTaps > 1) { Loading @@ -608,6 +716,10 @@ public class GestureLauncherService extends SystemService { (int) powerTapInterval); mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER); } } else if (launchWallet) { Slog.i(TAG, "Power button double tap gesture detected, launching wallet. Interval=" + powerTapInterval + "ms"); launchWallet = sendGestureTargetActivityPendingIntent(); } else if (launchEmergencyGesture) { Slog.i(TAG, "Emergency gesture detected, launching."); launchEmergencyGesture = handleEmergencyGesture(); Loading @@ -623,11 +735,75 @@ public class GestureLauncherService extends SystemService { mPowerButtonSlowConsecutiveTaps); mMetricsLogger.histogram("power_double_tap_interval", (int) powerTapInterval); outLaunched.value = launchCamera || launchEmergencyGesture; outLaunched.value = launchCamera || launchEmergencyGesture || launchWallet; // Intercept power key event if the press is part of a gesture (camera, eGesture) and the // user has completed setup. return intercept && isUserSetupComplete(); } /** * Fetches and sends gestureTargetActivityPendingIntent from QuickAccessWallet, which is a * specific activity that QuickAccessWalletService has defined to be launch on detection of the * power button gesture. */ private boolean sendGestureTargetActivityPendingIntent() { boolean userSetupComplete = isUserSetupComplete(); if (mQuickAccessWalletClient == null || !mQuickAccessWalletClient.isWalletServiceAvailable()) { Slog.w(TAG, "QuickAccessWalletService is not available, ignoring wallet gesture."); return false; } if (!userSetupComplete) { if (DBG) { Slog.d(TAG, "userSetupComplete = false, ignoring wallet gesture."); } return false; } if (DBG) { Slog.d(TAG, "userSetupComplete = true, performing wallet gesture."); } mQuickAccessWalletClient.getGestureTargetActivityPendingIntent( getContext().getMainExecutor(), gesturePendingIntent -> { if (gesturePendingIntent == null) { Slog.d(TAG, "getGestureTargetActivityPendingIntent is null."); sendFallbackPendingIntent(); return; } sendPendingIntentWithBackgroundStartPrivileges(gesturePendingIntent); }); return true; } /** * If gestureTargetActivityPendingIntent is null, this method is invoked to start the activity * that QuickAccessWalletService has defined to host the Wallet view, which is typically the * home screen of the Wallet application. */ private void sendFallbackPendingIntent() { mQuickAccessWalletClient.getWalletPendingIntent( getContext().getMainExecutor(), walletPendingIntent -> { if (walletPendingIntent == null) { Slog.w(TAG, "getWalletPendingIntent returns null. Not launching " + "anything for wallet."); return; } sendPendingIntentWithBackgroundStartPrivileges(walletPendingIntent); }); } private void sendPendingIntentWithBackgroundStartPrivileges(PendingIntent pendingIntent) { try { pendingIntent.send(GRANT_BACKGROUND_START_PRIVILEGES); } catch (PendingIntent.CanceledException e) { Slog.e(TAG, "PendingIntent was canceled", e); } } /** * @return true if camera was launched, false otherwise. */ Loading Loading @@ -709,6 +885,9 @@ public class GestureLauncherService extends SystemService { registerContentObservers(); updateCameraRegistered(); updateCameraDoubleTapPowerEnabled(); if (launchWalletOptionOnPowerDoubleTap()) { updateWalletDoubleTapPowerEnabled(); } updateEmergencyGestureEnabled(); updateEmergencyGesturePowerButtonCooldownPeriodMs(); } Loading @@ -720,6 +899,9 @@ public class GestureLauncherService extends SystemService { if (userId == mUserId) { updateCameraRegistered(); updateCameraDoubleTapPowerEnabled(); if (launchWalletOptionOnPowerDoubleTap()) { updateWalletDoubleTapPowerEnabled(); } updateEmergencyGestureEnabled(); updateEmergencyGesturePowerButtonCooldownPeriodMs(); } Loading
services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java +463 −86 File changed.Preview size limit exceeded, changes collapsed. Show changes