blob: d7b0765044661be63f32276b0c75e6ef7854e5e4 [file] [log] [blame]
Zhentao Sunc6cd1f92015-07-21 17:43:53 -07001/*
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
17package com.android.server;
18
19import android.app.KeyguardManager;
20import android.content.ComponentName;
21import android.content.Context;
22import android.content.Intent;
23import android.content.pm.PackageManager;
24import android.content.pm.ResolveInfo;
25import android.content.res.Resources;
26import android.hardware.Sensor;
27import android.hardware.SensorEvent;
28import android.hardware.SensorEventListener;
29import android.hardware.SensorManager;
30import android.os.PowerManager;
31import android.os.Vibrator;
32import android.os.PowerManager.WakeLock;
33import android.os.SystemProperties;
34import android.provider.MediaStore;
35import android.util.Slog;
36
37/**
38 * The service that listens for gestures detected in sensor firmware and starts the intent
39 * accordingly.
40 * <p>For now, only camera launch gesture is supported, and in the future, more gestures can be
41 * added.</p>
42 * @hide
43 */
44class GestureLauncherService extends SystemService {
45 private static final boolean DBG = false;
46 private static final String TAG = "GestureLauncherService";
47
48 /** The listener that receives the gesture event. */
49 private final GestureEventListener mGestureListener = new GestureEventListener();
50
51 private Sensor mCameraLaunchSensor;
52 private Vibrator mVibrator;
53 private KeyguardManager mKeyGuard;
54 private Context mContext;
55
56 /** The wake lock held when a gesture is detected. */
57 private WakeLock mWakeLock;
58
59 public GestureLauncherService(Context context) {
60 super(context);
61 mContext = context;
62 }
63
64 public void onStart() {
65 // Nothing to publish.
66 }
67
68 public void onBootPhase(int phase) {
69 if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
70 Resources resources = mContext.getResources();
71 if (!isGestureLauncherEnabled(resources)) {
72 if (DBG) Slog.d(TAG, "Gesture launcher is disabled in system properties.");
73 return;
74 }
75
76 mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
77 mKeyGuard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
78 PowerManager powerManager = (PowerManager) mContext.getSystemService(
79 Context.POWER_SERVICE);
80 mWakeLock = powerManager.newWakeLock(
81 PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
82 "GestureLauncherService");
83 if (isCameraLaunchEnabled(resources)) {
84 registerCameraLaunchGesture(resources);
85 }
86 }
87 }
88
89 /**
90 * Registers for the camera launch gesture.
91 */
92 private void registerCameraLaunchGesture(Resources resources) {
93 SensorManager sensorManager = (SensorManager) mContext.getSystemService(
94 Context.SENSOR_SERVICE);
95 int cameraLaunchGestureId = resources.getInteger(
96 com.android.internal.R.integer.config_cameraLaunchGestureSensorType);
97 if (cameraLaunchGestureId != -1) {
98 boolean registered = false;
99 String sensorName = resources.getString(
100 com.android.internal.R.string.config_cameraLaunchGestureSensorStringType);
101 mCameraLaunchSensor = sensorManager.getDefaultSensor(
102 cameraLaunchGestureId,
103 true /*wakeUp*/);
104
105 // Compare the camera gesture string type to that in the resource file to make
106 // sure we are registering the correct sensor. This is redundant check, it
107 // makes the code more robust.
108 if (mCameraLaunchSensor != null) {
109 if (sensorName.equals(mCameraLaunchSensor.getStringType())) {
110 registered = sensorManager.registerListener(mGestureListener,
111 mCameraLaunchSensor, 0);
112 } else {
113 String message = String.format("Wrong configuration. Sensor type and sensor "
114 + "string type don't match: %s in resources, %s in the sensor.",
115 sensorName, mCameraLaunchSensor.getStringType());
116 throw new RuntimeException(message);
117 }
118 }
119 if (DBG) Slog.d(TAG, "Camera launch sensor registered: " + registered);
120 } else {
121 if (DBG) Slog.d(TAG, "Camera launch sensor is not specified.");
122 }
123 }
124
125 /**
126 * Whether to enable the camera launch gesture.
127 */
128 public static boolean isCameraLaunchEnabled(Resources resources) {
129 boolean configSet = resources.getInteger(
130 com.android.internal.R.integer.config_cameraLaunchGestureSensorType) != -1;
131 return configSet &&
132 !SystemProperties.getBoolean("gesture.disable_camera_launch", false);
133 }
134
135 /**
136 * Whether GestureLauncherService should be enabled according to system properties.
137 */
138 public static boolean isGestureLauncherEnabled(Resources resources) {
139 // For now, the only supported gesture is camera launch gesture, so whether to enable this
140 // service equals to isCameraLaunchEnabled();
141 return isCameraLaunchEnabled(resources);
142 }
143
144 private final class GestureEventListener implements SensorEventListener {
145 @Override
146 public void onSensorChanged(SensorEvent event) {
147 if (event.sensor == mCameraLaunchSensor) {
148 handleCameraLaunchGesture();
149 return;
150 }
151 }
152
153 private void handleCameraLaunchGesture() {
154 if (DBG) Slog.d(TAG, "Received a camera launch event.");
155 boolean locked = mKeyGuard != null && mKeyGuard.inKeyguardRestrictedInputMode();
156 String action = locked
157 ? MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE
158 : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
159 Intent intent = new Intent(action);
160 PackageManager pm = mContext.getPackageManager();
161 ResolveInfo componentInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
162 if (componentInfo == null) {
163 if (DBG) Slog.d(TAG, "Couldn't find an app to process the camera intent.");
164 return;
165 }
166
167 if (mVibrator != null && mVibrator.hasVibrator()) {
168 mVibrator.vibrate(1000L);
169 }
170
171 // Turn on the screen before the camera launches.
172 mWakeLock.acquire(500L);
173 intent.setComponent(new ComponentName(componentInfo.activityInfo.packageName,
174 componentInfo.activityInfo.name));
175 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
176 mContext.startActivity(intent);
177 mWakeLock.release();
178 }
179
180 @Override
181 public void onAccuracyChanged(Sensor sensor, int accuracy) {
182 // Ignored.
183 }
184 }
185}