diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 06b6389f3bea2..531f109488357 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2269,4 +2269,9 @@
For now, only camera launch gesture is supported, and in the future, more gestures can be + * added.
+ * @hide + */ +class GestureLauncherService extends SystemService { + private static final boolean DBG = false; + private static final String TAG = "GestureLauncherService"; + + /** The listener that receives the gesture event. */ + private final GestureEventListener mGestureListener = new GestureEventListener(); + + private Sensor mCameraLaunchSensor; + private Vibrator mVibrator; + private KeyguardManager mKeyGuard; + private Context mContext; + + /** The wake lock held when a gesture is detected. */ + private WakeLock mWakeLock; + + public GestureLauncherService(Context context) { + super(context); + mContext = context; + } + + public void onStart() { + // Nothing to publish. + } + + public void onBootPhase(int phase) { + if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { + Resources resources = mContext.getResources(); + if (!isGestureLauncherEnabled(resources)) { + if (DBG) Slog.d(TAG, "Gesture launcher is disabled in system properties."); + return; + } + + mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE); + mKeyGuard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); + PowerManager powerManager = (PowerManager) mContext.getSystemService( + Context.POWER_SERVICE); + mWakeLock = powerManager.newWakeLock( + PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, + "GestureLauncherService"); + if (isCameraLaunchEnabled(resources)) { + registerCameraLaunchGesture(resources); + } + } + } + + /** + * Registers for the camera launch gesture. + */ + private void registerCameraLaunchGesture(Resources resources) { + SensorManager sensorManager = (SensorManager) mContext.getSystemService( + Context.SENSOR_SERVICE); + int cameraLaunchGestureId = resources.getInteger( + com.android.internal.R.integer.config_cameraLaunchGestureSensorType); + if (cameraLaunchGestureId != -1) { + boolean registered = false; + String sensorName = resources.getString( + com.android.internal.R.string.config_cameraLaunchGestureSensorStringType); + mCameraLaunchSensor = sensorManager.getDefaultSensor( + cameraLaunchGestureId, + true /*wakeUp*/); + + // Compare the camera gesture 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 (mCameraLaunchSensor != null) { + if (sensorName.equals(mCameraLaunchSensor.getStringType())) { + registered = sensorManager.registerListener(mGestureListener, + mCameraLaunchSensor, 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, mCameraLaunchSensor.getStringType()); + throw new RuntimeException(message); + } + } + if (DBG) Slog.d(TAG, "Camera launch sensor registered: " + registered); + } else { + if (DBG) Slog.d(TAG, "Camera launch sensor is not specified."); + } + } + + /** + * Whether to enable the camera launch gesture. + */ + public static boolean isCameraLaunchEnabled(Resources resources) { + boolean configSet = resources.getInteger( + com.android.internal.R.integer.config_cameraLaunchGestureSensorType) != -1; + return configSet && + !SystemProperties.getBoolean("gesture.disable_camera_launch", false); + } + + /** + * Whether GestureLauncherService should be enabled according to system properties. + */ + public static boolean isGestureLauncherEnabled(Resources resources) { + // For now, the only supported gesture is camera launch gesture, so whether to enable this + // service equals to isCameraLaunchEnabled(); + return isCameraLaunchEnabled(resources); + } + + private final class GestureEventListener implements SensorEventListener { + @Override + public void onSensorChanged(SensorEvent event) { + if (event.sensor == mCameraLaunchSensor) { + handleCameraLaunchGesture(); + return; + } + } + + private void handleCameraLaunchGesture() { + if (DBG) Slog.d(TAG, "Received a camera launch event."); + boolean locked = mKeyGuard != null && mKeyGuard.inKeyguardRestrictedInputMode(); + String action = locked + ? MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE + : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA; + Intent intent = new Intent(action); + PackageManager pm = mContext.getPackageManager(); + ResolveInfo componentInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + if (componentInfo == null) { + if (DBG) Slog.d(TAG, "Couldn't find an app to process the camera intent."); + return; + } + + if (mVibrator != null && mVibrator.hasVibrator()) { + mVibrator.vibrate(1000L); + } + + // Turn on the screen before the camera launches. + mWakeLock.acquire(500L); + intent.setComponent(new ComponentName(componentInfo.activityInfo.packageName, + componentInfo.activityInfo.name)); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + mWakeLock.release(); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + // Ignored. + } + } +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 46ace17f1c40d..1bd00f238b5bf 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -857,6 +857,11 @@ public final class SystemServer { if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_VOICE_RECOGNIZERS)) { mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS); } + + if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) { + Slog.i(TAG, "Gesture Launcher Service"); + mSystemServiceManager.startService(GestureLauncherService.class); + } } try {