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