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