1 /* 2 * Copyright (C) 2006 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 17 package com.android.internal.policy.impl; 18 19 import android.app.Activity; 20 import android.app.ActivityManagerNative; 21 import android.app.IActivityManager; 22 import android.app.IStatusBar; 23 import android.content.ActivityNotFoundException; 24 import android.content.BroadcastReceiver; 25 import android.content.ContentResolver; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.pm.ActivityInfo; 30 import android.content.pm.PackageManager; 31 import android.content.res.Configuration; 32 import android.content.res.Resources; 33 import android.database.ContentObserver; 34 import android.graphics.Rect; 35 import android.os.BatteryManager; 36 import android.os.Handler; 37 import android.os.IBinder; 38 import android.os.LocalPowerManager; 39 import android.os.PowerManager; 40 import android.os.RemoteException; 41 import android.os.ServiceManager; 42 import android.os.SystemClock; 43 import android.os.SystemProperties; 44 import android.os.Vibrator; 45 import android.provider.Settings; 46 47 import com.android.internal.policy.PolicyManager; 48 import com.android.internal.telephony.ITelephony; 49 import android.util.Config; 50 import android.util.EventLog; 51 import android.util.Log; 52 import android.view.Display; 53 import android.view.Gravity; 54 import android.view.HapticFeedbackConstants; 55 import android.view.IWindowManager; 56 import android.view.KeyEvent; 57 import android.view.MotionEvent; 58 import android.view.WindowOrientationListener; 59 import android.view.RawInputEvent; 60 import android.view.Surface; 61 import android.view.View; 62 import android.view.ViewConfiguration; 63 import android.view.Window; 64 import android.view.WindowManager; 65 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 66 import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; 67 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; 68 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 69 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; 70 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; 71 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 72 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; 73 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; 74 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 75 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 76 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; 77 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; 78 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; 79 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; 80 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 81 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD; 82 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; 83 import static android.view.WindowManager.LayoutParams.TYPE_PHONE; 84 import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; 85 import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR; 86 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 87 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; 88 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; 89 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; 90 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 91 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; 92 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; 93 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 94 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 95 import android.view.WindowManagerImpl; 96 import android.view.WindowManagerPolicy; 97 import android.view.WindowManagerPolicy.WindowState; 98 import android.view.animation.Animation; 99 import android.view.animation.AnimationUtils; 100 import android.media.IAudioService; 101 import android.media.AudioManager; 102 103 /** 104 * WindowManagerPolicy implementation for the Android phone UI. This 105 * introduces a new method suffix, Lp, for an internal lock of the 106 * PhoneWindowManager. This is used to protect some internal state, and 107 * can be acquired with either thw Lw and Li lock held, so has the restrictions 108 * of both of those when held. 109 */ 110 public class PhoneWindowManager implements WindowManagerPolicy { 111 static final String TAG = "WindowManager"; 112 static final boolean DEBUG = false; 113 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV; 114 static final boolean DEBUG_LAYOUT = false; 115 static final boolean SHOW_STARTING_ANIMATIONS = true; 116 static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; 117 118 // wallpaper is at the bottom, though the window manager may move it. 119 static final int WALLPAPER_LAYER = 2; 120 static final int APPLICATION_LAYER = 2; 121 static final int PHONE_LAYER = 3; 122 static final int SEARCH_BAR_LAYER = 4; 123 static final int STATUS_BAR_PANEL_LAYER = 5; 124 // toasts and the plugged-in battery thing 125 static final int TOAST_LAYER = 6; 126 static final int STATUS_BAR_LAYER = 7; 127 // SIM errors and unlock. Not sure if this really should be in a high layer. 128 static final int PRIORITY_PHONE_LAYER = 8; 129 // like the ANR / app crashed dialogs 130 static final int SYSTEM_ALERT_LAYER = 9; 131 // system-level error dialogs 132 static final int SYSTEM_ERROR_LAYER = 10; 133 // on-screen keyboards and other such input method user interfaces go here. 134 static final int INPUT_METHOD_LAYER = 11; 135 // on-screen keyboards and other such input method user interfaces go here. 136 static final int INPUT_METHOD_DIALOG_LAYER = 12; 137 // the keyguard; nothing on top of these can take focus, since they are 138 // responsible for power management when displayed. 139 static final int KEYGUARD_LAYER = 13; 140 static final int KEYGUARD_DIALOG_LAYER = 14; 141 // things in here CAN NOT take focus, but are shown on top of everything else. 142 static final int SYSTEM_OVERLAY_LAYER = 15; 143 144 static final int APPLICATION_MEDIA_SUBLAYER = -2; 145 static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; 146 static final int APPLICATION_PANEL_SUBLAYER = 1; 147 static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; 148 149 static final float SLIDE_TOUCH_EVENT_SIZE_LIMIT = 0.6f; 150 151 // Debugging: set this to have the system act like there is no hard keyboard. 152 static final boolean KEYBOARD_ALWAYS_HIDDEN = false; 153 154 static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; 155 static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; 156 static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; 157 158 final Object mLock = new Object(); 159 160 Context mContext; 161 IWindowManager mWindowManager; 162 LocalPowerManager mPowerManager; 163 Vibrator mVibrator; // Vibrator for giving feedback of orientation changes 164 165 // Vibrator pattern for haptic feedback of a long press. 166 long[] mLongPressVibePattern; 167 168 // Vibrator pattern for haptic feedback of virtual key press. 169 long[] mVirtualKeyVibePattern; 170 171 // Vibrator pattern for haptic feedback during boot when safe mode is disabled. 172 long[] mSafeModeDisabledVibePattern; 173 174 // Vibrator pattern for haptic feedback during boot when safe mode is enabled. 175 long[] mSafeModeEnabledVibePattern; 176 177 /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ 178 boolean mEnableShiftMenuBugReports = false; 179 180 boolean mSafeMode; 181 WindowState mStatusBar = null; 182 WindowState mKeyguard = null; 183 KeyguardViewMediator mKeyguardMediator; 184 GlobalActions mGlobalActions; 185 boolean mShouldTurnOffOnKeyUp; 186 RecentApplicationsDialog mRecentAppsDialog; 187 Handler mHandler; 188 189 final IntentFilter mBatteryStatusFilter = new IntentFilter(); 190 191 boolean mLidOpen; 192 int mPlugged; 193 boolean mRegisteredBatteryReceiver; 194 int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED; 195 int mLidOpenRotation; 196 int mCarDockRotation; 197 int mDeskDockRotation; 198 int mCarDockKeepsScreenOn; 199 int mDeskDockKeepsScreenOn; 200 boolean mCarDockEnablesAccelerometer; 201 boolean mDeskDockEnablesAccelerometer; 202 int mLidKeyboardAccessibility; 203 int mLidNavigationAccessibility; 204 boolean mScreenOn = false; 205 boolean mOrientationSensorEnabled = false; 206 int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 207 static final int DEFAULT_ACCELEROMETER_ROTATION = 0; 208 int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION; 209 boolean mHasSoftInput = false; 210 211 // The current size of the screen. 212 int mW, mH; 213 // During layout, the current screen borders with all outer decoration 214 // (status bar, input method dock) accounted for. 215 int mCurLeft, mCurTop, mCurRight, mCurBottom; 216 // During layout, the frame in which content should be displayed 217 // to the user, accounting for all screen decoration except for any 218 // space they deem as available for other content. This is usually 219 // the same as mCur*, but may be larger if the screen decor has supplied 220 // content insets. 221 int mContentLeft, mContentTop, mContentRight, mContentBottom; 222 // During layout, the current screen borders along with input method 223 // windows are placed. 224 int mDockLeft, mDockTop, mDockRight, mDockBottom; 225 // During layout, the layer at which the doc window is placed. 226 int mDockLayer; 227 228 static final Rect mTmpParentFrame = new Rect(); 229 static final Rect mTmpDisplayFrame = new Rect(); 230 static final Rect mTmpContentFrame = new Rect(); 231 static final Rect mTmpVisibleFrame = new Rect(); 232 233 WindowState mTopFullscreenOpaqueWindowState; 234 boolean mForceStatusBar; 235 boolean mHideLockScreen; 236 boolean mDismissKeyguard; 237 boolean mHomePressed; 238 Intent mHomeIntent; 239 Intent mCarDockIntent; 240 Intent mDeskDockIntent; 241 boolean mSearchKeyPressed; 242 boolean mConsumeSearchKeyUp; 243 244 static final int ENDCALL_HOME = 0x1; 245 static final int ENDCALL_SLEEPS = 0x2; 246 static final int DEFAULT_ENDCALL_BEHAVIOR = ENDCALL_SLEEPS; 247 int mEndcallBehavior; 248 249 int mLandscapeRotation = -1; 250 int mPortraitRotation = -1; 251 252 // Nothing to see here, move along... 253 int mFancyRotationAnimation; 254 255 ShortcutManager mShortcutManager; 256 PowerManager.WakeLock mBroadcastWakeLock; 257 PowerManager.WakeLock mDockWakeLock; 258 259 class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler)260 SettingsObserver(Handler handler) { 261 super(handler); 262 } 263 observe()264 void observe() { 265 ContentResolver resolver = mContext.getContentResolver(); 266 resolver.registerContentObserver(Settings.System.getUriFor( 267 Settings.System.END_BUTTON_BEHAVIOR), false, this); 268 resolver.registerContentObserver(Settings.System.getUriFor( 269 Settings.System.ACCELEROMETER_ROTATION), false, this); 270 resolver.registerContentObserver(Settings.Secure.getUriFor( 271 Settings.Secure.DEFAULT_INPUT_METHOD), false, this); 272 resolver.registerContentObserver(Settings.System.getUriFor( 273 "fancy_rotation_anim"), false, this); 274 update(); 275 } 276 onChange(boolean selfChange)277 @Override public void onChange(boolean selfChange) { 278 update(); 279 try { 280 mWindowManager.setRotation(USE_LAST_ROTATION, false, 281 mFancyRotationAnimation); 282 } catch (RemoteException e) { 283 // Ignore 284 } 285 } 286 update()287 public void update() { 288 ContentResolver resolver = mContext.getContentResolver(); 289 boolean updateRotation = false; 290 synchronized (mLock) { 291 mEndcallBehavior = Settings.System.getInt(resolver, 292 Settings.System.END_BUTTON_BEHAVIOR, DEFAULT_ENDCALL_BEHAVIOR); 293 mFancyRotationAnimation = Settings.System.getInt(resolver, 294 "fancy_rotation_anim", 0) != 0 ? 0x80 : 0; 295 int accelerometerDefault = Settings.System.getInt(resolver, 296 Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); 297 if (mAccelerometerDefault != accelerometerDefault) { 298 mAccelerometerDefault = accelerometerDefault; 299 updateOrientationListenerLp(); 300 } 301 String imId = Settings.Secure.getString(resolver, 302 Settings.Secure.DEFAULT_INPUT_METHOD); 303 boolean hasSoftInput = imId != null && imId.length() > 0; 304 if (mHasSoftInput != hasSoftInput) { 305 mHasSoftInput = hasSoftInput; 306 updateRotation = true; 307 } 308 } 309 if (updateRotation) { 310 updateRotation(0); 311 } 312 } 313 } 314 315 class MyOrientationListener extends WindowOrientationListener { MyOrientationListener(Context context)316 MyOrientationListener(Context context) { 317 super(context); 318 } 319 320 @Override onOrientationChanged(int rotation)321 public void onOrientationChanged(int rotation) { 322 // Send updates based on orientation value 323 if (localLOGV) Log.v(TAG, "onOrientationChanged, rotation changed to " +rotation); 324 try { 325 mWindowManager.setRotation(rotation, false, 326 mFancyRotationAnimation); 327 } catch (RemoteException e) { 328 // Ignore 329 330 } 331 } 332 } 333 MyOrientationListener mOrientationListener; 334 useSensorForOrientationLp(int appOrientation)335 boolean useSensorForOrientationLp(int appOrientation) { 336 // The app says use the sensor. 337 if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { 338 return true; 339 } 340 // The user preference says we can rotate, and the app is willing to rotate. 341 if (mAccelerometerDefault != 0 && 342 (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER 343 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) { 344 return true; 345 } 346 // We're in a dock that has a rotation affinity, an the app is willing to rotate. 347 if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) 348 || (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) { 349 // Note we override the nosensor flag here. 350 if (appOrientation == ActivityInfo.SCREEN_ORIENTATION_USER 351 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED 352 || appOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { 353 return true; 354 } 355 } 356 // Else, don't use the sensor. 357 return false; 358 } 359 360 /* 361 * We always let the sensor be switched on by default except when 362 * the user has explicitly disabled sensor based rotation or when the 363 * screen is switched off. 364 */ needSensorRunningLp()365 boolean needSensorRunningLp() { 366 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR) { 367 // If the application has explicitly requested to follow the 368 // orientation, then we need to turn the sensor or. 369 return true; 370 } 371 if ((mCarDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_CAR) || 372 (mDeskDockEnablesAccelerometer && mDockState == Intent.EXTRA_DOCK_STATE_DESK)) { 373 // enable accelerometer if we are docked in a dock that enables accelerometer 374 // orientation management, 375 return true; 376 } 377 if (mAccelerometerDefault == 0) { 378 // If the setting for using the sensor by default is enabled, then 379 // we will always leave it on. Note that the user could go to 380 // a window that forces an orientation that does not use the 381 // sensor and in theory we could turn it off... however, when next 382 // turning it on we won't have a good value for the current 383 // orientation for a little bit, which can cause orientation 384 // changes to lag, so we'd like to keep it always on. (It will 385 // still be turned off when the screen is off.) 386 return false; 387 } 388 return true; 389 } 390 391 /* 392 * Various use cases for invoking this function 393 * screen turning off, should always disable listeners if already enabled 394 * screen turned on and current app has sensor based orientation, enable listeners 395 * if not already enabled 396 * screen turned on and current app does not have sensor orientation, disable listeners if 397 * already enabled 398 * screen turning on and current app has sensor based orientation, enable listeners if needed 399 * screen turning on and current app has nosensor based orientation, do nothing 400 */ updateOrientationListenerLp()401 void updateOrientationListenerLp() { 402 if (!mOrientationListener.canDetectOrientation()) { 403 // If sensor is turned off or nonexistent for some reason 404 return; 405 } 406 //Could have been invoked due to screen turning on or off or 407 //change of the currently visible window's orientation 408 if (localLOGV) Log.v(TAG, "Screen status="+mScreenOn+ 409 ", current orientation="+mCurrentAppOrientation+ 410 ", SensorEnabled="+mOrientationSensorEnabled); 411 boolean disable = true; 412 if (mScreenOn) { 413 if (needSensorRunningLp()) { 414 disable = false; 415 //enable listener if not already enabled 416 if (!mOrientationSensorEnabled) { 417 mOrientationListener.enable(); 418 if(localLOGV) Log.v(TAG, "Enabling listeners"); 419 mOrientationSensorEnabled = true; 420 } 421 } 422 } 423 //check if sensors need to be disabled 424 if (disable && mOrientationSensorEnabled) { 425 mOrientationListener.disable(); 426 if(localLOGV) Log.v(TAG, "Disabling listeners"); 427 mOrientationSensorEnabled = false; 428 } 429 } 430 431 Runnable mPowerLongPress = new Runnable() { 432 public void run() { 433 mShouldTurnOffOnKeyUp = false; 434 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); 435 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); 436 showGlobalActionsDialog(); 437 } 438 }; 439 showGlobalActionsDialog()440 void showGlobalActionsDialog() { 441 if (mGlobalActions == null) { 442 mGlobalActions = new GlobalActions(mContext); 443 } 444 final boolean keyguardShowing = mKeyguardMediator.isShowing(); 445 mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); 446 if (keyguardShowing) { 447 // since it took two seconds of long press to bring this up, 448 // poke the wake lock so they have some time to see the dialog. 449 mKeyguardMediator.pokeWakelock(); 450 } 451 } 452 isDeviceProvisioned()453 boolean isDeviceProvisioned() { 454 return Settings.Secure.getInt( 455 mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; 456 } 457 458 /** 459 * When a home-key longpress expires, close other system windows and launch the recent apps 460 */ 461 Runnable mHomeLongPress = new Runnable() { 462 public void run() { 463 /* 464 * Eat the longpress so it won't dismiss the recent apps dialog when 465 * the user lets go of the home key 466 */ 467 mHomePressed = false; 468 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); 469 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); 470 showRecentAppsDialog(); 471 } 472 }; 473 474 /** 475 * Create (if necessary) and launch the recent apps dialog 476 */ showRecentAppsDialog()477 void showRecentAppsDialog() { 478 if (mRecentAppsDialog == null) { 479 mRecentAppsDialog = new RecentApplicationsDialog(mContext); 480 } 481 mRecentAppsDialog.show(); 482 } 483 484 /** {@inheritDoc} */ init(Context context, IWindowManager windowManager, LocalPowerManager powerManager)485 public void init(Context context, IWindowManager windowManager, 486 LocalPowerManager powerManager) { 487 mContext = context; 488 mWindowManager = windowManager; 489 mPowerManager = powerManager; 490 mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager); 491 mHandler = new Handler(); 492 mOrientationListener = new MyOrientationListener(mContext); 493 SettingsObserver settingsObserver = new SettingsObserver(mHandler); 494 settingsObserver.observe(); 495 mShortcutManager = new ShortcutManager(context, mHandler); 496 mShortcutManager.observe(); 497 mHomeIntent = new Intent(Intent.ACTION_MAIN, null); 498 mHomeIntent.addCategory(Intent.CATEGORY_HOME); 499 mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 500 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 501 mCarDockIntent = new Intent(Intent.ACTION_MAIN, null); 502 mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK); 503 mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 504 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 505 mDeskDockIntent = new Intent(Intent.ACTION_MAIN, null); 506 mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK); 507 mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 508 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 509 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 510 mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 511 "PhoneWindowManager.mBroadcastWakeLock"); 512 mDockWakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, 513 "PhoneWindowManager.mDockWakeLock"); 514 mDockWakeLock.setReferenceCounted(false); 515 mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); 516 mLidOpenRotation = readRotation( 517 com.android.internal.R.integer.config_lidOpenRotation); 518 mCarDockRotation = readRotation( 519 com.android.internal.R.integer.config_carDockRotation); 520 mDeskDockRotation = readRotation( 521 com.android.internal.R.integer.config_deskDockRotation); 522 mCarDockKeepsScreenOn = mContext.getResources().getInteger( 523 com.android.internal.R.integer.config_carDockKeepsScreenOn); 524 mDeskDockKeepsScreenOn = mContext.getResources().getInteger( 525 com.android.internal.R.integer.config_deskDockKeepsScreenOn); 526 mCarDockEnablesAccelerometer = mContext.getResources().getBoolean( 527 com.android.internal.R.bool.config_carDockEnablesAccelerometer); 528 mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean( 529 com.android.internal.R.bool.config_deskDockEnablesAccelerometer); 530 mLidKeyboardAccessibility = mContext.getResources().getInteger( 531 com.android.internal.R.integer.config_lidKeyboardAccessibility); 532 mLidNavigationAccessibility = mContext.getResources().getInteger( 533 com.android.internal.R.integer.config_lidNavigationAccessibility); 534 // register for battery events 535 mBatteryStatusFilter.addAction(Intent.ACTION_BATTERY_CHANGED); 536 mPlugged = 0; 537 updatePlugged(context.registerReceiver(null, mBatteryStatusFilter)); 538 // register for dock events 539 context.registerReceiver(mDockReceiver, new IntentFilter(Intent.ACTION_DOCK_EVENT)); 540 mVibrator = new Vibrator(); 541 mLongPressVibePattern = getLongIntArray(mContext.getResources(), 542 com.android.internal.R.array.config_longPressVibePattern); 543 mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(), 544 com.android.internal.R.array.config_virtualKeyVibePattern); 545 mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(), 546 com.android.internal.R.array.config_safeModeDisabledVibePattern); 547 mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), 548 com.android.internal.R.array.config_safeModeEnabledVibePattern); 549 } 550 updatePlugged(Intent powerIntent)551 void updatePlugged(Intent powerIntent) { 552 if (localLOGV) Log.v(TAG, "New battery status: " + powerIntent.getExtras()); 553 if (powerIntent != null) { 554 mPlugged = powerIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); 555 if (localLOGV) Log.v(TAG, "PLUGGED: " + mPlugged); 556 } 557 } 558 readRotation(int resID)559 private int readRotation(int resID) { 560 try { 561 int rotation = mContext.getResources().getInteger(resID); 562 switch (rotation) { 563 case 0: 564 return Surface.ROTATION_0; 565 case 90: 566 return Surface.ROTATION_90; 567 case 180: 568 return Surface.ROTATION_180; 569 case 270: 570 return Surface.ROTATION_270; 571 } 572 } catch (Resources.NotFoundException e) { 573 // fall through 574 } 575 return -1; 576 } 577 578 /** {@inheritDoc} */ checkAddPermission(WindowManager.LayoutParams attrs)579 public int checkAddPermission(WindowManager.LayoutParams attrs) { 580 int type = attrs.type; 581 582 if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW 583 || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { 584 return WindowManagerImpl.ADD_OKAY; 585 } 586 String permission = null; 587 switch (type) { 588 case TYPE_TOAST: 589 // XXX right now the app process has complete control over 590 // this... should introduce a token to let the system 591 // monitor/control what they are doing. 592 break; 593 case TYPE_INPUT_METHOD: 594 case TYPE_WALLPAPER: 595 // The window manager will check these. 596 break; 597 case TYPE_PHONE: 598 case TYPE_PRIORITY_PHONE: 599 case TYPE_SYSTEM_ALERT: 600 case TYPE_SYSTEM_ERROR: 601 case TYPE_SYSTEM_OVERLAY: 602 permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW; 603 break; 604 default: 605 permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; 606 } 607 if (permission != null) { 608 if (mContext.checkCallingOrSelfPermission(permission) 609 != PackageManager.PERMISSION_GRANTED) { 610 return WindowManagerImpl.ADD_PERMISSION_DENIED; 611 } 612 } 613 return WindowManagerImpl.ADD_OKAY; 614 } 615 adjustWindowParamsLw(WindowManager.LayoutParams attrs)616 public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) { 617 switch (attrs.type) { 618 case TYPE_SYSTEM_OVERLAY: 619 case TYPE_TOAST: 620 // These types of windows can't receive input events. 621 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 622 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 623 break; 624 } 625 } 626 readLidState()627 void readLidState() { 628 try { 629 int sw = mWindowManager.getSwitchState(RawInputEvent.SW_LID); 630 if (sw >= 0) { 631 mLidOpen = sw == 0; 632 } 633 } catch (RemoteException e) { 634 // Ignore 635 } 636 } 637 determineHiddenState(boolean lidOpen, int mode, int hiddenValue, int visibleValue)638 private int determineHiddenState(boolean lidOpen, 639 int mode, int hiddenValue, int visibleValue) { 640 switch (mode) { 641 case 1: 642 return lidOpen ? visibleValue : hiddenValue; 643 case 2: 644 return lidOpen ? hiddenValue : visibleValue; 645 } 646 return visibleValue; 647 } 648 649 /** {@inheritDoc} */ adjustConfigurationLw(Configuration config)650 public void adjustConfigurationLw(Configuration config) { 651 readLidState(); 652 final boolean lidOpen = !KEYBOARD_ALWAYS_HIDDEN && mLidOpen; 653 mPowerManager.setKeyboardVisibility(lidOpen); 654 config.hardKeyboardHidden = determineHiddenState(lidOpen, 655 mLidKeyboardAccessibility, Configuration.HARDKEYBOARDHIDDEN_YES, 656 Configuration.HARDKEYBOARDHIDDEN_NO); 657 config.navigationHidden = determineHiddenState(lidOpen, 658 mLidNavigationAccessibility, Configuration.NAVIGATIONHIDDEN_YES, 659 Configuration.NAVIGATIONHIDDEN_NO); 660 config.keyboardHidden = (config.hardKeyboardHidden 661 == Configuration.HARDKEYBOARDHIDDEN_NO || mHasSoftInput) 662 ? Configuration.KEYBOARDHIDDEN_NO 663 : Configuration.KEYBOARDHIDDEN_YES; 664 } 665 isCheekPressedAgainstScreen(MotionEvent ev)666 public boolean isCheekPressedAgainstScreen(MotionEvent ev) { 667 if(ev.getSize() > SLIDE_TOUCH_EVENT_SIZE_LIMIT) { 668 return true; 669 } 670 int size = ev.getHistorySize(); 671 for(int i = 0; i < size; i++) { 672 if(ev.getHistoricalSize(i) > SLIDE_TOUCH_EVENT_SIZE_LIMIT) { 673 return true; 674 } 675 } 676 return false; 677 } 678 679 /** {@inheritDoc} */ windowTypeToLayerLw(int type)680 public int windowTypeToLayerLw(int type) { 681 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { 682 return APPLICATION_LAYER; 683 } 684 switch (type) { 685 case TYPE_STATUS_BAR: 686 return STATUS_BAR_LAYER; 687 case TYPE_STATUS_BAR_PANEL: 688 return STATUS_BAR_PANEL_LAYER; 689 case TYPE_SEARCH_BAR: 690 return SEARCH_BAR_LAYER; 691 case TYPE_PHONE: 692 return PHONE_LAYER; 693 case TYPE_KEYGUARD: 694 return KEYGUARD_LAYER; 695 case TYPE_KEYGUARD_DIALOG: 696 return KEYGUARD_DIALOG_LAYER; 697 case TYPE_SYSTEM_ALERT: 698 return SYSTEM_ALERT_LAYER; 699 case TYPE_SYSTEM_ERROR: 700 return SYSTEM_ERROR_LAYER; 701 case TYPE_INPUT_METHOD: 702 return INPUT_METHOD_LAYER; 703 case TYPE_INPUT_METHOD_DIALOG: 704 return INPUT_METHOD_DIALOG_LAYER; 705 case TYPE_SYSTEM_OVERLAY: 706 return SYSTEM_OVERLAY_LAYER; 707 case TYPE_PRIORITY_PHONE: 708 return PRIORITY_PHONE_LAYER; 709 case TYPE_TOAST: 710 return TOAST_LAYER; 711 case TYPE_WALLPAPER: 712 return WALLPAPER_LAYER; 713 } 714 Log.e(TAG, "Unknown window type: " + type); 715 return APPLICATION_LAYER; 716 } 717 718 /** {@inheritDoc} */ subWindowTypeToLayerLw(int type)719 public int subWindowTypeToLayerLw(int type) { 720 switch (type) { 721 case TYPE_APPLICATION_PANEL: 722 case TYPE_APPLICATION_ATTACHED_DIALOG: 723 return APPLICATION_PANEL_SUBLAYER; 724 case TYPE_APPLICATION_MEDIA: 725 return APPLICATION_MEDIA_SUBLAYER; 726 case TYPE_APPLICATION_MEDIA_OVERLAY: 727 return APPLICATION_MEDIA_OVERLAY_SUBLAYER; 728 case TYPE_APPLICATION_SUB_PANEL: 729 return APPLICATION_SUB_PANEL_SUBLAYER; 730 } 731 Log.e(TAG, "Unknown sub-window type: " + type); 732 return 0; 733 } 734 getMaxWallpaperLayer()735 public int getMaxWallpaperLayer() { 736 return STATUS_BAR_LAYER; 737 } 738 doesForceHide(WindowState win, WindowManager.LayoutParams attrs)739 public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) { 740 return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD; 741 } 742 canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs)743 public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) { 744 return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR 745 && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER; 746 } 747 748 /** {@inheritDoc} */ addStartingWindow(IBinder appToken, String packageName, int theme, CharSequence nonLocalizedLabel, int labelRes, int icon)749 public View addStartingWindow(IBinder appToken, String packageName, 750 int theme, CharSequence nonLocalizedLabel, 751 int labelRes, int icon) { 752 if (!SHOW_STARTING_ANIMATIONS) { 753 return null; 754 } 755 if (packageName == null) { 756 return null; 757 } 758 759 Context context = mContext; 760 boolean setTheme = false; 761 //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel=" 762 // + nonLocalizedLabel + " theme=" + Integer.toHexString(theme)); 763 if (theme != 0 || labelRes != 0) { 764 try { 765 context = context.createPackageContext(packageName, 0); 766 if (theme != 0) { 767 context.setTheme(theme); 768 setTheme = true; 769 } 770 } catch (PackageManager.NameNotFoundException e) { 771 // Ignore 772 } 773 } 774 if (!setTheme) { 775 context.setTheme(com.android.internal.R.style.Theme); 776 } 777 778 Window win = PolicyManager.makeNewWindow(context); 779 if (win.getWindowStyle().getBoolean( 780 com.android.internal.R.styleable.Window_windowDisablePreview, false)) { 781 return null; 782 } 783 784 Resources r = context.getResources(); 785 win.setTitle(r.getText(labelRes, nonLocalizedLabel)); 786 787 win.setType( 788 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); 789 // Force the window flags: this is a fake window, so it is not really 790 // touchable or focusable by the user. We also add in the ALT_FOCUSABLE_IM 791 // flag because we do know that the next window will take input 792 // focus, so we want to get the IME window up on top of us right away. 793 win.setFlags( 794 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| 795 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| 796 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, 797 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| 798 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| 799 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 800 801 win.setLayout(WindowManager.LayoutParams.FILL_PARENT, 802 WindowManager.LayoutParams.FILL_PARENT); 803 804 final WindowManager.LayoutParams params = win.getAttributes(); 805 params.token = appToken; 806 params.packageName = packageName; 807 params.windowAnimations = win.getWindowStyle().getResourceId( 808 com.android.internal.R.styleable.Window_windowAnimationStyle, 0); 809 params.setTitle("Starting " + packageName); 810 811 try { 812 WindowManagerImpl wm = (WindowManagerImpl) 813 context.getSystemService(Context.WINDOW_SERVICE); 814 View view = win.getDecorView(); 815 816 if (win.isFloating()) { 817 // Whoops, there is no way to display an animation/preview 818 // of such a thing! After all that work... let's skip it. 819 // (Note that we must do this here because it is in 820 // getDecorView() where the theme is evaluated... maybe 821 // we should peek the floating attribute from the theme 822 // earlier.) 823 return null; 824 } 825 826 if (localLOGV) Log.v( 827 TAG, "Adding starting window for " + packageName 828 + " / " + appToken + ": " 829 + (view.getParent() != null ? view : null)); 830 831 wm.addView(view, params); 832 833 // Only return the view if it was successfully added to the 834 // window manager... which we can tell by it having a parent. 835 return view.getParent() != null ? view : null; 836 } catch (WindowManagerImpl.BadTokenException e) { 837 // ignore 838 Log.w(TAG, appToken + " already running, starting window not displayed"); 839 } 840 841 return null; 842 } 843 844 /** {@inheritDoc} */ removeStartingWindow(IBinder appToken, View window)845 public void removeStartingWindow(IBinder appToken, View window) { 846 // RuntimeException e = new RuntimeException(); 847 // Log.i(TAG, "remove " + appToken + " " + window, e); 848 849 if (localLOGV) Log.v( 850 TAG, "Removing starting window for " + appToken + ": " + window); 851 852 if (window != null) { 853 WindowManagerImpl wm = (WindowManagerImpl) mContext.getSystemService(Context.WINDOW_SERVICE); 854 wm.removeView(window); 855 } 856 } 857 858 /** 859 * Preflight adding a window to the system. 860 * 861 * Currently enforces that three window types are singletons: 862 * <ul> 863 * <li>STATUS_BAR_TYPE</li> 864 * <li>KEYGUARD_TYPE</li> 865 * </ul> 866 * 867 * @param win The window to be added 868 * @param attrs Information about the window to be added 869 * 870 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON 871 */ prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs)872 public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) { 873 switch (attrs.type) { 874 case TYPE_STATUS_BAR: 875 if (mStatusBar != null) { 876 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; 877 } 878 mStatusBar = win; 879 break; 880 case TYPE_KEYGUARD: 881 if (mKeyguard != null) { 882 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; 883 } 884 mKeyguard = win; 885 break; 886 } 887 return WindowManagerImpl.ADD_OKAY; 888 } 889 890 /** {@inheritDoc} */ removeWindowLw(WindowState win)891 public void removeWindowLw(WindowState win) { 892 if (mStatusBar == win) { 893 mStatusBar = null; 894 } 895 else if (mKeyguard == win) { 896 mKeyguard = null; 897 } 898 } 899 900 static final boolean PRINT_ANIM = false; 901 902 /** {@inheritDoc} */ selectAnimationLw(WindowState win, int transit)903 public int selectAnimationLw(WindowState win, int transit) { 904 if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win 905 + ": transit=" + transit); 906 if (transit == TRANSIT_PREVIEW_DONE) { 907 if (win.hasAppShownWindows()) { 908 if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT"); 909 return com.android.internal.R.anim.app_starting_exit; 910 } 911 } 912 913 return 0; 914 } 915 createForceHideEnterAnimation()916 public Animation createForceHideEnterAnimation() { 917 return AnimationUtils.loadAnimation(mContext, 918 com.android.internal.R.anim.lock_screen_behind_enter); 919 } 920 getPhoneInterface()921 static ITelephony getPhoneInterface() { 922 return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE)); 923 } 924 getAudioInterface()925 static IAudioService getAudioInterface() { 926 return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE)); 927 } 928 keyguardOn()929 boolean keyguardOn() { 930 return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode(); 931 } 932 933 private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = { 934 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, 935 WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, 936 }; 937 938 /** {@inheritDoc} */ interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, int repeatCount, int flags)939 public boolean interceptKeyTi(WindowState win, int code, int metaKeys, boolean down, 940 int repeatCount, int flags) { 941 boolean keyguardOn = keyguardOn(); 942 943 if (false) { 944 Log.d(TAG, "interceptKeyTi code=" + code + " down=" + down + " repeatCount=" 945 + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed); 946 } 947 948 // Clear a pending HOME longpress if the user releases Home 949 // TODO: This could probably be inside the next bit of logic, but that code 950 // turned out to be a bit fragile so I'm doing it here explicitly, for now. 951 if ((code == KeyEvent.KEYCODE_HOME) && !down) { 952 mHandler.removeCallbacks(mHomeLongPress); 953 } 954 955 // If the HOME button is currently being held, then we do special 956 // chording with it. 957 if (mHomePressed) { 958 959 // If we have released the home key, and didn't do anything else 960 // while it was pressed, then it is time to go home! 961 if (code == KeyEvent.KEYCODE_HOME) { 962 if (!down) { 963 mHomePressed = false; 964 965 if ((flags&KeyEvent.FLAG_CANCELED) == 0) { 966 // If an incoming call is ringing, HOME is totally disabled. 967 // (The user is already on the InCallScreen at this point, 968 // and his ONLY options are to answer or reject the call.) 969 boolean incomingRinging = false; 970 try { 971 ITelephony phoneServ = getPhoneInterface(); 972 if (phoneServ != null) { 973 incomingRinging = phoneServ.isRinging(); 974 } else { 975 Log.w(TAG, "Unable to find ITelephony interface"); 976 } 977 } catch (RemoteException ex) { 978 Log.w(TAG, "RemoteException from getPhoneInterface()", ex); 979 } 980 981 if (incomingRinging) { 982 Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); 983 } else { 984 launchHomeFromHotKey(); 985 } 986 } else { 987 Log.i(TAG, "Ignoring HOME; event canceled."); 988 } 989 } 990 } 991 992 return true; 993 } 994 995 // First we always handle the home key here, so applications 996 // can never break it, although if keyguard is on, we do let 997 // it handle it, because that gives us the correct 5 second 998 // timeout. 999 if (code == KeyEvent.KEYCODE_HOME) { 1000 1001 // If a system window has focus, then it doesn't make sense 1002 // right now to interact with applications. 1003 WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null; 1004 if (attrs != null) { 1005 final int type = attrs.type; 1006 if (type == WindowManager.LayoutParams.TYPE_KEYGUARD 1007 || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) { 1008 // the "app" is keyguard, so give it the key 1009 return false; 1010 } 1011 final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length; 1012 for (int i=0; i<typeCount; i++) { 1013 if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) { 1014 // don't do anything, but also don't pass it to the app 1015 return true; 1016 } 1017 } 1018 } 1019 1020 if (down && repeatCount == 0) { 1021 if (!keyguardOn) { 1022 mHandler.postDelayed(mHomeLongPress, ViewConfiguration.getGlobalActionKeyTimeout()); 1023 } 1024 mHomePressed = true; 1025 } 1026 return true; 1027 } else if (code == KeyEvent.KEYCODE_MENU) { 1028 // Hijack modified menu keys for debugging features 1029 final int chordBug = KeyEvent.META_SHIFT_ON; 1030 1031 if (down && repeatCount == 0) { 1032 if (mEnableShiftMenuBugReports && (metaKeys & chordBug) == chordBug) { 1033 Intent intent = new Intent(Intent.ACTION_BUG_REPORT); 1034 mContext.sendOrderedBroadcast(intent, null); 1035 return true; 1036 } else if (SHOW_PROCESSES_ON_ALT_MENU && 1037 (metaKeys & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) { 1038 Intent service = new Intent(); 1039 service.setClassName(mContext, "com.android.server.LoadAverageService"); 1040 ContentResolver res = mContext.getContentResolver(); 1041 boolean shown = Settings.System.getInt( 1042 res, Settings.System.SHOW_PROCESSES, 0) != 0; 1043 if (!shown) { 1044 mContext.startService(service); 1045 } else { 1046 mContext.stopService(service); 1047 } 1048 Settings.System.putInt( 1049 res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1); 1050 return true; 1051 } 1052 } 1053 } else if (code == KeyEvent.KEYCODE_NOTIFICATION) { 1054 if (down) { 1055 // this key doesn't exist on current hardware, but if a device 1056 // didn't have a touchscreen, it would want one of these to open 1057 // the status bar. 1058 IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar")); 1059 if (sbs != null) { 1060 try { 1061 sbs.toggle(); 1062 } catch (RemoteException e) { 1063 // we're screwed anyway, since it's in this process 1064 throw new RuntimeException(e); 1065 } 1066 } 1067 } 1068 return true; 1069 } else if (code == KeyEvent.KEYCODE_SEARCH) { 1070 if (down) { 1071 if (repeatCount == 0) { 1072 mSearchKeyPressed = true; 1073 } 1074 } else { 1075 mSearchKeyPressed = false; 1076 1077 if (mConsumeSearchKeyUp) { 1078 // Consume the up-event 1079 mConsumeSearchKeyUp = false; 1080 return true; 1081 } 1082 } 1083 } 1084 1085 // Shortcuts are invoked through Search+key, so intercept those here 1086 if (mSearchKeyPressed) { 1087 if (down && repeatCount == 0 && !keyguardOn) { 1088 Intent shortcutIntent = mShortcutManager.getIntent(code, metaKeys); 1089 if (shortcutIntent != null) { 1090 shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1091 mContext.startActivity(shortcutIntent); 1092 1093 /* 1094 * We launched an app, so the up-event of the search key 1095 * should be consumed 1096 */ 1097 mConsumeSearchKeyUp = true; 1098 return true; 1099 } 1100 } 1101 } 1102 1103 return false; 1104 } 1105 1106 /** 1107 * A home key -> launch home action was detected. Take the appropriate action 1108 * given the situation with the keyguard. 1109 */ launchHomeFromHotKey()1110 void launchHomeFromHotKey() { 1111 if (!mHideLockScreen && mKeyguardMediator.isShowing()) { 1112 // don't launch home if keyguard showing 1113 } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) { 1114 // when in keyguard restricted mode, must first verify unlock 1115 // before launching home 1116 mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() { 1117 public void onKeyguardExitResult(boolean success) { 1118 if (success) { 1119 try { 1120 ActivityManagerNative.getDefault().stopAppSwitches(); 1121 } catch (RemoteException e) { 1122 } 1123 sendCloseSystemWindows(); 1124 startDockOrHome(); 1125 } 1126 } 1127 }); 1128 } else { 1129 // no keyguard stuff to worry about, just launch home! 1130 try { 1131 ActivityManagerNative.getDefault().stopAppSwitches(); 1132 } catch (RemoteException e) { 1133 } 1134 sendCloseSystemWindows(); 1135 startDockOrHome(); 1136 } 1137 } 1138 getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset)1139 public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) { 1140 final int fl = attrs.flags; 1141 1142 if ((fl & 1143 (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) 1144 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { 1145 contentInset.set(mCurLeft, mCurTop, mW - mCurRight, mH - mCurBottom); 1146 } else { 1147 contentInset.setEmpty(); 1148 } 1149 } 1150 1151 /** {@inheritDoc} */ beginLayoutLw(int displayWidth, int displayHeight)1152 public void beginLayoutLw(int displayWidth, int displayHeight) { 1153 mW = displayWidth; 1154 mH = displayHeight; 1155 mDockLeft = mContentLeft = mCurLeft = 0; 1156 mDockTop = mContentTop = mCurTop = 0; 1157 mDockRight = mContentRight = mCurRight = displayWidth; 1158 mDockBottom = mContentBottom = mCurBottom = displayHeight; 1159 mDockLayer = 0x10000000; 1160 1161 mTopFullscreenOpaqueWindowState = null; 1162 mForceStatusBar = false; 1163 mHideLockScreen = false; 1164 mDismissKeyguard = false; 1165 1166 // decide where the status bar goes ahead of time 1167 if (mStatusBar != null) { 1168 final Rect pf = mTmpParentFrame; 1169 final Rect df = mTmpDisplayFrame; 1170 final Rect vf = mTmpVisibleFrame; 1171 pf.left = df.left = vf.left = 0; 1172 pf.top = df.top = vf.top = 0; 1173 pf.right = df.right = vf.right = displayWidth; 1174 pf.bottom = df.bottom = vf.bottom = displayHeight; 1175 1176 mStatusBar.computeFrameLw(pf, df, vf, vf); 1177 if (mStatusBar.isVisibleLw()) { 1178 // If the status bar is hidden, we don't want to cause 1179 // windows behind it to scroll. 1180 mDockTop = mContentTop = mCurTop = mStatusBar.getFrameLw().bottom; 1181 if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: mDockBottom=" 1182 + mDockBottom + " mContentBottom=" 1183 + mContentBottom + " mCurBottom=" + mCurBottom); 1184 } 1185 } 1186 } 1187 setAttachedWindowFrames(WindowState win, int fl, int sim, WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf)1188 void setAttachedWindowFrames(WindowState win, int fl, int sim, 1189 WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) { 1190 if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) { 1191 // Here's a special case: if this attached window is a panel that is 1192 // above the dock window, and the window it is attached to is below 1193 // the dock window, then the frames we computed for the window it is 1194 // attached to can not be used because the dock is effectively part 1195 // of the underlying window and the attached window is floating on top 1196 // of the whole thing. So, we ignore the attached window and explicitly 1197 // compute the frames that would be appropriate without the dock. 1198 df.left = cf.left = vf.left = mDockLeft; 1199 df.top = cf.top = vf.top = mDockTop; 1200 df.right = cf.right = vf.right = mDockRight; 1201 df.bottom = cf.bottom = vf.bottom = mDockBottom; 1202 } else { 1203 // The effective display frame of the attached window depends on 1204 // whether it is taking care of insetting its content. If not, 1205 // we need to use the parent's content frame so that the entire 1206 // window is positioned within that content. Otherwise we can use 1207 // the display frame and let the attached window take care of 1208 // positioning its content appropriately. 1209 if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { 1210 cf.set(attached.getDisplayFrameLw()); 1211 } else { 1212 // If the window is resizing, then we want to base the content 1213 // frame on our attached content frame to resize... however, 1214 // things can be tricky if the attached window is NOT in resize 1215 // mode, in which case its content frame will be larger. 1216 // Ungh. So to deal with that, make sure the content frame 1217 // we end up using is not covering the IM dock. 1218 cf.set(attached.getContentFrameLw()); 1219 if (attached.getSurfaceLayer() < mDockLayer) { 1220 if (cf.left < mContentLeft) cf.left = mContentLeft; 1221 if (cf.top < mContentTop) cf.top = mContentTop; 1222 if (cf.right > mContentRight) cf.right = mContentRight; 1223 if (cf.bottom > mContentBottom) cf.bottom = mContentBottom; 1224 } 1225 } 1226 df.set(insetDecors ? attached.getDisplayFrameLw() : cf); 1227 vf.set(attached.getVisibleFrameLw()); 1228 } 1229 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached 1230 // window should be positioned relative to its parent or the entire 1231 // screen. 1232 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 1233 ? attached.getFrameLw() : df); 1234 } 1235 1236 /** {@inheritDoc} */ layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached)1237 public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, 1238 WindowState attached) { 1239 // we've already done the status bar 1240 if (win == mStatusBar) { 1241 return; 1242 } 1243 1244 if (false) { 1245 if ("com.google.android.youtube".equals(attrs.packageName) 1246 && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { 1247 Log.i(TAG, "GOTCHA!"); 1248 } 1249 } 1250 1251 final int fl = attrs.flags; 1252 final int sim = attrs.softInputMode; 1253 1254 final Rect pf = mTmpParentFrame; 1255 final Rect df = mTmpDisplayFrame; 1256 final Rect cf = mTmpContentFrame; 1257 final Rect vf = mTmpVisibleFrame; 1258 1259 if (attrs.type == TYPE_INPUT_METHOD) { 1260 pf.left = df.left = cf.left = vf.left = mDockLeft; 1261 pf.top = df.top = cf.top = vf.top = mDockTop; 1262 pf.right = df.right = cf.right = vf.right = mDockRight; 1263 pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom; 1264 // IM dock windows always go to the bottom of the screen. 1265 attrs.gravity = Gravity.BOTTOM; 1266 mDockLayer = win.getSurfaceLayer(); 1267 } else { 1268 if ((fl & 1269 (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) 1270 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { 1271 // This is the case for a normal activity window: we want it 1272 // to cover all of the screen space, and it can take care of 1273 // moving its contents to account for screen decorations that 1274 // intrude into that space. 1275 if (attached != null) { 1276 // If this window is attached to another, our display 1277 // frame is the same as the one we are attached to. 1278 setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf); 1279 } else { 1280 pf.left = df.left = 0; 1281 pf.top = df.top = 0; 1282 pf.right = df.right = mW; 1283 pf.bottom = df.bottom = mH; 1284 if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { 1285 cf.left = mDockLeft; 1286 cf.top = mDockTop; 1287 cf.right = mDockRight; 1288 cf.bottom = mDockBottom; 1289 } else { 1290 cf.left = mContentLeft; 1291 cf.top = mContentTop; 1292 cf.right = mContentRight; 1293 cf.bottom = mContentBottom; 1294 } 1295 vf.left = mCurLeft; 1296 vf.top = mCurTop; 1297 vf.right = mCurRight; 1298 vf.bottom = mCurBottom; 1299 } 1300 } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) { 1301 // A window that has requested to fill the entire screen just 1302 // gets everything, period. 1303 pf.left = df.left = cf.left = 0; 1304 pf.top = df.top = cf.top = 0; 1305 pf.right = df.right = cf.right = mW; 1306 pf.bottom = df.bottom = cf.bottom = mH; 1307 vf.left = mCurLeft; 1308 vf.top = mCurTop; 1309 vf.right = mCurRight; 1310 vf.bottom = mCurBottom; 1311 } else if (attached != null) { 1312 // A child window should be placed inside of the same visible 1313 // frame that its parent had. 1314 setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf); 1315 } else { 1316 // Otherwise, a normal window must be placed inside the content 1317 // of all screen decorations. 1318 pf.left = mContentLeft; 1319 pf.top = mContentTop; 1320 pf.right = mContentRight; 1321 pf.bottom = mContentBottom; 1322 if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) { 1323 df.left = cf.left = mDockLeft; 1324 df.top = cf.top = mDockTop; 1325 df.right = cf.right = mDockRight; 1326 df.bottom = cf.bottom = mDockBottom; 1327 } else { 1328 df.left = cf.left = mContentLeft; 1329 df.top = cf.top = mContentTop; 1330 df.right = cf.right = mContentRight; 1331 df.bottom = cf.bottom = mContentBottom; 1332 } 1333 vf.left = mCurLeft; 1334 vf.top = mCurTop; 1335 vf.right = mCurRight; 1336 vf.bottom = mCurBottom; 1337 } 1338 } 1339 1340 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) { 1341 df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000; 1342 df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; 1343 } 1344 1345 if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle() 1346 + ": sim=#" + Integer.toHexString(sim) 1347 + " pf=" + pf.toShortString() + " df=" + df.toShortString() 1348 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); 1349 1350 if (false) { 1351 if ("com.google.android.youtube".equals(attrs.packageName) 1352 && attrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) { 1353 if (true || localLOGV) Log.v(TAG, "Computing frame of " + win + 1354 ": sim=#" + Integer.toHexString(sim) 1355 + " pf=" + pf.toShortString() + " df=" + df.toShortString() 1356 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); 1357 } 1358 } 1359 1360 win.computeFrameLw(pf, df, cf, vf); 1361 1362 if (mTopFullscreenOpaqueWindowState == null && 1363 win.isVisibleOrBehindKeyguardLw()) { 1364 if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { 1365 mForceStatusBar = true; 1366 } 1367 if (attrs.type >= FIRST_APPLICATION_WINDOW 1368 && attrs.type <= LAST_APPLICATION_WINDOW 1369 && win.fillsScreenLw(mW, mH, false, false)) { 1370 if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); 1371 mTopFullscreenOpaqueWindowState = win; 1372 if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { 1373 if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win); 1374 mHideLockScreen = true; 1375 } 1376 } 1377 if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) { 1378 if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win); 1379 mDismissKeyguard = true; 1380 } 1381 } 1382 1383 // Dock windows carve out the bottom of the screen, so normal windows 1384 // can't appear underneath them. 1385 if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) { 1386 int top = win.getContentFrameLw().top; 1387 top += win.getGivenContentInsetsLw().top; 1388 if (mContentBottom > top) { 1389 mContentBottom = top; 1390 } 1391 top = win.getVisibleFrameLw().top; 1392 top += win.getGivenVisibleInsetsLw().top; 1393 if (mCurBottom > top) { 1394 mCurBottom = top; 1395 } 1396 if (DEBUG_LAYOUT) Log.v(TAG, "Input method: mDockBottom=" 1397 + mDockBottom + " mContentBottom=" 1398 + mContentBottom + " mCurBottom=" + mCurBottom); 1399 } 1400 } 1401 1402 /** {@inheritDoc} */ finishLayoutLw()1403 public int finishLayoutLw() { 1404 int changes = 0; 1405 boolean hiding = false; 1406 if (mStatusBar != null) { 1407 if (localLOGV) Log.i(TAG, "force=" + mForceStatusBar 1408 + " top=" + mTopFullscreenOpaqueWindowState); 1409 if (mForceStatusBar) { 1410 if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); 1411 if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; 1412 } else if (mTopFullscreenOpaqueWindowState != null) { 1413 //Log.i(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() 1414 // + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw()); 1415 //Log.i(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()); 1416 WindowManager.LayoutParams lp = 1417 mTopFullscreenOpaqueWindowState.getAttrs(); 1418 boolean hideStatusBar = 1419 (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; 1420 if (hideStatusBar) { 1421 if (DEBUG_LAYOUT) Log.v(TAG, "Hiding status bar"); 1422 if (mStatusBar.hideLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; 1423 hiding = true; 1424 } else { 1425 if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar"); 1426 if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; 1427 } 1428 } 1429 } 1430 // Hide the key guard if a visible window explicitly specifies that it wants to be displayed 1431 // when the screen is locked 1432 if (mKeyguard != null) { 1433 if (localLOGV) Log.v(TAG, "finishLayoutLw::mHideKeyguard="+mHideLockScreen); 1434 if (mDismissKeyguard && !mKeyguardMediator.isSecure()) { 1435 if (mKeyguard.hideLw(false)) { 1436 changes |= FINISH_LAYOUT_REDO_LAYOUT 1437 | FINISH_LAYOUT_REDO_CONFIG 1438 | FINISH_LAYOUT_REDO_WALLPAPER; 1439 } 1440 if (mKeyguardMediator.isShowing()) { 1441 mHandler.post(new Runnable() { 1442 public void run() { 1443 mKeyguardMediator.keyguardDone(false, false); 1444 } 1445 }); 1446 } 1447 } else if (mHideLockScreen) { 1448 if (mKeyguard.hideLw(false)) { 1449 mKeyguardMediator.setHidden(true); 1450 changes |= FINISH_LAYOUT_REDO_LAYOUT 1451 | FINISH_LAYOUT_REDO_CONFIG 1452 | FINISH_LAYOUT_REDO_WALLPAPER; 1453 } 1454 } else { 1455 if (mKeyguard.showLw(false)) { 1456 mKeyguardMediator.setHidden(false); 1457 changes |= FINISH_LAYOUT_REDO_LAYOUT 1458 | FINISH_LAYOUT_REDO_CONFIG 1459 | FINISH_LAYOUT_REDO_WALLPAPER; 1460 } 1461 } 1462 } 1463 1464 if (changes != 0 && hiding) { 1465 IStatusBar sbs = IStatusBar.Stub.asInterface(ServiceManager.getService("statusbar")); 1466 if (sbs != null) { 1467 try { 1468 // Make sure the window shade is hidden. 1469 sbs.deactivate(); 1470 } catch (RemoteException e) { 1471 } 1472 } 1473 } 1474 1475 return changes; 1476 } 1477 1478 /** {@inheritDoc} */ beginAnimationLw(int displayWidth, int displayHeight)1479 public void beginAnimationLw(int displayWidth, int displayHeight) { 1480 } 1481 1482 /** {@inheritDoc} */ animatingWindowLw(WindowState win, WindowManager.LayoutParams attrs)1483 public void animatingWindowLw(WindowState win, 1484 WindowManager.LayoutParams attrs) { 1485 } 1486 1487 /** {@inheritDoc} */ finishAnimationLw()1488 public boolean finishAnimationLw() { 1489 return false; 1490 } 1491 1492 /** {@inheritDoc} */ preprocessInputEventTq(RawInputEvent event)1493 public boolean preprocessInputEventTq(RawInputEvent event) { 1494 switch (event.type) { 1495 case RawInputEvent.EV_SW: 1496 if (event.keycode == RawInputEvent.SW_LID) { 1497 // lid changed state 1498 mLidOpen = event.value == 0; 1499 boolean awakeNow = mKeyguardMediator.doLidChangeTq(mLidOpen); 1500 updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); 1501 if (awakeNow) { 1502 // If the lid opening and we don't have to keep the 1503 // keyguard up, then we can turn on the screen 1504 // immediately. 1505 mKeyguardMediator.pokeWakelock(); 1506 } else if (keyguardIsShowingTq()) { 1507 if (mLidOpen) { 1508 // If we are opening the lid and not hiding the 1509 // keyguard, then we need to have it turn on the 1510 // screen once it is shown. 1511 mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq( 1512 KeyEvent.KEYCODE_POWER); 1513 } 1514 } else { 1515 // Light up the keyboard if we are sliding up. 1516 if (mLidOpen) { 1517 mPowerManager.userActivity(SystemClock.uptimeMillis(), false, 1518 LocalPowerManager.BUTTON_EVENT); 1519 } else { 1520 mPowerManager.userActivity(SystemClock.uptimeMillis(), false, 1521 LocalPowerManager.OTHER_EVENT); 1522 } 1523 } 1524 } 1525 } 1526 return false; 1527 } 1528 1529 1530 /** {@inheritDoc} */ isAppSwitchKeyTqTiLwLi(int keycode)1531 public boolean isAppSwitchKeyTqTiLwLi(int keycode) { 1532 return keycode == KeyEvent.KEYCODE_HOME 1533 || keycode == KeyEvent.KEYCODE_ENDCALL; 1534 } 1535 1536 /** {@inheritDoc} */ isMovementKeyTi(int keycode)1537 public boolean isMovementKeyTi(int keycode) { 1538 switch (keycode) { 1539 case KeyEvent.KEYCODE_DPAD_UP: 1540 case KeyEvent.KEYCODE_DPAD_DOWN: 1541 case KeyEvent.KEYCODE_DPAD_LEFT: 1542 case KeyEvent.KEYCODE_DPAD_RIGHT: 1543 return true; 1544 } 1545 return false; 1546 } 1547 1548 1549 /** 1550 * @return Whether a telephone call is in progress right now. 1551 */ isInCall()1552 boolean isInCall() { 1553 final ITelephony phone = getPhoneInterface(); 1554 if (phone == null) { 1555 Log.w(TAG, "couldn't get ITelephony reference"); 1556 return false; 1557 } 1558 try { 1559 return phone.isOffhook(); 1560 } catch (RemoteException e) { 1561 Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e); 1562 return false; 1563 } 1564 } 1565 1566 /** 1567 * @return Whether music is being played right now. 1568 */ isMusicActive()1569 boolean isMusicActive() { 1570 final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); 1571 if (am == null) { 1572 Log.w(TAG, "isMusicActive: couldn't get AudioManager reference"); 1573 return false; 1574 } 1575 return am.isMusicActive(); 1576 } 1577 1578 /** 1579 * Tell the audio service to adjust the volume appropriate to the event. 1580 * @param keycode 1581 */ handleVolumeKey(int stream, int keycode)1582 void handleVolumeKey(int stream, int keycode) { 1583 final IAudioService audio = getAudioInterface(); 1584 if (audio == null) { 1585 Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference"); 1586 return; 1587 } 1588 try { 1589 // since audio is playing, we shouldn't have to hold a wake lock 1590 // during the call, but we do it as a precaution for the rare possibility 1591 // that the music stops right before we call this 1592 mBroadcastWakeLock.acquire(); 1593 audio.adjustStreamVolume(stream, 1594 keycode == KeyEvent.KEYCODE_VOLUME_UP 1595 ? AudioManager.ADJUST_RAISE 1596 : AudioManager.ADJUST_LOWER, 1597 0); 1598 } catch (RemoteException e) { 1599 Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e); 1600 } finally { 1601 mBroadcastWakeLock.release(); 1602 } 1603 } 1604 isMediaKey(int code)1605 static boolean isMediaKey(int code) { 1606 if (code == KeyEvent.KEYCODE_HEADSETHOOK || 1607 code == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || 1608 code == KeyEvent.KEYCODE_MEDIA_STOP || 1609 code == KeyEvent.KEYCODE_MEDIA_NEXT || 1610 code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || 1611 code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || 1612 code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) { 1613 return true; 1614 } 1615 return false; 1616 } 1617 1618 /** {@inheritDoc} */ interceptKeyTq(RawInputEvent event, boolean screenIsOn)1619 public int interceptKeyTq(RawInputEvent event, boolean screenIsOn) { 1620 int result = ACTION_PASS_TO_USER; 1621 final boolean isWakeKey = isWakeKeyTq(event); 1622 final boolean keyguardShowing = keyguardIsShowingTq(); 1623 1624 if (false) { 1625 Log.d(TAG, "interceptKeyTq event=" + event + " keycode=" + event.keycode 1626 + " screenIsOn=" + screenIsOn + " keyguardShowing=" + keyguardShowing); 1627 } 1628 1629 if (keyguardShowing) { 1630 if (screenIsOn) { 1631 // when the screen is on, always give the event to the keyguard 1632 result |= ACTION_PASS_TO_USER; 1633 } else { 1634 // otherwise, don't pass it to the user 1635 result &= ~ACTION_PASS_TO_USER; 1636 1637 final boolean isKeyDown = 1638 (event.type == RawInputEvent.EV_KEY) && (event.value != 0); 1639 if (isWakeKey && isKeyDown) { 1640 1641 // tell the mediator about a wake key, it may decide to 1642 // turn on the screen depending on whether the key is 1643 // appropriate. 1644 if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(event.keycode) 1645 && (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN 1646 || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) { 1647 if (isInCall()) { 1648 // if the keyguard didn't wake the device, we are in call, and 1649 // it is a volume key, turn on the screen so that the user 1650 // can more easily adjust the in call volume. 1651 mKeyguardMediator.pokeWakelock(); 1652 } else if (isMusicActive()) { 1653 // when keyguard is showing and screen off, we need 1654 // to handle the volume key for music here 1655 handleVolumeKey(AudioManager.STREAM_MUSIC, event.keycode); 1656 } 1657 } 1658 } 1659 } 1660 } else if (!screenIsOn) { 1661 // If we are in-call with screen off and keyguard is not showing, 1662 // then handle the volume key ourselves. 1663 // This is necessary because the phone app will disable the keyguard 1664 // when the proximity sensor is in use. 1665 if (isInCall() && event.type == RawInputEvent.EV_KEY && 1666 (event.keycode == KeyEvent.KEYCODE_VOLUME_DOWN 1667 || event.keycode == KeyEvent.KEYCODE_VOLUME_UP)) { 1668 result &= ~ACTION_PASS_TO_USER; 1669 handleVolumeKey(AudioManager.STREAM_VOICE_CALL, event.keycode); 1670 } 1671 if (isWakeKey) { 1672 // a wake key has a sole purpose of waking the device; don't pass 1673 // it to the user 1674 result |= ACTION_POKE_USER_ACTIVITY; 1675 result &= ~ACTION_PASS_TO_USER; 1676 } 1677 } 1678 1679 int type = event.type; 1680 int code = event.keycode; 1681 boolean down = event.value != 0; 1682 1683 if (type == RawInputEvent.EV_KEY) { 1684 if (code == KeyEvent.KEYCODE_ENDCALL 1685 || code == KeyEvent.KEYCODE_POWER) { 1686 if (down) { 1687 boolean handled = false; 1688 // key repeats are generated by the window manager, and we don't see them 1689 // here, so unless the driver is doing something it shouldn't be, we know 1690 // this is the real press event. 1691 ITelephony phoneServ = getPhoneInterface(); 1692 if (phoneServ != null) { 1693 try { 1694 if (code == KeyEvent.KEYCODE_ENDCALL) { 1695 handled = phoneServ.endCall(); 1696 } else if (code == KeyEvent.KEYCODE_POWER && phoneServ.isRinging()) { 1697 // Pressing power during incoming call should silence the ringer 1698 phoneServ.silenceRinger(); 1699 handled = true; 1700 } 1701 } catch (RemoteException ex) { 1702 Log.w(TAG, "ITelephony threw RemoteException" + ex); 1703 } 1704 } else { 1705 Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); 1706 } 1707 // power button should turn off screen in addition to hanging up the phone 1708 if ((handled && code != KeyEvent.KEYCODE_POWER) || !screenIsOn) { 1709 mShouldTurnOffOnKeyUp = false; 1710 } else { 1711 // only try to turn off the screen if we didn't already hang up 1712 mShouldTurnOffOnKeyUp = true; 1713 mHandler.postDelayed(mPowerLongPress, 1714 ViewConfiguration.getGlobalActionKeyTimeout()); 1715 result &= ~ACTION_PASS_TO_USER; 1716 } 1717 } else { 1718 mHandler.removeCallbacks(mPowerLongPress); 1719 if (mShouldTurnOffOnKeyUp) { 1720 mShouldTurnOffOnKeyUp = false; 1721 boolean gohome = (mEndcallBehavior & ENDCALL_HOME) != 0; 1722 boolean sleeps = (mEndcallBehavior & ENDCALL_SLEEPS) != 0; 1723 if (keyguardShowing 1724 || (sleeps && !gohome) 1725 || (gohome && !goHome() && sleeps)) { 1726 // they must already be on the keyguad or home screen, 1727 // go to sleep instead 1728 Log.d(TAG, "I'm tired mEndcallBehavior=0x" 1729 + Integer.toHexString(mEndcallBehavior)); 1730 result &= ~ACTION_POKE_USER_ACTIVITY; 1731 result |= ACTION_GO_TO_SLEEP; 1732 } 1733 result &= ~ACTION_PASS_TO_USER; 1734 } 1735 } 1736 } else if (isMediaKey(code)) { 1737 // This key needs to be handled even if the screen is off. 1738 // If others need to be handled while it's off, this is a reasonable 1739 // pattern to follow. 1740 if ((result & ACTION_PASS_TO_USER) == 0) { 1741 // Only do this if we would otherwise not pass it to the user. In that 1742 // case, the PhoneWindow class will do the same thing, except it will 1743 // only do it if the showing app doesn't process the key on its own. 1744 KeyEvent keyEvent = new KeyEvent(event.when, event.when, 1745 down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP, 1746 code, 0); 1747 mBroadcastWakeLock.acquire(); 1748 mHandler.post(new PassHeadsetKey(keyEvent)); 1749 } 1750 } else if (code == KeyEvent.KEYCODE_CALL) { 1751 // If an incoming call is ringing, answer it! 1752 // (We handle this key here, rather than in the InCallScreen, to make 1753 // sure we'll respond to the key even if the InCallScreen hasn't come to 1754 // the foreground yet.) 1755 1756 // We answer the call on the DOWN event, to agree with 1757 // the "fallback" behavior in the InCallScreen. 1758 if (down) { 1759 try { 1760 ITelephony phoneServ = getPhoneInterface(); 1761 if (phoneServ != null) { 1762 if (phoneServ.isRinging()) { 1763 Log.i(TAG, "interceptKeyTq:" 1764 + " CALL key-down while ringing: Answer the call!"); 1765 phoneServ.answerRingingCall(); 1766 1767 // And *don't* pass this key thru to the current activity 1768 // (which is presumably the InCallScreen.) 1769 result &= ~ACTION_PASS_TO_USER; 1770 } 1771 } else { 1772 Log.w(TAG, "CALL button: Unable to find ITelephony interface"); 1773 } 1774 } catch (RemoteException ex) { 1775 Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex); 1776 } 1777 } 1778 } else if ((code == KeyEvent.KEYCODE_VOLUME_UP) 1779 || (code == KeyEvent.KEYCODE_VOLUME_DOWN)) { 1780 // If an incoming call is ringing, either VOLUME key means 1781 // "silence ringer". We handle these keys here, rather than 1782 // in the InCallScreen, to make sure we'll respond to them 1783 // even if the InCallScreen hasn't come to the foreground yet. 1784 1785 // Look for the DOWN event here, to agree with the "fallback" 1786 // behavior in the InCallScreen. 1787 if (down) { 1788 try { 1789 ITelephony phoneServ = getPhoneInterface(); 1790 if (phoneServ != null) { 1791 if (phoneServ.isRinging()) { 1792 Log.i(TAG, "interceptKeyTq:" 1793 + " VOLUME key-down while ringing: Silence ringer!"); 1794 // Silence the ringer. (It's safe to call this 1795 // even if the ringer has already been silenced.) 1796 phoneServ.silenceRinger(); 1797 1798 // And *don't* pass this key thru to the current activity 1799 // (which is probably the InCallScreen.) 1800 result &= ~ACTION_PASS_TO_USER; 1801 } 1802 } else { 1803 Log.w(TAG, "VOLUME button: Unable to find ITelephony interface"); 1804 } 1805 } catch (RemoteException ex) { 1806 Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex); 1807 } 1808 } 1809 } 1810 } 1811 1812 return result; 1813 } 1814 1815 class PassHeadsetKey implements Runnable { 1816 KeyEvent mKeyEvent; 1817 PassHeadsetKey(KeyEvent keyEvent)1818 PassHeadsetKey(KeyEvent keyEvent) { 1819 mKeyEvent = keyEvent; 1820 } 1821 run()1822 public void run() { 1823 if (ActivityManagerNative.isSystemReady()) { 1824 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 1825 intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent); 1826 mContext.sendOrderedBroadcast(intent, null, mBroadcastDone, 1827 mHandler, Activity.RESULT_OK, null, null); 1828 } 1829 } 1830 } 1831 1832 BroadcastReceiver mBroadcastDone = new BroadcastReceiver() { 1833 public void onReceive(Context context, Intent intent) { 1834 mBroadcastWakeLock.release(); 1835 } 1836 }; 1837 1838 BroadcastReceiver mBatteryReceiver = new BroadcastReceiver() { 1839 public void onReceive(Context context, Intent intent) { 1840 updatePlugged(intent); 1841 updateDockKeepingScreenOn(); 1842 } 1843 }; 1844 1845 BroadcastReceiver mDockReceiver = new BroadcastReceiver() { 1846 public void onReceive(Context context, Intent intent) { 1847 mDockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 1848 Intent.EXTRA_DOCK_STATE_UNDOCKED); 1849 boolean watchBattery = mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED; 1850 if (watchBattery != mRegisteredBatteryReceiver) { 1851 mRegisteredBatteryReceiver = watchBattery; 1852 if (watchBattery) { 1853 updatePlugged(mContext.registerReceiver(mBatteryReceiver, 1854 mBatteryStatusFilter)); 1855 } else { 1856 mContext.unregisterReceiver(mBatteryReceiver); 1857 } 1858 } 1859 updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); 1860 updateDockKeepingScreenOn(); 1861 updateOrientationListenerLp(); 1862 } 1863 }; 1864 1865 /** {@inheritDoc} */ isWakeRelMovementTq(int device, int classes, RawInputEvent event)1866 public boolean isWakeRelMovementTq(int device, int classes, 1867 RawInputEvent event) { 1868 // if it's tagged with one of the wake bits, it wakes up the device 1869 return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0); 1870 } 1871 1872 /** {@inheritDoc} */ isWakeAbsMovementTq(int device, int classes, RawInputEvent event)1873 public boolean isWakeAbsMovementTq(int device, int classes, 1874 RawInputEvent event) { 1875 // if it's tagged with one of the wake bits, it wakes up the device 1876 return ((event.flags & (FLAG_WAKE | FLAG_WAKE_DROPPED)) != 0); 1877 } 1878 1879 /** 1880 * Given the current state of the world, should this key wake up the device? 1881 */ isWakeKeyTq(RawInputEvent event)1882 protected boolean isWakeKeyTq(RawInputEvent event) { 1883 // There are not key maps for trackball devices, but we'd still 1884 // like to have pressing it wake the device up, so force it here. 1885 int keycode = event.keycode; 1886 int flags = event.flags; 1887 if (keycode == RawInputEvent.BTN_MOUSE) { 1888 flags |= WindowManagerPolicy.FLAG_WAKE; 1889 } 1890 return (flags 1891 & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; 1892 } 1893 1894 /** {@inheritDoc} */ screenTurnedOff(int why)1895 public void screenTurnedOff(int why) { 1896 EventLog.writeEvent(70000, 0); 1897 mKeyguardMediator.onScreenTurnedOff(why); 1898 synchronized (mLock) { 1899 mScreenOn = false; 1900 updateOrientationListenerLp(); 1901 } 1902 } 1903 1904 /** {@inheritDoc} */ screenTurnedOn()1905 public void screenTurnedOn() { 1906 EventLog.writeEvent(70000, 1); 1907 mKeyguardMediator.onScreenTurnedOn(); 1908 synchronized (mLock) { 1909 mScreenOn = true; 1910 updateOrientationListenerLp(); 1911 } 1912 } 1913 1914 /** {@inheritDoc} */ enableKeyguard(boolean enabled)1915 public void enableKeyguard(boolean enabled) { 1916 mKeyguardMediator.setKeyguardEnabled(enabled); 1917 } 1918 1919 /** {@inheritDoc} */ exitKeyguardSecurely(OnKeyguardExitResult callback)1920 public void exitKeyguardSecurely(OnKeyguardExitResult callback) { 1921 mKeyguardMediator.verifyUnlock(callback); 1922 } 1923 1924 /** {@inheritDoc} */ keyguardIsShowingTq()1925 public boolean keyguardIsShowingTq() { 1926 return mKeyguardMediator.isShowing(); 1927 } 1928 1929 /** {@inheritDoc} */ inKeyguardRestrictedKeyInputMode()1930 public boolean inKeyguardRestrictedKeyInputMode() { 1931 return mKeyguardMediator.isInputRestricted(); 1932 } 1933 sendCloseSystemWindows()1934 void sendCloseSystemWindows() { 1935 sendCloseSystemWindows(mContext, null); 1936 } 1937 sendCloseSystemWindows(String reason)1938 void sendCloseSystemWindows(String reason) { 1939 sendCloseSystemWindows(mContext, reason); 1940 } 1941 sendCloseSystemWindows(Context context, String reason)1942 static void sendCloseSystemWindows(Context context, String reason) { 1943 if (ActivityManagerNative.isSystemReady()) { 1944 try { 1945 ActivityManagerNative.getDefault().closeSystemDialogs(reason); 1946 } catch (RemoteException e) { 1947 } 1948 } 1949 } 1950 rotationForOrientationLw(int orientation, int lastRotation, boolean displayEnabled)1951 public int rotationForOrientationLw(int orientation, int lastRotation, 1952 boolean displayEnabled) { 1953 1954 if (mPortraitRotation < 0) { 1955 // Initialize the rotation angles for each orientation once. 1956 Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) 1957 .getDefaultDisplay(); 1958 if (d.getWidth() > d.getHeight()) { 1959 mPortraitRotation = Surface.ROTATION_90; 1960 mLandscapeRotation = Surface.ROTATION_0; 1961 } else { 1962 mPortraitRotation = Surface.ROTATION_0; 1963 mLandscapeRotation = Surface.ROTATION_90; 1964 } 1965 } 1966 1967 synchronized (mLock) { 1968 switch (orientation) { 1969 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: 1970 //always return landscape if orientation set to landscape 1971 return mLandscapeRotation; 1972 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: 1973 //always return portrait if orientation set to portrait 1974 return mPortraitRotation; 1975 } 1976 // case for nosensor meaning ignore sensor and consider only lid 1977 // or orientation sensor disabled 1978 //or case.unspecified 1979 if (mLidOpen) { 1980 return mLidOpenRotation; 1981 } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) { 1982 return mCarDockRotation; 1983 } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { 1984 return mDeskDockRotation; 1985 } else { 1986 if (useSensorForOrientationLp(orientation)) { 1987 // If the user has enabled auto rotation by default, do it. 1988 int curRotation = mOrientationListener.getCurrentRotation(); 1989 return curRotation >= 0 ? curRotation : lastRotation; 1990 } 1991 return Surface.ROTATION_0; 1992 } 1993 } 1994 } 1995 detectSafeMode()1996 public boolean detectSafeMode() { 1997 try { 1998 int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); 1999 int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S); 2000 int dpadState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER); 2001 int trackballState = mWindowManager.getScancodeState(RawInputEvent.BTN_MOUSE); 2002 mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0; 2003 performHapticFeedbackLw(null, mSafeMode 2004 ? HapticFeedbackConstants.SAFE_MODE_ENABLED 2005 : HapticFeedbackConstants.SAFE_MODE_DISABLED, true); 2006 if (mSafeMode) { 2007 Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState 2008 + " dpad=" + dpadState + " trackball=" + trackballState + ")"); 2009 } else { 2010 Log.i(TAG, "SAFE MODE not enabled"); 2011 } 2012 return mSafeMode; 2013 } catch (RemoteException e) { 2014 // Doom! (it's also local) 2015 throw new RuntimeException("window manager dead"); 2016 } 2017 } 2018 getLongIntArray(Resources r, int resid)2019 static long[] getLongIntArray(Resources r, int resid) { 2020 int[] ar = r.getIntArray(resid); 2021 if (ar == null) { 2022 return null; 2023 } 2024 long[] out = new long[ar.length]; 2025 for (int i=0; i<ar.length; i++) { 2026 out[i] = ar[i]; 2027 } 2028 return out; 2029 } 2030 2031 /** {@inheritDoc} */ systemReady()2032 public void systemReady() { 2033 // tell the keyguard 2034 mKeyguardMediator.onSystemReady(); 2035 android.os.SystemProperties.set("dev.bootcomplete", "1"); 2036 synchronized (mLock) { 2037 updateOrientationListenerLp(); 2038 } 2039 } 2040 2041 2042 /** {@inheritDoc} */ enableScreenAfterBoot()2043 public void enableScreenAfterBoot() { 2044 readLidState(); 2045 updateRotation(Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); 2046 } 2047 updateDockKeepingScreenOn()2048 void updateDockKeepingScreenOn() { 2049 if (mPlugged != 0) { 2050 if (localLOGV) Log.v(TAG, "Update: mDockState=" + mDockState 2051 + " mPlugged=" + mPlugged 2052 + " mCarDockKeepsScreenOn" + mCarDockKeepsScreenOn 2053 + " mDeskDockKeepsScreenOn" + mDeskDockKeepsScreenOn); 2054 if (mDockState == Intent.EXTRA_DOCK_STATE_CAR 2055 && (mPlugged&mCarDockKeepsScreenOn) != 0) { 2056 if (!mDockWakeLock.isHeld()) { 2057 mDockWakeLock.acquire(); 2058 } 2059 return; 2060 } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK 2061 && (mPlugged&mDeskDockKeepsScreenOn) != 0) { 2062 if (!mDockWakeLock.isHeld()) { 2063 mDockWakeLock.acquire(); 2064 } 2065 return; 2066 } 2067 } 2068 2069 if (mDockWakeLock.isHeld()) { 2070 mDockWakeLock.release(); 2071 } 2072 } 2073 updateRotation(int animFlags)2074 void updateRotation(int animFlags) { 2075 mPowerManager.setKeyboardVisibility(mLidOpen); 2076 int rotation = Surface.ROTATION_0; 2077 if (mLidOpen) { 2078 rotation = mLidOpenRotation; 2079 } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR && mCarDockRotation >= 0) { 2080 rotation = mCarDockRotation; 2081 } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK && mDeskDockRotation >= 0) { 2082 rotation = mDeskDockRotation; 2083 } 2084 //if lid is closed orientation will be portrait 2085 try { 2086 //set orientation on WindowManager 2087 mWindowManager.setRotation(rotation, true, 2088 mFancyRotationAnimation | animFlags); 2089 } catch (RemoteException e) { 2090 // Ignore 2091 } 2092 } 2093 2094 /** 2095 * Return an Intent to launch the currently active dock as home. Returns 2096 * null if the standard home should be launched. 2097 * @return 2098 */ createHomeDockIntent()2099 Intent createHomeDockIntent() { 2100 if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) { 2101 return null; 2102 } 2103 2104 Intent intent; 2105 if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) { 2106 intent = mCarDockIntent; 2107 } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) { 2108 intent = mDeskDockIntent; 2109 } else { 2110 Log.w(TAG, "Unknown dock state: " + mDockState); 2111 return null; 2112 } 2113 2114 ActivityInfo ai = intent.resolveActivityInfo( 2115 mContext.getPackageManager(), PackageManager.GET_META_DATA); 2116 if (ai == null) { 2117 return null; 2118 } 2119 2120 if (ai.metaData != null && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) { 2121 intent = new Intent(intent); 2122 intent.setClassName(ai.packageName, ai.name); 2123 return intent; 2124 } 2125 2126 return null; 2127 } 2128 startDockOrHome()2129 void startDockOrHome() { 2130 Intent dock = createHomeDockIntent(); 2131 if (dock != null) { 2132 try { 2133 mContext.startActivity(dock); 2134 return; 2135 } catch (ActivityNotFoundException e) { 2136 } 2137 } 2138 mContext.startActivity(mHomeIntent); 2139 } 2140 2141 /** 2142 * goes to the home screen 2143 * @return whether it did anything 2144 */ goHome()2145 boolean goHome() { 2146 if (false) { 2147 // This code always brings home to the front. 2148 try { 2149 ActivityManagerNative.getDefault().stopAppSwitches(); 2150 } catch (RemoteException e) { 2151 } 2152 sendCloseSystemWindows(); 2153 startDockOrHome(); 2154 } else { 2155 // This code brings home to the front or, if it is already 2156 // at the front, puts the device to sleep. 2157 try { 2158 ActivityManagerNative.getDefault().stopAppSwitches(); 2159 sendCloseSystemWindows(); 2160 Intent dock = createHomeDockIntent(); 2161 if (dock != null) { 2162 int result = ActivityManagerNative.getDefault() 2163 .startActivity(null, dock, 2164 dock.resolveTypeIfNeeded(mContext.getContentResolver()), 2165 null, 0, null, null, 0, true /* onlyIfNeeded*/, false); 2166 if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { 2167 return false; 2168 } 2169 } 2170 int result = ActivityManagerNative.getDefault() 2171 .startActivity(null, mHomeIntent, 2172 mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), 2173 null, 0, null, null, 0, true /* onlyIfNeeded*/, false); 2174 if (result == IActivityManager.START_RETURN_INTENT_TO_CALLER) { 2175 return false; 2176 } 2177 } catch (RemoteException ex) { 2178 // bummer, the activity manager, which is in this process, is dead 2179 } 2180 } 2181 return true; 2182 } 2183 setCurrentOrientationLw(int newOrientation)2184 public void setCurrentOrientationLw(int newOrientation) { 2185 synchronized (mLock) { 2186 if (newOrientation != mCurrentAppOrientation) { 2187 mCurrentAppOrientation = newOrientation; 2188 updateOrientationListenerLp(); 2189 } 2190 } 2191 } 2192 performHapticFeedbackLw(WindowState win, int effectId, boolean always)2193 public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) { 2194 final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(), 2195 Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0; 2196 if (!always && (hapticsDisabled || mKeyguardMediator.isShowing())) { 2197 return false; 2198 } 2199 switch (effectId) { 2200 case HapticFeedbackConstants.LONG_PRESS: 2201 mVibrator.vibrate(mLongPressVibePattern, -1); 2202 return true; 2203 case HapticFeedbackConstants.VIRTUAL_KEY: 2204 mVibrator.vibrate(mVirtualKeyVibePattern, -1); 2205 return true; 2206 case HapticFeedbackConstants.SAFE_MODE_DISABLED: 2207 mVibrator.vibrate(mSafeModeDisabledVibePattern, -1); 2208 return true; 2209 case HapticFeedbackConstants.SAFE_MODE_ENABLED: 2210 mVibrator.vibrate(mSafeModeEnabledVibePattern, -1); 2211 return true; 2212 } 2213 return false; 2214 } 2215 keyFeedbackFromInput(KeyEvent event)2216 public void keyFeedbackFromInput(KeyEvent event) { 2217 if (event.getAction() == KeyEvent.ACTION_DOWN 2218 && (event.getFlags()&KeyEvent.FLAG_VIRTUAL_HARD_KEY) != 0) { 2219 performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); 2220 } 2221 } 2222 screenOnStoppedLw()2223 public void screenOnStoppedLw() { 2224 if (!mKeyguardMediator.isShowing() && mPowerManager.isScreenOn()) { 2225 long curTime = SystemClock.uptimeMillis(); 2226 mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); 2227 } 2228 } 2229 allowKeyRepeat()2230 public boolean allowKeyRepeat() { 2231 // disable key repeat when screen is off 2232 return mScreenOn; 2233 } 2234 } 2235 2236