nougat_device_meizu_m2note/keyhandler/src/com/cyanogenmod/settings/device/KeyHandler.java

451 lines
18 KiB
Java

/*
* Copyright (C) 2015 The CyanogenMod 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.cyanogenmod.settings.device;
import android.app.ActivityManagerNative;
import android.app.KeyguardManager;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraAccessException;
import android.media.session.MediaSessionLegacyHelper;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.Vibrator;
import android.provider.MediaStore;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.util.Log;
import android.view.KeyEvent;
import android.view.WindowManagerGlobal;
import cyanogenmod.hardware.CMHardwareManager;
import cyanogenmod.providers.CMSettings;
import com.android.internal.os.DeviceKeyHandler;
import com.android.internal.util.ArrayUtils;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import android.app.Instrumentation;
import android.content.SharedPreferences;
import android.content.ContextWrapper;
public class KeyHandler implements DeviceKeyHandler {
private static final String TAG = KeyHandler.class.getSimpleName();
private static final int GESTURE_REQUEST = 1;
private static final String MEIZU_GESTURE_DATA =
"/sys/devices/platform/mx-gs/gesture_data";
private static final String KEY_GESTURE_HAPTIC_FEEDBACK =
"touchscreen_gesture_haptic_feedback";
private static final String TOUCHSCREEN_GESTURE_HAPTIC_FEEDBACK =
"touchscreen_gesture_haptic_feedback";
private static final String ACTION_DISMISS_KEYGUARD =
"com.android.keyguard.action.DISMISS_KEYGUARD_SECURELY";
// M2Note gesture codes
public static final int DOUBLE_TAP = 0xA0; //160
public static final int SWIPE_X_LEFT = 0xB0; //176
public static final int SWIPE_X_RIGHT = 0xB1;
public static final int SWIPE_Y_UP = 0xB2;
public static final int SWIPE_Y_DOWN = 0xB3;
public static final int UNICODE_E = 0xC0; // 192
public static final int UNICODE_C = 0xC1;
public static final int UNICODE_W = 0xC2;
public static final int UNICODE_M = 0xC3;
public static final int UNICODE_O = 0xC4;
public static final int UNICODE_S = 0xC5;
public static final int UNICODE_V_UP = 0xC6;
public static final int UNICODE_V_DOWN = 0xC7;
public static final int UNICODE_V_L = 0xC8;
public static final int UNICODE_V_R = 0xC9;
public static final int UNICODE_Z = 0xCA;
private static final int GESTURE_WAKELOCK_DURATION = 3000;
private final Context mContext;
private final PowerManager mPowerManager;
private KeyguardManager mKeyguardManager;
private EventHandler mEventHandler;
private SensorManager mSensorManager;
private PackageManager mPackageManager;
private CameraManager mCameraManager;
private String mRearCameraId;
private boolean mTorchEnabled;
private Sensor mProximitySensor;
private Vibrator mVibrator;
private WakeLock mProximityWakeLock;
private WakeLock mGestureWakeLock;
private int mProximityTimeOut;
private boolean mProximityWakeSupported;
private Instrumentation m_Instrumentation;
private Context cmaContext = null;
private boolean isLastPressHomeButton = false;
private boolean mNotificationSliderVibrate;
public KeyHandler(Context context) {
mContext = context;
mPackageManager = context.getPackageManager();
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mEventHandler = new EventHandler();
m_Instrumentation = new Instrumentation();
mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"GestureWakeLock");
try {
cmaContext = mContext.createPackageContext("com.cyanogenmod.settings.device", Context.CONTEXT_RESTRICTED);
} catch (Exception e) {
e.printStackTrace();
}
final Resources resources = mContext.getResources();
mProximityTimeOut = resources.getInteger(
org.cyanogenmod.platform.internal.R.integer.config_proximityCheckTimeout);
mProximityWakeSupported = resources.getBoolean(
org.cyanogenmod.platform.internal.R.bool.config_proximityCheckOnWake);
if (mProximityWakeSupported) {
mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
mProximityWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"ProximityWakeLock");
}
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
if (mVibrator == null || !mVibrator.hasVibrator()) {
mVibrator = null;
}
mCameraManager = (CameraManager) mContext.getSystemService(Context.CAMERA_SERVICE);
mCameraManager.registerTorchCallback(new MyTorchCallback(), mEventHandler);
}
private class MyTorchCallback extends CameraManager.TorchCallback {
@Override
public void onTorchModeChanged(String cameraId, boolean enabled) {
if (!cameraId.equals(mRearCameraId))
return;
mTorchEnabled = enabled;
}
@Override
public void onTorchModeUnavailable(String cameraId) {
if (!cameraId.equals(mRearCameraId))
return;
mTorchEnabled = false;
}
}
private String getRearCameraId() {
if (mRearCameraId == null) {
try {
for (final String cameraId : mCameraManager.getCameraIdList()) {
CameraCharacteristics characteristics =
mCameraManager.getCameraCharacteristics(cameraId);
int cOrientation = characteristics.get(CameraCharacteristics.LENS_FACING);
if (cOrientation == CameraCharacteristics.LENS_FACING_BACK) {
mRearCameraId = cameraId;
break;
}
}
} catch (CameraAccessException e) {
// Ignore
}
}
return mRearCameraId;
}
private void ensureKeyguardManager() {
if (mKeyguardManager == null) {
mKeyguardManager =
(KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
}
}
private class EventHandler extends Handler {
@Override
public void handleMessage(Message msg) {
try {
boolean gestureHandled = true;
int gestureData = (int) msg.obj;
String prefValue = getCMAStringPref(String.valueOf(gestureData) + "_action");
Log.i(TAG, "Handling gesture: " + gestureData + " with action: " + prefValue);
switch (prefValue) {
case "wakeUp":
mPowerManager.wakeUp(SystemClock.uptimeMillis());
break;
case "unlock":
ensureKeyguardManager();
mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
mContext.sendBroadcastAsUser(new Intent(ACTION_DISMISS_KEYGUARD),
UserHandle.CURRENT);
mPowerManager.wakeUp(SystemClock.uptimeMillis());
break;
case "camera":
ensureKeyguardManager();
final String action;
mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
if (mKeyguardManager.isKeyguardSecure() && mKeyguardManager.isKeyguardLocked()) {
action = MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE;
} else {
mContext.sendBroadcastAsUser(new Intent(ACTION_DISMISS_KEYGUARD),
UserHandle.CURRENT);
action = MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
}
mPowerManager.wakeUp(SystemClock.uptimeMillis());
Intent intent = new Intent(action, null);
startActivitySafely(intent);
break;
case "play":
dispatchMediaKeyWithWakeLockToMediaSession(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
break;
case "flashlight":
String rearCameraId = getRearCameraId();
if (rearCameraId != null) {
mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
try {
mCameraManager.setTorchMode(rearCameraId, !mTorchEnabled);
mTorchEnabled = !mTorchEnabled;
} catch (CameraAccessException e) {
// Ignore
}
}
break;
case "prev":
dispatchMediaKeyWithWakeLockToMediaSession(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
break;
case "next":
dispatchMediaKeyWithWakeLockToMediaSession(KeyEvent.KEYCODE_MEDIA_NEXT);
break;
case "doNotDisturb":
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE,
Global.ZEN_MODE_NO_INTERRUPTIONS);
break;
case "normal":
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE,
Global.ZEN_MODE_OFF);
break;
case "mute":
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE,
Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
break;
default:
if (prefValue.startsWith("launch$")) {
String packageName = prefValue.replace("launch$", "");
ensureKeyguardManager();
mGestureWakeLock.acquire(GESTURE_WAKELOCK_DURATION);
if (!mKeyguardManager.isKeyguardSecure() && mKeyguardManager.isKeyguardLocked()) {
mContext.sendBroadcastAsUser(new Intent(ACTION_DISMISS_KEYGUARD),
UserHandle.CURRENT);
}
mPowerManager.wakeUp(SystemClock.uptimeMillis());
Intent appIntent = mPackageManager.getLaunchIntentForPackage(packageName);
startActivitySafely(appIntent);
} else {
gestureHandled = false;
}
break;
}
if (gestureHandled)
doHapticFeedback();
} catch (Exception e) {
Log.e(TAG, "Gesture EventHandler", e);
}
}
}
public KeyEvent handleKeyEvent(KeyEvent event) {
KeyEvent isHandled = event;
CMHardwareManager hardware = CMHardwareManager.getInstance(mContext);
boolean virtualKeysEnabled = hardware.get(CMHardwareManager.FEATURE_KEY_DISABLE);
switch (event.getScanCode()) {
case 102: // Home button event
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && isLastPressHomeButton) {
isHandled = null;
}
isLastPressHomeButton = mPowerManager.isInteractive()
&& event.getKeyCode() == KeyEvent.KEYCODE_HOME;
}
break;
case 195: // Gesture event
isHandled = null;
if (event.getAction() == KeyEvent.ACTION_DOWN) {
try {
int gestureData = readGestureData();
if (gestureData != 0 && !mEventHandler.hasMessages(GESTURE_REQUEST)) {
Message msg = getGestureMessage(gestureData);
boolean defaultProximity = mContext.getResources().getBoolean(
org.cyanogenmod.platform.internal.R.bool.config_proximityCheckOnWakeEnabledByDefault);
boolean proximityWakeCheckEnabled = CMSettings.System.getInt(mContext.getContentResolver(),
CMSettings.System.PROXIMITY_ON_WAKE, defaultProximity ? 1 : 0) == 1;
if (mProximityWakeSupported && proximityWakeCheckEnabled && mProximitySensor != null) {
mEventHandler.sendMessageDelayed(msg, mProximityTimeOut);
processEvent(event);
} else {
mEventHandler.sendMessage(msg);
}
}
} catch (Exception e) {
Log.e(TAG, "Gesture handling failed.", e);
isHandled = event;
}
}
}
if (event.getScanCode() == 102) {
return virtualKeysEnabled ? null : isHandled;
}
return isHandled;
}
private Message getGestureMessage(int gestureData) {
Message msg = mEventHandler.obtainMessage(GESTURE_REQUEST);
msg.obj = gestureData;
return msg;
}
private Message getMessageForKeyEvent(KeyEvent keyEvent) {
Message msg = mEventHandler.obtainMessage(GESTURE_REQUEST);
msg.obj = keyEvent;
return msg;
}
private void processEvent(final KeyEvent keyEvent) {
mProximityWakeLock.acquire();
mSensorManager.registerListener(new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
mProximityWakeLock.release();
mSensorManager.unregisterListener(this);
if (!mEventHandler.hasMessages(GESTURE_REQUEST)) {
// The sensor took to long, ignoring.
return;
}
mEventHandler.removeMessages(GESTURE_REQUEST);
if (event.values[0] == mProximitySensor.getMaximumRange()) {
Message msg = getMessageForKeyEvent(keyEvent);
mEventHandler.sendMessage(msg);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {}
}, mProximitySensor, SensorManager.SENSOR_DELAY_FASTEST);
}
private void dispatchMediaKeyWithWakeLockToMediaSession(int keycode) {
MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext);
if (helper != null) {
KeyEvent event = new KeyEvent(SystemClock.uptimeMillis(),
SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0);
helper.sendMediaButtonEvent(event, true);
event = KeyEvent.changeAction(event, KeyEvent.ACTION_UP);
helper.sendMediaButtonEvent(event, true);
} else {
Log.w(TAG, "Unable to send media key event");
}
}
private void startActivitySafely(Intent intent) {
intent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
UserHandle user = new UserHandle(UserHandle.USER_CURRENT);
mContext.startActivityAsUser(intent, null, user);
} catch (ActivityNotFoundException e) {
// Ignore
}
}
// TODO implement it more graceful way
private boolean getCMApref(String prefKey, boolean defVal) {
SharedPreferences cmaPrefs = null;
cmaPrefs = cmaContext.getSharedPreferences("com.cyanogenmod.settings.device_preferences", Context.MODE_MULTI_PROCESS);
return cmaPrefs.getBoolean(prefKey, defVal);
}
private String getCMAStringPref(String prefKey) {
SharedPreferences cmaPrefs = null;
cmaPrefs = cmaContext.getSharedPreferences("com.cyanogenmod.settings.device_preferences", Context.MODE_MULTI_PROCESS);
return cmaPrefs.getString(prefKey, "disabled");
}
private void doHapticFeedback() {
if (mVibrator == null) {
return;
}
boolean enabled = getCMApref(TOUCHSCREEN_GESTURE_HAPTIC_FEEDBACK, false);
if (enabled) {
mVibrator.vibrate(50);
}
}
public String readSingleLine(File f) throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(f));
String line = reader.readLine();
reader.close();
return line;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ignored) {
}
}
}
}
private int readGestureData() throws Exception {
File f = new File(MEIZU_GESTURE_DATA);
return Integer.valueOf(readSingleLine(f));
}
}