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