blob: 0fb0470231f7d69e8224fbf6aa2716259a0f2749 [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemProperties;
import android.os.Vibrator;
import android.provider.Settings;
import android.util.Slog;
import com.android.server.statusbar.StatusBarManagerInternal;
/**
* The service that listens for gestures detected in sensor firmware and starts the intent
* accordingly.
* <p>For now, only camera launch gesture is supported, and in the future, more gestures can be
* added.</p>
* @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 Context mContext;
/** The wake lock held when a gesture is detected. */
private WakeLock mWakeLock;
private boolean mRegistered;
private int mUserId;
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);
PowerManager powerManager = (PowerManager) mContext.getSystemService(
Context.POWER_SERVICE);
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"GestureLauncherService");
updateCameraRegistered();
mUserId = ActivityManager.getCurrentUser();
mContext.registerReceiver(mUserReceiver, new IntentFilter(Intent.ACTION_USER_SWITCHED));
registerContentObserver();
}
}
private void registerContentObserver() {
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.CAMERA_GESTURE_DISABLED),
false, mSettingObserver, mUserId);
}
private void updateCameraRegistered() {
Resources resources = mContext.getResources();
if (isCameraLaunchSettingEnabled(mContext, mUserId)) {
registerCameraLaunchGesture(resources);
} else {
unregisterCameraLaunchGesture();
}
}
private void unregisterCameraLaunchGesture() {
if (mRegistered) {
mRegistered = false;
SensorManager sensorManager = (SensorManager) mContext.getSystemService(
Context.SENSOR_SERVICE);
sensorManager.unregisterListener(mGestureListener);
}
}
/**
* Registers for the camera launch gesture.
*/
private void registerCameraLaunchGesture(Resources resources) {
if (mRegistered) {
return;
}
SensorManager sensorManager = (SensorManager) mContext.getSystemService(
Context.SENSOR_SERVICE);
int cameraLaunchGestureId = resources.getInteger(
com.android.internal.R.integer.config_cameraLaunchGestureSensorType);
if (cameraLaunchGestureId != -1) {
mRegistered = 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())) {
mRegistered = 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: " + mRegistered);
} else {
if (DBG) Slog.d(TAG, "Camera launch sensor is not specified.");
}
}
public static boolean isCameraLaunchSettingEnabled(Context context, int userId) {
return isCameraLaunchEnabled(context.getResources())
&& (Settings.Secure.getIntForUser(context.getContentResolver(),
Settings.Secure.CAMERA_GESTURE_DISABLED, 0, userId) == 0);
}
/**
* 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 BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
mUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
registerContentObserver();
updateCameraRegistered();
}
}
};
private final ContentObserver mSettingObserver = new ContentObserver(new Handler()) {
public void onChange(boolean selfChange, android.net.Uri uri, int userId) {
if (userId == mUserId) {
updateCameraRegistered();
}
}
};
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 userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
if (!userSetupComplete) {
if (DBG) Slog.d(TAG, String.format(
"userSetupComplete = %s, ignoring camera launch gesture.",
userSetupComplete));
return;
}
if (DBG) Slog.d(TAG, String.format(
"userSetupComplete = %s, performing camera launch gesture.",
userSetupComplete));
if (mVibrator != null && mVibrator.hasVibrator()) {
mVibrator.vibrate(1000L);
}
// Make sure we don't sleep too early
mWakeLock.acquire(500L);
StatusBarManagerInternal service = LocalServices.getService(
StatusBarManagerInternal.class);
service.onCameraLaunchGestureDetected();
mWakeLock.release();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Ignored.
}
}
}