import android.app.ActivityManager.StackId;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerInternal.SleepToken;
+import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
import android.app.AppOpsManager;
import android.app.IUiModeManager;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.hardware.hdmi.HdmiPlaybackClient;
import android.hardware.hdmi.HdmiPlaybackClient.OneTouchPlayCallback;
import android.hardware.input.InputManagerInternal;
+import android.hardware.input.InputManager;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.service.dreams.IDreamManager;
import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
+
+import cyanogenmod.hardware.CMHardwareManager;
+import cyanogenmod.providers.CMSettings;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
+import android.widget.Toast;
+
import com.android.internal.R;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.os.DeviceKeyHandler;
import com.android.internal.policy.PhoneWindow;
+import com.android.internal.policy.IKeyguardService;
import com.android.internal.policy.IShortcutService;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.ScreenShapeHelper;
+import com.android.internal.view.RotationPolicy;
import com.android.internal.widget.PointerLocationView;
import com.android.server.GestureLauncherService;
import com.android.server.LocalServices;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.List;
+import java.lang.reflect.Constructor;
+
+import cyanogenmod.providers.CMSettings;
+import dalvik.system.PathClassLoader;
/**
* WindowManagerPolicy implementation for the Android phone UI. This
static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
static public final String SYSTEM_DIALOG_REASON_ASSIST = "assist";
+ // Available custom actions to perform on a key press.
+ // Must match values for KEY_HOME_LONG_PRESS_ACTION in:
+ // core/java/android/provider/Settings.java
+ private static final int KEY_ACTION_NOTHING = 0;
+ private static final int KEY_ACTION_MENU = 1;
+ private static final int KEY_ACTION_APP_SWITCH = 2;
+ private static final int KEY_ACTION_SEARCH = 3;
+ private static final int KEY_ACTION_VOICE_SEARCH = 4;
+ private static final int KEY_ACTION_IN_APP_SEARCH = 5;
+ private static final int KEY_ACTION_LAUNCH_CAMERA = 6;
+ private static final int KEY_ACTION_SLEEP = 7;
+
+ // Masks for checking presence of hardware keys.
+ // Must match values in core/res/res/values/config.xml
+ private static final int KEY_MASK_HOME = 0x01;
+ private static final int KEY_MASK_BACK = 0x02;
+ private static final int KEY_MASK_MENU = 0x04;
+ private static final int KEY_MASK_ASSIST = 0x08;
+ private static final int KEY_MASK_APP_SWITCH = 0x10;
+ private static final int KEY_MASK_CAMERA = 0x20;
+ private static final int KEY_MASK_VOLUME = 0x40;
+
+
/**
* These are the system UI flags that, when changing, can cause the layout
* of the screen to change.
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
+ /**
+ * Broadcast Action: WiFi Display video is enabled or disabled
+ *
+ * <p>The intent will have the following extra values:</p>
+ * <ul>
+ * <li><em>state</em> - 0 for disabled, 1 for enabled. </li>
+ * </ul>
+ */
+
+ private static final String ACTION_WIFI_DISPLAY_VIDEO =
+ "org.codeaurora.intent.action.WIFI_DISPLAY_VIDEO";
+
+
// The panic gesture may become active only after the keyguard is dismissed and the immersive
// app shows again. If that doesn't happen for 30s we drop the gesture.
private static final long PANIC_GESTURE_EXPIRATION = 30000;
/** Amount of time (in milliseconds) to wait for windows drawn before powering on. */
static final int WAITING_FOR_DRAWN_TIMEOUT = 1000;
+ private DeviceKeyHandler mDeviceKeyHandler;
+
/**
* Lock protecting internal state. Must not call out into window
* manager with lock held. (This lock will be acquired in places
// This is for car dock and this is updated from resource.
private boolean mEnableCarDockHomeCapture = true;
+ boolean mNavigationBarLeftInLandscape = false; // Navigation bar left handed?
+
boolean mBootMessageNeedsHiding;
+
+ WindowState mKeyguardPanel;
+
+
KeyguardServiceDelegate mKeyguardDelegate;
final Runnable mWindowManagerDrawCallback = new Runnable() {
@Override
int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
int mUserRotation = Surface.ROTATION_0;
+ int mUserRotationAngles = -1;
boolean mAccelerometerDefault;
boolean mSupportAutoRotation;
boolean mHasSoftInput = false;
boolean mTranslucentDecorEnabled = true;
boolean mUseTvRouting;
+ int mBackKillTimeout;
+
+ int mDeviceHardwareKeys;
+
+ // Button wake control flags
+ boolean mHomeWakeScreen;
+ boolean mBackWakeScreen;
+ boolean mMenuWakeScreen;
+ boolean mAssistWakeScreen;
+ boolean mAppSwitchWakeScreen;
+ boolean mCameraWakeScreen;
+ boolean mVolumeWakeScreen;
+
+ // Camera button control flags and actions
+ boolean mCameraSleepOnRelease;
+ boolean mIsFocusPressed;
+ boolean mCameraLaunch;
+
+ // During wakeup by volume keys, we still need to capture subsequent events
+ // until the key is released. This is required since the beep sound is produced
+ // post keypressed.
+ boolean mVolumeDownWakeTriggered;
+ boolean mVolumeUpWakeTriggered;
+ boolean mVolumeMuteWakeTriggered;
int mPointerLocationMode = 0; // guarded by mLock
WindowState mFocusedWindow;
IApplicationToken mFocusedApp;
+ // Behavior of volbtn music controls
+ boolean mVolBtnMusicControls;
+ boolean mIsLongPress;
+
PointerLocationView mPointerLocationView;
// The current size of the screen; really; extends into the overscan area of
boolean mForcingShowNavBar;
int mForcingShowNavBarLayer;
+ boolean mDevForceNavbar = false;
+
// States of keyguard dismiss.
private static final int DISMISS_KEYGUARD_NONE = 0; // Keyguard not being dismissed.
private static final int DISMISS_KEYGUARD_START = 1; // Keyguard needs to be dismissed.
boolean mHomePressed;
boolean mHomeConsumed;
boolean mHomeDoubleTapPending;
+ boolean mMenuPressed;
+ boolean mAppSwitchLongPressed;
Intent mHomeIntent;
Intent mCarDockIntent;
Intent mDeskDockIntent;
int mInitialMetaState;
boolean mForceShowSystemBars;
+ // Tracks user-customisable behavior for certain key events
+ private int mLongPressOnHomeBehavior = -1;
+ private int mPressOnMenuBehavior = -1;
+ private int mLongPressOnMenuBehavior = -1;
+ private int mPressOnAssistBehavior = -1;
+ private int mLongPressOnAssistBehavior = -1;
+ private int mPressOnAppSwitchBehavior = -1;
+ private int mLongPressOnAppSwitchBehavior = -1;
+
// support for activating the lock screen while the screen is on
boolean mAllowLockscreenWhenOn;
int mLockScreenTimeout;
int mOverscanRight = 0;
int mOverscanBottom = 0;
- // What we do when the user long presses on home
- private int mLongPressOnHomeBehavior;
-
// What we do when the user double-taps on home
private int mDoubleTapOnHomeBehavior;
private static final int MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU = 17;
private static final int MSG_BACK_LONG_PRESS = 18;
private static final int MSG_DISPOSE_INPUT_CONSUMER = 19;
+ private static final int MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK = 20;
+ private static final int MSG_CAMERA_LONG_PRESS = 21;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
+ boolean mWifiDisplayConnected = false;
+ int mWifiDisplayCustomRotation = -1;
+
+ private CMHardwareManager mCMHardware;
private class PolicyHandler extends Handler {
@Override
case MSG_DISPOSE_INPUT_CONSUMER:
disposeInputConsumer((InputConsumer) msg.obj);
break;
+ case MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK: {
+ KeyEvent event = (KeyEvent) msg.obj;
+ mIsLongPress = true;
+ dispatchMediaKeyWithWakeLockToAudioService(event);
+ dispatchMediaKeyWithWakeLockToAudioService(
+ KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
+ break;
+ }
+ case MSG_CAMERA_LONG_PRESS: {
+ KeyEvent event = (KeyEvent) msg.obj;
+ mIsLongPress = true;
+ break;
+ }
}
}
}
resolver.registerContentObserver(Settings.System.getUriFor(
Settings.System.POINTER_LOCATION), false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_HOME_LONG_PRESS_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_HOME_DOUBLE_TAP_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_MENU_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_MENU_LONG_PRESS_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_ASSIST_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_ASSIST_LONG_PRESS_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_APP_SWITCH_ACTION), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.KEY_APP_SWITCH_LONG_PRESS_ACTION), false, this,
+ UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.DEFAULT_INPUT_METHOD), false, this,
UserHandle.USER_ALL);
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.POLICY_CONTROL), false, this,
UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.ACCELEROMETER_ROTATION_ANGLES), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.Global.getUriFor(
+ CMSettings.Global.DEV_FORCE_SHOW_NAVBAR), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.VOLBTN_MUSIC_CONTROLS), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.BACK_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.MENU_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.ASSIST_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.APP_SWITCH_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.CAMERA_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.CAMERA_SLEEP_ON_RELEASE), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.CAMERA_LAUNCH), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.VOLUME_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.HOME_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.VOLUME_WAKE_SCREEN), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(Settings.System.getUriFor(
+ Settings.System.ACCELEROMETER_ROTATION_ANGLES), false, this,
+ UserHandle.USER_ALL);
+ resolver.registerContentObserver(CMSettings.System.getUriFor(
+ CMSettings.System.NAVBAR_LEFT_IN_LANDSCAPE), false, this,
+ UserHandle.USER_ALL);
updateSettings();
}
mHandler.sendEmptyMessage(MSG_DISPATCH_SHOW_GLOBAL_ACTIONS);
}
+ Runnable mBackLongPress = new Runnable() {
+ public void run() {
+ if (unpinActivity(false)) {
+ return;
+ }
+ try {
+ final Intent intent = new Intent(Intent.ACTION_MAIN);
+ String defaultHomePackage = "com.android.launcher";
+ intent.addCategory(Intent.CATEGORY_HOME);
+ final ResolveInfo res = mContext.getPackageManager().resolveActivity(intent, 0);
+ if (res.activityInfo != null && !res.activityInfo.packageName.equals("android")) {
+ defaultHomePackage = res.activityInfo.packageName;
+ }
+ boolean targetKilled = false;
+ IActivityManager am = ActivityManagerNative.getDefault();
+ List<RunningAppProcessInfo> apps = am.getRunningAppProcesses();
+ for (RunningAppProcessInfo appInfo : apps) {
+ int uid = appInfo.uid;
+ // Make sure it's a foreground user application (not system,
+ // root, phone, etc.)
+ if (uid >= Process.FIRST_APPLICATION_UID && uid <= Process.LAST_APPLICATION_UID
+ && appInfo.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ if (appInfo.pkgList != null && (appInfo.pkgList.length > 0)) {
+ for (String pkg : appInfo.pkgList) {
+ if (!pkg.equals("com.android.systemui") && !pkg.equals(defaultHomePackage)) {
+ am.forceStopPackage(pkg, UserHandle.USER_CURRENT);
+ targetKilled = true;
+ break;
+ }
+ }
+ } else {
+ Process.killProcess(appInfo.pid);
+ targetKilled = true;
+ }
+ }
+ if (targetKilled) {
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ Toast.makeText(mContext, R.string.app_killed_message, Toast.LENGTH_SHORT).show();
+ break;
+ }
+ }
+ } catch (RemoteException remoteException) {
+ // Do nothing; just let it go.
+ }
+ }
+ };
+
void showGlobalActionsInternal() {
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
if (mGlobalActions == null) {
}
}
- private void handleLongPressOnHome(int deviceId) {
- if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_NOTHING) {
- return;
- }
- mHomeConsumed = true;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ private void triggerVirtualKeypress(final int keyCode) {
+ InputManager im = InputManager.getInstance();
+ long now = SystemClock.uptimeMillis();
+ final KeyEvent downEvent = new KeyEvent(now, now, KeyEvent.ACTION_DOWN,
+ keyCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
+ KeyEvent.FLAG_FROM_SYSTEM, InputDevice.SOURCE_KEYBOARD);
+ final KeyEvent upEvent = KeyEvent.changeAction(downEvent, KeyEvent.ACTION_UP);
- switch (mLongPressOnHomeBehavior) {
- case LONG_PRESS_HOME_RECENT_SYSTEM_UI:
- toggleRecentApps();
- break;
- case LONG_PRESS_HOME_ASSIST:
- launchAssistAction(null, deviceId);
- break;
- default:
- Log.w(TAG, "Undefined home long press behavior: " + mLongPressOnHomeBehavior);
- break;
- }
+ im.injectInputEvent(downEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ im.injectInputEvent(upEvent, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
}
- private void handleDoubleTapOnHome() {
- if (mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
- mHomeConsumed = true;
- toggleRecentApps();
- }
+ private void launchCameraAction() {
+ sendCloseSystemWindows();
+ Intent intent = new Intent(Intent.ACTION_CAMERA_BUTTON, null);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT_OR_SELF,
+ null, null, null, 0, null, null);
}
private void showTvPictureInPictureMenu(KeyEvent event) {
}
}
+ private void performKeyAction(int behavior, KeyEvent event) {
+ switch (behavior) {
+ case KEY_ACTION_NOTHING:
+ break;
+ case KEY_ACTION_MENU:
+ triggerVirtualKeypress(KeyEvent.KEYCODE_MENU);
+ break;
+ case KEY_ACTION_APP_SWITCH:
+ toggleRecentApps();
+ break;
+ case KEY_ACTION_SEARCH:
+ launchAssistAction(null, event.getDeviceId());
+ break;
+ case KEY_ACTION_VOICE_SEARCH:
+ launchAssistLongPressAction();
+ break;
+ case KEY_ACTION_IN_APP_SEARCH:
+ triggerVirtualKeypress(KeyEvent.KEYCODE_SEARCH);
+ break;
+ case KEY_ACTION_LAUNCH_CAMERA:
+ launchCameraAction();
+ break;
+ case KEY_ACTION_SLEEP:
+ mPowerManager.goToSleep(SystemClock.uptimeMillis());
+ break;
+ default:
+ break;
+ }
+ }
+
private final Runnable mHomeDoubleTapTimeoutRunnable = new Runnable() {
@Override
public void run() {
mOrientationListener.setCurrentRotation(windowManager.getRotation());
} catch (RemoteException ex) { }
mSettingsObserver = new SettingsObserver(mHandler);
- mSettingsObserver.observe();
mShortcutManager = new ShortcutManager(context);
mUiMode = context.getResources().getInteger(
com.android.internal.R.integer.config_defaultUiModeType);
mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
- readConfigurationDependentBehaviors();
+ mDeviceHardwareKeys = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_deviceHardwareKeys);
+ mBackKillTimeout = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_backKillTimeout);
+
+ updateKeyAssignments();
mAccessibilityManager = (AccessibilityManager) context.getSystemService(
Context.ACCESSIBILITY_SERVICE);
}
@Override
public void onSwipeFromRight() {
- if (mNavigationBar != null && !mNavigationBarOnBottom) {
+ if (mNavigationBar != null && !mNavigationBarOnBottom &&
+ !mNavigationBarLeftInLandscape) {
+ requestTransientBars(mNavigationBar);
+ }
+ }
+ @Override
+ public void onSwipeFromLeft() {
+ if (mNavigationBar != null && !mNavigationBarOnBottom &&
+ mNavigationBarLeftInLandscape) {
requestTransientBars(mNavigationBar);
}
}
mWindowManagerFuncs.registerPointerEventListener(mSystemGestures);
mVibrator = (Vibrator)context.getSystemService(Context.VIBRATOR_SERVICE);
+
+ /* Register for WIFI Display Intents */
+ IntentFilter wifiDisplayFilter = new IntentFilter(ACTION_WIFI_DISPLAY_VIDEO);
+ Intent wifidisplayIntent = context.registerReceiver(
+ mWifiDisplayReceiver, wifiDisplayFilter);
mLongPressVibePattern = getLongIntArray(mContext.getResources(),
com.android.internal.R.array.config_longPressVibePattern);
mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(),
mWindowManagerInternal.registerAppTransitionListener(
mStatusBarController.getAppTransitionListener());
+
+ String deviceKeyHandlerLib = mContext.getResources().getString(
+ com.android.internal.R.string.config_deviceKeyHandlerLib);
+
+ String deviceKeyHandlerClass = mContext.getResources().getString(
+ com.android.internal.R.string.config_deviceKeyHandlerClass);
+
+ if (!deviceKeyHandlerLib.isEmpty() && !deviceKeyHandlerClass.isEmpty()) {
+ PathClassLoader loader = new PathClassLoader(deviceKeyHandlerLib,
+ getClass().getClassLoader());
+ try {
+ Class<?> klass = loader.loadClass(deviceKeyHandlerClass);
+ Constructor<?> constructor = klass.getConstructor(Context.class);
+ mDeviceKeyHandler = (DeviceKeyHandler) constructor.newInstance(
+ mContext);
+ if(DEBUG) Slog.d(TAG, "Device key handler loaded");
+ } catch (Exception e) {
+ Slog.w(TAG, "Could not instantiate device key handler "
+ + deviceKeyHandlerClass + " from class "
+ + deviceKeyHandlerLib, e);
+ }
+ }
}
- /**
- * Read values from config.xml that may be overridden depending on
- * the configuration of the device.
- * eg. Disable long press on home goes to recents on sw600dp.
- */
- private void readConfigurationDependentBehaviors() {
+ private void updateKeyAssignments() {
+ int activeHardwareKeys = mDeviceHardwareKeys;
+
+ if (mDevForceNavbar) {
+ activeHardwareKeys = 0;
+ }
+ final boolean hasMenu = (activeHardwareKeys & KEY_MASK_MENU) != 0;
+ final boolean hasHome = (activeHardwareKeys & KEY_MASK_HOME) != 0;
+ final boolean hasAssist = (activeHardwareKeys & KEY_MASK_ASSIST) != 0;
+ final boolean hasAppSwitch = (activeHardwareKeys & KEY_MASK_APP_SWITCH) != 0;
+
+ final ContentResolver resolver = mContext.getContentResolver();
final Resources res = mContext.getResources();
+ // Initialize all assignments to sane defaults.
+ mPressOnMenuBehavior = KEY_ACTION_MENU;
+
+ mLongPressOnMenuBehavior = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_longPressOnMenuBehavior);
+
+ if (mLongPressOnMenuBehavior == KEY_ACTION_NOTHING &&
+ (hasMenu && !hasAssist)) {
+ mLongPressOnMenuBehavior = KEY_ACTION_SEARCH;
+ }
+ mPressOnAssistBehavior = KEY_ACTION_SEARCH;
+ mLongPressOnAssistBehavior = KEY_ACTION_VOICE_SEARCH;
+ mPressOnAppSwitchBehavior = KEY_ACTION_APP_SWITCH;
+ mLongPressOnAppSwitchBehavior = res.getInteger(
+ com.android.internal.R.integer.config_longPressOnAppSwitchBehavior);
+
mLongPressOnHomeBehavior = res.getInteger(
com.android.internal.R.integer.config_longPressOnHomeBehavior);
- if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING ||
- mLongPressOnHomeBehavior > LAST_LONG_PRESS_HOME_BEHAVIOR) {
- mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
+ if (mLongPressOnHomeBehavior < KEY_ACTION_NOTHING ||
+ mLongPressOnHomeBehavior > KEY_ACTION_SLEEP) {
+ mLongPressOnHomeBehavior = KEY_ACTION_NOTHING;
}
mDoubleTapOnHomeBehavior = res.getInteger(
com.android.internal.R.integer.config_doubleTapOnHomeBehavior);
- if (mDoubleTapOnHomeBehavior < DOUBLE_TAP_HOME_NOTHING ||
- mDoubleTapOnHomeBehavior > DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
- mDoubleTapOnHomeBehavior = LONG_PRESS_HOME_NOTHING;
+ if (mDoubleTapOnHomeBehavior < KEY_ACTION_NOTHING ||
+ mDoubleTapOnHomeBehavior > KEY_ACTION_SLEEP) {
+ mDoubleTapOnHomeBehavior = KEY_ACTION_NOTHING;
+ }
+
+ // Check for custom assignments and whether KEY_ACTION_MENU is assigned.
+ if (hasHome) {
+ mLongPressOnHomeBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_HOME_LONG_PRESS_ACTION,
+ mLongPressOnHomeBehavior, UserHandle.USER_CURRENT);
+ mDoubleTapOnHomeBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_HOME_DOUBLE_TAP_ACTION,
+ mDoubleTapOnHomeBehavior, UserHandle.USER_CURRENT);
+ }
+ if (hasMenu) {
+ mPressOnMenuBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_MENU_ACTION,
+ mPressOnMenuBehavior, UserHandle.USER_CURRENT);
+ mLongPressOnMenuBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_MENU_LONG_PRESS_ACTION,
+ mLongPressOnMenuBehavior, UserHandle.USER_CURRENT);
+ }
+ if (hasAssist) {
+ mPressOnAssistBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_ASSIST_ACTION,
+ mPressOnAssistBehavior, UserHandle.USER_CURRENT);
+ mLongPressOnAssistBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_ASSIST_LONG_PRESS_ACTION,
+ mLongPressOnAssistBehavior, UserHandle.USER_CURRENT);
+ }
+ if (hasAppSwitch) {
+ mPressOnAppSwitchBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_APP_SWITCH_ACTION,
+ mPressOnAppSwitchBehavior, UserHandle.USER_CURRENT);
+ mLongPressOnAppSwitchBehavior = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.KEY_APP_SWITCH_LONG_PRESS_ACTION,
+ mLongPressOnAppSwitchBehavior, UserHandle.USER_CURRENT);
}
mShortPressWindowBehavior = SHORT_PRESS_WINDOW_NOTHING;
* navigation bar and touch exploration is not enabled
*/
private boolean canHideNavigationBar() {
- return mHasNavigationBar;
+ return hasNavigationBar();
}
@Override
public void updateSettings() {
ContentResolver resolver = mContext.getContentResolver();
boolean updateRotation = false;
+ int mDeviceHardwareWakeKeys = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_deviceHardwareWakeKeys);
synchronized (mLock) {
mEndcallBehavior = Settings.System.getIntForUser(resolver,
Settings.System.END_BUTTON_BEHAVIOR,
Settings.System.END_BUTTON_BEHAVIOR_DEFAULT,
UserHandle.USER_CURRENT);
- mIncallPowerBehavior = Settings.Secure.getIntForUser(resolver,
- Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR,
- Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT,
- UserHandle.USER_CURRENT);
+ mHomeWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.HOME_WAKE_SCREEN, 1, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_HOME) != 0);
+ mBackWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.BACK_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_BACK) != 0);
+ mMenuWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.MENU_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_MENU) != 0);
+ mAssistWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.ASSIST_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_ASSIST) != 0);
+ mAppSwitchWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.APP_SWITCH_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_APP_SWITCH) != 0);
+ mCameraWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.CAMERA_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_CAMERA) != 0);
+ mCameraSleepOnRelease = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.CAMERA_SLEEP_ON_RELEASE, 0, UserHandle.USER_CURRENT) == 1);
+ mCameraLaunch = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.CAMERA_LAUNCH, 0, UserHandle.USER_CURRENT) == 1);
+ mVolumeWakeScreen = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.VOLUME_WAKE_SCREEN, 0, UserHandle.USER_CURRENT) == 1) &&
+ ((mDeviceHardwareWakeKeys & KEY_MASK_VOLUME) != 0);
+ mVolBtnMusicControls = (CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.VOLBTN_MUSIC_CONTROLS, 1, UserHandle.USER_CURRENT) == 1);
// Configure wake gesture.
boolean wakeGestureEnabledSetting = Settings.Secure.getIntForUser(resolver,
updateWakeGestureListenerLp();
}
+ boolean devForceNavbar = CMSettings.Global.getIntForUser(resolver,
+ CMSettings.Global.DEV_FORCE_SHOW_NAVBAR, 0, UserHandle.USER_CURRENT) == 1;
+ if (devForceNavbar != mDevForceNavbar) {
+ mDevForceNavbar = devForceNavbar;
+ if (mCMHardware.isSupported(CMHardwareManager.FEATURE_KEY_DISABLE)) {
+ mCMHardware.set(CMHardwareManager.FEATURE_KEY_DISABLE, mDevForceNavbar);
+ }
+ }
+
+ mNavigationBarLeftInLandscape = CMSettings.System.getIntForUser(resolver,
+ CMSettings.System.NAVBAR_LEFT_IN_LANDSCAPE, 0, UserHandle.USER_CURRENT) == 1;
+
+ updateKeyAssignments();
+
// Configure rotation lock.
int userRotation = Settings.System.getIntForUser(resolver,
Settings.System.USER_ROTATION, Surface.ROTATION_0,
updateOrientationListenerLp();
}
+ mUserRotationAngles = Settings.System.getInt(resolver,
+ Settings.System.ACCELEROMETER_ROTATION_ANGLES, -1);
+
if (mSystemReady) {
int pointerLocation = Settings.System.getIntForUser(resolver,
Settings.System.POINTER_LOCATION, 0, UserHandle.USER_CURRENT);
permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW;
outAppOp[0] = AppOpsManager.OP_SYSTEM_ALERT_WINDOW;
break;
+ case TYPE_KEYGUARD_PANEL:
+ permission =
+ org.cyanogenmod.platform.internal.Manifest.permission.THIRD_PARTY_KEYGUARD;
+ break;
default:
permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
}
case TYPE_VOLUME_OVERLAY:
case TYPE_PRIVATE_PRESENTATION:
case TYPE_DOCK_DIVIDER:
+ case TYPE_KEYGUARD_PANEL:
break;
}
}
}
+ private boolean isBuiltInKeyboardVisible() {
+ return mHaveBuiltInKeyboard && !isHidden(mLidKeyboardAccessibility);
+ }
+
/** {@inheritDoc} */
@Override
public void adjustConfigurationLw(Configuration config, int keyboardPresence,
int navigationPresence) {
mHaveBuiltInKeyboard = (keyboardPresence & PRESENCE_INTERNAL) != 0;
- readConfigurationDependentBehaviors();
readLidState();
if (config.keyboard == Configuration.KEYBOARD_NOKEYS
// the safety window that shows behind keyguard while keyguard is starting
return 14;
case TYPE_STATUS_BAR_SUB_PANEL:
+ case TYPE_KEYGUARD_PANEL:
return 15;
case TYPE_STATUS_BAR:
return 16;
@Override
public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation,
int uiMode) {
- if (mHasNavigationBar) {
+ if (hasNavigationBar()) {
// For a basic navigation bar, when we are in landscape mode we place
// the navigation bar to the side.
if (mNavigationBarCanMove && fullWidth > fullHeight) {
@Override
public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation,
int uiMode) {
- if (mHasNavigationBar) {
+ if (hasNavigationBar()) {
// For a basic navigation bar, when we are in portrait mode we place
// the navigation bar to the bottom.
if (!mNavigationBarCanMove || fullWidth < fullHeight) {
android.Manifest.permission.STATUS_BAR_SERVICE,
"PhoneWindowManager");
break;
+ case TYPE_KEYGUARD_PANEL:
+ mContext.enforceCallingOrSelfPermission(
+ org.cyanogenmod.platform.internal.Manifest.permission.THIRD_PARTY_KEYGUARD,
+ "PhoneWindowManager");
+ if (mKeyguardPanel != null) {
+ return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+ }
+ mKeyguardPanel = win;
+ break;
case TYPE_KEYGUARD_SCRIM:
if (mKeyguardScrim != null) {
return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
} else if (mKeyguardScrim == win) {
Log.v(TAG, "Removing keyguard scrim");
mKeyguardScrim = null;
- } if (mNavigationBar == win) {
+ } else if (mNavigationBar == win) {
mNavigationBar = null;
mNavigationBarController.setWindow(null);
+ } else if (mKeyguardPanel == win) {
+ mKeyguardPanel = null;
}
}
if (win.getAttrs().windowAnimations != 0) {
return 0;
}
- // This can be on either the bottom or the right.
+ // This can be on either the bottom, left, or the right.
if (mNavigationBarOnBottom) {
if (transit == TRANSIT_EXIT
|| transit == TRANSIT_HIDE) {
} else {
if (transit == TRANSIT_EXIT
|| transit == TRANSIT_HIDE) {
- return R.anim.dock_right_exit;
+ return mNavigationBarLeftInLandscape
+ ? R.anim.dock_left_exit : R.anim.dock_right_exit;
} else if (transit == TRANSIT_ENTER
|| transit == TRANSIT_SHOW) {
- return R.anim.dock_right_enter;
+ return mNavigationBarLeftInLandscape
+ ? R.anim.dock_left_enter : R.anim.dock_right_enter;
}
}
} else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
@Override
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
final boolean keyguardOn = keyguardOn();
- final int keyCode = event.getKeyCode();
final int repeatCount = event.getRepeatCount();
final int metaState = event.getMetaState();
final int flags = event.getFlags();
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
+ final boolean longPress = (flags & KeyEvent.FLAG_LONG_PRESS) != 0;
+ final boolean virtualKey = event.getDeviceId() == KeyCharacterMap.VIRTUAL_KEYBOARD;
+ final int keyCode = event.getKeyCode();
if (DEBUG_INPUT) {
Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
+ " canceled=" + canceled);
}
+ // If the boot mode is power off alarm, we should not dispatch the several physical keys
+ // in power off alarm UI to avoid pausing power off alarm UI.
+ boolean isAlarmBoot = SystemProperties.getBoolean("ro.alarm_boot", false);
+ if (isAlarmBoot && (keyCode == KeyEvent.KEYCODE_HOME
+ || keyCode == KeyEvent.KEYCODE_SEARCH
+ || keyCode == KeyEvent.KEYCODE_MENU
+ || keyCode == KeyEvent.KEYCODE_APP_SWITCH
+ || keyCode == KeyEvent.KEYCODE_BACK)) {
+ return -1;
+ }
+
// If we think we might have a volume down & power key chord on the way
// but we're not sure, then tell the dispatcher to wait a little while and
// try again later before dispatching.
mPendingCapsLockToggle = false;
}
+ if (keyCode == KeyEvent.KEYCODE_BACK && !down) {
+ mHandler.removeCallbacks(mBackLongPress);
+ }
+
// First we always handle the home key here, so applications
// can never break it, although if keyguard is on, we do let
// it handle it, because that gives us the correct 5 second
// If we have released the home key, and didn't do anything else
// while it was pressed, then it is time to go home!
if (!down) {
- cancelPreloadRecentApps();
+ if (mDoubleTapOnHomeBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
mHomePressed = false;
if (mHomeConsumed) {
}
// Delay handling home if a double-tap is possible.
- if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) {
+ if (mDoubleTapOnHomeBehavior != KEY_ACTION_NOTHING) {
mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case
mHomeDoubleTapPending = true;
mHandler.postDelayed(mHomeDoubleTapTimeoutRunnable,
if (mHomeDoubleTapPending) {
mHomeDoubleTapPending = false;
mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable);
- handleDoubleTapOnHome();
- } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI
- || mDoubleTapOnHomeBehavior == DOUBLE_TAP_HOME_RECENT_SYSTEM_UI) {
+ performKeyAction(mDoubleTapOnHomeBehavior, event);
+ mHomeConsumed = true;
+ } else if (mLongPressOnHomeBehavior == KEY_ACTION_APP_SWITCH
+ || mDoubleTapOnHomeBehavior == KEY_ACTION_APP_SWITCH) {
preloadRecentApps();
}
- } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
- if (!keyguardOn) {
- handleLongPressOnHome(event.getDeviceId());
+ } else if (longPress) {
+ if (!keyguardOn && !mHomeConsumed &&
+ mLongPressOnHomeBehavior != KEY_ACTION_NOTHING) {
+ if (mLongPressOnHomeBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ mHomePressed = true;
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ performKeyAction(mLongPressOnHomeBehavior, event);
+ mHomeConsumed = true;
}
}
return -1;
} else if (keyCode == KeyEvent.KEYCODE_MENU) {
// Hijack modified menu keys for debugging features
final int chordBug = KeyEvent.META_SHIFT_ON;
+ if (virtualKey || keyguardOn) {
+ // Let the app handle the key
+ return 0;
+ }
- if (down && repeatCount == 0) {
- if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
- Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
- mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
- null, null, null, 0, null, null);
- return -1;
- } else if (SHOW_PROCESSES_ON_ALT_MENU &&
- (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
- Intent service = new Intent();
- service.setClassName(mContext, "com.android.server.LoadAverageService");
- ContentResolver res = mContext.getContentResolver();
- boolean shown = Settings.Global.getInt(
- res, Settings.Global.SHOW_PROCESSES, 0) != 0;
- if (!shown) {
- mContext.startService(service);
- } else {
- mContext.stopService(service);
+ if (down) {
+ if (mPressOnMenuBehavior == KEY_ACTION_APP_SWITCH
+ || mLongPressOnMenuBehavior == KEY_ACTION_APP_SWITCH) {
+ preloadRecentApps();
+ }
+ if (repeatCount == 0) {
+ mMenuPressed = true;
+ if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) {
+ Intent intent = new Intent(Intent.ACTION_BUG_REPORT);
+ mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT,
+ null, null, null, 0, null, null);
+ return -1;
+ } else if (SHOW_PROCESSES_ON_ALT_MENU &&
+ (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) {
+ Intent service = new Intent();
+ service.setClassName(mContext, "com.android.server.LoadAverageService");
+ ContentResolver res = mContext.getContentResolver();
+ boolean shown = Settings.Global.getInt(
+ res, Settings.Global.SHOW_PROCESSES, 0) != 0;
+ if (!shown) {
+ mContext.startService(service);
+ } else {
+ mContext.stopService(service);
+ }
+ Settings.Global.putInt(
+ res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
+ return -1;
+ }
+ } else if (longPress) {
+ if (!keyguardOn && mLongPressOnMenuBehavior != KEY_ACTION_NOTHING) {
+ if (mLongPressOnMenuBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ performKeyAction(mLongPressOnMenuBehavior, event);
+ mMenuPressed = false;
+ return -1;
}
- Settings.Global.putInt(
- res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
- return -1;
}
}
+ if (!down && mMenuPressed) {
+ if (mPressOnMenuBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ mMenuPressed = false;
+ if (!canceled) {
+ performKeyAction(mPressOnMenuBehavior, event);
+ }
+ }
+ return -1;
} else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
if (down) {
if (repeatCount == 0) {
}
return 0;
} else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) {
- if (!keyguardOn) {
- if (down && repeatCount == 0) {
+ if (down) {
+ if (mPressOnAppSwitchBehavior == KEY_ACTION_APP_SWITCH
+ || mLongPressOnAppSwitchBehavior == KEY_ACTION_APP_SWITCH) {
preloadRecentApps();
- } else if (!down) {
- toggleRecentApps();
+ }
+ if (repeatCount == 0) {
+ mAppSwitchLongPressed = false;
+ } else if (longPress) {
+ if (!keyguardOn && mLongPressOnAppSwitchBehavior != KEY_ACTION_NOTHING) {
+ if (mLongPressOnAppSwitchBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ performKeyAction(mLongPressOnAppSwitchBehavior, event);
+ mAppSwitchLongPressed = true;
+ }
+ }
+ } else {
+ if (mAppSwitchLongPressed) {
+ mAppSwitchLongPressed = false;
+ } else {
+ if (mPressOnAppSwitchBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ if (!canceled) {
+ performKeyAction(mPressOnAppSwitchBehavior, event);
+ }
}
}
return -1;
}
} else if (keyCode == KeyEvent.KEYCODE_ASSIST) {
if (down) {
+ if (mPressOnAssistBehavior == KEY_ACTION_APP_SWITCH
+ || mLongPressOnAssistBehavior == KEY_ACTION_APP_SWITCH) {
+ preloadRecentApps();
+ }
if (repeatCount == 0) {
mAssistKeyLongPressed = false;
- } else if (repeatCount == 1) {
- mAssistKeyLongPressed = true;
- if (!keyguardOn) {
- launchAssistLongPressAction();
+ } else if (longPress) {
+ if (!keyguardOn && mLongPressOnAssistBehavior != KEY_ACTION_NOTHING) {
+ if (mLongPressOnAssistBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+ performKeyAction(mLongPressOnAssistBehavior, event);
+ mAssistKeyLongPressed = true;
}
}
} else {
if (mAssistKeyLongPressed) {
mAssistKeyLongPressed = false;
} else {
- if (!keyguardOn) {
- launchAssistAction(null, event.getDeviceId());
+ if (mPressOnAssistBehavior != KEY_ACTION_APP_SWITCH) {
+ cancelPreloadRecentApps();
+ }
+ if (!canceled) {
+ performKeyAction(mPressOnAssistBehavior, event);
}
}
}
launchAssistAction(Intent.EXTRA_ASSIST_INPUT_HINT_KEYBOARD, event.getDeviceId());
}
return -1;
+ } else if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (unpinActivity(true) || CMSettings.Secure.getInt(mContext.getContentResolver(),
+ CMSettings.Secure.KILL_APP_LONGPRESS_BACK, 0) == 1) {
+ if (down && repeatCount == 0) {
+ mHandler.postDelayed(mBackLongPress, mBackKillTimeout);
+ }
+ }
}
// Shortcuts are invoked through Search+key, so intercept those here
return -1;
}
+ // Specific device key handling
+ if (mDeviceKeyHandler != null) {
+ try {
+ // The device only should consume known keys.
+ if (mDeviceKeyHandler.handleKeyEvent(event)) {
+ return -1;
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Could not dispatch event to device key handler", e);
+ }
+ }
+
if (down) {
long shortcutCode = keyCode;
if (event.isCtrlPressed()) {
return 0;
}
+ private boolean unpinActivity(boolean checkOnly) {
+ if (!hasNavigationBar()) {
+ try {
+ if (ActivityManagerNative.getDefault().isInLockTaskMode()) {
+ if (!checkOnly) {
+ ActivityManagerNative.getDefault().stopSystemLockTaskMode();
+ }
+ return true;
+ }
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+ return false;
+ }
+
/** {@inheritDoc} */
@Override
public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
awakenDreams();
}
hideRecentApps(false, true);
- } else {
- // Otherwise, just launch Home
+ } else if (mScreenOnFully) {
+ // check if screen is fully on before going home
+ // to avoid hardware home button wake going home
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
startDockOrHome(true /*fromHomeKey*/, awakenFromDreams);
}
navVisible |= !canHideNavigationBar();
boolean updateSysUiVisibility = layoutNavigationBar(displayWidth, displayHeight,
- displayRotation, uiMode, overscanRight, overscanBottom, dcf, navVisible, navTranslucent,
- navAllowedHidden, statusBarExpandedNotKeyguard);
+ displayRotation, uiMode, overscanLeft, overscanRight, overscanBottom,
+ dcf, navVisible, navTranslucent, navAllowedHidden, statusBarExpandedNotKeyguard);
if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)",
mDockLeft, mDockTop, mDockRight, mDockBottom));
updateSysUiVisibility |= layoutStatusBar(pf, df, of, vf, dcf, sysui, isKeyguardShowing);
}
private boolean layoutNavigationBar(int displayWidth, int displayHeight, int displayRotation,
- int uiMode, int overscanRight, int overscanBottom, Rect dcf, boolean navVisible,
- boolean navTranslucent, boolean navAllowedHidden,
+ int uiMode, int overscanLeft, int overscanRight, int overscanBottom, Rect dcf,
+ boolean navVisible, boolean navTranslucent, boolean navAllowedHidden,
boolean statusBarExpandedNotKeyguard) {
if (mNavigationBar != null) {
boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
// we can tell the app that it is covered by it.
mSystemBottom = mTmpNavigationFrame.top;
}
+ } else if (mNavigationBarLeftInLandscape) {
+ // Landscape screen; nav bar goes to the left.
+ int right = overscanLeft + getNavigationBarWidth(displayRotation, uiMode);
+ mTmpNavigationFrame.set(0, 0, right, displayHeight);
+ mStableLeft = mStableFullscreenLeft = mTmpNavigationFrame.right;
+ if (transientNavBarShowing) {
+ mNavigationBarController.setBarShowingLw(true);
+ } else if (navVisible) {
+ mNavigationBarController.setBarShowingLw(true);
+ mDockLeft = mTmpNavigationFrame.right;
+ mRestrictedScreenLeft = mDockLeft;
+ mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
+ mRestrictedOverscanScreenLeft = mRestrictedScreenLeft;
+ mRestrictedOverscanScreenWidth = mDockRight
+ - mRestrictedOverscanScreenLeft;
+ } else {
+ // We currently want to hide the navigation UI - unless we expanded the status
+ // bar.
+ mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);
+ }
+ if (navVisible && !navTranslucent && !navAllowedHidden
+ && !mNavigationBar.isAnimatingLw()
+ && !mNavigationBarController.wasRecentlyTranslucent()) {
+ // If the nav bar is currently requested to be visible,
+ // and not in the process of animating on or off, then
+ // we can tell the app that it is covered by it.
+ mSystemLeft = mTmpNavigationFrame.right;
+ }
} else {
// Landscape screen; nav bar goes to the right.
int left = displayWidth - overscanRight
// gets everything, period.
if (attrs.type == TYPE_STATUS_BAR_PANEL
|| attrs.type == TYPE_STATUS_BAR_SUB_PANEL
- || attrs.type == TYPE_VOLUME_OVERLAY) {
+ || attrs.type == TYPE_VOLUME_OVERLAY
+ || attrs.type == TYPE_KEYGUARD_PANEL) {
pf.left = df.left = of.left = cf.left = hasNavBar
? mDockLeft : mUnrestrictedScreenLeft;
pf.top = df.top = of.top = cf.top = mUnrestrictedScreenTop;
setHdmiPlugged(!mHdmiPlugged);
}
+ /**
+ * @return Whether music is being played right now "locally" (e.g. on the device's speakers
+ * or wired headphones) or "remotely" (e.g. on a device using the Cast protocol and
+ * controlled by this device, or through remote submix).
+ */
+ private boolean isMusicActive() {
+ final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE);
+ if (am == null) {
+ Log.w(TAG, "isMusicActive: couldn't get AudioManager reference");
+ return false;
+ }
+ return am.isMusicActive();
+ }
+
final Object mScreenshotLock = new Object();
ServiceConnection mScreenshotConnection = null;
mContext.sendBroadcastAsUser(errorIntent, UserHandle.CURRENT);
}
+ private void setVolumeWakeTriggered(final int keyCode, boolean triggered) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ mVolumeDownWakeTriggered = triggered;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ mVolumeUpWakeTriggered = triggered;
+ break;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ mVolumeMuteWakeTriggered = triggered;
+ break;
+ default:
+ Log.w(TAG, "setVolumeWakeTriggered: unexpected keyCode=" + keyCode);
+ }
+ }
+
+ private boolean getVolumeWakeTriggered(final int keyCode) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ return mVolumeDownWakeTriggered;
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ return mVolumeUpWakeTriggered;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ return mVolumeMuteWakeTriggered;
+ default:
+ Log.w(TAG, "getVolumeWakeTriggered: unexpected keyCode=" + keyCode);
+ return false;
+ }
+ }
+
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final boolean canceled = event.isCanceled();
final int keyCode = event.getKeyCode();
+ final int scanCode = event.getScanCode();
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
// If we're currently dozing with the screen on and the keyguard showing, pass the key
// to the application but preserve its wake key status to make sure we still move
// from dozing to fully interactive if we would normally go from off to fully
- // interactive.
+ // interactive, unless the user has explicitly disabled this wake key.
result = ACTION_PASS_TO_USER;
+ isWakeKey = isWakeKey && isWakeKeyEnabled(keyCode);
} else {
// When the screen is off and the key is not injected, determine whether
// to wake the device but don't pass the key to the application.
&& (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0
&& event.getRepeatCount() == 0;
+ // Specific device key handling
+ if (mDeviceKeyHandler != null) {
+ try {
+ // The device only should consume known keys.
+ if (mDeviceKeyHandler.handleKeyEvent(event)) {
+ return 0;
+ }
+ } catch (Exception e) {
+ Slog.w(TAG, "Could not dispatch event to device key handler", e);
+ }
+ }
+
// Handle special keys.
switch (keyCode) {
case KeyEvent.KEYCODE_BACK: {
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
+ // Eat all down & up keys when using volume wake.
+ // This disables volume control, music control, and "beep" on key up.
+ if (isWakeKey && mVolumeWakeScreen) {
+ setVolumeWakeTriggered(keyCode, true);
+ break;
+ } else if (getVolumeWakeTriggered(keyCode) && !down) {
+ result &= ~ACTION_PASS_TO_USER;
+ setVolumeWakeTriggered(keyCode, false);
+ break;
+ }
+
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
if (down) {
if (interactive && !mScreenshotChordVolumeDownKeyTriggered
MediaSessionLegacyHelper.getHelper(mContext)
.sendVolumeKeyEvent(event, true);
}
+
+ // Disable music and volume control when used as wake key
+ if ((result & ACTION_PASS_TO_USER) == 0 && !mVolumeWakeScreen) {
+ boolean mayChangeVolume = false;
+
+ if (isMusicActive()) {
+ if (mVolBtnMusicControls && (keyCode != KeyEvent.KEYCODE_VOLUME_MUTE)) {
+ // Detect long key presses.
+ if (down) {
+ mIsLongPress = false;
+ // TODO: Long press of MUTE could be mapped to KEYCODE_MEDIA_PLAY_PAUSE
+ int newKeyCode = event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP ?
+ KeyEvent.KEYCODE_MEDIA_NEXT : KeyEvent.KEYCODE_MEDIA_PREVIOUS;
+ scheduleLongPressKeyEvent(event, newKeyCode);
+ // Consume key down events of all presses.
+ break;
+ } else {
+ mHandler.removeMessages(MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK);
+ // Consume key up events of long presses only.
+ if (mIsLongPress) {
+ break;
+ }
+ // Change volume only on key up events of short presses.
+ mayChangeVolume = true;
+ }
+ } else {
+ // Long key press detection not applicable, change volume only
+ // on key down events
+ mayChangeVolume = down;
+ }
+ }
+
+ if (mayChangeVolume) {
+ if (mUseTvRouting) {
+ dispatchDirectAudioEvent(event);
+ } else {
+ // If we aren't passing to the user and no one else
+ // handled it send it to the session manager to figure
+ // out.
+
+ // Rewrite the event to use key-down as sendVolumeKeyEvent will
+ // only change the volume on key down.
+ KeyEvent newEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
+ MediaSessionLegacyHelper.getHelper(mContext)
+ .sendVolumeKeyEvent(newEvent, true);
+ }
+ }
+ break;
+ }
break;
}
+ case KeyEvent.KEYCODE_HOME:
+ if (down && !interactive && mHomeWakeScreen) {
+ isWakeKey = true;
+ }
+ break;
+
+ case KeyEvent.KEYCODE_FOCUS:
+ if (down && !interactive && mCameraSleepOnRelease) {
+ mIsFocusPressed = true;
+ } else if ((event.getAction() == KeyEvent.ACTION_UP)
+ && mScreenOnFully && mIsFocusPressed) {
+ // Check if screen is fully on before letting the device go to sleep
+ mPowerManager.goToSleep(SystemClock.uptimeMillis());
+ mIsFocusPressed = false;
+ }
+ break;
+
+ case KeyEvent.KEYCODE_CAMERA:
+ if (down && mIsFocusPressed) {
+ mIsFocusPressed = false;
+ }
+ if (down) {
+ mIsLongPress = false;
+ scheduleLongPressKeyEvent(event, KeyEvent.KEYCODE_CAMERA);
+ // Consume key down events of all presses.
+ break;
+ } else {
+ mHandler.removeMessages(MSG_CAMERA_LONG_PRESS);
+ // Consume key up events of long presses only.
+ if (mIsLongPress && mCameraLaunch) {
+ Intent intent;
+ if (keyguardActive) {
+ intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE);
+ } else {
+ intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
+ }
+ isWakeKey = true;
+ startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
+ }
+ }
+ break;
+
case KeyEvent.KEYCODE_ENDCALL: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
}
case KeyEvent.KEYCODE_POWER: {
+ if ((mTopFullscreenOpaqueWindowState.getAttrs().privateFlags
+ & WindowManager.LayoutParams.PRIVATE_FLAG_PREVENT_POWER_KEY) != 0
+ && mScreenOnFully) {
+ return result;
+ }
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
return result;
}
+ private void scheduleLongPressKeyEvent(KeyEvent origEvent, int keyCode) {
+ KeyEvent event = new KeyEvent(origEvent.getDownTime(), origEvent.getEventTime(),
+ origEvent.getAction(), keyCode, 0);
+ Message msg;
+ if (keyCode == KeyEvent.KEYCODE_CAMERA) {
+ msg = mHandler.obtainMessage(MSG_CAMERA_LONG_PRESS, event);
+ } else {
+ msg = mHandler.obtainMessage(MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK, event);
+ }
+ msg.setAsynchronous(true);
+ mHandler.sendMessageDelayed(msg, ViewConfiguration.getLongPressTimeout());
+ }
+
/**
* Returns true if the key can have global actions attached to it.
* We reserve all power management keys for the system since they require
}
/**
+ * Check if the given keyCode represents a key that is considered a wake key
+ * and is currently enabled by the user in Settings or for another reason.
+ */
+ private boolean isWakeKeyEnabled(int keyCode) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_UP:
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ // Volume keys are still wake keys if the device is docked.
+ return mVolumeWakeScreen || mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ case KeyEvent.KEYCODE_BACK:
+ return mBackWakeScreen;
+ case KeyEvent.KEYCODE_MENU:
+ return mMenuWakeScreen;
+ case KeyEvent.KEYCODE_ASSIST:
+ return mAssistWakeScreen;
+ case KeyEvent.KEYCODE_APP_SWITCH:
+ return mAppSwitchWakeScreen;
+ case KeyEvent.KEYCODE_CAMERA:
+ case KeyEvent.KEYCODE_FOCUS:
+ return mCameraWakeScreen;
+ }
+ return true;
+ }
+
+ /**
* When the screen is off we ignore some keys that might otherwise typically
* be considered wake keys. We filter them out here.
*
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE:
- return mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED;
+ return mVolumeWakeScreen || mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED;
- // ignore media and camera keys
+ // ignore media keys
case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
- case KeyEvent.KEYCODE_CAMERA:
return false;
+
+ case KeyEvent.KEYCODE_BACK:
+ return mBackWakeScreen;
+ case KeyEvent.KEYCODE_MENU:
+ return mMenuWakeScreen;
+ case KeyEvent.KEYCODE_ASSIST:
+ return mAssistWakeScreen;
+ case KeyEvent.KEYCODE_APP_SWITCH:
+ return mAppSwitchWakeScreen;
+ case KeyEvent.KEYCODE_CAMERA:
+ case KeyEvent.KEYCODE_FOCUS:
+ return mCameraWakeScreen;
}
return true;
}
IDreamManager dreamManager = getDreamManager();
try {
- if (dreamManager != null && dreamManager.isDreaming()) {
+ if (dreamManager != null && dreamManager.isDreaming() && !dreamManager.isDozing()) {
return true;
}
} catch (RemoteException e) {
// current user.
mSettingsObserver.onChange(false);
+ if (mGlobalActions != null) {
+ mGlobalActions.updatePowerMenuActions();
+ }
+
// force a re-application of focused window sysui visibility.
// the window may never have been shown for this user
// e.g. the keyguard when going through the new-user setup flow
}
}
+
+ BroadcastReceiver mWifiDisplayReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(ACTION_WIFI_DISPLAY_VIDEO)) {
+ int state = intent.getIntExtra("state", 0);
+ if(state == 1) {
+ mWifiDisplayConnected = true;
+ } else {
+ mWifiDisplayConnected = false;
+ }
+ mWifiDisplayCustomRotation =
+ intent.getIntExtra("wfd_UIBC_rot", -1);
+ updateRotation(true);
+ }
+ }
+ };
+
// Called on the PowerManager's Notifier thread.
@Override
public void startedGoingToSleep(int why) {
// enable 180 degree rotation while docked.
preferredRotation = mDeskDockEnablesAccelerometer
? sensorRotation : mDeskDockRotation;
- } else if (mHdmiPlugged && mDemoHdmiRotationLock) {
+ } else if ((mHdmiPlugged || mWifiDisplayConnected) && mDemoHdmiRotationLock) {
// Ignore sensor when plugged into HDMI when demo HDMI rotation lock enabled.
// Note that the dock orientation overrides the HDMI orientation.
preferredRotation = mDemoHdmiRotation;
+ } else if (mWifiDisplayConnected && (mWifiDisplayCustomRotation > -1)) {
+ // Ignore sensor when WFD is active and UIBC rotation is enabled
+ preferredRotation = mWifiDisplayCustomRotation;
} else if (mHdmiPlugged && mDockMode == Intent.EXTRA_DOCK_STATE_UNDOCKED
&& mUndockedHdmiRotation >= 0) {
// Ignore sensor when plugged into HDMI and an undocked orientation has
mAllowAllRotations = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0;
}
- if (sensorRotation != Surface.ROTATION_180
- || mAllowAllRotations == 1
- || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
- || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
+ boolean allowed = true;
+ if (orientation != ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR
+ && orientation != ActivityInfo.SCREEN_ORIENTATION_FULL_USER) {
+ allowed = RotationPolicy.isRotationAllowed(sensorRotation,
+ mUserRotationAngles, mAllowAllRotations != 0);
+ }
+ if (allowed) {
preferredRotation = sensorRotation;
} else {
preferredRotation = lastRotation;
mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
mKeyguardDelegate.onSystemReady();
+ mCMHardware = CMHardwareManager.getInstance(mContext);
+ // Ensure observe happens in systemReady() since we need
+ // CMHardwareService to be up and running
+ mSettingsObserver.observe();
+
readCameraLensCoverState();
updateUiMode();
boolean bindKeyguardNow;
}
private void applyLidSwitchState() {
+ mPowerManager.setKeyboardVisibility(isBuiltInKeyboardVisible());
+
if (mLidState == LID_CLOSED && mLidControlsSleep) {
mPowerManager.goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH,
// overridden by qemu.hw.mainkeys in the emulator.
@Override
public boolean hasNavigationBar() {
+ return mHasNavigationBar || mDevForceNavbar;
+ }
+
+ public boolean needsNavigationBar() {
return mHasNavigationBar;
}