• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server;
18 
19 import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap;
20 import static android.service.quickaccesswallet.Flags.launchWalletViaSysuiCallbacks;
21 
22 import static com.android.internal.R.integer.config_defaultMinEmergencyGestureTapDurationMillis;
23 
24 import android.app.ActivityManager;
25 import android.app.ActivityOptions;
26 import android.app.PendingIntent;
27 import android.app.StatusBarManager;
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.pm.PackageManager;
33 import android.content.res.Resources;
34 import android.database.ContentObserver;
35 import android.hardware.Sensor;
36 import android.hardware.SensorEvent;
37 import android.hardware.SensorEventListener;
38 import android.hardware.SensorManager;
39 import android.hardware.TriggerEvent;
40 import android.hardware.TriggerEventListener;
41 import android.os.Bundle;
42 import android.os.Handler;
43 import android.os.PowerManager;
44 import android.os.PowerManager.WakeLock;
45 import android.os.SystemClock;
46 import android.os.SystemProperties;
47 import android.os.Trace;
48 import android.os.UserHandle;
49 import android.provider.Settings;
50 import android.service.quickaccesswallet.QuickAccessWalletClient;
51 import android.util.MutableBoolean;
52 import android.util.Slog;
53 import android.view.KeyEvent;
54 
55 import com.android.internal.R;
56 import com.android.internal.annotations.VisibleForTesting;
57 import com.android.internal.logging.MetricsLogger;
58 import com.android.internal.logging.UiEvent;
59 import com.android.internal.logging.UiEventLogger;
60 import com.android.internal.logging.UiEventLoggerImpl;
61 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
62 import com.android.server.statusbar.StatusBarManagerInternal;
63 import com.android.server.wm.WindowManagerInternal;
64 
65 /**
66  * The service that listens for gestures detected in sensor firmware and starts the intent
67  * accordingly.
68  *
69  * @hide
70  */
71 public class GestureLauncherService extends SystemService {
72     private static final boolean DBG = false;
73     private static final boolean DBG_CAMERA_LIFT = false;
74     private static final String TAG = "GestureLauncherService";
75 
76     /**
77      * Time in milliseconds in which the power button must be pressed twice so it will be considered
78      * as a camera launch.
79      */
80     @VisibleForTesting static final long POWER_DOUBLE_TAP_MAX_TIME_MS = 300;
81 
82 
83     /**
84      * Interval in milliseconds in which the power button must be depressed in succession to be
85      * considered part of an extended sequence of taps. Note that this is a looser threshold than
86      * the camera launch gesture, because the purpose of this threshold is to measure the
87      * frequency of consecutive taps, for evaluation for future gestures.
88      */
89     @VisibleForTesting static final long POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS = 500;
90 
91     /**
92      * Number of taps required to launch emergency gesture ui.
93      */
94     private static final int EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD = 5;
95 
96     /**
97      * Default value of the power button "cooldown" period after the Emergency gesture is triggered.
98      * See {@link Settings.Global#EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS}
99      */
100     private static final int EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_DEFAULT = 3000;
101 
102     /**
103      * Maximum value of the power button "cooldown" period after the Emergency gesture is triggered.
104      * The value read from {@link Settings.Global#EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS}
105      * is capped at this maximum.
106      */
107     @VisibleForTesting
108     static final int EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX = 5000;
109 
110     /** Configuration value indicating double tap power gesture is disabled. */
111     @VisibleForTesting static final int DOUBLE_TAP_POWER_DISABLED_MODE = 0;
112 
113     /** Configuration value indicating double tap power gesture should launch camera. */
114     @VisibleForTesting static final int DOUBLE_TAP_POWER_LAUNCH_CAMERA_MODE = 1;
115 
116     /**
117      * Configuration value indicating double tap power gesture should launch one of many target
118      * actions.
119      */
120     @VisibleForTesting static final int DOUBLE_TAP_POWER_MULTI_TARGET_MODE = 2;
121 
122     /** Indicates camera launch is selected as target action for multi target double tap power. */
123     @VisibleForTesting static final int LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER = 0;
124 
125     /** Indicates wallet launch is selected as target action for multi target double tap power. */
126     @VisibleForTesting static final int LAUNCH_WALLET_ON_DOUBLE_TAP_POWER = 1;
127 
128     /** Number of taps required to launch the double tap shortcut (either camera or wallet). */
129     public static final int DOUBLE_POWER_TAP_COUNT_THRESHOLD = 2;
130 
131     /** Bundle to send with PendingIntent to grant background activity start privileges. */
132     private static final Bundle GRANT_BACKGROUND_START_PRIVILEGES =
133             ActivityOptions.makeBasic()
134                     .setPendingIntentBackgroundActivityStartMode(
135                             ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS)
136                     .toBundle();
137 
138     private final QuickAccessWalletClient mQuickAccessWalletClient;
139 
140     /** The listener that receives the gesture event. */
141     private final GestureEventListener mGestureListener = new GestureEventListener();
142     private final CameraLiftTriggerEventListener mCameraLiftTriggerListener =
143             new CameraLiftTriggerEventListener();
144 
145     private Sensor mCameraLaunchSensor;
146     private Sensor mCameraLiftTriggerSensor;
147     private Context mContext;
148     private final MetricsLogger mMetricsLogger;
149     private PowerManager mPowerManager;
150     private WindowManagerInternal mWindowManagerInternal;
151 
152     /** The wake lock held when a gesture is detected. */
153     private WakeLock mWakeLock;
154     private boolean mCameraLaunchRegistered;
155     private boolean mCameraLiftRegistered;
156     private int mUserId;
157 
158     // Below are fields used for event logging only.
159     /** Elapsed real time when the camera gesture is turned on. */
160     private long mCameraGestureOnTimeMs = 0L;
161 
162     /** Elapsed real time when the last camera gesture was detected. */
163     private long mCameraGestureLastEventTime = 0L;
164 
165     /**
166      * How long the sensor 1 has been turned on since camera launch sensor was
167      * subscribed to and when the last camera launch gesture was detected.
168      * <p>Sensor 1 is the main sensor used to detect camera launch gesture.</p>
169      */
170     private long mCameraGestureSensor1LastOnTimeMs = 0L;
171 
172     /**
173      * If applicable, how long the sensor 2 has been turned on since camera
174      * launch sensor was subscribed to and when the last camera launch
175      * gesture was detected.
176      * <p>Sensor 2 is the secondary sensor used to detect camera launch gesture.
177      * This is optional and if only sensor 1 is used for detect camera launch
178      * gesture, this value would always be 0.</p>
179      */
180     private long mCameraGestureSensor2LastOnTimeMs = 0L;
181 
182     /**
183      * Extra information about the event when the last camera launch gesture
184      * was detected.
185      */
186     private int mCameraLaunchLastEventExtra = 0;
187 
188     /**
189      * Whether camera double tap power button gesture is currently enabled;
190      */
191     private boolean mCameraDoubleTapPowerEnabled;
192 
193     /** Whether wallet double tap power button gesture is currently enabled. */
194     private boolean mWalletDoubleTapPowerEnabled;
195 
196     /**
197      * Whether emergency gesture is currently enabled
198      */
199     private boolean mEmergencyGestureEnabled;
200 
201     /**
202      * Power button cooldown period in milliseconds, after emergency gesture is triggered. A zero
203      * value means the cooldown period is disabled.
204      */
205     private int mEmergencyGesturePowerButtonCooldownPeriodMs;
206 
207     private long mLastPowerDown;
208     private long mFirstPowerDown;
209     private long mLastEmergencyGestureTriggered;
210     private int mPowerButtonConsecutiveTaps;
211     private int mPowerButtonSlowConsecutiveTaps;
212     private final UiEventLogger mUiEventLogger;
213 
214     private boolean mHasFeatureWatch;
215 
216     @VisibleForTesting
217     public enum GestureLauncherEvent implements UiEventLogger.UiEventEnum {
218         @UiEvent(doc = "The user lifted the device just the right way to launch the camera.")
219         GESTURE_CAMERA_LIFT(658),
220 
221         @UiEvent(doc = "The user wiggled the device just the right way to launch the camera.")
222         GESTURE_CAMERA_WIGGLE(659),
223 
224         @UiEvent(doc = "The user double-tapped power quickly enough to launch the camera.")
225         GESTURE_CAMERA_DOUBLE_TAP_POWER(660),
226 
227         @UiEvent(doc = "The user multi-tapped power quickly enough to signal an emergency.")
228         GESTURE_EMERGENCY_TAP_POWER(661);
229 
230         private final int mId;
231 
GestureLauncherEvent(int id)232         GestureLauncherEvent(int id) {
233             mId = id;
234         }
235 
236         @Override
getId()237         public int getId() {
238             return mId;
239         }
240     }
241 
GestureLauncherService(Context context)242     public GestureLauncherService(Context context) {
243         this(context, new MetricsLogger(),
244                 QuickAccessWalletClient.create(context), new UiEventLoggerImpl());
245     }
246 
247     @VisibleForTesting
GestureLauncherService(Context context, MetricsLogger metricsLogger, QuickAccessWalletClient quickAccessWalletClient, UiEventLogger uiEventLogger)248     public GestureLauncherService(Context context, MetricsLogger metricsLogger,
249             QuickAccessWalletClient quickAccessWalletClient, UiEventLogger uiEventLogger) {
250         super(context);
251         mContext = context;
252         mMetricsLogger = metricsLogger;
253         mQuickAccessWalletClient = quickAccessWalletClient;
254         mUiEventLogger = uiEventLogger;
255     }
256 
257     @Override
onStart()258     public void onStart() {
259         LocalServices.addService(GestureLauncherService.class, this);
260     }
261 
262     @Override
onBootPhase(int phase)263     public void onBootPhase(int phase) {
264         if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
265             Resources resources = mContext.getResources();
266             if (!isGestureLauncherEnabled(resources)) {
267                 if (DBG) Slog.d(TAG, "Gesture launcher is disabled in system properties.");
268                 return;
269             }
270 
271             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
272             mPowerManager = (PowerManager) mContext.getSystemService(
273                     Context.POWER_SERVICE);
274             mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
275                     "GestureLauncherService");
276             updateCameraRegistered();
277             updateCameraDoubleTapPowerEnabled();
278             if (launchWalletOptionOnPowerDoubleTap()) {
279                 updateWalletDoubleTapPowerEnabled();
280             }
281             updateEmergencyGestureEnabled();
282             updateEmergencyGesturePowerButtonCooldownPeriodMs();
283 
284             mUserId = ActivityManager.getCurrentUser();
285             mContext.registerReceiver(mUserReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
286             registerContentObservers();
287 
288             mHasFeatureWatch =
289                     mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
290         }
291     }
292 
registerContentObservers()293     private void registerContentObservers() {
294         if (launchWalletOptionOnPowerDoubleTap()) {
295             mContext.getContentResolver().registerContentObserver(
296                     Settings.Secure.getUriFor(
297                             Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED),
298                     false, mSettingObserver, mUserId);
299             mContext.getContentResolver().registerContentObserver(
300                     Settings.Secure.getUriFor(
301                             Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE),
302                     false, mSettingObserver, mUserId);
303         }
304         mContext.getContentResolver().registerContentObserver(
305                 Settings.Secure.getUriFor(Settings.Secure.CAMERA_GESTURE_DISABLED),
306                 false, mSettingObserver, mUserId);
307         mContext.getContentResolver().registerContentObserver(
308                 Settings.Secure.getUriFor(
309                         Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED),
310                 false, mSettingObserver, mUserId);
311         mContext.getContentResolver().registerContentObserver(
312                 Settings.Secure.getUriFor(Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED),
313                 false, mSettingObserver, mUserId);
314         mContext.getContentResolver().registerContentObserver(
315                 Settings.Secure.getUriFor(Settings.Secure.EMERGENCY_GESTURE_ENABLED),
316                 false, mSettingObserver, mUserId);
317         mContext.getContentResolver().registerContentObserver(
318                 Settings.Global.getUriFor(
319                         Settings.Global.EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS),
320                 false, mSettingObserver, mUserId);
321     }
322 
updateCameraRegistered()323     private void updateCameraRegistered() {
324         Resources resources = mContext.getResources();
325         if (isCameraLaunchSettingEnabled(mContext, mUserId)) {
326             registerCameraLaunchGesture(resources);
327         } else {
328             unregisterCameraLaunchGesture();
329         }
330 
331         if (isCameraLiftTriggerSettingEnabled(mContext, mUserId)) {
332             registerCameraLiftTrigger(resources);
333         } else {
334             unregisterCameraLiftTrigger();
335         }
336     }
337 
338     @VisibleForTesting
updateCameraDoubleTapPowerEnabled()339     void updateCameraDoubleTapPowerEnabled() {
340         boolean enabled = isCameraDoubleTapPowerSettingEnabled(mContext, mUserId);
341         synchronized (this) {
342             mCameraDoubleTapPowerEnabled = enabled;
343         }
344     }
345 
346     @VisibleForTesting
updateWalletDoubleTapPowerEnabled()347     void updateWalletDoubleTapPowerEnabled() {
348         boolean enabled = isWalletDoubleTapPowerSettingEnabled(mContext, mUserId);
349         synchronized (this) {
350             mWalletDoubleTapPowerEnabled = enabled;
351         }
352     }
353 
354     @VisibleForTesting
updateEmergencyGestureEnabled()355     void updateEmergencyGestureEnabled() {
356         boolean enabled = isEmergencyGestureSettingEnabled(mContext, mUserId);
357         synchronized (this) {
358             mEmergencyGestureEnabled = enabled;
359         }
360     }
361 
362     @VisibleForTesting
updateEmergencyGesturePowerButtonCooldownPeriodMs()363     void updateEmergencyGesturePowerButtonCooldownPeriodMs() {
364         int cooldownPeriodMs = getEmergencyGesturePowerButtonCooldownPeriodMs(mContext, mUserId);
365         synchronized (this) {
366             mEmergencyGesturePowerButtonCooldownPeriodMs = cooldownPeriodMs;
367         }
368     }
369 
unregisterCameraLaunchGesture()370     private void unregisterCameraLaunchGesture() {
371         if (mCameraLaunchRegistered) {
372             mCameraLaunchRegistered = false;
373             mCameraGestureOnTimeMs = 0L;
374             mCameraGestureLastEventTime = 0L;
375             mCameraGestureSensor1LastOnTimeMs = 0;
376             mCameraGestureSensor2LastOnTimeMs = 0;
377             mCameraLaunchLastEventExtra = 0;
378 
379             SensorManager sensorManager = (SensorManager) mContext.getSystemService(
380                     Context.SENSOR_SERVICE);
381             sensorManager.unregisterListener(mGestureListener);
382         }
383     }
384 
385     /**
386      * Registers for the camera launch gesture.
387      */
registerCameraLaunchGesture(Resources resources)388     private void registerCameraLaunchGesture(Resources resources) {
389         if (mCameraLaunchRegistered) {
390             return;
391         }
392         mCameraGestureOnTimeMs = SystemClock.elapsedRealtime();
393         mCameraGestureLastEventTime = mCameraGestureOnTimeMs;
394         SensorManager sensorManager = (SensorManager) mContext.getSystemService(
395                 Context.SENSOR_SERVICE);
396         int cameraLaunchGestureId = resources.getInteger(
397                 com.android.internal.R.integer.config_cameraLaunchGestureSensorType);
398         if (cameraLaunchGestureId != -1) {
399             mCameraLaunchRegistered = false;
400             String sensorName = resources.getString(
401                 com.android.internal.R.string.config_cameraLaunchGestureSensorStringType);
402             mCameraLaunchSensor = sensorManager.getDefaultSensor(
403                     cameraLaunchGestureId,
404                     true /*wakeUp*/);
405 
406             // Compare the camera gesture string type to that in the resource file to make
407             // sure we are registering the correct sensor. This is redundant check, it
408             // makes the code more robust.
409             if (mCameraLaunchSensor != null) {
410                 if (sensorName.equals(mCameraLaunchSensor.getStringType())) {
411                     mCameraLaunchRegistered = sensorManager.registerListener(mGestureListener,
412                             mCameraLaunchSensor, 0);
413                 } else {
414                     String message = String.format("Wrong configuration. Sensor type and sensor "
415                             + "string type don't match: %s in resources, %s in the sensor.",
416                             sensorName, mCameraLaunchSensor.getStringType());
417                     throw new RuntimeException(message);
418                 }
419             }
420             if (DBG) Slog.d(TAG, "Camera launch sensor registered: " + mCameraLaunchRegistered);
421         } else {
422             if (DBG) Slog.d(TAG, "Camera launch sensor is not specified.");
423         }
424     }
425 
unregisterCameraLiftTrigger()426     private void unregisterCameraLiftTrigger() {
427         if (mCameraLiftRegistered) {
428             mCameraLiftRegistered = false;
429 
430             SensorManager sensorManager = (SensorManager) mContext.getSystemService(
431                     Context.SENSOR_SERVICE);
432             sensorManager.cancelTriggerSensor(mCameraLiftTriggerListener, mCameraLiftTriggerSensor);
433         }
434     }
435 
436     /**
437      * Registers for the camera lift trigger.
438      */
registerCameraLiftTrigger(Resources resources)439     private void registerCameraLiftTrigger(Resources resources) {
440         if (mCameraLiftRegistered) {
441             return;
442         }
443         SensorManager sensorManager = (SensorManager) mContext.getSystemService(
444                 Context.SENSOR_SERVICE);
445         int cameraLiftTriggerId = resources.getInteger(
446                 com.android.internal.R.integer.config_cameraLiftTriggerSensorType);
447         if (cameraLiftTriggerId != -1) {
448             mCameraLiftRegistered = false;
449             String sensorName = resources.getString(
450                 com.android.internal.R.string.config_cameraLiftTriggerSensorStringType);
451             mCameraLiftTriggerSensor = sensorManager.getDefaultSensor(
452                     cameraLiftTriggerId,
453                     true /*wakeUp*/);
454 
455             // Compare the camera lift trigger string type to that in the resource file to make
456             // sure we are registering the correct sensor. This is redundant check, it
457             // makes the code more robust.
458             if (mCameraLiftTriggerSensor != null) {
459                 if (sensorName.equals(mCameraLiftTriggerSensor.getStringType())) {
460                     mCameraLiftRegistered = sensorManager.requestTriggerSensor(mCameraLiftTriggerListener,
461                             mCameraLiftTriggerSensor);
462                 } else {
463                     String message = String.format("Wrong configuration. Sensor type and sensor "
464                             + "string type don't match: %s in resources, %s in the sensor.",
465                             sensorName, mCameraLiftTriggerSensor.getStringType());
466                     throw new RuntimeException(message);
467                 }
468             }
469             if (DBG) Slog.d(TAG, "Camera lift trigger sensor registered: " + mCameraLiftRegistered);
470         } else {
471             if (DBG) Slog.d(TAG, "Camera lift trigger sensor is not specified.");
472         }
473     }
474 
isCameraLaunchSettingEnabled(Context context, int userId)475     public static boolean isCameraLaunchSettingEnabled(Context context, int userId) {
476         return isCameraLaunchEnabled(context.getResources())
477                 && (Settings.Secure.getIntForUser(context.getContentResolver(),
478                         Settings.Secure.CAMERA_GESTURE_DISABLED, 0, userId) == 0);
479     }
480 
481     /** Checks if camera should be launched on double press of the power button. */
isCameraDoubleTapPowerSettingEnabled(Context context, int userId)482     public static boolean isCameraDoubleTapPowerSettingEnabled(Context context, int userId) {
483         if (!launchWalletOptionOnPowerDoubleTap()) {
484             return isCameraDoubleTapPowerEnabled(context.getResources())
485                     && (Settings.Secure.getIntForUser(context.getContentResolver(),
486                     Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0);
487         }
488 
489         final int doubleTapPowerGestureSettingMode = getDoubleTapPowerGestureMode(
490                 context.getResources());
491 
492         return switch (doubleTapPowerGestureSettingMode) {
493             case DOUBLE_TAP_POWER_LAUNCH_CAMERA_MODE -> Settings.Secure.getIntForUser(
494                     context.getContentResolver(),
495                     Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0;
496             case DOUBLE_TAP_POWER_MULTI_TARGET_MODE ->
497                     isMultiTargetDoubleTapPowerGestureSettingEnabled(context, userId)
498                             && getDoubleTapPowerGestureAction(context, userId)
499                             == LAUNCH_CAMERA_ON_DOUBLE_TAP_POWER;
500             default -> false;
501         };
502     }
503 
504     /** Checks if wallet should be launched on double tap of the power button. */
isWalletDoubleTapPowerSettingEnabled(Context context, int userId)505     public static boolean isWalletDoubleTapPowerSettingEnabled(Context context, int userId) {
506         if (!launchWalletOptionOnPowerDoubleTap()) {
507             return false;
508         }
509 
510         return getDoubleTapPowerGestureMode(context.getResources())
511                 == DOUBLE_TAP_POWER_MULTI_TARGET_MODE
512                 && isMultiTargetDoubleTapPowerGestureSettingEnabled(context, userId)
513                 && getDoubleTapPowerGestureAction(context, userId)
514                 == LAUNCH_WALLET_ON_DOUBLE_TAP_POWER;
515     }
516 
isCameraLiftTriggerSettingEnabled(Context context, int userId)517     public static boolean isCameraLiftTriggerSettingEnabled(Context context, int userId) {
518         return isCameraLiftTriggerEnabled(context.getResources())
519                 && (Settings.Secure.getIntForUser(context.getContentResolver(),
520                         Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED,
521                         Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED_DEFAULT, userId) != 0);
522     }
523 
524     /**
525      * Whether to enable emergency gesture.
526      */
isEmergencyGestureSettingEnabled(Context context, int userId)527     public static boolean isEmergencyGestureSettingEnabled(Context context, int userId) {
528         return isEmergencyGestureEnabled(context.getResources())
529                 && Settings.Secure.getIntForUser(context.getContentResolver(),
530                 Settings.Secure.EMERGENCY_GESTURE_ENABLED,
531                 isDefaultEmergencyGestureEnabled(context.getResources()) ? 1 : 0, userId) != 0;
532     }
533 
534     /** Gets the double tap power gesture mode. */
getDoubleTapPowerGestureMode(Resources resources)535     private static int getDoubleTapPowerGestureMode(Resources resources) {
536         return resources.getInteger(R.integer.config_doubleTapPowerGestureMode);
537     }
538 
539     /**
540      * Whether the setting for multi target double tap power gesture is enabled.
541      *
542      * <p>Multi target double tap power gesture allows the user to choose one of many target actions
543      * when double tapping the power button.
544      * </p>
545      */
isMultiTargetDoubleTapPowerGestureSettingEnabled(Context context, int userId)546     private static boolean isMultiTargetDoubleTapPowerGestureSettingEnabled(Context context,
547             int userId) {
548         return Settings.Secure.getIntForUser(
549                 context.getContentResolver(),
550                 Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE_ENABLED,
551                 getDoubleTapPowerGestureMode(context.getResources())
552                         == DOUBLE_TAP_POWER_MULTI_TARGET_MODE ? 1 : 0,
553                 userId)
554                 == 1;
555     }
556 
557     /** Gets the selected target action for the multi target double tap power gesture.
558      *
559      * <p>The target actions are defined in {@link Settings.Secure#DOUBLE_TAP_POWER_BUTTON_GESTURE}.
560      * </p>
561      */
getDoubleTapPowerGestureAction(Context context, int userId)562     private static int getDoubleTapPowerGestureAction(Context context, int userId) {
563         return Settings.Secure.getIntForUser(
564                 context.getContentResolver(),
565                 Settings.Secure.DOUBLE_TAP_POWER_BUTTON_GESTURE,
566                 context.getResources().getInteger(
567                         R.integer.config_doubleTapPowerGestureMultiTargetDefaultAction),
568                 userId);
569     }
570 
571     /**
572      * Gets power button cooldown period in milliseconds after emergency gesture is triggered. The
573      * value is capped at a maximum
574      * {@link GestureLauncherService#EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX}. If the
575      * value is zero, it means the cooldown period is disabled.
576      */
577     @VisibleForTesting
getEmergencyGesturePowerButtonCooldownPeriodMs(Context context, int userId)578     static int getEmergencyGesturePowerButtonCooldownPeriodMs(Context context, int userId) {
579         int cooldown = Settings.Global.getInt(context.getContentResolver(),
580                 Settings.Global.EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS,
581                 EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_DEFAULT);
582 
583         return Math.min(cooldown, EMERGENCY_GESTURE_POWER_BUTTON_COOLDOWN_PERIOD_MS_MAX);
584     }
585 
586     /**
587      * Whether to enable the camera launch gesture.
588      */
isCameraLaunchEnabled(Resources resources)589     private static boolean isCameraLaunchEnabled(Resources resources) {
590         boolean configSet = resources.getInteger(
591                 com.android.internal.R.integer.config_cameraLaunchGestureSensorType) != -1;
592         return configSet &&
593                 !SystemProperties.getBoolean("gesture.disable_camera_launch", false);
594     }
595 
596     @VisibleForTesting
isCameraDoubleTapPowerEnabled(Resources resources)597     static boolean isCameraDoubleTapPowerEnabled(Resources resources) {
598         return resources.getBoolean(
599                 com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled);
600     }
601 
isCameraLiftTriggerEnabled(Resources resources)602     private static boolean isCameraLiftTriggerEnabled(Resources resources) {
603         boolean configSet = resources.getInteger(
604                 com.android.internal.R.integer.config_cameraLiftTriggerSensorType) != -1;
605         return configSet;
606     }
607 
608     /**
609      * Whether or not the emergency gesture feature is enabled by platform
610      */
isEmergencyGestureEnabled(Resources resources)611     private static boolean isEmergencyGestureEnabled(Resources resources) {
612         return resources.getBoolean(com.android.internal.R.bool.config_emergencyGestureEnabled);
613     }
614 
isDefaultEmergencyGestureEnabled(Resources resources)615     private static boolean isDefaultEmergencyGestureEnabled(Resources resources) {
616         return resources.getBoolean(
617                 com.android.internal.R.bool.config_defaultEmergencyGestureEnabled);
618     }
619 
620     /**
621      * Whether GestureLauncherService should be enabled according to system properties.
622      */
isGestureLauncherEnabled(Resources resources)623     public static boolean isGestureLauncherEnabled(Resources resources) {
624         boolean res =
625                 isCameraLaunchEnabled(resources)
626                         || isCameraLiftTriggerEnabled(resources)
627                         || isEmergencyGestureEnabled(resources);
628         if (launchWalletOptionOnPowerDoubleTap()) {
629             res |= getDoubleTapPowerGestureMode(resources) != DOUBLE_TAP_POWER_DISABLED_MODE;
630         } else {
631             res |= isCameraDoubleTapPowerEnabled(resources);
632         }
633         return res;
634     }
635 
636     /**
637      * Attempts to intercept power key down event by detecting certain gesture patterns
638      *
639      * @param interactive true if the event's policy contains {@code FLAG_INTERACTIVE}
640      * @param outLaunched true if some action is taken as part of the key intercept (eg, app launch)
641      * @return true if the key down event is intercepted
642      */
interceptPowerKeyDown(KeyEvent event, boolean interactive, MutableBoolean outLaunched)643     public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive,
644             MutableBoolean outLaunched) {
645         if (mEmergencyGestureEnabled && mEmergencyGesturePowerButtonCooldownPeriodMs >= 0
646                 && event.getEventTime() - mLastEmergencyGestureTriggered
647                 < mEmergencyGesturePowerButtonCooldownPeriodMs) {
648             Slog.i(TAG, String.format(
649                     "Suppressing power button: within %dms cooldown period after Emergency "
650                             + "Gesture. Begin=%dms, end=%dms.",
651                     mEmergencyGesturePowerButtonCooldownPeriodMs,
652                     mLastEmergencyGestureTriggered,
653                     mLastEmergencyGestureTriggered + mEmergencyGesturePowerButtonCooldownPeriodMs));
654             outLaunched.value = false;
655             return true;
656         }
657 
658         if (event.isLongPress()) {
659             // Long presses are sent as a second key down. If the long press threshold is set lower
660             // than the double tap of sequence interval thresholds, this could cause false double
661             // taps or consecutive taps, so we want to ignore the long press event.
662             outLaunched.value = false;
663             return false;
664         }
665         boolean launchCamera = false;
666         boolean launchWallet = false;
667         boolean launchEmergencyGesture = false;
668         boolean intercept = false;
669         long powerTapInterval;
670         synchronized (this) {
671             powerTapInterval = event.getEventTime() - mLastPowerDown;
672             mLastPowerDown = event.getEventTime();
673             if (powerTapInterval >= POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) {
674                 // Tap too slow, reset consecutive tap counts.
675                 mFirstPowerDown  = event.getEventTime();
676                 mPowerButtonConsecutiveTaps = 1;
677                 mPowerButtonSlowConsecutiveTaps = 1;
678             } else if (powerTapInterval >= POWER_DOUBLE_TAP_MAX_TIME_MS) {
679                 // Tap too slow for shortcuts
680                 mFirstPowerDown  = event.getEventTime();
681                 mPowerButtonConsecutiveTaps = 1;
682                 mPowerButtonSlowConsecutiveTaps++;
683             } else {
684                 // Fast consecutive tap
685                 mPowerButtonConsecutiveTaps++;
686                 mPowerButtonSlowConsecutiveTaps++;
687             }
688             // Check if we need to launch camera or emergency gesture flows
689             if (mEmergencyGestureEnabled) {
690                 // Commit to intercepting the powerkey event after the second "quick" tap to avoid
691                 // lockscreen changes between launching camera and the emergency gesture flow.
692                 // Since watch doesn't have camera gesture, only intercept power key event after
693                 // emergency gesture tap count.
694                 if (mPowerButtonConsecutiveTaps
695                         > (mHasFeatureWatch ? EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD : 1)) {
696                     intercept = interactive;
697                 }
698                 if (mPowerButtonConsecutiveTaps == EMERGENCY_GESTURE_POWER_TAP_COUNT_THRESHOLD) {
699                     long emergencyGestureSpentTime = event.getEventTime() - mFirstPowerDown;
700                     long emergencyGestureTapDetectionMinTimeMs = Settings.Global.getInt(
701                             mContext.getContentResolver(),
702                             Settings.Global.EMERGENCY_GESTURE_TAP_DETECTION_MIN_TIME_MS,
703                             mContext.getResources().getInteger(
704                                     config_defaultMinEmergencyGestureTapDurationMillis));
705                     if (emergencyGestureSpentTime <= emergencyGestureTapDetectionMinTimeMs) {
706                         Slog.i(TAG, "Emergency gesture detected but it's too fast. Gesture time: "
707                                 + emergencyGestureSpentTime + " ms");
708                         // Reset consecutive tap counts.
709                         mFirstPowerDown = event.getEventTime();
710                         mPowerButtonConsecutiveTaps = 1;
711                         mPowerButtonSlowConsecutiveTaps = 1;
712                     } else {
713                         Slog.i(TAG, "Emergency gesture detected. Gesture time: "
714                                 + emergencyGestureSpentTime + " ms");
715                         launchEmergencyGesture = true;
716                         mMetricsLogger.histogram("emergency_gesture_spent_time",
717                                 (int) emergencyGestureSpentTime);
718 
719                     }
720                 }
721             }
722             if (mCameraDoubleTapPowerEnabled
723                     && powerTapInterval < POWER_DOUBLE_TAP_MAX_TIME_MS
724                     && mPowerButtonConsecutiveTaps == DOUBLE_POWER_TAP_COUNT_THRESHOLD) {
725                 launchCamera = true;
726                 intercept = interactive;
727             } else if (launchWalletOptionOnPowerDoubleTap()
728                     && mWalletDoubleTapPowerEnabled
729                     && powerTapInterval < POWER_DOUBLE_TAP_MAX_TIME_MS
730                     && mPowerButtonConsecutiveTaps == DOUBLE_POWER_TAP_COUNT_THRESHOLD) {
731                 launchWallet = true;
732                 intercept = interactive;
733             }
734         }
735         if (mPowerButtonConsecutiveTaps > 1 || mPowerButtonSlowConsecutiveTaps > 1) {
736             Slog.i(TAG, Long.valueOf(mPowerButtonConsecutiveTaps)
737                     + " consecutive power button taps detected, "
738                     + Long.valueOf(mPowerButtonSlowConsecutiveTaps)
739                     + " consecutive slow power button taps detected");
740         }
741         if (launchCamera) {
742             Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval="
743                     + powerTapInterval + "ms");
744             launchCamera = handleCameraGesture(false /* useWakelock */,
745                     StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
746             if (launchCamera) {
747                 mMetricsLogger.action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
748                         (int) powerTapInterval);
749                 mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_DOUBLE_TAP_POWER);
750             }
751         } else if (launchWallet) {
752             Slog.i(TAG, "Power button double tap gesture detected, launching wallet. Interval="
753                     + powerTapInterval + "ms");
754             launchWallet = launchWalletViaSysuiCallbacks() ?
755                     handleWalletGesture() : sendGestureTargetActivityPendingIntent();
756         } else if (launchEmergencyGesture) {
757             Slog.i(TAG, "Emergency gesture detected, launching.");
758             launchEmergencyGesture = handleEmergencyGesture();
759             mUiEventLogger.log(GestureLauncherEvent.GESTURE_EMERGENCY_TAP_POWER);
760             // Record emergency trigger time if emergency UI was launched
761             if (launchEmergencyGesture) {
762                 synchronized (this) {
763                     mLastEmergencyGestureTriggered = event.getEventTime();
764                 }
765             }
766         }
767         mMetricsLogger.histogram("power_consecutive_short_tap_count",
768                 mPowerButtonSlowConsecutiveTaps);
769         mMetricsLogger.histogram("power_double_tap_interval", (int) powerTapInterval);
770 
771         outLaunched.value = launchCamera || launchEmergencyGesture || launchWallet;
772         // Intercept power key event if the press is part of a gesture (camera, eGesture) and the
773         // user has completed setup.
774         return intercept && isUserSetupComplete();
775     }
776 
777     /**
778      * Fetches and sends gestureTargetActivityPendingIntent from QuickAccessWallet, which is a
779      * specific activity that QuickAccessWalletService has defined to be launch on detection of the
780      * power button gesture.
781      */
sendGestureTargetActivityPendingIntent()782     private boolean sendGestureTargetActivityPendingIntent() {
783         boolean userSetupComplete = isUserSetupComplete();
784         if (mQuickAccessWalletClient == null
785                 || !mQuickAccessWalletClient.isWalletServiceAvailable()) {
786             Slog.w(TAG, "QuickAccessWalletService is not available, ignoring wallet gesture.");
787             return false;
788         }
789 
790         if (!userSetupComplete) {
791             if (DBG) {
792                 Slog.d(TAG, "userSetupComplete = false, ignoring wallet gesture.");
793             }
794             return false;
795         }
796         if (DBG) {
797             Slog.d(TAG, "userSetupComplete = true, performing wallet gesture.");
798         }
799 
800         mQuickAccessWalletClient.getGestureTargetActivityPendingIntent(
801                 getContext().getMainExecutor(),
802                 gesturePendingIntent -> {
803                     if (gesturePendingIntent == null) {
804                         Slog.d(TAG, "getGestureTargetActivityPendingIntent is null.");
805                         sendFallbackPendingIntent();
806                         return;
807                     }
808                     sendPendingIntentWithBackgroundStartPrivileges(gesturePendingIntent);
809                 });
810         return true;
811     }
812 
813     /**
814      * If gestureTargetActivityPendingIntent is null, this method is invoked to start the activity
815      * that QuickAccessWalletService has defined to host the Wallet view, which is typically the
816      * home screen of the Wallet application.
817      */
sendFallbackPendingIntent()818     private void sendFallbackPendingIntent() {
819         mQuickAccessWalletClient.getWalletPendingIntent(
820                 getContext().getMainExecutor(),
821                 walletPendingIntent -> {
822                     if (walletPendingIntent == null) {
823                         Slog.w(TAG, "getWalletPendingIntent returns null. Not launching "
824                                 + "anything for wallet.");
825                         return;
826                     }
827                     sendPendingIntentWithBackgroundStartPrivileges(walletPendingIntent);
828                 });
829     }
830 
sendPendingIntentWithBackgroundStartPrivileges(PendingIntent pendingIntent)831     private void sendPendingIntentWithBackgroundStartPrivileges(PendingIntent pendingIntent) {
832         try {
833             pendingIntent.send(GRANT_BACKGROUND_START_PRIVILEGES);
834         } catch (PendingIntent.CanceledException e) {
835             Slog.e(TAG, "PendingIntent was canceled", e);
836         }
837     }
838 
839 
840     /**
841      * @return true if camera was launched, false otherwise.
842      */
843     @VisibleForTesting
handleCameraGesture(boolean useWakelock, int source)844     boolean handleCameraGesture(boolean useWakelock, int source) {
845         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "GestureLauncher:handleCameraGesture");
846         try {
847             boolean userSetupComplete = isUserSetupComplete();
848             if (!userSetupComplete) {
849                 if (DBG) {
850                     Slog.d(TAG, String.format(
851                             "userSetupComplete = %s, ignoring camera gesture.",
852                             userSetupComplete));
853                 }
854                 return false;
855             }
856             if (DBG) {
857                 Slog.d(TAG, String.format(
858                         "userSetupComplete = %s, performing camera gesture.",
859                         userSetupComplete));
860             }
861 
862             if (useWakelock) {
863                 // Make sure we don't sleep too early
864                 mWakeLock.acquire(500L);
865             }
866             StatusBarManagerInternal service = LocalServices.getService(
867                     StatusBarManagerInternal.class);
868             service.onCameraLaunchGestureDetected(source);
869             return true;
870         } finally {
871             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
872         }
873     }
874 
875     @VisibleForTesting
handleWalletGesture()876     boolean handleWalletGesture() {
877         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
878                 "GestureLauncher:handleWalletGesture");
879         try {
880             boolean userSetupComplete = isUserSetupComplete();
881             if (!userSetupComplete) {
882                 if (DBG) {
883                     Slog.d(TAG, "userSetupComplete = false, ignoring wallet gesture.");
884                 }
885                 return false;
886             }
887             if (DBG) {
888                 Slog.d(TAG, "userSetupComplete = true, performing wallet gesture.");
889             }
890 
891             StatusBarManagerInternal service = LocalServices.getService(
892                     StatusBarManagerInternal.class);
893             service.onWalletLaunchGestureDetected();
894             return true;
895         } finally {
896             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
897         }
898     }
899 
900     /**
901      * @return true if emergency gesture UI was launched, false otherwise.
902      */
903     @VisibleForTesting
handleEmergencyGesture()904     boolean handleEmergencyGesture() {
905         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
906                 "GestureLauncher:handleEmergencyGesture");
907         try {
908             boolean userSetupComplete = isUserSetupComplete();
909             if (!userSetupComplete) {
910                 if (DBG) {
911                     Slog.d(TAG, String.format(
912                             "userSetupComplete = %s, ignoring emergency gesture.",
913                             userSetupComplete));
914                 }
915                 return false;
916             }
917             if (DBG) {
918                 Slog.d(TAG, String.format(
919                         "userSetupComplete = %s, performing emergency gesture.",
920                         userSetupComplete));
921             }
922 
923             StatusBarManagerInternal service = LocalServices.getService(
924                     StatusBarManagerInternal.class);
925             service.onEmergencyActionLaunchGestureDetected();
926             return true;
927         } finally {
928             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
929         }
930     }
931 
isUserSetupComplete()932     private boolean isUserSetupComplete() {
933         return Settings.Secure.getIntForUser(mContext.getContentResolver(),
934                 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
935     }
936 
937     private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
938         @Override
939         public void onReceive(Context context, Intent intent) {
940             if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
941                 mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
942                 mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
943                 registerContentObservers();
944                 updateCameraRegistered();
945                 updateCameraDoubleTapPowerEnabled();
946                 if (launchWalletOptionOnPowerDoubleTap()) {
947                     updateWalletDoubleTapPowerEnabled();
948                 }
949                 updateEmergencyGestureEnabled();
950                 updateEmergencyGesturePowerButtonCooldownPeriodMs();
951             }
952         }
953     };
954 
955     private final ContentObserver mSettingObserver = new ContentObserver(new Handler()) {
956         public void onChange(boolean selfChange, android.net.Uri uri, int userId) {
957             if (userId == mUserId) {
958                 updateCameraRegistered();
959                 updateCameraDoubleTapPowerEnabled();
960                 if (launchWalletOptionOnPowerDoubleTap()) {
961                     updateWalletDoubleTapPowerEnabled();
962                 }
963                 updateEmergencyGestureEnabled();
964                 updateEmergencyGesturePowerButtonCooldownPeriodMs();
965             }
966         }
967     };
968 
969     private final class GestureEventListener implements SensorEventListener {
970         @Override
onSensorChanged(SensorEvent event)971         public void onSensorChanged(SensorEvent event) {
972             if (!mCameraLaunchRegistered) {
973               if (DBG) Slog.d(TAG, "Ignoring gesture event because it's unregistered.");
974               return;
975             }
976             if (event.sensor == mCameraLaunchSensor) {
977                 if (DBG) {
978                     float[] values = event.values;
979                     Slog.d(TAG, String.format("Received a camera launch event: " +
980                             "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
981                 }
982                 if (handleCameraGesture(true /* useWakelock */,
983                         StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
984                     mMetricsLogger.action(MetricsEvent.ACTION_WIGGLE_CAMERA_GESTURE);
985                     mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_WIGGLE);
986                     trackCameraLaunchEvent(event);
987                 }
988                 return;
989             }
990         }
991 
992         @Override
onAccuracyChanged(Sensor sensor, int accuracy)993         public void onAccuracyChanged(Sensor sensor, int accuracy) {
994             // Ignored.
995         }
996 
trackCameraLaunchEvent(SensorEvent event)997         private void trackCameraLaunchEvent(SensorEvent event) {
998             long now = SystemClock.elapsedRealtime();
999             long totalDuration = now - mCameraGestureOnTimeMs;
1000             // values[0]: ratio between total time duration when accel is turned on and time
1001             //            duration since camera launch gesture is subscribed.
1002             // values[1]: ratio between total time duration when gyro is turned on and time duration
1003             //            since camera launch gesture is subscribed.
1004             // values[2]: extra information
1005             float[] values = event.values;
1006 
1007             long sensor1OnTime = (long) (totalDuration * (double) values[0]);
1008             long sensor2OnTime = (long) (totalDuration * (double) values[1]);
1009             int extra = (int) values[2];
1010 
1011             // We only log the difference in the event log to make aggregation easier.
1012             long gestureOnTimeDiff = now - mCameraGestureLastEventTime;
1013             long sensor1OnTimeDiff = sensor1OnTime - mCameraGestureSensor1LastOnTimeMs;
1014             long sensor2OnTimeDiff = sensor2OnTime - mCameraGestureSensor2LastOnTimeMs;
1015             int extraDiff = extra - mCameraLaunchLastEventExtra;
1016 
1017             // Gating against negative time difference. This doesn't usually happen, but it may
1018             // happen because of numeric errors.
1019             if (gestureOnTimeDiff < 0 || sensor1OnTimeDiff < 0 || sensor2OnTimeDiff < 0) {
1020                 if (DBG) Slog.d(TAG, "Skipped event logging because negative numbers.");
1021                 return;
1022             }
1023 
1024             if (DBG) Slog.d(TAG, String.format("totalDuration: %d, sensor1OnTime: %s, " +
1025                     "sensor2OnTime: %d, extra: %d",
1026                     gestureOnTimeDiff,
1027                     sensor1OnTimeDiff,
1028                     sensor2OnTimeDiff,
1029                     extraDiff));
1030             EventLogTags.writeCameraGestureTriggered(
1031                     gestureOnTimeDiff,
1032                     sensor1OnTimeDiff,
1033                     sensor2OnTimeDiff,
1034                     extraDiff);
1035 
1036             mCameraGestureLastEventTime = now;
1037             mCameraGestureSensor1LastOnTimeMs = sensor1OnTime;
1038             mCameraGestureSensor2LastOnTimeMs = sensor2OnTime;
1039             mCameraLaunchLastEventExtra = extra;
1040         }
1041     }
1042 
1043     private final class CameraLiftTriggerEventListener extends TriggerEventListener {
1044         @Override
onTrigger(TriggerEvent event)1045         public void onTrigger(TriggerEvent event) {
1046             if (DBG_CAMERA_LIFT) Slog.d(TAG, String.format("onTrigger event - time: %d, name: %s",
1047                     event.timestamp, event.sensor.getName()));
1048             if (!mCameraLiftRegistered) {
1049               if (DBG_CAMERA_LIFT) Slog.d(TAG, "Ignoring camera lift event because it's " +
1050                       "unregistered.");
1051               return;
1052             }
1053             if (event.sensor == mCameraLiftTriggerSensor) {
1054                 Resources resources = mContext.getResources();
1055                 SensorManager sensorManager = (SensorManager) mContext.getSystemService(
1056                         Context.SENSOR_SERVICE);
1057                 boolean keyguardShowingAndNotOccluded =
1058                         mWindowManagerInternal.isKeyguardShowingAndNotOccluded();
1059                 boolean interactive = mPowerManager.isInteractive();
1060                 if (DBG_CAMERA_LIFT) {
1061                     float[] values = event.values;
1062                     Slog.d(TAG, String.format("Received a camera lift trigger " +
1063                             "event: values=[%.4f], keyguard showing: %b, interactive: %b", values[0],
1064                             keyguardShowingAndNotOccluded, interactive));
1065                 }
1066                 if (keyguardShowingAndNotOccluded || !interactive) {
1067                     if (handleCameraGesture(true /* useWakelock */,
1068                             StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER)) {
1069                         MetricsLogger.action(mContext, MetricsEvent.ACTION_CAMERA_LIFT_TRIGGER);
1070                         mUiEventLogger.log(GestureLauncherEvent.GESTURE_CAMERA_LIFT);
1071                     }
1072                 } else {
1073                     if (DBG_CAMERA_LIFT) Slog.d(TAG, "Ignoring lift event");
1074                 }
1075 
1076                 mCameraLiftRegistered = sensorManager.requestTriggerSensor(
1077                         mCameraLiftTriggerListener, mCameraLiftTriggerSensor);
1078 
1079                 if (DBG_CAMERA_LIFT) Slog.d(TAG, "Camera lift trigger sensor re-registered: " +
1080                         mCameraLiftRegistered);
1081                 return;
1082             }
1083         }
1084     }
1085 }
1086