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 android.app.ActivityManager;
20 import android.app.StatusBarManager;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.res.Resources;
26 import android.database.ContentObserver;
27 import android.hardware.Sensor;
28 import android.hardware.SensorEvent;
29 import android.hardware.SensorEventListener;
30 import android.hardware.SensorManager;
31 import android.hardware.TriggerEvent;
32 import android.hardware.TriggerEventListener;
33 import android.os.Handler;
34 import android.os.PowerManager;
35 import android.os.PowerManager.WakeLock;
36 import android.os.SystemClock;
37 import android.os.SystemProperties;
38 import android.os.Trace;
39 import android.os.UserHandle;
40 import android.provider.Settings;
41 import android.util.MutableBoolean;
42 import android.util.Slog;
43 import android.view.KeyEvent;
44 
45 import com.android.internal.annotations.VisibleForTesting;
46 import com.android.internal.logging.MetricsLogger;
47 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
48 import com.android.server.LocalServices;
49 import com.android.server.statusbar.StatusBarManagerInternal;
50 import com.android.server.wm.WindowManagerInternal;
51 
52 /**
53  * The service that listens for gestures detected in sensor firmware and starts the intent
54  * accordingly.
55  * <p>For now, only camera launch gesture is supported, and in the future, more gestures can be
56  * added.</p>
57  * @hide
58  */
59 public class GestureLauncherService extends SystemService {
60     private static final boolean DBG = false;
61     private static final boolean DBG_CAMERA_LIFT = false;
62     private static final String TAG = "GestureLauncherService";
63 
64     /**
65      * Time in milliseconds in which the power button must be pressed twice so it will be considered
66      * as a camera launch.
67      */
68     @VisibleForTesting static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300;
69 
70     /**
71      * Interval in milliseconds in which the power button must be depressed in succession to be
72      * considered part of an extended sequence of taps. Note that this is a looser threshold than
73      * the camera launch gesture, because the purpose of this threshold is to measure the
74      * frequency of consecutive taps, for evaluation for future gestures.
75      */
76     @VisibleForTesting static final long POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS = 500;
77 
78     /** The listener that receives the gesture event. */
79     private final GestureEventListener mGestureListener = new GestureEventListener();
80     private final CameraLiftTriggerEventListener mCameraLiftTriggerListener =
81             new CameraLiftTriggerEventListener();
82 
83     private Sensor mCameraLaunchSensor;
84     private Sensor mCameraLiftTriggerSensor;
85     private Context mContext;
86     private final MetricsLogger mMetricsLogger;
87     private PowerManager mPowerManager;
88     private WindowManagerInternal mWindowManagerInternal;
89 
90     /** The wake lock held when a gesture is detected. */
91     private WakeLock mWakeLock;
92     private boolean mCameraLaunchRegistered;
93     private boolean mCameraLiftRegistered;
94     private int mUserId;
95 
96     // Below are fields used for event logging only.
97     /** Elapsed real time when the camera gesture is turned on. */
98     private long mCameraGestureOnTimeMs = 0L;
99 
100     /** Elapsed real time when the last camera gesture was detected. */
101     private long mCameraGestureLastEventTime = 0L;
102 
103     /**
104      * How long the sensor 1 has been turned on since camera launch sensor was
105      * subscribed to and when the last camera launch gesture was detected.
106      * <p>Sensor 1 is the main sensor used to detect camera launch gesture.</p>
107      */
108     private long mCameraGestureSensor1LastOnTimeMs = 0L;
109 
110     /**
111      * If applicable, how long the sensor 2 has been turned on since camera
112      * launch sensor was subscribed to and when the last camera launch
113      * gesture was detected.
114      * <p>Sensor 2 is the secondary sensor used to detect camera launch gesture.
115      * This is optional and if only sensor 1 is used for detect camera launch
116      * gesture, this value would always be 0.</p>
117      */
118     private long mCameraGestureSensor2LastOnTimeMs = 0L;
119 
120     /**
121      * Extra information about the event when the last camera launch gesture
122      * was detected.
123      */
124     private int mCameraLaunchLastEventExtra = 0;
125 
126     /**
127      * Whether camera double tap power button gesture is currently enabled;
128      */
129     private boolean mCameraDoubleTapPowerEnabled;
130     private long mLastPowerDown;
131     private int mPowerButtonConsecutiveTaps;
132 
GestureLauncherService(Context context)133     public GestureLauncherService(Context context) {
134         this(context, new MetricsLogger());
135     }
136 
137     @VisibleForTesting
GestureLauncherService(Context context, MetricsLogger metricsLogger)138     GestureLauncherService(Context context, MetricsLogger metricsLogger) {
139         super(context);
140         mContext = context;
141         mMetricsLogger = metricsLogger;
142     }
143 
onStart()144     public void onStart() {
145         LocalServices.addService(GestureLauncherService.class, this);
146     }
147 
onBootPhase(int phase)148     public void onBootPhase(int phase) {
149         if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
150             Resources resources = mContext.getResources();
151             if (!isGestureLauncherEnabled(resources)) {
152                 if (DBG) Slog.d(TAG, "Gesture launcher is disabled in system properties.");
153                 return;
154             }
155 
156             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
157             mPowerManager = (PowerManager) mContext.getSystemService(
158                     Context.POWER_SERVICE);
159             mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
160                     "GestureLauncherService");
161             updateCameraRegistered();
162             updateCameraDoubleTapPowerEnabled();
163 
164             mUserId = ActivityManager.getCurrentUser();
165             mContext.registerReceiver(mUserReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
166             registerContentObservers();
167         }
168     }
169 
registerContentObservers()170     private void registerContentObservers() {
171         mContext.getContentResolver().registerContentObserver(
172                 Settings.Secure.getUriFor(Settings.Secure.CAMERA_GESTURE_DISABLED),
173                 false, mSettingObserver, mUserId);
174         mContext.getContentResolver().registerContentObserver(
175                 Settings.Secure.getUriFor(Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED),
176                 false, mSettingObserver, mUserId);
177         mContext.getContentResolver().registerContentObserver(
178                 Settings.Secure.getUriFor(Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED),
179                 false, mSettingObserver, mUserId);
180     }
181 
updateCameraRegistered()182     private void updateCameraRegistered() {
183         Resources resources = mContext.getResources();
184         if (isCameraLaunchSettingEnabled(mContext, mUserId)) {
185             registerCameraLaunchGesture(resources);
186         } else {
187             unregisterCameraLaunchGesture();
188         }
189 
190         if (isCameraLiftTriggerSettingEnabled(mContext, mUserId)) {
191             registerCameraLiftTrigger(resources);
192         } else {
193             unregisterCameraLiftTrigger();
194         }
195     }
196 
197     @VisibleForTesting
updateCameraDoubleTapPowerEnabled()198     void updateCameraDoubleTapPowerEnabled() {
199         boolean enabled = isCameraDoubleTapPowerSettingEnabled(mContext, mUserId);
200         synchronized (this) {
201             mCameraDoubleTapPowerEnabled = enabled;
202         }
203     }
204 
unregisterCameraLaunchGesture()205     private void unregisterCameraLaunchGesture() {
206         if (mCameraLaunchRegistered) {
207             mCameraLaunchRegistered = false;
208             mCameraGestureOnTimeMs = 0L;
209             mCameraGestureLastEventTime = 0L;
210             mCameraGestureSensor1LastOnTimeMs = 0;
211             mCameraGestureSensor2LastOnTimeMs = 0;
212             mCameraLaunchLastEventExtra = 0;
213 
214             SensorManager sensorManager = (SensorManager) mContext.getSystemService(
215                     Context.SENSOR_SERVICE);
216             sensorManager.unregisterListener(mGestureListener);
217         }
218     }
219 
220     /**
221      * Registers for the camera launch gesture.
222      */
registerCameraLaunchGesture(Resources resources)223     private void registerCameraLaunchGesture(Resources resources) {
224         if (mCameraLaunchRegistered) {
225             return;
226         }
227         mCameraGestureOnTimeMs = SystemClock.elapsedRealtime();
228         mCameraGestureLastEventTime = mCameraGestureOnTimeMs;
229         SensorManager sensorManager = (SensorManager) mContext.getSystemService(
230                 Context.SENSOR_SERVICE);
231         int cameraLaunchGestureId = resources.getInteger(
232                 com.android.internal.R.integer.config_cameraLaunchGestureSensorType);
233         if (cameraLaunchGestureId != -1) {
234             mCameraLaunchRegistered = false;
235             String sensorName = resources.getString(
236                 com.android.internal.R.string.config_cameraLaunchGestureSensorStringType);
237             mCameraLaunchSensor = sensorManager.getDefaultSensor(
238                     cameraLaunchGestureId,
239                     true /*wakeUp*/);
240 
241             // Compare the camera gesture string type to that in the resource file to make
242             // sure we are registering the correct sensor. This is redundant check, it
243             // makes the code more robust.
244             if (mCameraLaunchSensor != null) {
245                 if (sensorName.equals(mCameraLaunchSensor.getStringType())) {
246                     mCameraLaunchRegistered = sensorManager.registerListener(mGestureListener,
247                             mCameraLaunchSensor, 0);
248                 } else {
249                     String message = String.format("Wrong configuration. Sensor type and sensor "
250                             + "string type don't match: %s in resources, %s in the sensor.",
251                             sensorName, mCameraLaunchSensor.getStringType());
252                     throw new RuntimeException(message);
253                 }
254             }
255             if (DBG) Slog.d(TAG, "Camera launch sensor registered: " + mCameraLaunchRegistered);
256         } else {
257             if (DBG) Slog.d(TAG, "Camera launch sensor is not specified.");
258         }
259     }
260 
unregisterCameraLiftTrigger()261     private void unregisterCameraLiftTrigger() {
262         if (mCameraLiftRegistered) {
263             mCameraLiftRegistered = false;
264 
265             SensorManager sensorManager = (SensorManager) mContext.getSystemService(
266                     Context.SENSOR_SERVICE);
267             sensorManager.cancelTriggerSensor(mCameraLiftTriggerListener, mCameraLiftTriggerSensor);
268         }
269     }
270 
271     /**
272      * Registers for the camera lift trigger.
273      */
registerCameraLiftTrigger(Resources resources)274     private void registerCameraLiftTrigger(Resources resources) {
275         if (mCameraLiftRegistered) {
276             return;
277         }
278         SensorManager sensorManager = (SensorManager) mContext.getSystemService(
279                 Context.SENSOR_SERVICE);
280         int cameraLiftTriggerId = resources.getInteger(
281                 com.android.internal.R.integer.config_cameraLiftTriggerSensorType);
282         if (cameraLiftTriggerId != -1) {
283             mCameraLiftRegistered = false;
284             String sensorName = resources.getString(
285                 com.android.internal.R.string.config_cameraLiftTriggerSensorStringType);
286             mCameraLiftTriggerSensor = sensorManager.getDefaultSensor(
287                     cameraLiftTriggerId,
288                     true /*wakeUp*/);
289 
290             // Compare the camera lift trigger string type to that in the resource file to make
291             // sure we are registering the correct sensor. This is redundant check, it
292             // makes the code more robust.
293             if (mCameraLiftTriggerSensor != null) {
294                 if (sensorName.equals(mCameraLiftTriggerSensor.getStringType())) {
295                     mCameraLiftRegistered = sensorManager.requestTriggerSensor(mCameraLiftTriggerListener,
296                             mCameraLiftTriggerSensor);
297                 } else {
298                     String message = String.format("Wrong configuration. Sensor type and sensor "
299                             + "string type don't match: %s in resources, %s in the sensor.",
300                             sensorName, mCameraLiftTriggerSensor.getStringType());
301                     throw new RuntimeException(message);
302                 }
303             }
304             if (DBG) Slog.d(TAG, "Camera lift trigger sensor registered: " + mCameraLiftRegistered);
305         } else {
306             if (DBG) Slog.d(TAG, "Camera lift trigger sensor is not specified.");
307         }
308     }
309 
isCameraLaunchSettingEnabled(Context context, int userId)310     public static boolean isCameraLaunchSettingEnabled(Context context, int userId) {
311         return isCameraLaunchEnabled(context.getResources())
312                 && (Settings.Secure.getIntForUser(context.getContentResolver(),
313                         Settings.Secure.CAMERA_GESTURE_DISABLED, 0, userId) == 0);
314     }
315 
isCameraDoubleTapPowerSettingEnabled(Context context, int userId)316     public static boolean isCameraDoubleTapPowerSettingEnabled(Context context, int userId) {
317         return isCameraDoubleTapPowerEnabled(context.getResources())
318                 && (Settings.Secure.getIntForUser(context.getContentResolver(),
319                         Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0);
320     }
321 
isCameraLiftTriggerSettingEnabled(Context context, int userId)322     public static boolean isCameraLiftTriggerSettingEnabled(Context context, int userId) {
323         return isCameraLiftTriggerEnabled(context.getResources())
324                 && (Settings.Secure.getIntForUser(context.getContentResolver(),
325                         Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED,
326                         Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED_DEFAULT, userId) != 0);
327     }
328 
329     /**
330      * Whether to enable the camera launch gesture.
331      */
isCameraLaunchEnabled(Resources resources)332     public static boolean isCameraLaunchEnabled(Resources resources) {
333         boolean configSet = resources.getInteger(
334                 com.android.internal.R.integer.config_cameraLaunchGestureSensorType) != -1;
335         return configSet &&
336                 !SystemProperties.getBoolean("gesture.disable_camera_launch", false);
337     }
338 
isCameraDoubleTapPowerEnabled(Resources resources)339     public static boolean isCameraDoubleTapPowerEnabled(Resources resources) {
340         return resources.getBoolean(
341                 com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled);
342     }
343 
isCameraLiftTriggerEnabled(Resources resources)344     public static boolean isCameraLiftTriggerEnabled(Resources resources) {
345         boolean configSet = resources.getInteger(
346                 com.android.internal.R.integer.config_cameraLiftTriggerSensorType) != -1;
347         return configSet;
348     }
349 
350     /**
351      * Whether GestureLauncherService should be enabled according to system properties.
352      */
isGestureLauncherEnabled(Resources resources)353     public static boolean isGestureLauncherEnabled(Resources resources) {
354         return isCameraLaunchEnabled(resources) || isCameraDoubleTapPowerEnabled(resources) ||
355                 isCameraLiftTriggerEnabled(resources);
356     }
357 
interceptPowerKeyDown(KeyEvent event, boolean interactive, MutableBoolean outLaunched)358     public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive,
359             MutableBoolean outLaunched) {
360         if (event.isLongPress()) {
361             // Long presses are sent as a second key down. If the long press threshold is set lower
362             // than the double tap of sequence interval thresholds, this could cause false double
363             // taps or consecutive taps, so we want to ignore the long press event.
364             return false;
365         }
366         boolean launched = false;
367         boolean intercept = false;
368         long powerTapInterval;
369         synchronized (this) {
370             powerTapInterval = event.getEventTime() - mLastPowerDown;
371             if (mCameraDoubleTapPowerEnabled
372                     && powerTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS) {
373                 launched = true;
374                 intercept = interactive;
375                 mPowerButtonConsecutiveTaps++;
376             } else if (powerTapInterval < POWER_SHORT_TAP_SEQUENCE_MAX_INTERVAL_MS) {
377                 mPowerButtonConsecutiveTaps++;
378             } else {
379                 mPowerButtonConsecutiveTaps = 1;
380             }
381             mLastPowerDown = event.getEventTime();
382         }
383         if (DBG && mPowerButtonConsecutiveTaps > 1) {
384             Slog.i(TAG, Long.valueOf(mPowerButtonConsecutiveTaps) +
385                     " consecutive power button taps detected");
386         }
387         if (launched) {
388             Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval="
389                     + powerTapInterval + "ms");
390             launched = handleCameraGesture(false /* useWakelock */,
391                     StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
392             if (launched) {
393                 mMetricsLogger.action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
394                         (int) powerTapInterval);
395             }
396         }
397         mMetricsLogger.histogram("power_consecutive_short_tap_count", mPowerButtonConsecutiveTaps);
398         mMetricsLogger.histogram("power_double_tap_interval", (int) powerTapInterval);
399         outLaunched.value = launched;
400         return intercept && launched;
401     }
402 
403     /**
404      * @return true if camera was launched, false otherwise.
405      */
406     @VisibleForTesting
handleCameraGesture(boolean useWakelock, int source)407     boolean handleCameraGesture(boolean useWakelock, int source) {
408         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "GestureLauncher:handleCameraGesture");
409         try {
410             boolean userSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),
411                     Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
412             if (!userSetupComplete) {
413                 if (DBG) {
414                     Slog.d(TAG, String.format(
415                             "userSetupComplete = %s, ignoring camera gesture.",
416                             userSetupComplete));
417                 }
418                 return false;
419             }
420             if (DBG) {
421                 Slog.d(TAG, String.format(
422                         "userSetupComplete = %s, performing camera gesture.",
423                         userSetupComplete));
424             }
425 
426             if (useWakelock) {
427                 // Make sure we don't sleep too early
428                 mWakeLock.acquire(500L);
429             }
430             StatusBarManagerInternal service = LocalServices.getService(
431                     StatusBarManagerInternal.class);
432             service.onCameraLaunchGestureDetected(source);
433             return true;
434         } finally {
435             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
436         }
437     }
438 
439     private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
440         @Override
441         public void onReceive(Context context, Intent intent) {
442             if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
443                 mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
444                 mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
445                 registerContentObservers();
446                 updateCameraRegistered();
447                 updateCameraDoubleTapPowerEnabled();
448             }
449         }
450     };
451 
452     private final ContentObserver mSettingObserver = new ContentObserver(new Handler()) {
453         public void onChange(boolean selfChange, android.net.Uri uri, int userId) {
454             if (userId == mUserId) {
455                 updateCameraRegistered();
456                 updateCameraDoubleTapPowerEnabled();
457             }
458         }
459     };
460 
461     private final class GestureEventListener implements SensorEventListener {
462         @Override
onSensorChanged(SensorEvent event)463         public void onSensorChanged(SensorEvent event) {
464             if (!mCameraLaunchRegistered) {
465               if (DBG) Slog.d(TAG, "Ignoring gesture event because it's unregistered.");
466               return;
467             }
468             if (event.sensor == mCameraLaunchSensor) {
469                 if (DBG) {
470                     float[] values = event.values;
471                     Slog.d(TAG, String.format("Received a camera launch event: " +
472                             "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
473                 }
474                 if (handleCameraGesture(true /* useWakelock */,
475                         StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
476                     mMetricsLogger.action(MetricsEvent.ACTION_WIGGLE_CAMERA_GESTURE);
477                     trackCameraLaunchEvent(event);
478                 }
479                 return;
480             }
481         }
482 
483         @Override
onAccuracyChanged(Sensor sensor, int accuracy)484         public void onAccuracyChanged(Sensor sensor, int accuracy) {
485             // Ignored.
486         }
487 
trackCameraLaunchEvent(SensorEvent event)488         private void trackCameraLaunchEvent(SensorEvent event) {
489             long now = SystemClock.elapsedRealtime();
490             long totalDuration = now - mCameraGestureOnTimeMs;
491             // values[0]: ratio between total time duration when accel is turned on and time
492             //            duration since camera launch gesture is subscribed.
493             // values[1]: ratio between total time duration when gyro is turned on and time duration
494             //            since camera launch gesture is subscribed.
495             // values[2]: extra information
496             float[] values = event.values;
497 
498             long sensor1OnTime = (long) (totalDuration * (double) values[0]);
499             long sensor2OnTime = (long) (totalDuration * (double) values[1]);
500             int extra = (int) values[2];
501 
502             // We only log the difference in the event log to make aggregation easier.
503             long gestureOnTimeDiff = now - mCameraGestureLastEventTime;
504             long sensor1OnTimeDiff = sensor1OnTime - mCameraGestureSensor1LastOnTimeMs;
505             long sensor2OnTimeDiff = sensor2OnTime - mCameraGestureSensor2LastOnTimeMs;
506             int extraDiff = extra - mCameraLaunchLastEventExtra;
507 
508             // Gating against negative time difference. This doesn't usually happen, but it may
509             // happen because of numeric errors.
510             if (gestureOnTimeDiff < 0 || sensor1OnTimeDiff < 0 || sensor2OnTimeDiff < 0) {
511                 if (DBG) Slog.d(TAG, "Skipped event logging because negative numbers.");
512                 return;
513             }
514 
515             if (DBG) Slog.d(TAG, String.format("totalDuration: %d, sensor1OnTime: %s, " +
516                     "sensor2OnTime: %d, extra: %d",
517                     gestureOnTimeDiff,
518                     sensor1OnTimeDiff,
519                     sensor2OnTimeDiff,
520                     extraDiff));
521             EventLogTags.writeCameraGestureTriggered(
522                     gestureOnTimeDiff,
523                     sensor1OnTimeDiff,
524                     sensor2OnTimeDiff,
525                     extraDiff);
526 
527             mCameraGestureLastEventTime = now;
528             mCameraGestureSensor1LastOnTimeMs = sensor1OnTime;
529             mCameraGestureSensor2LastOnTimeMs = sensor2OnTime;
530             mCameraLaunchLastEventExtra = extra;
531         }
532     }
533 
534     private final class CameraLiftTriggerEventListener extends TriggerEventListener {
535         @Override
onTrigger(TriggerEvent event)536         public void onTrigger(TriggerEvent event) {
537             if (DBG_CAMERA_LIFT) Slog.d(TAG, String.format("onTrigger event - time: %d, name: %s",
538                     event.timestamp, event.sensor.getName()));
539             if (!mCameraLiftRegistered) {
540               if (DBG_CAMERA_LIFT) Slog.d(TAG, "Ignoring camera lift event because it's " +
541                       "unregistered.");
542               return;
543             }
544             if (event.sensor == mCameraLiftTriggerSensor) {
545                 Resources resources = mContext.getResources();
546                 SensorManager sensorManager = (SensorManager) mContext.getSystemService(
547                         Context.SENSOR_SERVICE);
548                 boolean keyguardShowingAndNotOccluded =
549                         mWindowManagerInternal.isKeyguardShowingAndNotOccluded();
550                 boolean interactive = mPowerManager.isInteractive();
551                 if (DBG_CAMERA_LIFT) {
552                     float[] values = event.values;
553                     Slog.d(TAG, String.format("Received a camera lift trigger " +
554                             "event: values=[%.4f], keyguard showing: %b, interactive: %b", values[0],
555                             keyguardShowingAndNotOccluded, interactive));
556                 }
557                 if (keyguardShowingAndNotOccluded || !interactive) {
558                     if (handleCameraGesture(true /* useWakelock */,
559                             StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER)) {
560                         MetricsLogger.action(mContext, MetricsEvent.ACTION_CAMERA_LIFT_TRIGGER);
561                     }
562                 } else {
563                     if (DBG_CAMERA_LIFT) Slog.d(TAG, "Ignoring lift event");
564                 }
565 
566                 mCameraLiftRegistered = sensorManager.requestTriggerSensor(
567                         mCameraLiftTriggerListener, mCameraLiftTriggerSensor);
568 
569                 if (DBG_CAMERA_LIFT) Slog.d(TAG, "Camera lift trigger sensor re-registered: " +
570                         mCameraLiftRegistered);
571                 return;
572             }
573         }
574     }
575 }
576