diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index e57a9b5231e3e..ab301bdedcac3 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -92,6 +92,7 @@ public class StatusBarManager {
public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0;
public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1;
+ public static final int CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = 2;
private Context mContext;
private IStatusBarService mService;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index be53f2c82150a..b557ace7064c6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2947,4 +2947,10 @@
67
+
+
+ -1
+
+
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 18c18a8d9425d..ff966adf54187 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2523,6 +2523,8 @@
+
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 41a60e24e7005..037e901d05691 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -100,6 +100,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL
public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance";
public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture";
public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap";
+ public static final String CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER = "lift_to_launch_ml";
public static final String EXTRA_CAMERA_LAUNCH_SOURCE
= "com.android.systemui.camera_launch_source";
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 9cc3d817c515a..290119b033423 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2390,6 +2390,8 @@ public class NotificationPanelView extends PanelView implements
mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP;
} else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) {
mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE;
+ } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER) {
+ mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER;
} else {
// Default.
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index b755dd6d17d7e..818f47862b53b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3974,6 +3974,11 @@ message MetricsEvent {
// OPEN: Settings > Battery > High Usage
DIALOG_HANDLE_ANOMALY = 988;
+ // ACTION: Camera lift gesture
+ // CATEGORY: GLOBAL_SYSTEM_UI
+ // OS: O
+ ACTION_CAMERA_LIFT_TRIGGER = 989;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 2e2ddbad2bdb7..6c44cc83a27d2 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -71,14 +71,18 @@ public class GestureLauncherService extends SystemService {
/** The listener that receives the gesture event. */
private final GestureEventListener mGestureListener = new GestureEventListener();
+ private final CameraLiftTriggerEventListener mCameraLiftTriggerListener =
+ new CameraLiftTriggerEventListener();
private Sensor mCameraLaunchSensor;
+ private Sensor mCameraLiftTriggerSensor;
private Context mContext;
private final MetricsLogger mMetricsLogger;
/** The wake lock held when a gesture is detected. */
private WakeLock mWakeLock;
- private boolean mRegistered;
+ private boolean mCameraLaunchRegistered;
+ private boolean mCameraLiftRegistered;
private int mUserId;
// Below are fields used for event logging only.
@@ -161,6 +165,9 @@ public class GestureLauncherService extends SystemService {
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED),
false, mSettingObserver, mUserId);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED),
+ false, mSettingObserver, mUserId);
}
private void updateCameraRegistered() {
@@ -170,6 +177,12 @@ public class GestureLauncherService extends SystemService {
} else {
unregisterCameraLaunchGesture();
}
+
+ if (isCameraLiftTriggerSettingEnabled(mContext, mUserId)) {
+ registerCameraLiftTrigger(resources);
+ } else {
+ unregisterCameraLiftTrigger();
+ }
}
@VisibleForTesting
@@ -181,8 +194,8 @@ public class GestureLauncherService extends SystemService {
}
private void unregisterCameraLaunchGesture() {
- if (mRegistered) {
- mRegistered = false;
+ if (mCameraLaunchRegistered) {
+ mCameraLaunchRegistered = false;
mCameraGestureOnTimeMs = 0L;
mCameraGestureLastEventTime = 0L;
mCameraGestureSensor1LastOnTimeMs = 0;
@@ -199,7 +212,7 @@ public class GestureLauncherService extends SystemService {
* Registers for the camera launch gesture.
*/
private void registerCameraLaunchGesture(Resources resources) {
- if (mRegistered) {
+ if (mCameraLaunchRegistered) {
return;
}
mCameraGestureOnTimeMs = SystemClock.elapsedRealtime();
@@ -209,7 +222,7 @@ public class GestureLauncherService extends SystemService {
int cameraLaunchGestureId = resources.getInteger(
com.android.internal.R.integer.config_cameraLaunchGestureSensorType);
if (cameraLaunchGestureId != -1) {
- mRegistered = false;
+ mCameraLaunchRegistered = false;
String sensorName = resources.getString(
com.android.internal.R.string.config_cameraLaunchGestureSensorStringType);
mCameraLaunchSensor = sensorManager.getDefaultSensor(
@@ -221,7 +234,7 @@ public class GestureLauncherService extends SystemService {
// makes the code more robust.
if (mCameraLaunchSensor != null) {
if (sensorName.equals(mCameraLaunchSensor.getStringType())) {
- mRegistered = sensorManager.registerListener(mGestureListener,
+ mCameraLaunchRegistered = sensorManager.registerListener(mGestureListener,
mCameraLaunchSensor, 0);
} else {
String message = String.format("Wrong configuration. Sensor type and sensor "
@@ -230,12 +243,61 @@ public class GestureLauncherService extends SystemService {
throw new RuntimeException(message);
}
}
- if (DBG) Slog.d(TAG, "Camera launch sensor registered: " + mRegistered);
+ if (DBG) Slog.d(TAG, "Camera launch sensor registered: " + mCameraLaunchRegistered);
} else {
if (DBG) Slog.d(TAG, "Camera launch sensor is not specified.");
}
}
+ private void unregisterCameraLiftTrigger() {
+ if (mCameraLiftRegistered) {
+ mCameraLiftRegistered = false;
+
+ SensorManager sensorManager = (SensorManager) mContext.getSystemService(
+ Context.SENSOR_SERVICE);
+ sensorManager.unregisterListener(mCameraLiftTriggerListener);
+ }
+ }
+
+ /**
+ * Registers for the camera lift trigger.
+ */
+ private void registerCameraLiftTrigger(Resources resources) {
+ if (mCameraLiftRegistered) {
+ return;
+ }
+ SensorManager sensorManager = (SensorManager) mContext.getSystemService(
+ Context.SENSOR_SERVICE);
+ int cameraLiftTriggerId = resources.getInteger(
+ com.android.internal.R.integer.config_cameraLiftTriggerSensorType);
+ if (cameraLiftTriggerId != -1) {
+ mCameraLiftRegistered = false;
+ String sensorName = resources.getString(
+ com.android.internal.R.string.config_cameraLiftTriggerSensorStringType);
+ mCameraLiftTriggerSensor = sensorManager.getDefaultSensor(
+ cameraLiftTriggerId,
+ false /*wakeUp*/);
+
+ // Compare the camera lift trigger string type to that in the resource file to make
+ // sure we are registering the correct sensor. This is redundant check, it
+ // makes the code more robust.
+ if (mCameraLiftTriggerSensor != null) {
+ if (sensorName.equals(mCameraLiftTriggerSensor.getStringType())) {
+ mCameraLiftRegistered = sensorManager.registerListener(mCameraLiftTriggerListener,
+ mCameraLiftTriggerSensor, 0);
+ } else {
+ String message = String.format("Wrong configuration. Sensor type and sensor "
+ + "string type don't match: %s in resources, %s in the sensor.",
+ sensorName, mCameraLiftTriggerSensor.getStringType());
+ throw new RuntimeException(message);
+ }
+ }
+ if (DBG) Slog.d(TAG, "Camera lift trigger sensor registered: " + mCameraLiftRegistered);
+ } else {
+ if (DBG) Slog.d(TAG, "Camera lift trigger sensor is not specified.");
+ }
+ }
+
public static boolean isCameraLaunchSettingEnabled(Context context, int userId) {
return isCameraLaunchEnabled(context.getResources())
&& (Settings.Secure.getIntForUser(context.getContentResolver(),
@@ -248,6 +310,12 @@ public class GestureLauncherService extends SystemService {
Settings.Secure.CAMERA_DOUBLE_TAP_POWER_GESTURE_DISABLED, 0, userId) == 0);
}
+ public static boolean isCameraLiftTriggerSettingEnabled(Context context, int userId) {
+ return isCameraLiftTriggerEnabled(context.getResources())
+ && (Settings.Secure.getIntForUser(context.getContentResolver(),
+ Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, 0, userId) != 0);
+ }
+
/**
* Whether to enable the camera launch gesture.
*/
@@ -263,11 +331,18 @@ public class GestureLauncherService extends SystemService {
com.android.internal.R.bool.config_cameraDoubleTapPowerGestureEnabled);
}
+ public static boolean isCameraLiftTriggerEnabled(Resources resources) {
+ boolean configSet = resources.getInteger(
+ com.android.internal.R.integer.config_cameraLiftTriggerSensorType) != -1;
+ return configSet;
+ }
+
/**
* Whether GestureLauncherService should be enabled according to system properties.
*/
public static boolean isGestureLauncherEnabled(Resources resources) {
- return isCameraLaunchEnabled(resources) || isCameraDoubleTapPowerEnabled(resources);
+ return isCameraLaunchEnabled(resources) || isCameraDoubleTapPowerEnabled(resources) ||
+ isCameraLiftTriggerEnabled(resources);
}
public boolean interceptPowerKeyDown(KeyEvent event, boolean interactive,
@@ -296,7 +371,7 @@ public class GestureLauncherService extends SystemService {
if (launched) {
Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval="
+ powerTapInterval + "ms");
- launched = handleCameraLaunchGesture(false /* useWakelock */,
+ launched = handleCameraGesture(false /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
if (launched) {
mMetricsLogger.action(MetricsEvent.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
@@ -313,17 +388,17 @@ public class GestureLauncherService extends SystemService {
* @return true if camera was launched, false otherwise.
*/
@VisibleForTesting
- boolean handleCameraLaunchGesture(boolean useWakelock, int source) {
+ boolean handleCameraGesture(boolean useWakelock, int source) {
boolean userSetupComplete = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
if (!userSetupComplete) {
if (DBG) Slog.d(TAG, String.format(
- "userSetupComplete = %s, ignoring camera launch gesture.",
+ "userSetupComplete = %s, ignoring camera gesture.",
userSetupComplete));
return false;
}
if (DBG) Slog.d(TAG, String.format(
- "userSetupComplete = %s, performing camera launch gesture.",
+ "userSetupComplete = %s, performing camera gesture.",
userSetupComplete));
if (useWakelock) {
@@ -361,7 +436,7 @@ public class GestureLauncherService extends SystemService {
private final class GestureEventListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
- if (!mRegistered) {
+ if (!mCameraLaunchRegistered) {
if (DBG) Slog.d(TAG, "Ignoring gesture event because it's unregistered.");
return;
}
@@ -371,7 +446,7 @@ public class GestureLauncherService extends SystemService {
Slog.d(TAG, String.format("Received a camera launch event: " +
"values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
}
- if (handleCameraLaunchGesture(true /* useWakelock */,
+ if (handleCameraGesture(true /* useWakelock */,
StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
mMetricsLogger.action(MetricsEvent.ACTION_WIGGLE_CAMERA_GESTURE);
trackCameraLaunchEvent(event);
@@ -430,4 +505,31 @@ public class GestureLauncherService extends SystemService {
mCameraLaunchLastEventExtra = extra;
}
}
+
+ private final class CameraLiftTriggerEventListener implements SensorEventListener {
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (!mCameraLiftRegistered) {
+ if (DBG) Slog.d(TAG, "Ignoring camera lift event because it's unregistered.");
+ return;
+ }
+ if (event.sensor == mCameraLiftTriggerSensor) {
+ if (DBG) {
+ float[] values = event.values;
+ Slog.d(TAG, String.format("Received a camera lift trigger event: " +
+ "values=[%.4f].", values[0]));
+ }
+ if (handleCameraGesture(true /* useWakelock */,
+ StatusBarManager.CAMERA_LAUNCH_SOURCE_LIFT_TRIGGER)) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_CAMERA_LIFT_TRIGGER);
+ }
+ return;
+ }
+ }
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Ignored.
+ }
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
index f281bd7e42614..33e4165718a55 100644
--- a/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/GestureLauncherServiceTest.java
@@ -154,7 +154,7 @@ public class GestureLauncherServiceTest {
withUserSetupCompleteValue(true);
boolean useWakeLock = false;
- assertTrue(mGestureLauncherService.handleCameraLaunchGesture(useWakeLock, FAKE_SOURCE));
+ assertTrue(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
verify(mStatusBarManagerInternal).onCameraLaunchGestureDetected(FAKE_SOURCE);
}
@@ -163,7 +163,7 @@ public class GestureLauncherServiceTest {
withUserSetupCompleteValue(false);
boolean useWakeLock = false;
- assertFalse(mGestureLauncherService.handleCameraLaunchGesture(useWakeLock, FAKE_SOURCE));
+ assertFalse(mGestureLauncherService.handleCameraGesture(useWakeLock, FAKE_SOURCE));
}
@Test