PhoneWindowManager.java revision e90585f89d550a61e3efd5050efdc5be2be494af
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.ActivityManager; 21import android.app.ActivityManagerNative; 22import android.app.IUiModeManager; 23import android.app.ProgressDialog; 24import android.app.UiModeManager; 25import android.content.ActivityNotFoundException; 26import android.content.BroadcastReceiver; 27import android.content.ComponentName; 28import android.content.ContentResolver; 29import android.content.Context; 30import android.content.Intent; 31import android.content.IntentFilter; 32import android.content.ServiceConnection; 33import android.content.pm.ActivityInfo; 34import android.content.pm.PackageManager; 35import android.content.res.CompatibilityInfo; 36import android.content.res.Configuration; 37import android.content.res.Resources; 38import android.database.ContentObserver; 39import android.graphics.PixelFormat; 40import android.graphics.Rect; 41import android.graphics.RectF; 42import android.media.AudioManager; 43import android.media.IAudioService; 44import android.os.BatteryManager; 45import android.os.Bundle; 46import android.os.Handler; 47import android.os.IBinder; 48import android.os.IRemoteCallback; 49import android.os.LocalPowerManager; 50import android.os.Looper; 51import android.os.Message; 52import android.os.Messenger; 53import android.os.PowerManager; 54import android.os.RemoteException; 55import android.os.ServiceManager; 56import android.os.SystemClock; 57import android.os.SystemProperties; 58import android.os.UEventObserver; 59import android.os.Vibrator; 60import android.provider.Settings; 61 62import com.android.internal.R; 63import com.android.internal.app.ShutdownThread; 64import com.android.internal.policy.PolicyManager; 65import com.android.internal.statusbar.IStatusBarService; 66import com.android.internal.telephony.ITelephony; 67import com.android.internal.widget.PointerLocationView; 68 69import android.speech.RecognizerIntent; 70import android.util.DisplayMetrics; 71import android.util.EventLog; 72import android.util.Log; 73import android.util.Slog; 74import android.util.SparseArray; 75import android.view.Gravity; 76import android.view.HapticFeedbackConstants; 77import android.view.IApplicationToken; 78import android.view.IWindowManager; 79import android.view.InputChannel; 80import android.view.InputDevice; 81import android.view.InputEvent; 82import android.view.InputEventReceiver; 83import android.view.KeyCharacterMap; 84import android.view.KeyEvent; 85import android.view.MotionEvent; 86import android.view.WindowOrientationListener; 87import android.view.Surface; 88import android.view.View; 89import android.view.ViewConfiguration; 90import android.view.Window; 91import android.view.WindowManager; 92import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 93import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; 94import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; 95import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 96import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; 97import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; 98import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 99import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; 100import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; 101import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; 102import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 103import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 104import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 105import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA; 106import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; 107import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_PANEL; 108import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL; 109import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 110import static android.view.WindowManager.LayoutParams.TYPE_DRAG; 111import static android.view.WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER; 112import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD; 113import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; 114import static android.view.WindowManager.LayoutParams.TYPE_PHONE; 115import static android.view.WindowManager.LayoutParams.TYPE_PRIORITY_PHONE; 116import static android.view.WindowManager.LayoutParams.TYPE_SEARCH_BAR; 117import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; 118import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 119import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; 120import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; 121import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG; 122import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; 123import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; 124import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 125import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; 126import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; 127import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 128import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; 129import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 130import static android.view.WindowManager.LayoutParams.TYPE_POINTER; 131import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; 132import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; 133import android.view.WindowManagerImpl; 134import android.view.WindowManagerPolicy; 135import android.view.KeyCharacterMap.FallbackAction; 136import android.view.accessibility.AccessibilityEvent; 137import android.view.animation.Animation; 138import android.view.animation.AnimationUtils; 139 140import java.io.File; 141import java.io.FileDescriptor; 142import java.io.FileReader; 143import java.io.IOException; 144import java.io.PrintWriter; 145import java.util.ArrayList; 146 147/** 148 * WindowManagerPolicy implementation for the Android phone UI. This 149 * introduces a new method suffix, Lp, for an internal lock of the 150 * PhoneWindowManager. This is used to protect some internal state, and 151 * can be acquired with either thw Lw and Li lock held, so has the restrictions 152 * of both of those when held. 153 */ 154public class PhoneWindowManager implements WindowManagerPolicy { 155 static final String TAG = "WindowManager"; 156 static final boolean DEBUG = false; 157 static final boolean localLOGV = false; 158 static final boolean DEBUG_LAYOUT = false; 159 static final boolean DEBUG_FALLBACK = false; 160 static final boolean SHOW_STARTING_ANIMATIONS = true; 161 static final boolean SHOW_PROCESSES_ON_ALT_MENU = false; 162 163 // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key. 164 // No longer recommended for desk docks; still useful in car docks. 165 static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true; 166 static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false; 167 168 // Should screen savers use their own timeout, or the SCREEN_OFF_TIMEOUT? 169 static final boolean SEPARATE_TIMEOUT_FOR_SCREEN_SAVER = false; 170 171 static final int LONG_PRESS_POWER_NOTHING = 0; 172 static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; 173 static final int LONG_PRESS_POWER_SHUT_OFF = 2; 174 175 // These need to match the documentation/constant in 176 // core/res/res/values/config.xml 177 static final int LONG_PRESS_HOME_NOTHING = 0; 178 static final int LONG_PRESS_HOME_RECENT_DIALOG = 1; 179 static final int LONG_PRESS_HOME_RECENT_SYSTEM_UI = 2; 180 static final int LONG_PRESS_HOME_VOICE_SEARCH = 3; 181 182 // wallpaper is at the bottom, though the window manager may move it. 183 static final int WALLPAPER_LAYER = 2; 184 static final int APPLICATION_LAYER = 2; 185 static final int PHONE_LAYER = 3; 186 static final int SEARCH_BAR_LAYER = 4; 187 static final int SYSTEM_DIALOG_LAYER = 5; 188 // toasts and the plugged-in battery thing 189 static final int TOAST_LAYER = 6; 190 // SIM errors and unlock. Not sure if this really should be in a high layer. 191 static final int PRIORITY_PHONE_LAYER = 7; 192 // like the ANR / app crashed dialogs 193 static final int SYSTEM_ALERT_LAYER = 8; 194 // on-screen keyboards and other such input method user interfaces go here. 195 static final int INPUT_METHOD_LAYER = 9; 196 // on-screen keyboards and other such input method user interfaces go here. 197 static final int INPUT_METHOD_DIALOG_LAYER = 10; 198 // the keyguard; nothing on top of these can take focus, since they are 199 // responsible for power management when displayed. 200 static final int KEYGUARD_LAYER = 11; 201 static final int KEYGUARD_DIALOG_LAYER = 12; 202 static final int STATUS_BAR_SUB_PANEL_LAYER = 13; 203 static final int STATUS_BAR_LAYER = 14; 204 static final int STATUS_BAR_PANEL_LAYER = 15; 205 // the on-screen volume indicator and controller shown when the user 206 // changes the device volume 207 static final int VOLUME_OVERLAY_LAYER = 16; 208 // things in here CAN NOT take focus, but are shown on top of everything else. 209 static final int SYSTEM_OVERLAY_LAYER = 17; 210 // the navigation bar, if available, shows atop most things 211 static final int NAVIGATION_BAR_LAYER = 18; 212 // system-level error dialogs 213 static final int SYSTEM_ERROR_LAYER = 19; 214 // the drag layer: input for drag-and-drop is associated with this window, 215 // which sits above all other focusable windows 216 static final int DRAG_LAYER = 20; 217 static final int SECURE_SYSTEM_OVERLAY_LAYER = 21; 218 static final int BOOT_PROGRESS_LAYER = 22; 219 // the (mouse) pointer layer 220 static final int POINTER_LAYER = 23; 221 static final int HIDDEN_NAV_CONSUMER_LAYER = 24; 222 223 static final int APPLICATION_MEDIA_SUBLAYER = -2; 224 static final int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1; 225 static final int APPLICATION_PANEL_SUBLAYER = 1; 226 static final int APPLICATION_SUB_PANEL_SUBLAYER = 2; 227 228 static public final String SYSTEM_DIALOG_REASON_KEY = "reason"; 229 static public final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions"; 230 static public final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps"; 231 static public final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey"; 232 233 // Useful scan codes. 234 private static final int SW_LID = 0x00; 235 private static final int BTN_MOUSE = 0x110; 236 237 /* Table of Application Launch keys. Maps from key codes to intent categories. 238 * 239 * These are special keys that are used to launch particular kinds of applications, 240 * such as a web browser. HID defines nearly a hundred of them in the Consumer (0x0C) 241 * usage page. We don't support quite that many yet... 242 */ 243 static SparseArray<String> sApplicationLaunchKeyCategories; 244 static { 245 sApplicationLaunchKeyCategories = new SparseArray<String>(); 246 sApplicationLaunchKeyCategories.append( 247 KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER); 248 sApplicationLaunchKeyCategories.append( 249 KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL); 250 sApplicationLaunchKeyCategories.append( 251 KeyEvent.KEYCODE_CONTACTS, Intent.CATEGORY_APP_CONTACTS); 252 sApplicationLaunchKeyCategories.append( 253 KeyEvent.KEYCODE_CALENDAR, Intent.CATEGORY_APP_CALENDAR); 254 sApplicationLaunchKeyCategories.append( 255 KeyEvent.KEYCODE_MUSIC, Intent.CATEGORY_APP_MUSIC); 256 sApplicationLaunchKeyCategories.append( 257 KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR); 258 } 259 260 /** 261 * Lock protecting internal state. Must not call out into window 262 * manager with lock held. (This lock will be acquired in places 263 * where the window manager is calling in with its own lock held.) 264 */ 265 final Object mLock = new Object(); 266 267 Context mContext; 268 IWindowManager mWindowManager; 269 WindowManagerFuncs mWindowManagerFuncs; 270 LocalPowerManager mPowerManager; 271 IStatusBarService mStatusBarService; 272 Vibrator mVibrator; // Vibrator for giving feedback of orientation changes 273 274 // Vibrator pattern for haptic feedback of a long press. 275 long[] mLongPressVibePattern; 276 277 // Vibrator pattern for haptic feedback of virtual key press. 278 long[] mVirtualKeyVibePattern; 279 280 // Vibrator pattern for a short vibration. 281 long[] mKeyboardTapVibePattern; 282 283 // Vibrator pattern for haptic feedback during boot when safe mode is disabled. 284 long[] mSafeModeDisabledVibePattern; 285 286 // Vibrator pattern for haptic feedback during boot when safe mode is enabled. 287 long[] mSafeModeEnabledVibePattern; 288 289 /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */ 290 boolean mEnableShiftMenuBugReports = false; 291 292 boolean mHeadless; 293 boolean mSafeMode; 294 WindowState mStatusBar = null; 295 boolean mStatusBarCanHide; 296 int mStatusBarHeight; 297 final ArrayList<WindowState> mStatusBarPanels = new ArrayList<WindowState>(); 298 WindowState mNavigationBar = null; 299 boolean mHasNavigationBar = false; 300 int mNavigationBarWidth = 0, mNavigationBarHeight = 0; 301 302 WindowState mKeyguard = null; 303 KeyguardViewMediator mKeyguardMediator; 304 GlobalActions mGlobalActions; 305 volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread 306 boolean mPendingPowerKeyUpCanceled; 307 Handler mHandler; 308 309 static final int RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS = 0; 310 static final int RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW = 1; 311 static final int RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH = 2; 312 313 RecentApplicationsDialog mRecentAppsDialog; 314 int mRecentAppsDialogHeldModifiers; 315 316 private static final int LID_ABSENT = -1; 317 private static final int LID_CLOSED = 0; 318 private static final int LID_OPEN = 1; 319 320 int mLidOpen = LID_ABSENT; 321 322 boolean mSystemReady; 323 boolean mSystemBooted; 324 boolean mHdmiPlugged; 325 int mUiMode; 326 int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; 327 int mLidOpenRotation; 328 int mCarDockRotation; 329 int mDeskDockRotation; 330 int mHdmiRotation; 331 332 int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE; 333 int mUserRotation = Surface.ROTATION_0; 334 335 int mAllowAllRotations = -1; 336 boolean mCarDockEnablesAccelerometer; 337 boolean mDeskDockEnablesAccelerometer; 338 int mLidKeyboardAccessibility; 339 int mLidNavigationAccessibility; 340 int mLongPressOnPowerBehavior = -1; 341 boolean mScreenOnEarly = false; 342 boolean mScreenOnFully = false; 343 boolean mOrientationSensorEnabled = false; 344 int mCurrentAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 345 static final int DEFAULT_ACCELEROMETER_ROTATION = 0; 346 int mAccelerometerDefault = DEFAULT_ACCELEROMETER_ROTATION; 347 boolean mHasSoftInput = false; 348 349 int mPointerLocationMode = 0; 350 PointerLocationView mPointerLocationView = null; 351 InputChannel mPointerLocationInputChannel; 352 353 // The last window we were told about in focusChanged. 354 WindowState mFocusedWindow; 355 IApplicationToken mFocusedApp; 356 357 final class PointerLocationInputEventReceiver extends InputEventReceiver { 358 public PointerLocationInputEventReceiver(InputChannel inputChannel, Looper looper) { 359 super(inputChannel, looper); 360 } 361 362 @Override 363 public void onInputEvent(InputEvent event) { 364 boolean handled = false; 365 try { 366 if (event instanceof MotionEvent 367 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { 368 final MotionEvent motionEvent = (MotionEvent)event; 369 synchronized (mLock) { 370 if (mPointerLocationView != null) { 371 mPointerLocationView.addPointerEvent(motionEvent); 372 handled = true; 373 } 374 } 375 } 376 } finally { 377 finishInputEvent(event, handled); 378 } 379 } 380 } 381 PointerLocationInputEventReceiver mPointerLocationInputEventReceiver; 382 383 // The current size of the screen; really; (ir)regardless of whether the status 384 // bar can be hidden or not 385 int mUnrestrictedScreenLeft, mUnrestrictedScreenTop; 386 int mUnrestrictedScreenWidth, mUnrestrictedScreenHeight; 387 // The current size of the screen; these may be different than (0,0)-(dw,dh) 388 // if the status bar can't be hidden; in that case it effectively carves out 389 // that area of the display from all other windows. 390 int mRestrictedScreenLeft, mRestrictedScreenTop; 391 int mRestrictedScreenWidth, mRestrictedScreenHeight; 392 // During layout, the current screen borders with all outer decoration 393 // (status bar, input method dock) accounted for. 394 int mCurLeft, mCurTop, mCurRight, mCurBottom; 395 // During layout, the frame in which content should be displayed 396 // to the user, accounting for all screen decoration except for any 397 // space they deem as available for other content. This is usually 398 // the same as mCur*, but may be larger if the screen decor has supplied 399 // content insets. 400 int mContentLeft, mContentTop, mContentRight, mContentBottom; 401 // During layout, the current screen borders along which input method 402 // windows are placed. 403 int mDockLeft, mDockTop, mDockRight, mDockBottom; 404 // During layout, the layer at which the doc window is placed. 405 int mDockLayer; 406 int mLastSystemUiFlags; 407 // Bits that we are in the process of clearing, so we want to prevent 408 // them from being set by applications until everything has been updated 409 // to have them clear. 410 int mResettingSystemUiFlags = 0; 411 // Bits that we are currently always keeping cleared. 412 int mForceClearedSystemUiFlags = 0; 413 // What we last reported to system UI about whether the compatibility 414 // menu needs to be displayed. 415 boolean mLastFocusNeedsMenu = false; 416 417 FakeWindow mHideNavFakeWindow = null; 418 419 static final Rect mTmpParentFrame = new Rect(); 420 static final Rect mTmpDisplayFrame = new Rect(); 421 static final Rect mTmpContentFrame = new Rect(); 422 static final Rect mTmpVisibleFrame = new Rect(); 423 static final Rect mTmpNavigationFrame = new Rect(); 424 425 WindowState mTopFullscreenOpaqueWindowState; 426 boolean mTopIsFullscreen; 427 boolean mForceStatusBar; 428 boolean mHideLockScreen; 429 boolean mDismissKeyguard; 430 boolean mHomePressed; 431 Intent mHomeIntent; 432 Intent mCarDockIntent; 433 Intent mDeskDockIntent; 434 int mShortcutKeyPressed = -1; 435 boolean mConsumeShortcutKeyUp; 436 437 // support for activating the lock screen while the screen is on 438 boolean mAllowLockscreenWhenOn; 439 int mLockScreenTimeout; 440 boolean mLockScreenTimerActive; 441 442 // visual screen saver support 443 int mScreenSaverTimeout = 0; 444 boolean mScreenSaverEnabledByUser = false; 445 boolean mScreenSaverMayRun = true; // false if a wakelock is held 446 boolean mPluggedIn; 447 448 // Behavior of ENDCALL Button. (See Settings.System.END_BUTTON_BEHAVIOR.) 449 int mEndcallBehavior; 450 451 // Behavior of POWER button while in-call and screen on. 452 // (See Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR.) 453 int mIncallPowerBehavior; 454 455 int mLandscapeRotation = 0; // default landscape rotation 456 int mSeascapeRotation = 0; // "other" landscape rotation, 180 degrees from mLandscapeRotation 457 int mPortraitRotation = 0; // default portrait rotation 458 int mUpsideDownRotation = 0; // "other" portrait rotation 459 460 // What we do when the user long presses on home 461 private int mLongPressOnHomeBehavior = -1; 462 463 // Screenshot trigger states 464 // Time to volume and power must be pressed within this interval of each other. 465 private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150; 466 private boolean mScreenshotChordEnabled; 467 private boolean mVolumeDownKeyTriggered; 468 private long mVolumeDownKeyTime; 469 private boolean mVolumeDownKeyConsumedByScreenshotChord; 470 private boolean mVolumeUpKeyTriggered; 471 private boolean mPowerKeyTriggered; 472 private long mPowerKeyTime; 473 474 ShortcutManager mShortcutManager; 475 PowerManager.WakeLock mBroadcastWakeLock; 476 477 final KeyCharacterMap.FallbackAction mFallbackAction = new KeyCharacterMap.FallbackAction(); 478 479 private UEventObserver mHDMIObserver = new UEventObserver() { 480 @Override 481 public void onUEvent(UEventObserver.UEvent event) { 482 setHdmiPlugged("1".equals(event.get("SWITCH_STATE"))); 483 } 484 }; 485 486 class SettingsObserver extends ContentObserver { 487 SettingsObserver(Handler handler) { 488 super(handler); 489 } 490 491 void observe() { 492 ContentResolver resolver = mContext.getContentResolver(); 493 resolver.registerContentObserver(Settings.System.getUriFor( 494 Settings.System.END_BUTTON_BEHAVIOR), false, this); 495 resolver.registerContentObserver(Settings.Secure.getUriFor( 496 Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR), false, this); 497 resolver.registerContentObserver(Settings.System.getUriFor( 498 Settings.System.ACCELEROMETER_ROTATION), false, this); 499 resolver.registerContentObserver(Settings.System.getUriFor( 500 Settings.System.USER_ROTATION), false, this); 501 resolver.registerContentObserver(Settings.System.getUriFor( 502 Settings.System.SCREEN_OFF_TIMEOUT), false, this); 503 resolver.registerContentObserver(Settings.System.getUriFor( 504 Settings.System.WINDOW_ORIENTATION_LISTENER_LOG), false, this); 505 resolver.registerContentObserver(Settings.System.getUriFor( 506 Settings.System.POINTER_LOCATION), false, this); 507 resolver.registerContentObserver(Settings.Secure.getUriFor( 508 Settings.Secure.DEFAULT_INPUT_METHOD), false, this); 509 resolver.registerContentObserver(Settings.System.getUriFor( 510 "fancy_rotation_anim"), false, this); 511 resolver.registerContentObserver(Settings.Secure.getUriFor( 512 Settings.Secure.SCREENSAVER_ENABLED), false, this); 513 if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) { 514 resolver.registerContentObserver(Settings.Secure.getUriFor( 515 "screensaver_timeout"), false, this); 516 } // otherwise SCREEN_OFF_TIMEOUT will do nicely 517 updateSettings(); 518 } 519 520 @Override public void onChange(boolean selfChange) { 521 updateSettings(); 522 updateRotation(false); 523 } 524 } 525 526 class MyOrientationListener extends WindowOrientationListener { 527 MyOrientationListener(Context context) { 528 super(context); 529 } 530 531 @Override 532 public void onProposedRotationChanged(int rotation) { 533 if (localLOGV) Log.v(TAG, "onProposedRotationChanged, rotation=" + rotation); 534 updateRotation(false); 535 } 536 } 537 MyOrientationListener mOrientationListener; 538 539 /* 540 * We always let the sensor be switched on by default except when 541 * the user has explicitly disabled sensor based rotation or when the 542 * screen is switched off. 543 */ 544 boolean needSensorRunningLp() { 545 if (mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR 546 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR 547 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT 548 || mCurrentAppOrientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE) { 549 // If the application has explicitly requested to follow the 550 // orientation, then we need to turn the sensor or. 551 return true; 552 } 553 if ((mCarDockEnablesAccelerometer && mDockMode == Intent.EXTRA_DOCK_STATE_CAR) || 554 (mDeskDockEnablesAccelerometer && (mDockMode == Intent.EXTRA_DOCK_STATE_DESK 555 || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK 556 || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK))) { 557 // enable accelerometer if we are docked in a dock that enables accelerometer 558 // orientation management, 559 return true; 560 } 561 if (mAccelerometerDefault == 0) { 562 // If the setting for using the sensor by default is enabled, then 563 // we will always leave it on. Note that the user could go to 564 // a window that forces an orientation that does not use the 565 // sensor and in theory we could turn it off... however, when next 566 // turning it on we won't have a good value for the current 567 // orientation for a little bit, which can cause orientation 568 // changes to lag, so we'd like to keep it always on. (It will 569 // still be turned off when the screen is off.) 570 return false; 571 } 572 return true; 573 } 574 575 /* 576 * Various use cases for invoking this function 577 * screen turning off, should always disable listeners if already enabled 578 * screen turned on and current app has sensor based orientation, enable listeners 579 * if not already enabled 580 * screen turned on and current app does not have sensor orientation, disable listeners if 581 * already enabled 582 * screen turning on and current app has sensor based orientation, enable listeners if needed 583 * screen turning on and current app has nosensor based orientation, do nothing 584 */ 585 void updateOrientationListenerLp() { 586 if (!mOrientationListener.canDetectOrientation()) { 587 // If sensor is turned off or nonexistent for some reason 588 return; 589 } 590 //Could have been invoked due to screen turning on or off or 591 //change of the currently visible window's orientation 592 if (localLOGV) Log.v(TAG, "Screen status="+mScreenOnEarly+ 593 ", current orientation="+mCurrentAppOrientation+ 594 ", SensorEnabled="+mOrientationSensorEnabled); 595 boolean disable = true; 596 if (mScreenOnEarly) { 597 if (needSensorRunningLp()) { 598 disable = false; 599 //enable listener if not already enabled 600 if (!mOrientationSensorEnabled) { 601 mOrientationListener.enable(); 602 if(localLOGV) Log.v(TAG, "Enabling listeners"); 603 mOrientationSensorEnabled = true; 604 } 605 } 606 } 607 //check if sensors need to be disabled 608 if (disable && mOrientationSensorEnabled) { 609 mOrientationListener.disable(); 610 if(localLOGV) Log.v(TAG, "Disabling listeners"); 611 mOrientationSensorEnabled = false; 612 } 613 } 614 615 private void interceptPowerKeyDown(boolean handled) { 616 mPowerKeyHandled = handled; 617 if (!handled) { 618 mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout()); 619 } 620 } 621 622 private boolean interceptPowerKeyUp(boolean canceled) { 623 if (!mPowerKeyHandled) { 624 mHandler.removeCallbacks(mPowerLongPress); 625 return !canceled; 626 } 627 return false; 628 } 629 630 private void cancelPendingPowerKeyAction() { 631 if (!mPowerKeyHandled) { 632 mHandler.removeCallbacks(mPowerLongPress); 633 } 634 if (mPowerKeyTriggered) { 635 mPendingPowerKeyUpCanceled = true; 636 } 637 } 638 639 private void interceptScreenshotChord() { 640 if (mScreenshotChordEnabled 641 && mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) { 642 final long now = SystemClock.uptimeMillis(); 643 if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS 644 && now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) { 645 mVolumeDownKeyConsumedByScreenshotChord = true; 646 cancelPendingPowerKeyAction(); 647 648 mHandler.postDelayed(mScreenshotChordLongPress, 649 ViewConfiguration.getGlobalActionKeyTimeout()); 650 } 651 } 652 } 653 654 private void cancelPendingScreenshotChordAction() { 655 mHandler.removeCallbacks(mScreenshotChordLongPress); 656 } 657 658 private final Runnable mPowerLongPress = new Runnable() { 659 public void run() { 660 // The context isn't read 661 if (mLongPressOnPowerBehavior < 0) { 662 mLongPressOnPowerBehavior = mContext.getResources().getInteger( 663 com.android.internal.R.integer.config_longPressOnPowerBehavior); 664 } 665 switch (mLongPressOnPowerBehavior) { 666 case LONG_PRESS_POWER_NOTHING: 667 break; 668 case LONG_PRESS_POWER_GLOBAL_ACTIONS: 669 mPowerKeyHandled = true; 670 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); 671 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); 672 showGlobalActionsDialog(); 673 break; 674 case LONG_PRESS_POWER_SHUT_OFF: 675 mPowerKeyHandled = true; 676 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); 677 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); 678 ShutdownThread.shutdown(mContext, true); 679 break; 680 } 681 } 682 }; 683 684 private final Runnable mScreenshotChordLongPress = new Runnable() { 685 public void run() { 686 takeScreenshot(); 687 } 688 }; 689 690 void showGlobalActionsDialog() { 691 if (mGlobalActions == null) { 692 mGlobalActions = new GlobalActions(mContext); 693 } 694 final boolean keyguardShowing = keyguardIsShowingTq(); 695 mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); 696 if (keyguardShowing) { 697 // since it took two seconds of long press to bring this up, 698 // poke the wake lock so they have some time to see the dialog. 699 mKeyguardMediator.pokeWakelock(); 700 } 701 } 702 703 boolean isDeviceProvisioned() { 704 return Settings.Secure.getInt( 705 mContext.getContentResolver(), Settings.Secure.DEVICE_PROVISIONED, 0) != 0; 706 } 707 708 private void handleLongPressOnHome() { 709 // We can't initialize this in init() since the configuration hasn't been loaded yet. 710 if (mLongPressOnHomeBehavior < 0) { 711 mLongPressOnHomeBehavior 712 = mContext.getResources().getInteger(R.integer.config_longPressOnHomeBehavior); 713 if (mLongPressOnHomeBehavior < LONG_PRESS_HOME_NOTHING || 714 mLongPressOnHomeBehavior > LONG_PRESS_HOME_RECENT_SYSTEM_UI) { 715 mLongPressOnHomeBehavior = LONG_PRESS_HOME_NOTHING; 716 } 717 if (hasNavigationBar()) { 718 mLongPressOnHomeBehavior = LONG_PRESS_HOME_VOICE_SEARCH; 719 } 720 } 721 722 if (mLongPressOnHomeBehavior != LONG_PRESS_HOME_NOTHING) { 723 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); 724 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); 725 726 // Eat the longpress so it won't dismiss the recent apps dialog when 727 // the user lets go of the home key 728 mHomePressed = false; 729 } 730 731 if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_DIALOG) { 732 showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS); 733 } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_RECENT_SYSTEM_UI) { 734 try { 735 mStatusBarService.toggleRecentApps(); 736 } catch (RemoteException e) { 737 Slog.e(TAG, "RemoteException when showing recent apps", e); 738 } 739 } else if (mLongPressOnHomeBehavior == LONG_PRESS_HOME_VOICE_SEARCH) { 740 Intent intent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH); 741 try { 742 intent.setFlags( 743 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 744 mContext.startActivity(intent); 745 } catch (ActivityNotFoundException e) { 746 Log.e(TAG, "Unable to launch. tag=" + TAG + " intent=" + intent, e); 747 } catch (SecurityException e) { 748 Log.e(TAG, "PhoneWindowManager does not have the permission to launch " + 749 "tag=" + TAG + " intent=" + intent, e); 750 } 751 } 752 } 753 754 /** 755 * Create (if necessary) and show or dismiss the recent apps dialog according 756 * according to the requested behavior. 757 */ 758 void showOrHideRecentAppsDialog(final int behavior) { 759 mHandler.post(new Runnable() { 760 @Override 761 public void run() { 762 if (mRecentAppsDialog == null) { 763 mRecentAppsDialog = new RecentApplicationsDialog(mContext); 764 } 765 if (mRecentAppsDialog.isShowing()) { 766 switch (behavior) { 767 case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS: 768 mRecentAppsDialog.dismiss(); 769 break; 770 case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH: 771 mRecentAppsDialog.dismissAndSwitch(); 772 break; 773 case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW: 774 default: 775 break; 776 } 777 } else { 778 switch (behavior) { 779 case RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS: 780 mRecentAppsDialog.show(); 781 break; 782 case RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW: 783 try { 784 mWindowManager.setInTouchMode(false); 785 } catch (RemoteException e) { 786 } 787 mRecentAppsDialog.show(); 788 break; 789 case RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH: 790 default: 791 break; 792 } 793 } 794 } 795 }); 796 } 797 798 /** {@inheritDoc} */ 799 public void init(Context context, IWindowManager windowManager, 800 WindowManagerFuncs windowManagerFuncs, 801 LocalPowerManager powerManager) { 802 mContext = context; 803 mWindowManager = windowManager; 804 mWindowManagerFuncs = windowManagerFuncs; 805 mPowerManager = powerManager; 806 mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0")); 807 if (!mHeadless) { 808 // don't create KeyguardViewMediator if headless 809 mKeyguardMediator = new KeyguardViewMediator(context, this, powerManager); 810 } 811 mHandler = new Handler(); 812 mOrientationListener = new MyOrientationListener(mContext); 813 try { 814 mOrientationListener.setCurrentRotation(windowManager.getRotation()); 815 } catch (RemoteException ex) { } 816 SettingsObserver settingsObserver = new SettingsObserver(mHandler); 817 settingsObserver.observe(); 818 mShortcutManager = new ShortcutManager(context, mHandler); 819 mShortcutManager.observe(); 820 mUiMode = context.getResources().getInteger( 821 com.android.internal.R.integer.config_defaultUiModeType); 822 mHomeIntent = new Intent(Intent.ACTION_MAIN, null); 823 mHomeIntent.addCategory(Intent.CATEGORY_HOME); 824 mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 825 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 826 mCarDockIntent = new Intent(Intent.ACTION_MAIN, null); 827 mCarDockIntent.addCategory(Intent.CATEGORY_CAR_DOCK); 828 mCarDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 829 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 830 mDeskDockIntent = new Intent(Intent.ACTION_MAIN, null); 831 mDeskDockIntent.addCategory(Intent.CATEGORY_DESK_DOCK); 832 mDeskDockIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 833 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); 834 835 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 836 mBroadcastWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 837 "PhoneWindowManager.mBroadcastWakeLock"); 838 mEnableShiftMenuBugReports = "1".equals(SystemProperties.get("ro.debuggable")); 839 mLidOpenRotation = readRotation( 840 com.android.internal.R.integer.config_lidOpenRotation); 841 mCarDockRotation = readRotation( 842 com.android.internal.R.integer.config_carDockRotation); 843 mDeskDockRotation = readRotation( 844 com.android.internal.R.integer.config_deskDockRotation); 845 mCarDockEnablesAccelerometer = mContext.getResources().getBoolean( 846 com.android.internal.R.bool.config_carDockEnablesAccelerometer); 847 mDeskDockEnablesAccelerometer = mContext.getResources().getBoolean( 848 com.android.internal.R.bool.config_deskDockEnablesAccelerometer); 849 mLidKeyboardAccessibility = mContext.getResources().getInteger( 850 com.android.internal.R.integer.config_lidKeyboardAccessibility); 851 mLidNavigationAccessibility = mContext.getResources().getInteger( 852 com.android.internal.R.integer.config_lidNavigationAccessibility); 853 // register for dock events 854 IntentFilter filter = new IntentFilter(); 855 filter.addAction(UiModeManager.ACTION_ENTER_CAR_MODE); 856 filter.addAction(UiModeManager.ACTION_EXIT_CAR_MODE); 857 filter.addAction(UiModeManager.ACTION_ENTER_DESK_MODE); 858 filter.addAction(UiModeManager.ACTION_EXIT_DESK_MODE); 859 filter.addAction(Intent.ACTION_DOCK_EVENT); 860 Intent intent = context.registerReceiver(mDockReceiver, filter); 861 if (intent != null) { 862 // Retrieve current sticky dock event broadcast. 863 mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 864 Intent.EXTRA_DOCK_STATE_UNDOCKED); 865 } 866 867 // watch the plug to know whether to trigger the screen saver 868 filter = new IntentFilter(); 869 filter.addAction(Intent.ACTION_BATTERY_CHANGED); 870 intent = context.registerReceiver(mPowerReceiver, filter); 871 if (intent != null) { 872 mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0)); 873 } 874 875 mVibrator = new Vibrator(); 876 mLongPressVibePattern = getLongIntArray(mContext.getResources(), 877 com.android.internal.R.array.config_longPressVibePattern); 878 mVirtualKeyVibePattern = getLongIntArray(mContext.getResources(), 879 com.android.internal.R.array.config_virtualKeyVibePattern); 880 mKeyboardTapVibePattern = getLongIntArray(mContext.getResources(), 881 com.android.internal.R.array.config_keyboardTapVibePattern); 882 mSafeModeDisabledVibePattern = getLongIntArray(mContext.getResources(), 883 com.android.internal.R.array.config_safeModeDisabledVibePattern); 884 mSafeModeEnabledVibePattern = getLongIntArray(mContext.getResources(), 885 com.android.internal.R.array.config_safeModeEnabledVibePattern); 886 887 mScreenshotChordEnabled = mContext.getResources().getBoolean( 888 com.android.internal.R.bool.config_enableScreenshotChord); 889 890 // Controls rotation and the like. 891 initializeHdmiState(); 892 893 // Match current screen state. 894 if (mPowerManager.isScreenOn()) { 895 screenTurningOn(null); 896 } else { 897 screenTurnedOff(WindowManagerPolicy.OFF_BECAUSE_OF_USER); 898 } 899 } 900 901 public void setInitialDisplaySize(int width, int height) { 902 int shortSize; 903 if (width > height) { 904 shortSize = height; 905 mLandscapeRotation = Surface.ROTATION_0; 906 mSeascapeRotation = Surface.ROTATION_180; 907 if (mContext.getResources().getBoolean( 908 com.android.internal.R.bool.config_reverseDefaultRotation)) { 909 mPortraitRotation = Surface.ROTATION_90; 910 mUpsideDownRotation = Surface.ROTATION_270; 911 } else { 912 mPortraitRotation = Surface.ROTATION_270; 913 mUpsideDownRotation = Surface.ROTATION_90; 914 } 915 } else { 916 shortSize = width; 917 mPortraitRotation = Surface.ROTATION_0; 918 mUpsideDownRotation = Surface.ROTATION_180; 919 if (mContext.getResources().getBoolean( 920 com.android.internal.R.bool.config_reverseDefaultRotation)) { 921 mLandscapeRotation = Surface.ROTATION_270; 922 mSeascapeRotation = Surface.ROTATION_90; 923 } else { 924 mLandscapeRotation = Surface.ROTATION_90; 925 mSeascapeRotation = Surface.ROTATION_270; 926 } 927 } 928 929 // Determine whether the status bar can hide based on the size 930 // of the screen. We assume sizes > 600dp are tablets where we 931 // will use the system bar. 932 int shortSizeDp = shortSize 933 * DisplayMetrics.DENSITY_DEFAULT 934 / DisplayMetrics.DENSITY_DEVICE; 935 mStatusBarCanHide = shortSizeDp < 600; 936 mStatusBarHeight = mContext.getResources().getDimensionPixelSize( 937 mStatusBarCanHide 938 ? com.android.internal.R.dimen.status_bar_height 939 : com.android.internal.R.dimen.system_bar_height); 940 941 mHasNavigationBar = mContext.getResources().getBoolean( 942 com.android.internal.R.bool.config_showNavigationBar); 943 // Allow a system property to override this. Used by the emulator. 944 // See also hasNavigationBar(). 945 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys"); 946 if (! "".equals(navBarOverride)) { 947 if (navBarOverride.equals("1")) mHasNavigationBar = false; 948 else if (navBarOverride.equals("0")) mHasNavigationBar = true; 949 } 950 951 mNavigationBarHeight = mHasNavigationBar 952 ? mContext.getResources().getDimensionPixelSize( 953 com.android.internal.R.dimen.navigation_bar_height) 954 : 0; 955 mNavigationBarWidth = mHasNavigationBar 956 ? mContext.getResources().getDimensionPixelSize( 957 com.android.internal.R.dimen.navigation_bar_width) 958 : 0; 959 960 if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) { 961 mHdmiRotation = mPortraitRotation; 962 } else { 963 mHdmiRotation = mLandscapeRotation; 964 } 965 } 966 967 public void updateSettings() { 968 ContentResolver resolver = mContext.getContentResolver(); 969 boolean updateRotation = false; 970 View addView = null; 971 View removeView = null; 972 synchronized (mLock) { 973 mEndcallBehavior = Settings.System.getInt(resolver, 974 Settings.System.END_BUTTON_BEHAVIOR, 975 Settings.System.END_BUTTON_BEHAVIOR_DEFAULT); 976 mIncallPowerBehavior = Settings.Secure.getInt(resolver, 977 Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR, 978 Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_DEFAULT); 979 int accelerometerDefault = Settings.System.getInt(resolver, 980 Settings.System.ACCELEROMETER_ROTATION, DEFAULT_ACCELEROMETER_ROTATION); 981 982 // set up rotation lock state 983 mUserRotationMode = (accelerometerDefault == 0) 984 ? WindowManagerPolicy.USER_ROTATION_LOCKED 985 : WindowManagerPolicy.USER_ROTATION_FREE; 986 mUserRotation = Settings.System.getInt(resolver, 987 Settings.System.USER_ROTATION, 988 Surface.ROTATION_0); 989 990 if (mAccelerometerDefault != accelerometerDefault) { 991 mAccelerometerDefault = accelerometerDefault; 992 updateOrientationListenerLp(); 993 } 994 995 mOrientationListener.setLogEnabled( 996 Settings.System.getInt(resolver, 997 Settings.System.WINDOW_ORIENTATION_LISTENER_LOG, 0) != 0); 998 999 if (mSystemReady) { 1000 int pointerLocation = Settings.System.getInt(resolver, 1001 Settings.System.POINTER_LOCATION, 0); 1002 if (mPointerLocationMode != pointerLocation) { 1003 mPointerLocationMode = pointerLocation; 1004 if (pointerLocation != 0) { 1005 if (mPointerLocationView == null) { 1006 mPointerLocationView = new PointerLocationView(mContext); 1007 mPointerLocationView.setPrintCoords(false); 1008 addView = mPointerLocationView; 1009 } 1010 } else { 1011 removeView = mPointerLocationView; 1012 mPointerLocationView = null; 1013 } 1014 } 1015 } 1016 // use screen off timeout setting as the timeout for the lockscreen 1017 mLockScreenTimeout = Settings.System.getInt(resolver, 1018 Settings.System.SCREEN_OFF_TIMEOUT, 0); 1019 String imId = Settings.Secure.getString(resolver, 1020 Settings.Secure.DEFAULT_INPUT_METHOD); 1021 boolean hasSoftInput = imId != null && imId.length() > 0; 1022 if (mHasSoftInput != hasSoftInput) { 1023 mHasSoftInput = hasSoftInput; 1024 updateRotation = true; 1025 } 1026 1027 mScreenSaverEnabledByUser = 0 != Settings.Secure.getInt(resolver, 1028 Settings.Secure.SCREENSAVER_ENABLED, 1); 1029 1030 if (SEPARATE_TIMEOUT_FOR_SCREEN_SAVER) { 1031 mScreenSaverTimeout = Settings.Secure.getInt(resolver, 1032 "screensaver_timeout", 0); 1033 } else { 1034 mScreenSaverTimeout = Settings.System.getInt(resolver, 1035 Settings.System.SCREEN_OFF_TIMEOUT, 0); 1036 if (mScreenSaverTimeout > 0) { 1037 // We actually want to activate the screensaver just before the 1038 // power manager's screen timeout 1039 mScreenSaverTimeout -= 5000; 1040 } 1041 } 1042 updateScreenSaverTimeoutLocked(); 1043 } 1044 if (updateRotation) { 1045 updateRotation(true); 1046 } 1047 if (addView != null) { 1048 WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 1049 WindowManager.LayoutParams.MATCH_PARENT, 1050 WindowManager.LayoutParams.MATCH_PARENT); 1051 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; 1052 lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN 1053 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 1054 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1055 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 1056 lp.format = PixelFormat.TRANSLUCENT; 1057 lp.setTitle("PointerLocation"); 1058 WindowManager wm = (WindowManager) 1059 mContext.getSystemService(Context.WINDOW_SERVICE); 1060 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; 1061 wm.addView(addView, lp); 1062 1063 if (mPointerLocationInputChannel == null) { 1064 try { 1065 mPointerLocationInputChannel = 1066 mWindowManager.monitorInput("PointerLocationView"); 1067 mPointerLocationInputEventReceiver = 1068 new PointerLocationInputEventReceiver( 1069 mPointerLocationInputChannel, mHandler.getLooper()); 1070 } catch (RemoteException ex) { 1071 Slog.e(TAG, "Could not set up input monitoring channel for PointerLocation.", 1072 ex); 1073 } 1074 } 1075 } 1076 if (removeView != null) { 1077 if (mPointerLocationInputEventReceiver != null) { 1078 mPointerLocationInputEventReceiver.dispose(); 1079 mPointerLocationInputEventReceiver = null; 1080 } 1081 if (mPointerLocationInputChannel != null) { 1082 mPointerLocationInputChannel.dispose(); 1083 mPointerLocationInputChannel = null; 1084 } 1085 1086 WindowManager wm = (WindowManager) 1087 mContext.getSystemService(Context.WINDOW_SERVICE); 1088 wm.removeView(removeView); 1089 } 1090 } 1091 1092 private int readRotation(int resID) { 1093 try { 1094 int rotation = mContext.getResources().getInteger(resID); 1095 switch (rotation) { 1096 case 0: 1097 return Surface.ROTATION_0; 1098 case 90: 1099 return Surface.ROTATION_90; 1100 case 180: 1101 return Surface.ROTATION_180; 1102 case 270: 1103 return Surface.ROTATION_270; 1104 } 1105 } catch (Resources.NotFoundException e) { 1106 // fall through 1107 } 1108 return -1; 1109 } 1110 1111 /** {@inheritDoc} */ 1112 public int checkAddPermission(WindowManager.LayoutParams attrs) { 1113 int type = attrs.type; 1114 1115 if (type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW 1116 || type > WindowManager.LayoutParams.LAST_SYSTEM_WINDOW) { 1117 return WindowManagerImpl.ADD_OKAY; 1118 } 1119 String permission = null; 1120 switch (type) { 1121 case TYPE_TOAST: 1122 // XXX right now the app process has complete control over 1123 // this... should introduce a token to let the system 1124 // monitor/control what they are doing. 1125 break; 1126 case TYPE_INPUT_METHOD: 1127 case TYPE_WALLPAPER: 1128 // The window manager will check these. 1129 break; 1130 case TYPE_PHONE: 1131 case TYPE_PRIORITY_PHONE: 1132 case TYPE_SYSTEM_ALERT: 1133 case TYPE_SYSTEM_ERROR: 1134 case TYPE_SYSTEM_OVERLAY: 1135 permission = android.Manifest.permission.SYSTEM_ALERT_WINDOW; 1136 break; 1137 default: 1138 permission = android.Manifest.permission.INTERNAL_SYSTEM_WINDOW; 1139 } 1140 if (permission != null) { 1141 if (mContext.checkCallingOrSelfPermission(permission) 1142 != PackageManager.PERMISSION_GRANTED) { 1143 return WindowManagerImpl.ADD_PERMISSION_DENIED; 1144 } 1145 } 1146 return WindowManagerImpl.ADD_OKAY; 1147 } 1148 1149 public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) { 1150 switch (attrs.type) { 1151 case TYPE_SYSTEM_OVERLAY: 1152 case TYPE_SECURE_SYSTEM_OVERLAY: 1153 case TYPE_TOAST: 1154 // These types of windows can't receive input events. 1155 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 1156 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 1157 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; 1158 break; 1159 } 1160 } 1161 1162 void readLidState() { 1163 try { 1164 int sw = mWindowManager.getSwitchState(SW_LID); 1165 if (sw > 0) { 1166 mLidOpen = LID_OPEN; 1167 } else if (sw == 0) { 1168 mLidOpen = LID_CLOSED; 1169 } else { 1170 mLidOpen = LID_ABSENT; 1171 } 1172 } catch (RemoteException e) { 1173 // Ignore 1174 } 1175 } 1176 1177 private int determineHiddenState(int mode, int hiddenValue, int visibleValue) { 1178 if (mLidOpen != LID_ABSENT) { 1179 switch (mode) { 1180 case 1: 1181 return mLidOpen == LID_OPEN ? visibleValue : hiddenValue; 1182 case 2: 1183 return mLidOpen == LID_OPEN ? hiddenValue : visibleValue; 1184 } 1185 } 1186 return visibleValue; 1187 } 1188 1189 /** {@inheritDoc} */ 1190 public void adjustConfigurationLw(Configuration config) { 1191 readLidState(); 1192 updateKeyboardVisibility(); 1193 1194 if (config.keyboard == Configuration.KEYBOARD_NOKEYS) { 1195 config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_YES; 1196 } else { 1197 config.hardKeyboardHidden = determineHiddenState(mLidKeyboardAccessibility, 1198 Configuration.HARDKEYBOARDHIDDEN_YES, Configuration.HARDKEYBOARDHIDDEN_NO); 1199 } 1200 1201 if (config.navigation == Configuration.NAVIGATION_NONAV) { 1202 config.navigationHidden = Configuration.NAVIGATIONHIDDEN_YES; 1203 } else { 1204 config.navigationHidden = determineHiddenState(mLidNavigationAccessibility, 1205 Configuration.NAVIGATIONHIDDEN_YES, Configuration.NAVIGATIONHIDDEN_NO); 1206 } 1207 1208 if (mHasSoftInput || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) { 1209 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO; 1210 } else { 1211 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_YES; 1212 } 1213 } 1214 1215 /** {@inheritDoc} */ 1216 public int windowTypeToLayerLw(int type) { 1217 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { 1218 return APPLICATION_LAYER; 1219 } 1220 switch (type) { 1221 case TYPE_STATUS_BAR: 1222 return STATUS_BAR_LAYER; 1223 case TYPE_STATUS_BAR_PANEL: 1224 return STATUS_BAR_PANEL_LAYER; 1225 case TYPE_STATUS_BAR_SUB_PANEL: 1226 return STATUS_BAR_SUB_PANEL_LAYER; 1227 case TYPE_SYSTEM_DIALOG: 1228 return SYSTEM_DIALOG_LAYER; 1229 case TYPE_SEARCH_BAR: 1230 return SEARCH_BAR_LAYER; 1231 case TYPE_PHONE: 1232 return PHONE_LAYER; 1233 case TYPE_KEYGUARD: 1234 return KEYGUARD_LAYER; 1235 case TYPE_KEYGUARD_DIALOG: 1236 return KEYGUARD_DIALOG_LAYER; 1237 case TYPE_SYSTEM_ALERT: 1238 return SYSTEM_ALERT_LAYER; 1239 case TYPE_SYSTEM_ERROR: 1240 return SYSTEM_ERROR_LAYER; 1241 case TYPE_INPUT_METHOD: 1242 return INPUT_METHOD_LAYER; 1243 case TYPE_INPUT_METHOD_DIALOG: 1244 return INPUT_METHOD_DIALOG_LAYER; 1245 case TYPE_VOLUME_OVERLAY: 1246 return VOLUME_OVERLAY_LAYER; 1247 case TYPE_SYSTEM_OVERLAY: 1248 return SYSTEM_OVERLAY_LAYER; 1249 case TYPE_SECURE_SYSTEM_OVERLAY: 1250 return SECURE_SYSTEM_OVERLAY_LAYER; 1251 case TYPE_PRIORITY_PHONE: 1252 return PRIORITY_PHONE_LAYER; 1253 case TYPE_TOAST: 1254 return TOAST_LAYER; 1255 case TYPE_WALLPAPER: 1256 return WALLPAPER_LAYER; 1257 case TYPE_DRAG: 1258 return DRAG_LAYER; 1259 case TYPE_POINTER: 1260 return POINTER_LAYER; 1261 case TYPE_NAVIGATION_BAR: 1262 return NAVIGATION_BAR_LAYER; 1263 case TYPE_BOOT_PROGRESS: 1264 return BOOT_PROGRESS_LAYER; 1265 case TYPE_HIDDEN_NAV_CONSUMER: 1266 return HIDDEN_NAV_CONSUMER_LAYER; 1267 } 1268 Log.e(TAG, "Unknown window type: " + type); 1269 return APPLICATION_LAYER; 1270 } 1271 1272 /** {@inheritDoc} */ 1273 public int subWindowTypeToLayerLw(int type) { 1274 switch (type) { 1275 case TYPE_APPLICATION_PANEL: 1276 case TYPE_APPLICATION_ATTACHED_DIALOG: 1277 return APPLICATION_PANEL_SUBLAYER; 1278 case TYPE_APPLICATION_MEDIA: 1279 return APPLICATION_MEDIA_SUBLAYER; 1280 case TYPE_APPLICATION_MEDIA_OVERLAY: 1281 return APPLICATION_MEDIA_OVERLAY_SUBLAYER; 1282 case TYPE_APPLICATION_SUB_PANEL: 1283 return APPLICATION_SUB_PANEL_SUBLAYER; 1284 } 1285 Log.e(TAG, "Unknown sub-window type: " + type); 1286 return 0; 1287 } 1288 1289 public int getMaxWallpaperLayer() { 1290 return STATUS_BAR_LAYER; 1291 } 1292 1293 public boolean canStatusBarHide() { 1294 return mStatusBarCanHide; 1295 } 1296 1297 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) { 1298 // Assumes that the navigation bar appears on the side of the display in landscape. 1299 if (fullWidth > fullHeight) { 1300 return fullWidth - mNavigationBarWidth; 1301 } 1302 return fullWidth; 1303 } 1304 1305 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) { 1306 // Assumes the navigation bar appears on the bottom of the display in portrait. 1307 return fullHeight 1308 - (mStatusBarCanHide ? 0 : mStatusBarHeight) 1309 - ((fullWidth > fullHeight) ? 0 : mNavigationBarHeight); 1310 } 1311 1312 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation) { 1313 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation); 1314 } 1315 1316 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) { 1317 // This is the same as getNonDecorDisplayHeight, unless the status bar 1318 // can hide. If the status bar can hide, we don't count that as part 1319 // of the decor; however for purposes of configurations, we do want to 1320 // exclude it since applications can't generally use that part of the 1321 // screen. 1322 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation) 1323 - (mStatusBarCanHide ? mStatusBarHeight : 0); 1324 } 1325 1326 public boolean doesForceHide(WindowState win, WindowManager.LayoutParams attrs) { 1327 return attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD; 1328 } 1329 1330 public boolean canBeForceHidden(WindowState win, WindowManager.LayoutParams attrs) { 1331 return attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR 1332 && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER; 1333 } 1334 1335 /** {@inheritDoc} */ 1336 public View addStartingWindow(IBinder appToken, String packageName, int theme, 1337 CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, 1338 int icon, int windowFlags) { 1339 if (!SHOW_STARTING_ANIMATIONS) { 1340 return null; 1341 } 1342 if (packageName == null) { 1343 return null; 1344 } 1345 1346 try { 1347 Context context = mContext; 1348 //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel=" 1349 // + nonLocalizedLabel + " theme=" + Integer.toHexString(theme)); 1350 if (theme != context.getThemeResId() || labelRes != 0) { 1351 try { 1352 context = context.createPackageContext(packageName, 0); 1353 context.setTheme(theme); 1354 } catch (PackageManager.NameNotFoundException e) { 1355 // Ignore 1356 } 1357 } 1358 1359 Window win = PolicyManager.makeNewWindow(context); 1360 if (win.getWindowStyle().getBoolean( 1361 com.android.internal.R.styleable.Window_windowDisablePreview, false)) { 1362 return null; 1363 } 1364 1365 Resources r = context.getResources(); 1366 win.setTitle(r.getText(labelRes, nonLocalizedLabel)); 1367 1368 win.setType( 1369 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); 1370 // Force the window flags: this is a fake window, so it is not really 1371 // touchable or focusable by the user. We also add in the ALT_FOCUSABLE_IM 1372 // flag because we do know that the next window will take input 1373 // focus, so we want to get the IME window up on top of us right away. 1374 win.setFlags( 1375 windowFlags| 1376 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| 1377 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| 1378 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, 1379 windowFlags| 1380 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE| 1381 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| 1382 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); 1383 1384 if (!compatInfo.supportsScreen()) { 1385 win.addFlags(WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW); 1386 } 1387 1388 win.setLayout(WindowManager.LayoutParams.MATCH_PARENT, 1389 WindowManager.LayoutParams.MATCH_PARENT); 1390 1391 final WindowManager.LayoutParams params = win.getAttributes(); 1392 params.token = appToken; 1393 params.packageName = packageName; 1394 params.windowAnimations = win.getWindowStyle().getResourceId( 1395 com.android.internal.R.styleable.Window_windowAnimationStyle, 0); 1396 params.privateFlags |= 1397 WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED; 1398 params.setTitle("Starting " + packageName); 1399 1400 WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); 1401 View view = win.getDecorView(); 1402 1403 if (win.isFloating()) { 1404 // Whoops, there is no way to display an animation/preview 1405 // of such a thing! After all that work... let's skip it. 1406 // (Note that we must do this here because it is in 1407 // getDecorView() where the theme is evaluated... maybe 1408 // we should peek the floating attribute from the theme 1409 // earlier.) 1410 return null; 1411 } 1412 1413 if (localLOGV) Log.v( 1414 TAG, "Adding starting window for " + packageName 1415 + " / " + appToken + ": " 1416 + (view.getParent() != null ? view : null)); 1417 1418 wm.addView(view, params); 1419 1420 // Only return the view if it was successfully added to the 1421 // window manager... which we can tell by it having a parent. 1422 return view.getParent() != null ? view : null; 1423 } catch (WindowManagerImpl.BadTokenException e) { 1424 // ignore 1425 Log.w(TAG, appToken + " already running, starting window not displayed"); 1426 } catch (RuntimeException e) { 1427 // don't crash if something else bad happens, for example a 1428 // failure loading resources because we are loading from an app 1429 // on external storage that has been unmounted. 1430 Log.w(TAG, appToken + " failed creating starting window", e); 1431 } 1432 1433 return null; 1434 } 1435 1436 /** {@inheritDoc} */ 1437 public void removeStartingWindow(IBinder appToken, View window) { 1438 // RuntimeException e = new RuntimeException(); 1439 // Log.i(TAG, "remove " + appToken + " " + window, e); 1440 1441 if (localLOGV) Log.v( 1442 TAG, "Removing starting window for " + appToken + ": " + window); 1443 1444 if (window != null) { 1445 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); 1446 wm.removeView(window); 1447 } 1448 } 1449 1450 /** 1451 * Preflight adding a window to the system. 1452 * 1453 * Currently enforces that three window types are singletons: 1454 * <ul> 1455 * <li>STATUS_BAR_TYPE</li> 1456 * <li>KEYGUARD_TYPE</li> 1457 * </ul> 1458 * 1459 * @param win The window to be added 1460 * @param attrs Information about the window to be added 1461 * 1462 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, WindowManagerImpl.ADD_MULTIPLE_SINGLETON 1463 */ 1464 public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) { 1465 switch (attrs.type) { 1466 case TYPE_STATUS_BAR: 1467 mContext.enforceCallingOrSelfPermission( 1468 android.Manifest.permission.STATUS_BAR_SERVICE, 1469 "PhoneWindowManager"); 1470 // TODO: Need to handle the race condition of the status bar proc 1471 // dying and coming back before the removeWindowLw cleanup has happened. 1472 if (mStatusBar != null) { 1473 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; 1474 } 1475 mStatusBar = win; 1476 break; 1477 case TYPE_NAVIGATION_BAR: 1478 mContext.enforceCallingOrSelfPermission( 1479 android.Manifest.permission.STATUS_BAR_SERVICE, 1480 "PhoneWindowManager"); 1481 mNavigationBar = win; 1482 if (DEBUG_LAYOUT) Log.i(TAG, "NAVIGATION BAR: " + mNavigationBar); 1483 break; 1484 case TYPE_STATUS_BAR_PANEL: 1485 mContext.enforceCallingOrSelfPermission( 1486 android.Manifest.permission.STATUS_BAR_SERVICE, 1487 "PhoneWindowManager"); 1488 mStatusBarPanels.add(win); 1489 break; 1490 case TYPE_STATUS_BAR_SUB_PANEL: 1491 mContext.enforceCallingOrSelfPermission( 1492 android.Manifest.permission.STATUS_BAR_SERVICE, 1493 "PhoneWindowManager"); 1494 mStatusBarPanels.add(win); 1495 break; 1496 case TYPE_KEYGUARD: 1497 if (mKeyguard != null) { 1498 return WindowManagerImpl.ADD_MULTIPLE_SINGLETON; 1499 } 1500 mKeyguard = win; 1501 break; 1502 } 1503 return WindowManagerImpl.ADD_OKAY; 1504 } 1505 1506 /** {@inheritDoc} */ 1507 public void removeWindowLw(WindowState win) { 1508 if (mStatusBar == win) { 1509 mStatusBar = null; 1510 } else if (mKeyguard == win) { 1511 mKeyguard = null; 1512 } else if (mNavigationBar == win) { 1513 mNavigationBar = null; 1514 } else { 1515 mStatusBarPanels.remove(win); 1516 } 1517 } 1518 1519 static final boolean PRINT_ANIM = false; 1520 1521 /** {@inheritDoc} */ 1522 public int selectAnimationLw(WindowState win, int transit) { 1523 if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win 1524 + ": transit=" + transit); 1525 if (transit == TRANSIT_PREVIEW_DONE) { 1526 if (win.hasAppShownWindows()) { 1527 if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT"); 1528 return com.android.internal.R.anim.app_starting_exit; 1529 } 1530 } 1531 1532 return 0; 1533 } 1534 1535 public Animation createForceHideEnterAnimation() { 1536 return AnimationUtils.loadAnimation(mContext, 1537 com.android.internal.R.anim.lock_screen_behind_enter); 1538 } 1539 1540 static ITelephony getTelephonyService() { 1541 return ITelephony.Stub.asInterface( 1542 ServiceManager.checkService(Context.TELEPHONY_SERVICE)); 1543 } 1544 1545 static IAudioService getAudioService() { 1546 IAudioService audioService = IAudioService.Stub.asInterface( 1547 ServiceManager.checkService(Context.AUDIO_SERVICE)); 1548 if (audioService == null) { 1549 Log.w(TAG, "Unable to find IAudioService interface."); 1550 } 1551 return audioService; 1552 } 1553 1554 boolean keyguardOn() { 1555 return keyguardIsShowingTq() || inKeyguardRestrictedKeyInputMode(); 1556 } 1557 1558 private static final int[] WINDOW_TYPES_WHERE_HOME_DOESNT_WORK = { 1559 WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, 1560 WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, 1561 }; 1562 1563 /** {@inheritDoc} */ 1564 @Override 1565 public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) { 1566 final boolean keyguardOn = keyguardOn(); 1567 final int keyCode = event.getKeyCode(); 1568 final int repeatCount = event.getRepeatCount(); 1569 final int metaState = event.getMetaState(); 1570 final int flags = event.getFlags(); 1571 final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; 1572 final boolean canceled = event.isCanceled(); 1573 1574 if (false) { 1575 Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount=" 1576 + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed); 1577 } 1578 1579 // If we think we might have a volume down & power key chord on the way 1580 // but we're not sure, then tell the dispatcher to wait a little while and 1581 // try again later before dispatching. 1582 if (mScreenshotChordEnabled && (flags & KeyEvent.FLAG_FALLBACK) == 0) { 1583 if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) { 1584 final long now = SystemClock.uptimeMillis(); 1585 final long timeoutTime = mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS; 1586 if (now < timeoutTime) { 1587 return timeoutTime - now; 1588 } 1589 } 1590 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN 1591 && mVolumeDownKeyConsumedByScreenshotChord) { 1592 if (!down) { 1593 mVolumeDownKeyConsumedByScreenshotChord = false; 1594 } 1595 return -1; 1596 } 1597 } 1598 1599 // First we always handle the home key here, so applications 1600 // can never break it, although if keyguard is on, we do let 1601 // it handle it, because that gives us the correct 5 second 1602 // timeout. 1603 if (keyCode == KeyEvent.KEYCODE_HOME) { 1604 // If we have released the home key, and didn't do anything else 1605 // while it was pressed, then it is time to go home! 1606 if (mHomePressed && !down) { 1607 mHomePressed = false; 1608 if (!canceled) { 1609 // If an incoming call is ringing, HOME is totally disabled. 1610 // (The user is already on the InCallScreen at this point, 1611 // and his ONLY options are to answer or reject the call.) 1612 boolean incomingRinging = false; 1613 try { 1614 ITelephony telephonyService = getTelephonyService(); 1615 if (telephonyService != null) { 1616 incomingRinging = telephonyService.isRinging(); 1617 } 1618 } catch (RemoteException ex) { 1619 Log.w(TAG, "RemoteException from getPhoneInterface()", ex); 1620 } 1621 1622 if (incomingRinging) { 1623 Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); 1624 } else { 1625 launchHomeFromHotKey(); 1626 } 1627 } else { 1628 Log.i(TAG, "Ignoring HOME; event canceled."); 1629 } 1630 return -1; 1631 } 1632 1633 // If a system window has focus, then it doesn't make sense 1634 // right now to interact with applications. 1635 WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null; 1636 if (attrs != null) { 1637 final int type = attrs.type; 1638 if (type == WindowManager.LayoutParams.TYPE_KEYGUARD 1639 || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) { 1640 // the "app" is keyguard, so give it the key 1641 return 0; 1642 } 1643 final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length; 1644 for (int i=0; i<typeCount; i++) { 1645 if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) { 1646 // don't do anything, but also don't pass it to the app 1647 return -1; 1648 } 1649 } 1650 } 1651 1652 if (down) { 1653 if (repeatCount == 0) { 1654 mHomePressed = true; 1655 } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { 1656 if (!keyguardOn) { 1657 handleLongPressOnHome(); 1658 } 1659 } 1660 } 1661 return -1; 1662 } else if (keyCode == KeyEvent.KEYCODE_MENU) { 1663 // Hijack modified menu keys for debugging features 1664 final int chordBug = KeyEvent.META_SHIFT_ON; 1665 1666 if (down && repeatCount == 0) { 1667 if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) { 1668 Intent intent = new Intent(Intent.ACTION_BUG_REPORT); 1669 mContext.sendOrderedBroadcast(intent, null); 1670 return -1; 1671 } else if (SHOW_PROCESSES_ON_ALT_MENU && 1672 (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) { 1673 Intent service = new Intent(); 1674 service.setClassName(mContext, "com.android.server.LoadAverageService"); 1675 ContentResolver res = mContext.getContentResolver(); 1676 boolean shown = Settings.System.getInt( 1677 res, Settings.System.SHOW_PROCESSES, 0) != 0; 1678 if (!shown) { 1679 mContext.startService(service); 1680 } else { 1681 mContext.stopService(service); 1682 } 1683 Settings.System.putInt( 1684 res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1); 1685 return -1; 1686 } 1687 } 1688 } else if (keyCode == KeyEvent.KEYCODE_SEARCH) { 1689 if (down) { 1690 if (repeatCount == 0) { 1691 mShortcutKeyPressed = keyCode; 1692 mConsumeShortcutKeyUp = false; 1693 } 1694 } else if (keyCode == mShortcutKeyPressed) { 1695 mShortcutKeyPressed = -1; 1696 if (mConsumeShortcutKeyUp) { 1697 mConsumeShortcutKeyUp = false; 1698 return -1; 1699 } 1700 } 1701 return 0; 1702 } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) { 1703 if (down && repeatCount == 0) { 1704 showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_SHOW_OR_DISMISS); 1705 } 1706 return -1; 1707 } 1708 1709 // Shortcuts are invoked through Search+key, so intercept those here 1710 // Any printing key that is chorded with Search should be consumed 1711 // even if no shortcut was invoked. This prevents text from being 1712 // inadvertently inserted when using a keyboard that has built-in macro 1713 // shortcut keys (that emit Search+x) and some of them are not registered. 1714 if (mShortcutKeyPressed != -1) { 1715 final KeyCharacterMap kcm = event.getKeyCharacterMap(); 1716 if (kcm.isPrintingKey(keyCode)) { 1717 mConsumeShortcutKeyUp = true; 1718 if (down && repeatCount == 0 && !keyguardOn) { 1719 Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, metaState); 1720 if (shortcutIntent != null) { 1721 shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1722 try { 1723 mContext.startActivity(shortcutIntent); 1724 } catch (ActivityNotFoundException ex) { 1725 Slog.w(TAG, "Dropping shortcut key combination because " 1726 + "the activity to which it is registered was not found: " 1727 + KeyEvent.keyCodeToString(mShortcutKeyPressed) 1728 + "+" + KeyEvent.keyCodeToString(keyCode), ex); 1729 } 1730 } else { 1731 Slog.i(TAG, "Dropping unregistered shortcut key combination: " 1732 + KeyEvent.keyCodeToString(mShortcutKeyPressed) 1733 + "+" + KeyEvent.keyCodeToString(keyCode)); 1734 } 1735 } 1736 return -1; 1737 } 1738 } 1739 1740 // Invoke shortcuts using Meta. 1741 if (down && repeatCount == 0 1742 && (metaState & KeyEvent.META_META_ON) != 0) { 1743 final KeyCharacterMap kcm = event.getKeyCharacterMap(); 1744 Intent shortcutIntent = mShortcutManager.getIntent(kcm, keyCode, 1745 metaState & ~(KeyEvent.META_META_ON 1746 | KeyEvent.META_META_LEFT_ON | KeyEvent.META_META_RIGHT_ON)); 1747 if (shortcutIntent != null) { 1748 shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1749 try { 1750 mContext.startActivity(shortcutIntent); 1751 } catch (ActivityNotFoundException ex) { 1752 Slog.w(TAG, "Dropping shortcut key combination because " 1753 + "the activity to which it is registered was not found: " 1754 + "META+" + KeyEvent.keyCodeToString(keyCode), ex); 1755 } 1756 return -1; 1757 } 1758 } 1759 1760 // Handle application launch keys. 1761 if (down && repeatCount == 0) { 1762 String category = sApplicationLaunchKeyCategories.get(keyCode); 1763 if (category != null) { 1764 Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category); 1765 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1766 try { 1767 mContext.startActivity(intent); 1768 } catch (ActivityNotFoundException ex) { 1769 Slog.w(TAG, "Dropping application launch key because " 1770 + "the activity to which it is registered was not found: " 1771 + "keyCode=" + keyCode + ", category=" + category, ex); 1772 } 1773 return -1; 1774 } 1775 } 1776 1777 // Display task switcher for ALT-TAB or Meta-TAB. 1778 if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) { 1779 if (mRecentAppsDialogHeldModifiers == 0) { 1780 final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK; 1781 if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON) 1782 || KeyEvent.metaStateHasModifiers( 1783 shiftlessModifiers, KeyEvent.META_META_ON)) { 1784 mRecentAppsDialogHeldModifiers = shiftlessModifiers; 1785 showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_EXIT_TOUCH_MODE_AND_SHOW); 1786 return -1; 1787 } 1788 } 1789 } else if (!down && mRecentAppsDialogHeldModifiers != 0 1790 && (metaState & mRecentAppsDialogHeldModifiers) == 0) { 1791 mRecentAppsDialogHeldModifiers = 0; 1792 showOrHideRecentAppsDialog(RECENT_APPS_BEHAVIOR_DISMISS_AND_SWITCH); 1793 } 1794 1795 // Let the application handle the key. 1796 return 0; 1797 } 1798 1799 /** {@inheritDoc} */ 1800 @Override 1801 public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) { 1802 // Note: This method is only called if the initial down was unhandled. 1803 if (DEBUG_FALLBACK) { 1804 Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction() 1805 + ", flags=" + event.getFlags() 1806 + ", keyCode=" + event.getKeyCode() 1807 + ", scanCode=" + event.getScanCode() 1808 + ", metaState=" + event.getMetaState() 1809 + ", repeatCount=" + event.getRepeatCount() 1810 + ", policyFlags=" + policyFlags); 1811 } 1812 1813 if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { 1814 final KeyCharacterMap kcm = event.getKeyCharacterMap(); 1815 final int keyCode = event.getKeyCode(); 1816 final int metaState = event.getMetaState(); 1817 1818 // Check for fallback actions specified by the key character map. 1819 if (getFallbackAction(kcm, keyCode, metaState, mFallbackAction)) { 1820 if (DEBUG_FALLBACK) { 1821 Slog.d(TAG, "Fallback: keyCode=" + mFallbackAction.keyCode 1822 + " metaState=" + Integer.toHexString(mFallbackAction.metaState)); 1823 } 1824 1825 int flags = event.getFlags() | KeyEvent.FLAG_FALLBACK; 1826 KeyEvent fallbackEvent = KeyEvent.obtain( 1827 event.getDownTime(), event.getEventTime(), 1828 event.getAction(), mFallbackAction.keyCode, 1829 event.getRepeatCount(), mFallbackAction.metaState, 1830 event.getDeviceId(), event.getScanCode(), 1831 flags, event.getSource(), null); 1832 int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true); 1833 if ((actions & ACTION_PASS_TO_USER) != 0) { 1834 long delayMillis = interceptKeyBeforeDispatching( 1835 win, fallbackEvent, policyFlags); 1836 if (delayMillis == 0) { 1837 if (DEBUG_FALLBACK) { 1838 Slog.d(TAG, "Performing fallback."); 1839 } 1840 return fallbackEvent; 1841 } 1842 } 1843 fallbackEvent.recycle(); 1844 } 1845 } 1846 1847 if (DEBUG_FALLBACK) { 1848 Slog.d(TAG, "No fallback."); 1849 } 1850 return null; 1851 } 1852 1853 private boolean getFallbackAction(KeyCharacterMap kcm, int keyCode, int metaState, 1854 FallbackAction outFallbackAction) { 1855 // Consult the key character map for specific fallback actions. 1856 // For example, map NUMPAD_1 to MOVE_HOME when NUMLOCK is not pressed. 1857 return kcm.getFallbackAction(keyCode, metaState, outFallbackAction); 1858 } 1859 1860 /** 1861 * A home key -> launch home action was detected. Take the appropriate action 1862 * given the situation with the keyguard. 1863 */ 1864 void launchHomeFromHotKey() { 1865 if (mKeyguardMediator != null && mKeyguardMediator.isShowingAndNotHidden()) { 1866 // don't launch home if keyguard showing 1867 } else if (!mHideLockScreen && mKeyguardMediator.isInputRestricted()) { 1868 // when in keyguard restricted mode, must first verify unlock 1869 // before launching home 1870 mKeyguardMediator.verifyUnlock(new OnKeyguardExitResult() { 1871 public void onKeyguardExitResult(boolean success) { 1872 if (success) { 1873 try { 1874 ActivityManagerNative.getDefault().stopAppSwitches(); 1875 } catch (RemoteException e) { 1876 } 1877 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); 1878 startDockOrHome(); 1879 } 1880 } 1881 }); 1882 } else { 1883 // no keyguard stuff to worry about, just launch home! 1884 try { 1885 ActivityManagerNative.getDefault().stopAppSwitches(); 1886 } catch (RemoteException e) { 1887 } 1888 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY); 1889 startDockOrHome(); 1890 } 1891 } 1892 1893 /** 1894 * A delayed callback use to determine when it is okay to re-allow applications 1895 * to use certain system UI flags. This is used to prevent applications from 1896 * spamming system UI changes that prevent the navigation bar from being shown. 1897 */ 1898 final Runnable mAllowSystemUiDelay = new Runnable() { 1899 @Override public void run() { 1900 } 1901 }; 1902 1903 /** 1904 * Input handler used while nav bar is hidden. Captures any touch on the screen, 1905 * to determine when the nav bar should be shown and prevent applications from 1906 * receiving those touches. 1907 */ 1908 final class HideNavInputEventReceiver extends InputEventReceiver { 1909 public HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) { 1910 super(inputChannel, looper); 1911 } 1912 1913 @Override 1914 public void onInputEvent(InputEvent event) { 1915 boolean handled = false; 1916 try { 1917 if (event instanceof MotionEvent 1918 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { 1919 final MotionEvent motionEvent = (MotionEvent)event; 1920 if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { 1921 // When the user taps down, we re-show the nav bar. 1922 boolean changed = false; 1923 synchronized (mLock) { 1924 // Any user activity always causes us to show the navigation controls, 1925 // if they had been hidden. 1926 int newVal = mResettingSystemUiFlags 1927 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 1928 if (mResettingSystemUiFlags != newVal) { 1929 mResettingSystemUiFlags = newVal; 1930 changed = true; 1931 } 1932 // We don't allow the system's nav bar to be hidden 1933 // again for 1 second, to prevent applications from 1934 // spamming us and keeping it from being shown. 1935 newVal = mForceClearedSystemUiFlags 1936 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 1937 if (mForceClearedSystemUiFlags != newVal) { 1938 mForceClearedSystemUiFlags = newVal; 1939 changed = true; 1940 mHandler.postDelayed(new Runnable() { 1941 @Override public void run() { 1942 synchronized (mLock) { 1943 mForceClearedSystemUiFlags &= 1944 ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 1945 } 1946 mWindowManagerFuncs.reevaluateStatusBarVisibility(); 1947 } 1948 }, 1000); 1949 } 1950 } 1951 if (changed) { 1952 mWindowManagerFuncs.reevaluateStatusBarVisibility(); 1953 } 1954 } 1955 } 1956 } finally { 1957 finishInputEvent(event, handled); 1958 } 1959 } 1960 } 1961 final InputEventReceiver.Factory mHideNavInputEventReceiverFactory = 1962 new InputEventReceiver.Factory() { 1963 @Override 1964 public InputEventReceiver createInputEventReceiver( 1965 InputChannel inputChannel, Looper looper) { 1966 return new HideNavInputEventReceiver(inputChannel, looper); 1967 } 1968 }; 1969 1970 @Override 1971 public int adjustSystemUiVisibilityLw(int visibility) { 1972 // Reset any bits in mForceClearingStatusBarVisibility that 1973 // are now clear. 1974 mResettingSystemUiFlags &= visibility; 1975 // Clear any bits in the new visibility that are currently being 1976 // force cleared, before reporting it. 1977 return visibility & ~mResettingSystemUiFlags 1978 & ~mForceClearedSystemUiFlags; 1979 } 1980 1981 public void getContentInsetHintLw(WindowManager.LayoutParams attrs, Rect contentInset) { 1982 final int fl = attrs.flags; 1983 1984 if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) 1985 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { 1986 contentInset.set(mCurLeft, mCurTop, 1987 (mRestrictedScreenLeft+mRestrictedScreenWidth) - mCurRight, 1988 (mRestrictedScreenTop+mRestrictedScreenHeight) - mCurBottom); 1989 } else { 1990 contentInset.setEmpty(); 1991 } 1992 } 1993 1994 /** {@inheritDoc} */ 1995 public void beginLayoutLw(int displayWidth, int displayHeight, int displayRotation) { 1996 mUnrestrictedScreenLeft = mUnrestrictedScreenTop = 0; 1997 mUnrestrictedScreenWidth = displayWidth; 1998 mUnrestrictedScreenHeight = displayHeight; 1999 mRestrictedScreenLeft = mRestrictedScreenTop = 0; 2000 mRestrictedScreenWidth = displayWidth; 2001 mRestrictedScreenHeight = displayHeight; 2002 mDockLeft = mContentLeft = mCurLeft = 0; 2003 mDockTop = mContentTop = mCurTop = 0; 2004 mDockRight = mContentRight = mCurRight = displayWidth; 2005 mDockBottom = mContentBottom = mCurBottom = displayHeight; 2006 mDockLayer = 0x10000000; 2007 2008 // start with the current dock rect, which will be (0,0,displayWidth,displayHeight) 2009 final Rect pf = mTmpParentFrame; 2010 final Rect df = mTmpDisplayFrame; 2011 final Rect vf = mTmpVisibleFrame; 2012 pf.left = df.left = vf.left = mDockLeft; 2013 pf.top = df.top = vf.top = mDockTop; 2014 pf.right = df.right = vf.right = mDockRight; 2015 pf.bottom = df.bottom = vf.bottom = mDockBottom; 2016 2017 final boolean navVisible = (mNavigationBar == null || mNavigationBar.isVisibleLw()) && 2018 (mLastSystemUiFlags&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; 2019 2020 // When the navigation bar isn't visible, we put up a fake 2021 // input window to catch all touch events. This way we can 2022 // detect when the user presses anywhere to bring back the nav 2023 // bar and ensure the application doesn't see the event. 2024 if (navVisible) { 2025 if (mHideNavFakeWindow != null) { 2026 mHideNavFakeWindow.dismiss(); 2027 mHideNavFakeWindow = null; 2028 } 2029 } else if (mHideNavFakeWindow == null) { 2030 mHideNavFakeWindow = mWindowManagerFuncs.addFakeWindow( 2031 mHandler.getLooper(), mHideNavInputEventReceiverFactory, 2032 "hidden nav", WindowManager.LayoutParams.TYPE_HIDDEN_NAV_CONSUMER, 2033 0, false, false, true); 2034 } 2035 2036 // decide where the status bar goes ahead of time 2037 if (mStatusBar != null) { 2038 if (mNavigationBar != null) { 2039 // Force the navigation bar to its appropriate place and 2040 // size. We need to do this directly, instead of relying on 2041 // it to bubble up from the nav bar, because this needs to 2042 // change atomically with screen rotations. 2043 if (displayWidth < displayHeight) { 2044 // Portrait screen; nav bar goes on bottom. 2045 mTmpNavigationFrame.set(0, displayHeight-mNavigationBarHeight, 2046 displayWidth, displayHeight); 2047 if (navVisible) { 2048 mDockBottom = mTmpNavigationFrame.top; 2049 mRestrictedScreenHeight = mDockBottom - mDockTop; 2050 } else { 2051 // We currently want to hide the navigation UI. Do this by just 2052 // moving it off the screen, so it can still receive input events 2053 // to know when to be re-shown. 2054 mTmpNavigationFrame.offset(0, mNavigationBarHeight); 2055 } 2056 } else { 2057 // Landscape screen; nav bar goes to the right. 2058 mTmpNavigationFrame.set(displayWidth-mNavigationBarWidth, 0, 2059 displayWidth, displayHeight); 2060 if (navVisible) { 2061 mDockRight = mTmpNavigationFrame.left; 2062 mRestrictedScreenWidth = mDockRight - mDockLeft; 2063 } else { 2064 // We currently want to hide the navigation UI. Do this by just 2065 // moving it off the screen, so it can still receive input events 2066 // to know when to be re-shown. 2067 mTmpNavigationFrame.offset(mNavigationBarWidth, 0); 2068 } 2069 } 2070 // Make sure the content and current rectangles are updated to 2071 // account for the restrictions from the navigation bar. 2072 mContentTop = mCurTop = mDockTop; 2073 mContentBottom = mCurBottom = mDockBottom; 2074 mContentLeft = mCurLeft = mDockLeft; 2075 mContentRight = mCurRight = mDockRight; 2076 // And compute the final frame. 2077 mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame, 2078 mTmpNavigationFrame, mTmpNavigationFrame); 2079 if (DEBUG_LAYOUT) Log.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame); 2080 } 2081 if (DEBUG_LAYOUT) Log.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)", 2082 mDockLeft, mDockTop, mDockRight, mDockBottom)); 2083 2084 // apply navigation bar insets 2085 pf.left = df.left = vf.left = mDockLeft; 2086 pf.top = df.top = vf.top = mDockTop; 2087 pf.right = df.right = vf.right = mDockRight; 2088 pf.bottom = df.bottom = vf.bottom = mDockBottom; 2089 2090 mStatusBar.computeFrameLw(pf, df, vf, vf); 2091 2092 if (mStatusBar.isVisibleLw()) { 2093 // If the status bar is hidden, we don't want to cause 2094 // windows behind it to scroll. 2095 final Rect r = mStatusBar.getFrameLw(); 2096 if (mStatusBarCanHide) { 2097 // Status bar may go away, so the screen area it occupies 2098 // is available to apps but just covering them when the 2099 // status bar is visible. 2100 if (mDockTop == r.top) mDockTop = r.bottom; 2101 else if (mDockBottom == r.bottom) mDockBottom = r.top; 2102 2103 mContentTop = mCurTop = mDockTop; 2104 mContentBottom = mCurBottom = mDockBottom; 2105 mContentLeft = mCurLeft = mDockLeft; 2106 mContentRight = mCurRight = mDockRight; 2107 2108 if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: " + 2109 String.format( 2110 "dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]", 2111 mDockLeft, mDockTop, mDockRight, mDockBottom, 2112 mContentLeft, mContentTop, mContentRight, mContentBottom, 2113 mCurLeft, mCurTop, mCurRight, mCurBottom)); 2114 } else { 2115 // Status bar can't go away; the part of the screen it 2116 // covers does not exist for anything behind it. 2117 if (mRestrictedScreenTop == r.top) { 2118 mRestrictedScreenTop = r.bottom; 2119 mRestrictedScreenHeight -= (r.bottom-r.top); 2120 } else if ((mRestrictedScreenHeight-mRestrictedScreenTop) == r.bottom) { 2121 mRestrictedScreenHeight -= (r.bottom-r.top); 2122 } 2123 2124 mContentTop = mCurTop = mDockTop = mRestrictedScreenTop; 2125 mContentBottom = mCurBottom = mDockBottom 2126 = mRestrictedScreenTop + mRestrictedScreenHeight; 2127 if (DEBUG_LAYOUT) Log.v(TAG, "Status bar: restricted screen area: (" 2128 + mRestrictedScreenLeft + "," 2129 + mRestrictedScreenTop + "," 2130 + (mRestrictedScreenLeft + mRestrictedScreenWidth) + "," 2131 + (mRestrictedScreenTop + mRestrictedScreenHeight) + ")"); 2132 } 2133 } 2134 } 2135 } 2136 2137 void setAttachedWindowFrames(WindowState win, int fl, int adjust, 2138 WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) { 2139 if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) { 2140 // Here's a special case: if this attached window is a panel that is 2141 // above the dock window, and the window it is attached to is below 2142 // the dock window, then the frames we computed for the window it is 2143 // attached to can not be used because the dock is effectively part 2144 // of the underlying window and the attached window is floating on top 2145 // of the whole thing. So, we ignore the attached window and explicitly 2146 // compute the frames that would be appropriate without the dock. 2147 df.left = cf.left = vf.left = mDockLeft; 2148 df.top = cf.top = vf.top = mDockTop; 2149 df.right = cf.right = vf.right = mDockRight; 2150 df.bottom = cf.bottom = vf.bottom = mDockBottom; 2151 } else { 2152 // The effective display frame of the attached window depends on 2153 // whether it is taking care of insetting its content. If not, 2154 // we need to use the parent's content frame so that the entire 2155 // window is positioned within that content. Otherwise we can use 2156 // the display frame and let the attached window take care of 2157 // positioning its content appropriately. 2158 if (adjust != SOFT_INPUT_ADJUST_RESIZE) { 2159 cf.set(attached.getDisplayFrameLw()); 2160 } else { 2161 // If the window is resizing, then we want to base the content 2162 // frame on our attached content frame to resize... however, 2163 // things can be tricky if the attached window is NOT in resize 2164 // mode, in which case its content frame will be larger. 2165 // Ungh. So to deal with that, make sure the content frame 2166 // we end up using is not covering the IM dock. 2167 cf.set(attached.getContentFrameLw()); 2168 if (attached.getSurfaceLayer() < mDockLayer) { 2169 if (cf.left < mContentLeft) cf.left = mContentLeft; 2170 if (cf.top < mContentTop) cf.top = mContentTop; 2171 if (cf.right > mContentRight) cf.right = mContentRight; 2172 if (cf.bottom > mContentBottom) cf.bottom = mContentBottom; 2173 } 2174 } 2175 df.set(insetDecors ? attached.getDisplayFrameLw() : cf); 2176 vf.set(attached.getVisibleFrameLw()); 2177 } 2178 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached 2179 // window should be positioned relative to its parent or the entire 2180 // screen. 2181 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 2182 ? attached.getFrameLw() : df); 2183 } 2184 2185 /** {@inheritDoc} */ 2186 public void layoutWindowLw(WindowState win, WindowManager.LayoutParams attrs, 2187 WindowState attached) { 2188 // we've already done the status bar 2189 if (win == mStatusBar || win == mNavigationBar) { 2190 return; 2191 } 2192 2193 final int fl = attrs.flags; 2194 final int sim = attrs.softInputMode; 2195 2196 final Rect pf = mTmpParentFrame; 2197 final Rect df = mTmpDisplayFrame; 2198 final Rect cf = mTmpContentFrame; 2199 final Rect vf = mTmpVisibleFrame; 2200 2201 final boolean hasNavBar = (mHasNavigationBar 2202 && mNavigationBar != null && mNavigationBar.isVisibleLw()); 2203 2204 if (attrs.type == TYPE_INPUT_METHOD) { 2205 pf.left = df.left = cf.left = vf.left = mDockLeft; 2206 pf.top = df.top = cf.top = vf.top = mDockTop; 2207 pf.right = df.right = cf.right = vf.right = mDockRight; 2208 pf.bottom = df.bottom = cf.bottom = vf.bottom = mDockBottom; 2209 // IM dock windows always go to the bottom of the screen. 2210 attrs.gravity = Gravity.BOTTOM; 2211 mDockLayer = win.getSurfaceLayer(); 2212 } else { 2213 final int adjust = sim & SOFT_INPUT_MASK_ADJUST; 2214 2215 if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR)) 2216 == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) { 2217 if (DEBUG_LAYOUT) 2218 Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() 2219 + "): IN_SCREEN, INSET_DECOR, !FULLSCREEN"); 2220 // This is the case for a normal activity window: we want it 2221 // to cover all of the screen space, and it can take care of 2222 // moving its contents to account for screen decorations that 2223 // intrude into that space. 2224 if (attached != null) { 2225 // If this window is attached to another, our display 2226 // frame is the same as the one we are attached to. 2227 setAttachedWindowFrames(win, fl, sim, attached, true, pf, df, cf, vf); 2228 } else { 2229 if (attrs.type == TYPE_STATUS_BAR_PANEL 2230 || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) { 2231 // Status bar panels are the only windows who can go on top of 2232 // the status bar. They are protected by the STATUS_BAR_SERVICE 2233 // permission, so they have the same privileges as the status 2234 // bar itself. 2235 // 2236 // However, they should still dodge the navigation bar if it exists. 2237 2238 pf.left = df.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft; 2239 pf.top = df.top = mUnrestrictedScreenTop; 2240 pf.right = df.right = hasNavBar 2241 ? mRestrictedScreenLeft+mRestrictedScreenWidth 2242 : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; 2243 pf.bottom = df.bottom = hasNavBar 2244 ? mRestrictedScreenTop+mRestrictedScreenHeight 2245 : mUnrestrictedScreenTop+mUnrestrictedScreenHeight; 2246 2247 if (DEBUG_LAYOUT) { 2248 Log.v(TAG, String.format( 2249 "Laying out status bar window: (%d,%d - %d,%d)", 2250 pf.left, pf.top, pf.right, pf.bottom)); 2251 } 2252 } else { 2253 pf.left = df.left = mRestrictedScreenLeft; 2254 pf.top = df.top = mRestrictedScreenTop; 2255 pf.right = df.right = mRestrictedScreenLeft+mRestrictedScreenWidth; 2256 pf.bottom = df.bottom = mRestrictedScreenTop+mRestrictedScreenHeight; 2257 } 2258 if (adjust != SOFT_INPUT_ADJUST_RESIZE) { 2259 cf.left = mDockLeft; 2260 cf.top = mDockTop; 2261 cf.right = mDockRight; 2262 cf.bottom = mDockBottom; 2263 } else { 2264 cf.left = mContentLeft; 2265 cf.top = mContentTop; 2266 cf.right = mContentRight; 2267 cf.bottom = mContentBottom; 2268 } 2269 if (adjust != SOFT_INPUT_ADJUST_NOTHING) { 2270 vf.left = mCurLeft; 2271 vf.top = mCurTop; 2272 vf.right = mCurRight; 2273 vf.bottom = mCurBottom; 2274 } else { 2275 vf.set(cf); 2276 } 2277 } 2278 } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) { 2279 if (DEBUG_LAYOUT) 2280 Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): IN_SCREEN"); 2281 // A window that has requested to fill the entire screen just 2282 // gets everything, period. 2283 if (attrs.type == TYPE_STATUS_BAR_PANEL 2284 || attrs.type == TYPE_STATUS_BAR_SUB_PANEL) { 2285 pf.left = df.left = cf.left = hasNavBar ? mDockLeft : mUnrestrictedScreenLeft; 2286 pf.top = df.top = cf.top = mUnrestrictedScreenTop; 2287 pf.right = df.right = cf.right = hasNavBar 2288 ? mRestrictedScreenLeft+mRestrictedScreenWidth 2289 : mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; 2290 pf.bottom = df.bottom = cf.bottom = hasNavBar 2291 ? mRestrictedScreenTop+mRestrictedScreenHeight 2292 : mUnrestrictedScreenTop+mUnrestrictedScreenHeight; 2293 2294 if (DEBUG_LAYOUT) { 2295 Log.v(TAG, String.format( 2296 "Laying out IN_SCREEN status bar window: (%d,%d - %d,%d)", 2297 pf.left, pf.top, pf.right, pf.bottom)); 2298 } 2299 } else if (attrs.type == TYPE_NAVIGATION_BAR) { 2300 // The navigation bar has Real Ultimate Power. 2301 pf.left = df.left = mUnrestrictedScreenLeft; 2302 pf.top = df.top = mUnrestrictedScreenTop; 2303 pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; 2304 pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; 2305 if (DEBUG_LAYOUT) { 2306 Log.v(TAG, String.format( 2307 "Laying out navigation bar window: (%d,%d - %d,%d)", 2308 pf.left, pf.top, pf.right, pf.bottom)); 2309 } 2310 } else if ((attrs.type == TYPE_SECURE_SYSTEM_OVERLAY 2311 || attrs.type == TYPE_BOOT_PROGRESS) 2312 && ((fl & FLAG_FULLSCREEN) != 0)) { 2313 // Fullscreen secure system overlays get what they ask for. 2314 pf.left = df.left = mUnrestrictedScreenLeft; 2315 pf.top = df.top = mUnrestrictedScreenTop; 2316 pf.right = df.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; 2317 pf.bottom = df.bottom = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; 2318 } else if (attrs.type == TYPE_BOOT_PROGRESS) { 2319 // Boot progress screen always covers entire display. 2320 pf.left = df.left = cf.left = mUnrestrictedScreenLeft; 2321 pf.top = df.top = cf.top = mUnrestrictedScreenTop; 2322 pf.right = df.right = cf.right = mUnrestrictedScreenLeft+mUnrestrictedScreenWidth; 2323 pf.bottom = df.bottom = cf.bottom 2324 = mUnrestrictedScreenTop+mUnrestrictedScreenHeight; 2325 } else { 2326 pf.left = df.left = cf.left = mRestrictedScreenLeft; 2327 pf.top = df.top = cf.top = mRestrictedScreenTop; 2328 pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth; 2329 pf.bottom = df.bottom = cf.bottom 2330 = mRestrictedScreenTop+mRestrictedScreenHeight; 2331 } 2332 if (adjust != SOFT_INPUT_ADJUST_NOTHING) { 2333 vf.left = mCurLeft; 2334 vf.top = mCurTop; 2335 vf.right = mCurRight; 2336 vf.bottom = mCurBottom; 2337 } else { 2338 vf.set(cf); 2339 } 2340 } else if (attached != null) { 2341 if (DEBUG_LAYOUT) 2342 Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): attached to " + attached); 2343 // A child window should be placed inside of the same visible 2344 // frame that its parent had. 2345 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf); 2346 } else { 2347 if (DEBUG_LAYOUT) 2348 Log.v(TAG, "layoutWindowLw(" + attrs.getTitle() + "): normal window"); 2349 // Otherwise, a normal window must be placed inside the content 2350 // of all screen decorations. 2351 if (attrs.type == TYPE_STATUS_BAR_PANEL) { 2352 // Status bar panels are the only windows who can go on top of 2353 // the status bar. They are protected by the STATUS_BAR_SERVICE 2354 // permission, so they have the same privileges as the status 2355 // bar itself. 2356 pf.left = df.left = cf.left = mRestrictedScreenLeft; 2357 pf.top = df.top = cf.top = mRestrictedScreenTop; 2358 pf.right = df.right = cf.right = mRestrictedScreenLeft+mRestrictedScreenWidth; 2359 pf.bottom = df.bottom = cf.bottom 2360 = mRestrictedScreenTop+mRestrictedScreenHeight; 2361 } else { 2362 pf.left = mContentLeft; 2363 pf.top = mContentTop; 2364 pf.right = mContentRight; 2365 pf.bottom = mContentBottom; 2366 if (adjust != SOFT_INPUT_ADJUST_RESIZE) { 2367 df.left = cf.left = mDockLeft; 2368 df.top = cf.top = mDockTop; 2369 df.right = cf.right = mDockRight; 2370 df.bottom = cf.bottom = mDockBottom; 2371 } else { 2372 df.left = cf.left = mContentLeft; 2373 df.top = cf.top = mContentTop; 2374 df.right = cf.right = mContentRight; 2375 df.bottom = cf.bottom = mContentBottom; 2376 } 2377 if (adjust != SOFT_INPUT_ADJUST_NOTHING) { 2378 vf.left = mCurLeft; 2379 vf.top = mCurTop; 2380 vf.right = mCurRight; 2381 vf.bottom = mCurBottom; 2382 } else { 2383 vf.set(cf); 2384 } 2385 } 2386 } 2387 } 2388 2389 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0) { 2390 df.left = df.top = cf.left = cf.top = vf.left = vf.top = -10000; 2391 df.right = df.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; 2392 } 2393 2394 if (DEBUG_LAYOUT) Log.v(TAG, "Compute frame " + attrs.getTitle() 2395 + ": sim=#" + Integer.toHexString(sim) 2396 + " attach=" + attached + " type=" + attrs.type 2397 + String.format(" flags=0x%08x", fl) 2398 + " pf=" + pf.toShortString() + " df=" + df.toShortString() 2399 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()); 2400 2401 win.computeFrameLw(pf, df, cf, vf); 2402 2403 // Dock windows carve out the bottom of the screen, so normal windows 2404 // can't appear underneath them. 2405 if (attrs.type == TYPE_INPUT_METHOD && !win.getGivenInsetsPendingLw()) { 2406 int top = win.getContentFrameLw().top; 2407 top += win.getGivenContentInsetsLw().top; 2408 if (mContentBottom > top) { 2409 mContentBottom = top; 2410 } 2411 top = win.getVisibleFrameLw().top; 2412 top += win.getGivenVisibleInsetsLw().top; 2413 if (mCurBottom > top) { 2414 mCurBottom = top; 2415 } 2416 if (DEBUG_LAYOUT) Log.v(TAG, "Input method: mDockBottom=" 2417 + mDockBottom + " mContentBottom=" 2418 + mContentBottom + " mCurBottom=" + mCurBottom); 2419 } 2420 } 2421 2422 /** {@inheritDoc} */ 2423 @Override 2424 public void finishLayoutLw() { 2425 return; 2426 } 2427 2428 /** {@inheritDoc} */ 2429 public void beginAnimationLw(int displayWidth, int displayHeight) { 2430 mTopFullscreenOpaqueWindowState = null; 2431 mForceStatusBar = false; 2432 2433 mHideLockScreen = false; 2434 mAllowLockscreenWhenOn = false; 2435 mDismissKeyguard = false; 2436 } 2437 2438 /** {@inheritDoc} */ 2439 public void animatingWindowLw(WindowState win, 2440 WindowManager.LayoutParams attrs) { 2441 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": isVisibleOrBehindKeyguardLw=" 2442 + win.isVisibleOrBehindKeyguardLw()); 2443 if (mTopFullscreenOpaqueWindowState == null && 2444 win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()) { 2445 if ((attrs.flags & FLAG_FORCE_NOT_FULLSCREEN) != 0) { 2446 mForceStatusBar = true; 2447 } 2448 if (attrs.type >= FIRST_APPLICATION_WINDOW 2449 && attrs.type <= LAST_APPLICATION_WINDOW 2450 && attrs.x == 0 && attrs.y == 0 2451 && attrs.width == WindowManager.LayoutParams.MATCH_PARENT 2452 && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) { 2453 if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win); 2454 mTopFullscreenOpaqueWindowState = win; 2455 if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { 2456 if (localLOGV) Log.v(TAG, "Setting mHideLockScreen to true by win " + win); 2457 mHideLockScreen = true; 2458 } 2459 if ((attrs.flags & FLAG_DISMISS_KEYGUARD) != 0) { 2460 if (localLOGV) Log.v(TAG, "Setting mDismissKeyguard to true by win " + win); 2461 mDismissKeyguard = true; 2462 } 2463 if ((attrs.flags & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { 2464 mAllowLockscreenWhenOn = true; 2465 } 2466 } 2467 } 2468 } 2469 2470 /** {@inheritDoc} */ 2471 public int finishAnimationLw() { 2472 int changes = 0; 2473 boolean topIsFullscreen = false; 2474 2475 final WindowManager.LayoutParams lp = (mTopFullscreenOpaqueWindowState != null) 2476 ? mTopFullscreenOpaqueWindowState.getAttrs() 2477 : null; 2478 2479 if (mStatusBar != null) { 2480 if (DEBUG_LAYOUT) Log.i(TAG, "force=" + mForceStatusBar 2481 + " top=" + mTopFullscreenOpaqueWindowState); 2482 if (mForceStatusBar) { 2483 if (DEBUG_LAYOUT) Log.v(TAG, "Showing status bar: forced"); 2484 if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; 2485 } else if (mTopFullscreenOpaqueWindowState != null) { 2486 if (localLOGV) { 2487 Log.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() 2488 + " shown frame: " + mTopFullscreenOpaqueWindowState.getShownFrameLw()); 2489 Log.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs() 2490 + " lp.flags=0x" + Integer.toHexString(lp.flags)); 2491 } 2492 topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; 2493 // The subtle difference between the window for mTopFullscreenOpaqueWindowState 2494 // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window 2495 // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the 2496 // case though. 2497 if (topIsFullscreen) { 2498 if (mStatusBarCanHide) { 2499 if (DEBUG_LAYOUT) Log.v(TAG, "** HIDING status bar"); 2500 if (mStatusBar.hideLw(true)) { 2501 changes |= FINISH_LAYOUT_REDO_LAYOUT; 2502 2503 mHandler.post(new Runnable() { public void run() { 2504 if (mStatusBarService != null) { 2505 try { 2506 mStatusBarService.collapse(); 2507 } catch (RemoteException ex) {} 2508 } 2509 }}); 2510 } 2511 } else if (DEBUG_LAYOUT) { 2512 Log.v(TAG, "Preventing status bar from hiding by policy"); 2513 } 2514 } else { 2515 if (DEBUG_LAYOUT) Log.v(TAG, "** SHOWING status bar: top is not fullscreen"); 2516 if (mStatusBar.showLw(true)) changes |= FINISH_LAYOUT_REDO_LAYOUT; 2517 } 2518 } 2519 } 2520 2521 mTopIsFullscreen = topIsFullscreen; 2522 2523 // Hide the key guard if a visible window explicitly specifies that it wants to be displayed 2524 // when the screen is locked 2525 if (mKeyguard != null) { 2526 if (localLOGV) Log.v(TAG, "finishAnimationLw::mHideKeyguard="+mHideLockScreen); 2527 if (mDismissKeyguard && !mKeyguardMediator.isSecure()) { 2528 if (mKeyguard.hideLw(true)) { 2529 changes |= FINISH_LAYOUT_REDO_LAYOUT 2530 | FINISH_LAYOUT_REDO_CONFIG 2531 | FINISH_LAYOUT_REDO_WALLPAPER; 2532 } 2533 if (mKeyguardMediator.isShowing()) { 2534 mHandler.post(new Runnable() { 2535 public void run() { 2536 mKeyguardMediator.keyguardDone(false, false); 2537 } 2538 }); 2539 } 2540 } else if (mHideLockScreen) { 2541 if (mKeyguard.hideLw(true)) { 2542 changes |= FINISH_LAYOUT_REDO_LAYOUT 2543 | FINISH_LAYOUT_REDO_CONFIG 2544 | FINISH_LAYOUT_REDO_WALLPAPER; 2545 } 2546 mKeyguardMediator.setHidden(true); 2547 } else { 2548 if (mKeyguard.showLw(true)) { 2549 changes |= FINISH_LAYOUT_REDO_LAYOUT 2550 | FINISH_LAYOUT_REDO_CONFIG 2551 | FINISH_LAYOUT_REDO_WALLPAPER; 2552 } 2553 mKeyguardMediator.setHidden(false); 2554 } 2555 } 2556 2557 if ((updateSystemUiVisibilityLw()&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) { 2558 // If the navigation bar has been hidden or shown, we need to do another 2559 // layout pass to update that window. 2560 changes |= FINISH_LAYOUT_REDO_LAYOUT; 2561 } 2562 2563 // update since mAllowLockscreenWhenOn might have changed 2564 updateLockScreenTimeout(); 2565 return changes; 2566 } 2567 2568 public boolean allowAppAnimationsLw() { 2569 if (mKeyguard != null && mKeyguard.isVisibleLw()) { 2570 // If keyguard is currently visible, no reason to animate 2571 // behind it. 2572 return false; 2573 } 2574 if (false) { 2575 // Don't do this on the tablet, since the system bar never completely 2576 // covers the screen, and with all its transparency this will 2577 // incorrectly think it does cover it when it doesn't. We'll revisit 2578 // this later when we re-do the phone status bar. 2579 if (mStatusBar != null && mStatusBar.isVisibleLw()) { 2580 RectF rect = new RectF(mStatusBar.getShownFrameLw()); 2581 for (int i=mStatusBarPanels.size()-1; i>=0; i--) { 2582 WindowState w = mStatusBarPanels.get(i); 2583 if (w.isVisibleLw()) { 2584 rect.union(w.getShownFrameLw()); 2585 } 2586 } 2587 final int insetw = mRestrictedScreenWidth/10; 2588 final int inseth = mRestrictedScreenHeight/10; 2589 if (rect.contains(insetw, inseth, mRestrictedScreenWidth-insetw, 2590 mRestrictedScreenHeight-inseth)) { 2591 // All of the status bar windows put together cover the 2592 // screen, so the app can't be seen. (Note this test doesn't 2593 // work if the rects of these windows are at off offsets or 2594 // sizes, causing gaps in the rect union we have computed.) 2595 return false; 2596 } 2597 } 2598 } 2599 return true; 2600 } 2601 2602 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) { 2603 mFocusedWindow = newFocus; 2604 if ((updateSystemUiVisibilityLw()&View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0) { 2605 // If the navigation bar has been hidden or shown, we need to do another 2606 // layout pass to update that window. 2607 return FINISH_LAYOUT_REDO_LAYOUT; 2608 } 2609 return 0; 2610 } 2611 2612 /** {@inheritDoc} */ 2613 public void notifyLidSwitchChanged(long whenNanos, boolean lidOpen) { 2614 // do nothing if headless 2615 if (mHeadless) return; 2616 2617 // lid changed state 2618 mLidOpen = lidOpen ? LID_OPEN : LID_CLOSED; 2619 updateKeyboardVisibility(); 2620 2621 boolean awakeNow = mKeyguardMediator.doLidChangeTq(lidOpen); 2622 updateRotation(true); 2623 if (awakeNow) { 2624 // If the lid is opening and we don't have to keep the 2625 // keyguard up, then we can turn on the screen 2626 // immediately. 2627 mKeyguardMediator.pokeWakelock(); 2628 } else if (keyguardIsShowingTq()) { 2629 if (lidOpen) { 2630 // If we are opening the lid and not hiding the 2631 // keyguard, then we need to have it turn on the 2632 // screen once it is shown. 2633 mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq( 2634 KeyEvent.KEYCODE_POWER, mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED); 2635 } 2636 } else { 2637 // Light up the keyboard if we are sliding up. 2638 if (lidOpen) { 2639 mPowerManager.userActivity(SystemClock.uptimeMillis(), false, 2640 LocalPowerManager.BUTTON_EVENT); 2641 } else { 2642 mPowerManager.userActivity(SystemClock.uptimeMillis(), false, 2643 LocalPowerManager.OTHER_EVENT); 2644 } 2645 } 2646 } 2647 2648 void setHdmiPlugged(boolean plugged) { 2649 if (mHdmiPlugged != plugged) { 2650 mHdmiPlugged = plugged; 2651 updateRotation(true); 2652 Intent intent = new Intent(ACTION_HDMI_PLUGGED); 2653 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 2654 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged); 2655 mContext.sendStickyBroadcast(intent); 2656 } 2657 } 2658 2659 void initializeHdmiState() { 2660 boolean plugged = false; 2661 // watch for HDMI plug messages if the hdmi switch exists 2662 if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) { 2663 mHDMIObserver.startObserving("DEVPATH=/devices/virtual/switch/hdmi"); 2664 2665 final String filename = "/sys/class/switch/hdmi/state"; 2666 FileReader reader = null; 2667 try { 2668 reader = new FileReader(filename); 2669 char[] buf = new char[15]; 2670 int n = reader.read(buf); 2671 if (n > 1) { 2672 plugged = 0 != Integer.parseInt(new String(buf, 0, n-1)); 2673 } 2674 } catch (IOException ex) { 2675 Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex); 2676 } catch (NumberFormatException ex) { 2677 Slog.w(TAG, "Couldn't read hdmi state from " + filename + ": " + ex); 2678 } finally { 2679 if (reader != null) { 2680 try { 2681 reader.close(); 2682 } catch (IOException ex) { 2683 } 2684 } 2685 } 2686 } 2687 // This dance forces the code in setHdmiPlugged to run. 2688 // Always do this so the sticky intent is stuck (to false) if there is no hdmi. 2689 mHdmiPlugged = !plugged; 2690 setHdmiPlugged(!mHdmiPlugged); 2691 } 2692 2693 /** 2694 * @return Whether music is being played right now. 2695 */ 2696 boolean isMusicActive() { 2697 final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); 2698 if (am == null) { 2699 Log.w(TAG, "isMusicActive: couldn't get AudioManager reference"); 2700 return false; 2701 } 2702 return am.isMusicActive(); 2703 } 2704 2705 /** 2706 * Tell the audio service to adjust the volume appropriate to the event. 2707 * @param keycode 2708 */ 2709 void handleVolumeKey(int stream, int keycode) { 2710 IAudioService audioService = getAudioService(); 2711 if (audioService == null) { 2712 return; 2713 } 2714 try { 2715 // since audio is playing, we shouldn't have to hold a wake lock 2716 // during the call, but we do it as a precaution for the rare possibility 2717 // that the music stops right before we call this 2718 // TODO: Actually handle MUTE. 2719 mBroadcastWakeLock.acquire(); 2720 audioService.adjustStreamVolume(stream, 2721 keycode == KeyEvent.KEYCODE_VOLUME_UP 2722 ? AudioManager.ADJUST_RAISE 2723 : AudioManager.ADJUST_LOWER, 2724 0); 2725 } catch (RemoteException e) { 2726 Log.w(TAG, "IAudioService.adjustStreamVolume() threw RemoteException " + e); 2727 } finally { 2728 mBroadcastWakeLock.release(); 2729 } 2730 } 2731 2732 final Object mScreenshotLock = new Object(); 2733 ServiceConnection mScreenshotConnection = null; 2734 2735 final Runnable mScreenshotTimeout = new Runnable() { 2736 @Override public void run() { 2737 synchronized (mScreenshotLock) { 2738 if (mScreenshotConnection != null) { 2739 mContext.unbindService(mScreenshotConnection); 2740 mScreenshotConnection = null; 2741 } 2742 } 2743 } 2744 }; 2745 2746 // Assume this is called from the Handler thread. 2747 private void takeScreenshot() { 2748 synchronized (mScreenshotLock) { 2749 if (mScreenshotConnection != null) { 2750 return; 2751 } 2752 ComponentName cn = new ComponentName("com.android.systemui", 2753 "com.android.systemui.screenshot.TakeScreenshotService"); 2754 Intent intent = new Intent(); 2755 intent.setComponent(cn); 2756 ServiceConnection conn = new ServiceConnection() { 2757 @Override 2758 public void onServiceConnected(ComponentName name, IBinder service) { 2759 synchronized (mScreenshotLock) { 2760 if (mScreenshotConnection != this) { 2761 return; 2762 } 2763 Messenger messenger = new Messenger(service); 2764 Message msg = Message.obtain(null, 1); 2765 final ServiceConnection myConn = this; 2766 Handler h = new Handler(mHandler.getLooper()) { 2767 @Override 2768 public void handleMessage(Message msg) { 2769 synchronized (mScreenshotLock) { 2770 if (mScreenshotConnection == myConn) { 2771 mContext.unbindService(mScreenshotConnection); 2772 mScreenshotConnection = null; 2773 mHandler.removeCallbacks(mScreenshotTimeout); 2774 } 2775 } 2776 } 2777 }; 2778 msg.replyTo = new Messenger(h); 2779 msg.arg1 = msg.arg2 = 0; 2780 if (mStatusBar != null && mStatusBar.isVisibleLw()) 2781 msg.arg1 = 1; 2782 if (mNavigationBar != null && mNavigationBar.isVisibleLw()) 2783 msg.arg2 = 1; 2784 try { 2785 messenger.send(msg); 2786 } catch (RemoteException e) { 2787 } 2788 } 2789 } 2790 @Override 2791 public void onServiceDisconnected(ComponentName name) {} 2792 }; 2793 if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) { 2794 mScreenshotConnection = conn; 2795 mHandler.postDelayed(mScreenshotTimeout, 10000); 2796 } 2797 } 2798 } 2799 2800 /** {@inheritDoc} */ 2801 @Override 2802 public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) { 2803 final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; 2804 final boolean canceled = event.isCanceled(); 2805 final int keyCode = event.getKeyCode(); 2806 2807 final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0; 2808 2809 // If screen is off then we treat the case where the keyguard is open but hidden 2810 // the same as if it were open and in front. 2811 // This will prevent any keys other than the power button from waking the screen 2812 // when the keyguard is hidden by another activity. 2813 final boolean keyguardActive = (mKeyguardMediator == null ? false : 2814 (isScreenOn ? 2815 mKeyguardMediator.isShowingAndNotHidden() : 2816 mKeyguardMediator.isShowing())); 2817 2818 if (!mSystemBooted) { 2819 // If we have not yet booted, don't let key events do anything. 2820 return 0; 2821 } 2822 2823 if (false) { 2824 Log.d(TAG, "interceptKeyTq keycode=" + keyCode 2825 + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive); 2826 } 2827 2828 if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0 2829 && event.getRepeatCount() == 0) { 2830 performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); 2831 } 2832 2833 if (keyCode == KeyEvent.KEYCODE_POWER) { 2834 policyFlags |= WindowManagerPolicy.FLAG_WAKE; 2835 } 2836 final boolean isWakeKey = (policyFlags & (WindowManagerPolicy.FLAG_WAKE 2837 | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; 2838 2839 // Basic policy based on screen state and keyguard. 2840 // FIXME: This policy isn't quite correct. We shouldn't care whether the screen 2841 // is on or off, really. We should care about whether the device is in an 2842 // interactive state or is in suspend pretending to be "off". 2843 // The primary screen might be turned off due to proximity sensor or 2844 // because we are presenting media on an auxiliary screen or remotely controlling 2845 // the device some other way (which is why we have an exemption here for injected 2846 // events). 2847 int result; 2848 if ((isScreenOn && !mHeadless) || (isInjected && !isWakeKey)) { 2849 // When the screen is on or if the key is injected pass the key to the application. 2850 result = ACTION_PASS_TO_USER; 2851 } else { 2852 // When the screen is off and the key is not injected, determine whether 2853 // to wake the device but don't pass the key to the application. 2854 result = 0; 2855 if (down && isWakeKey) { 2856 if (keyguardActive) { 2857 // If the keyguard is showing, let it decide what to do with the wake key. 2858 mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode, 2859 mDockMode != Intent.EXTRA_DOCK_STATE_UNDOCKED); 2860 } else { 2861 // Otherwise, wake the device ourselves. 2862 result |= ACTION_POKE_USER_ACTIVITY; 2863 } 2864 } 2865 } 2866 2867 // Handle special keys. 2868 switch (keyCode) { 2869 case KeyEvent.KEYCODE_VOLUME_DOWN: 2870 case KeyEvent.KEYCODE_VOLUME_UP: 2871 case KeyEvent.KEYCODE_VOLUME_MUTE: { 2872 if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { 2873 if (down) { 2874 if (isScreenOn && !mVolumeDownKeyTriggered 2875 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { 2876 mVolumeDownKeyTriggered = true; 2877 mVolumeDownKeyTime = event.getDownTime(); 2878 mVolumeDownKeyConsumedByScreenshotChord = false; 2879 cancelPendingPowerKeyAction(); 2880 interceptScreenshotChord(); 2881 } 2882 } else { 2883 mVolumeDownKeyTriggered = false; 2884 cancelPendingScreenshotChordAction(); 2885 } 2886 } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { 2887 if (down) { 2888 if (isScreenOn && !mVolumeUpKeyTriggered 2889 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { 2890 mVolumeUpKeyTriggered = true; 2891 cancelPendingPowerKeyAction(); 2892 cancelPendingScreenshotChordAction(); 2893 } 2894 } else { 2895 mVolumeUpKeyTriggered = false; 2896 cancelPendingScreenshotChordAction(); 2897 } 2898 } 2899 if (down) { 2900 ITelephony telephonyService = getTelephonyService(); 2901 if (telephonyService != null) { 2902 try { 2903 if (telephonyService.isRinging()) { 2904 // If an incoming call is ringing, either VOLUME key means 2905 // "silence ringer". We handle these keys here, rather than 2906 // in the InCallScreen, to make sure we'll respond to them 2907 // even if the InCallScreen hasn't come to the foreground yet. 2908 // Look for the DOWN event here, to agree with the "fallback" 2909 // behavior in the InCallScreen. 2910 Log.i(TAG, "interceptKeyBeforeQueueing:" 2911 + " VOLUME key-down while ringing: Silence ringer!"); 2912 2913 // Silence the ringer. (It's safe to call this 2914 // even if the ringer has already been silenced.) 2915 telephonyService.silenceRinger(); 2916 2917 // And *don't* pass this key thru to the current activity 2918 // (which is probably the InCallScreen.) 2919 result &= ~ACTION_PASS_TO_USER; 2920 break; 2921 } 2922 if (telephonyService.isOffhook() 2923 && (result & ACTION_PASS_TO_USER) == 0) { 2924 // If we are in call but we decided not to pass the key to 2925 // the application, handle the volume change here. 2926 handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode); 2927 break; 2928 } 2929 } catch (RemoteException ex) { 2930 Log.w(TAG, "ITelephony threw RemoteException", ex); 2931 } 2932 } 2933 2934 if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) { 2935 // If music is playing but we decided not to pass the key to the 2936 // application, handle the volume change here. 2937 handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode); 2938 break; 2939 } 2940 } 2941 break; 2942 } 2943 2944 case KeyEvent.KEYCODE_ENDCALL: { 2945 result &= ~ACTION_PASS_TO_USER; 2946 if (down) { 2947 ITelephony telephonyService = getTelephonyService(); 2948 boolean hungUp = false; 2949 if (telephonyService != null) { 2950 try { 2951 hungUp = telephonyService.endCall(); 2952 } catch (RemoteException ex) { 2953 Log.w(TAG, "ITelephony threw RemoteException", ex); 2954 } 2955 } 2956 interceptPowerKeyDown(!isScreenOn || hungUp); 2957 } else { 2958 if (interceptPowerKeyUp(canceled)) { 2959 if ((mEndcallBehavior 2960 & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) { 2961 if (goHome()) { 2962 break; 2963 } 2964 } 2965 if ((mEndcallBehavior 2966 & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) { 2967 result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP; 2968 } 2969 } 2970 } 2971 break; 2972 } 2973 2974 case KeyEvent.KEYCODE_POWER: { 2975 result &= ~ACTION_PASS_TO_USER; 2976 if (down) { 2977 if (isScreenOn && !mPowerKeyTriggered 2978 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { 2979 mPowerKeyTriggered = true; 2980 mPowerKeyTime = event.getDownTime(); 2981 interceptScreenshotChord(); 2982 } 2983 2984 ITelephony telephonyService = getTelephonyService(); 2985 boolean hungUp = false; 2986 if (telephonyService != null) { 2987 try { 2988 if (telephonyService.isRinging()) { 2989 // Pressing Power while there's a ringing incoming 2990 // call should silence the ringer. 2991 telephonyService.silenceRinger(); 2992 } else if ((mIncallPowerBehavior 2993 & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 2994 && telephonyService.isOffhook()) { 2995 // Otherwise, if "Power button ends call" is enabled, 2996 // the Power button will hang up any current active call. 2997 hungUp = telephonyService.endCall(); 2998 } 2999 } catch (RemoteException ex) { 3000 Log.w(TAG, "ITelephony threw RemoteException", ex); 3001 } 3002 } 3003 interceptPowerKeyDown(!isScreenOn || hungUp 3004 || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered); 3005 } else { 3006 mPowerKeyTriggered = false; 3007 cancelPendingScreenshotChordAction(); 3008 if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) { 3009 result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP; 3010 } 3011 mPendingPowerKeyUpCanceled = false; 3012 } 3013 break; 3014 } 3015 3016 case KeyEvent.KEYCODE_MEDIA_PLAY: 3017 case KeyEvent.KEYCODE_MEDIA_PAUSE: 3018 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 3019 if (down) { 3020 ITelephony telephonyService = getTelephonyService(); 3021 if (telephonyService != null) { 3022 try { 3023 if (!telephonyService.isIdle()) { 3024 // Suppress PLAY/PAUSE toggle when phone is ringing or in-call 3025 // to avoid music playback. 3026 break; 3027 } 3028 } catch (RemoteException ex) { 3029 Log.w(TAG, "ITelephony threw RemoteException", ex); 3030 } 3031 } 3032 } 3033 case KeyEvent.KEYCODE_HEADSETHOOK: 3034 case KeyEvent.KEYCODE_MUTE: 3035 case KeyEvent.KEYCODE_MEDIA_STOP: 3036 case KeyEvent.KEYCODE_MEDIA_NEXT: 3037 case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 3038 case KeyEvent.KEYCODE_MEDIA_REWIND: 3039 case KeyEvent.KEYCODE_MEDIA_RECORD: 3040 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: { 3041 if ((result & ACTION_PASS_TO_USER) == 0) { 3042 // Only do this if we would otherwise not pass it to the user. In that 3043 // case, the PhoneWindow class will do the same thing, except it will 3044 // only do it if the showing app doesn't process the key on its own. 3045 mBroadcastWakeLock.acquire(); 3046 mHandler.post(new PassHeadsetKey(new KeyEvent(event))); 3047 } 3048 break; 3049 } 3050 3051 case KeyEvent.KEYCODE_CALL: { 3052 if (down) { 3053 ITelephony telephonyService = getTelephonyService(); 3054 if (telephonyService != null) { 3055 try { 3056 if (telephonyService.isRinging()) { 3057 Log.i(TAG, "interceptKeyBeforeQueueing:" 3058 + " CALL key-down while ringing: Answer the call!"); 3059 telephonyService.answerRingingCall(); 3060 3061 // And *don't* pass this key thru to the current activity 3062 // (which is presumably the InCallScreen.) 3063 result &= ~ACTION_PASS_TO_USER; 3064 } 3065 } catch (RemoteException ex) { 3066 Log.w(TAG, "ITelephony threw RemoteException", ex); 3067 } 3068 } 3069 } 3070 break; 3071 } 3072 } 3073 return result; 3074 } 3075 3076 /** {@inheritDoc} */ 3077 @Override 3078 public int interceptMotionBeforeQueueingWhenScreenOff(int policyFlags) { 3079 int result = 0; 3080 3081 final boolean isWakeMotion = (policyFlags 3082 & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0; 3083 if (isWakeMotion) { 3084 if (mKeyguardMediator != null && mKeyguardMediator.isShowing()) { 3085 // If the keyguard is showing, let it decide what to do with the wake motion. 3086 mKeyguardMediator.onWakeMotionWhenKeyguardShowingTq(); 3087 } else { 3088 // Otherwise, wake the device ourselves. 3089 result |= ACTION_POKE_USER_ACTIVITY; 3090 } 3091 } 3092 return result; 3093 } 3094 3095 class PassHeadsetKey implements Runnable { 3096 KeyEvent mKeyEvent; 3097 3098 PassHeadsetKey(KeyEvent keyEvent) { 3099 mKeyEvent = keyEvent; 3100 } 3101 3102 public void run() { 3103 if (ActivityManagerNative.isSystemReady()) { 3104 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 3105 intent.putExtra(Intent.EXTRA_KEY_EVENT, mKeyEvent); 3106 mContext.sendOrderedBroadcast(intent, null, mBroadcastDone, 3107 mHandler, Activity.RESULT_OK, null, null); 3108 } 3109 } 3110 } 3111 3112 BroadcastReceiver mBroadcastDone = new BroadcastReceiver() { 3113 public void onReceive(Context context, Intent intent) { 3114 mBroadcastWakeLock.release(); 3115 } 3116 }; 3117 3118 BroadcastReceiver mDockReceiver = new BroadcastReceiver() { 3119 public void onReceive(Context context, Intent intent) { 3120 if (Intent.ACTION_DOCK_EVENT.equals(intent.getAction())) { 3121 mDockMode = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 3122 Intent.EXTRA_DOCK_STATE_UNDOCKED); 3123 } else { 3124 try { 3125 IUiModeManager uiModeService = IUiModeManager.Stub.asInterface( 3126 ServiceManager.getService(Context.UI_MODE_SERVICE)); 3127 mUiMode = uiModeService.getCurrentModeType(); 3128 } catch (RemoteException e) { 3129 } 3130 } 3131 updateRotation(true); 3132 updateOrientationListenerLp(); 3133 } 3134 }; 3135 3136 BroadcastReceiver mPowerReceiver = new BroadcastReceiver() { 3137 public void onReceive(Context context, Intent intent) { 3138 if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) { 3139 mPluggedIn = (0 != intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0)); 3140 if (localLOGV) Log.v(TAG, "BATTERY_CHANGED: " + intent + " plugged=" + mPluggedIn); 3141 } 3142 } 3143 }; 3144 3145 /** {@inheritDoc} */ 3146 public void screenTurnedOff(int why) { 3147 EventLog.writeEvent(70000, 0); 3148 synchronized (mLock) { 3149 mScreenOnEarly = false; 3150 mScreenOnFully = false; 3151 } 3152 if (mKeyguardMediator != null) { 3153 mKeyguardMediator.onScreenTurnedOff(why); 3154 } 3155 synchronized (mLock) { 3156 updateOrientationListenerLp(); 3157 updateLockScreenTimeout(); 3158 updateScreenSaverTimeoutLocked(); 3159 } 3160 } 3161 3162 /** {@inheritDoc} */ 3163 public void screenTurningOn(final ScreenOnListener screenOnListener) { 3164 EventLog.writeEvent(70000, 1); 3165 if (false) { 3166 RuntimeException here = new RuntimeException("here"); 3167 here.fillInStackTrace(); 3168 Slog.i(TAG, "Screen turning on...", here); 3169 } 3170 if (screenOnListener != null) { 3171 if (mKeyguardMediator != null) { 3172 mKeyguardMediator.onScreenTurnedOn(new KeyguardViewManager.ShowListener() { 3173 @Override public void onShown(IBinder windowToken) { 3174 if (windowToken != null) { 3175 try { 3176 mWindowManager.waitForWindowDrawn(windowToken, 3177 new IRemoteCallback.Stub() { 3178 @Override public void sendResult(Bundle data) { 3179 Slog.i(TAG, "Lock screen displayed!"); 3180 screenOnListener.onScreenOn(); 3181 synchronized (mLock) { 3182 mScreenOnFully = true; 3183 } 3184 } 3185 }); 3186 } catch (RemoteException e) { 3187 } 3188 } else { 3189 Slog.i(TAG, "No lock screen!"); 3190 screenOnListener.onScreenOn(); 3191 synchronized (mLock) { 3192 mScreenOnFully = true; 3193 } 3194 } 3195 } 3196 }); 3197 } 3198 } else { 3199 synchronized (mLock) { 3200 mScreenOnFully = true; 3201 } 3202 } 3203 synchronized (mLock) { 3204 mScreenOnEarly = true; 3205 updateOrientationListenerLp(); 3206 updateLockScreenTimeout(); 3207 updateScreenSaverTimeoutLocked(); 3208 } 3209 } 3210 3211 /** {@inheritDoc} */ 3212 public boolean isScreenOnEarly() { 3213 return mScreenOnEarly; 3214 } 3215 3216 /** {@inheritDoc} */ 3217 public boolean isScreenOnFully() { 3218 return mScreenOnFully; 3219 } 3220 3221 /** {@inheritDoc} */ 3222 public void enableKeyguard(boolean enabled) { 3223 if (mKeyguardMediator != null) { 3224 mKeyguardMediator.setKeyguardEnabled(enabled); 3225 } 3226 } 3227 3228 /** {@inheritDoc} */ 3229 public void exitKeyguardSecurely(OnKeyguardExitResult callback) { 3230 if (mKeyguardMediator != null) { 3231 mKeyguardMediator.verifyUnlock(callback); 3232 } 3233 } 3234 3235 private boolean keyguardIsShowingTq() { 3236 if (mKeyguardMediator == null) return false; 3237 return mKeyguardMediator.isShowingAndNotHidden(); 3238 } 3239 3240 3241 /** {@inheritDoc} */ 3242 public boolean isKeyguardLocked() { 3243 return keyguardOn(); 3244 } 3245 3246 /** {@inheritDoc} */ 3247 public boolean isKeyguardSecure() { 3248 if (mKeyguardMediator == null) return false; 3249 return mKeyguardMediator.isSecure(); 3250 } 3251 3252 /** {@inheritDoc} */ 3253 public boolean inKeyguardRestrictedKeyInputMode() { 3254 if (mKeyguardMediator == null) return false; 3255 return mKeyguardMediator.isInputRestricted(); 3256 } 3257 3258 public void dismissKeyguardLw() { 3259 if (!mKeyguardMediator.isSecure()) { 3260 if (mKeyguardMediator.isShowing()) { 3261 mHandler.post(new Runnable() { 3262 public void run() { 3263 mKeyguardMediator.keyguardDone(false, true); 3264 } 3265 }); 3266 } 3267 } 3268 } 3269 3270 void sendCloseSystemWindows() { 3271 sendCloseSystemWindows(mContext, null); 3272 } 3273 3274 void sendCloseSystemWindows(String reason) { 3275 sendCloseSystemWindows(mContext, reason); 3276 } 3277 3278 static void sendCloseSystemWindows(Context context, String reason) { 3279 if (ActivityManagerNative.isSystemReady()) { 3280 try { 3281 ActivityManagerNative.getDefault().closeSystemDialogs(reason); 3282 } catch (RemoteException e) { 3283 } 3284 } 3285 } 3286 3287 @Override 3288 public int rotationForOrientationLw(int orientation, int lastRotation) { 3289 if (false) { 3290 Slog.v(TAG, "rotationForOrientationLw(orient=" 3291 + orientation + ", last=" + lastRotation 3292 + "); user=" + mUserRotation + " " 3293 + ((mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) 3294 ? "USER_ROTATION_LOCKED" : "") 3295 ); 3296 } 3297 3298 synchronized (mLock) { 3299 int sensorRotation = mOrientationListener.getProposedRotation(); // may be -1 3300 if (sensorRotation < 0) { 3301 sensorRotation = lastRotation; 3302 } 3303 3304 final int preferredRotation; 3305 if (mLidOpen == LID_OPEN && mLidOpenRotation >= 0) { 3306 // Ignore sensor when lid switch is open and rotation is forced. 3307 preferredRotation = mLidOpenRotation; 3308 } else if (mDockMode == Intent.EXTRA_DOCK_STATE_CAR 3309 && (mCarDockEnablesAccelerometer || mCarDockRotation >= 0)) { 3310 // Ignore sensor when in car dock unless explicitly enabled. 3311 // This case can override the behavior of NOSENSOR, and can also 3312 // enable 180 degree rotation while docked. 3313 preferredRotation = mCarDockEnablesAccelerometer 3314 ? sensorRotation : mCarDockRotation; 3315 } else if ((mDockMode == Intent.EXTRA_DOCK_STATE_DESK 3316 || mDockMode == Intent.EXTRA_DOCK_STATE_LE_DESK 3317 || mDockMode == Intent.EXTRA_DOCK_STATE_HE_DESK) 3318 && (mDeskDockEnablesAccelerometer || mDeskDockRotation >= 0)) { 3319 // Ignore sensor when in desk dock unless explicitly enabled. 3320 // This case can override the behavior of NOSENSOR, and can also 3321 // enable 180 degree rotation while docked. 3322 preferredRotation = mDeskDockEnablesAccelerometer 3323 ? sensorRotation : mDeskDockRotation; 3324 } else if (mHdmiPlugged) { 3325 // Ignore sensor when plugged into HDMI. 3326 // Note that the dock orientation overrides the HDMI orientation. 3327 preferredRotation = mHdmiRotation; 3328 } else if ((mAccelerometerDefault != 0 /* implies not rotation locked */ 3329 && (orientation == ActivityInfo.SCREEN_ORIENTATION_USER 3330 || orientation == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)) 3331 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR 3332 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR 3333 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE 3334 || orientation == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT) { 3335 // Otherwise, use sensor only if requested by the application or enabled 3336 // by default for USER or UNSPECIFIED modes. Does not apply to NOSENSOR. 3337 if (mAllowAllRotations < 0) { 3338 // Can't read this during init() because the context doesn't 3339 // have display metrics at that time so we cannot determine 3340 // tablet vs. phone then. 3341 mAllowAllRotations = mContext.getResources().getBoolean( 3342 com.android.internal.R.bool.config_allowAllRotations) ? 1 : 0; 3343 } 3344 if (sensorRotation != Surface.ROTATION_180 3345 || mAllowAllRotations == 1 3346 || orientation == ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR) { 3347 preferredRotation = sensorRotation; 3348 } else { 3349 preferredRotation = lastRotation; 3350 } 3351 } else if (mUserRotationMode == WindowManagerPolicy.USER_ROTATION_LOCKED) { 3352 // Apply rotation lock. 3353 preferredRotation = mUserRotation; 3354 } else { 3355 // No overriding preference. 3356 // We will do exactly what the application asked us to do. 3357 preferredRotation = -1; 3358 } 3359 3360 switch (orientation) { 3361 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: 3362 // Return portrait unless overridden. 3363 if (isAnyPortrait(preferredRotation)) { 3364 return preferredRotation; 3365 } 3366 return mPortraitRotation; 3367 3368 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: 3369 // Return landscape unless overridden. 3370 if (isLandscapeOrSeascape(preferredRotation)) { 3371 return preferredRotation; 3372 } 3373 return mLandscapeRotation; 3374 3375 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: 3376 // Return reverse portrait unless overridden. 3377 if (isAnyPortrait(preferredRotation)) { 3378 return preferredRotation; 3379 } 3380 return mUpsideDownRotation; 3381 3382 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: 3383 // Return seascape unless overridden. 3384 if (isLandscapeOrSeascape(preferredRotation)) { 3385 return preferredRotation; 3386 } 3387 return mSeascapeRotation; 3388 3389 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: 3390 // Return either landscape rotation. 3391 if (isLandscapeOrSeascape(preferredRotation)) { 3392 return preferredRotation; 3393 } 3394 if (isLandscapeOrSeascape(lastRotation)) { 3395 return lastRotation; 3396 } 3397 return mLandscapeRotation; 3398 3399 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: 3400 // Return either portrait rotation. 3401 if (isAnyPortrait(preferredRotation)) { 3402 return preferredRotation; 3403 } 3404 if (isAnyPortrait(lastRotation)) { 3405 return lastRotation; 3406 } 3407 return mPortraitRotation; 3408 3409 default: 3410 // For USER, UNSPECIFIED, NOSENSOR, SENSOR and FULL_SENSOR, 3411 // just return the preferred orientation we already calculated. 3412 if (preferredRotation >= 0) { 3413 return preferredRotation; 3414 } 3415 return Surface.ROTATION_0; 3416 } 3417 } 3418 } 3419 3420 @Override 3421 public boolean rotationHasCompatibleMetricsLw(int orientation, int rotation) { 3422 switch (orientation) { 3423 case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT: 3424 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT: 3425 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT: 3426 return isAnyPortrait(rotation); 3427 3428 case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE: 3429 case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE: 3430 case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE: 3431 return isLandscapeOrSeascape(rotation); 3432 3433 default: 3434 return true; 3435 } 3436 } 3437 3438 @Override 3439 public void setRotationLw(int rotation) { 3440 mOrientationListener.setCurrentRotation(rotation); 3441 } 3442 3443 private boolean isLandscapeOrSeascape(int rotation) { 3444 return rotation == mLandscapeRotation || rotation == mSeascapeRotation; 3445 } 3446 3447 private boolean isAnyPortrait(int rotation) { 3448 return rotation == mPortraitRotation || rotation == mUpsideDownRotation; 3449 } 3450 3451 3452 // User rotation: to be used when all else fails in assigning an orientation to the device 3453 public void setUserRotationMode(int mode, int rot) { 3454 ContentResolver res = mContext.getContentResolver(); 3455 3456 // mUserRotationMode and mUserRotation will be assigned by the content observer 3457 if (mode == WindowManagerPolicy.USER_ROTATION_LOCKED) { 3458 Settings.System.putInt(res, 3459 Settings.System.USER_ROTATION, 3460 rot); 3461 Settings.System.putInt(res, 3462 Settings.System.ACCELEROMETER_ROTATION, 3463 0); 3464 } else { 3465 Settings.System.putInt(res, 3466 Settings.System.ACCELEROMETER_ROTATION, 3467 1); 3468 } 3469 } 3470 3471 public boolean detectSafeMode() { 3472 try { 3473 int menuState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_MENU); 3474 int sState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_S); 3475 int dpadState = mWindowManager.getDPadKeycodeState(KeyEvent.KEYCODE_DPAD_CENTER); 3476 int trackballState = mWindowManager.getTrackballScancodeState(BTN_MOUSE); 3477 int volumeDownState = mWindowManager.getKeycodeState(KeyEvent.KEYCODE_VOLUME_DOWN); 3478 mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0 3479 || volumeDownState > 0; 3480 performHapticFeedbackLw(null, mSafeMode 3481 ? HapticFeedbackConstants.SAFE_MODE_ENABLED 3482 : HapticFeedbackConstants.SAFE_MODE_DISABLED, true); 3483 if (mSafeMode) { 3484 Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState 3485 + " dpad=" + dpadState + " trackball=" + trackballState + ")"); 3486 } else { 3487 Log.i(TAG, "SAFE MODE not enabled"); 3488 } 3489 return mSafeMode; 3490 } catch (RemoteException e) { 3491 // Doom! (it's also local) 3492 throw new RuntimeException("window manager dead"); 3493 } 3494 } 3495 3496 static long[] getLongIntArray(Resources r, int resid) { 3497 int[] ar = r.getIntArray(resid); 3498 if (ar == null) { 3499 return null; 3500 } 3501 long[] out = new long[ar.length]; 3502 for (int i=0; i<ar.length; i++) { 3503 out[i] = ar[i]; 3504 } 3505 return out; 3506 } 3507 3508 /** {@inheritDoc} */ 3509 public void systemReady() { 3510 if (mKeyguardMediator != null) { 3511 // tell the keyguard 3512 mKeyguardMediator.onSystemReady(); 3513 } 3514 synchronized (mLock) { 3515 updateOrientationListenerLp(); 3516 mSystemReady = true; 3517 mHandler.post(new Runnable() { 3518 public void run() { 3519 updateSettings(); 3520 } 3521 }); 3522 } 3523 } 3524 3525 /** {@inheritDoc} */ 3526 public void systemBooted() { 3527 synchronized (mLock) { 3528 mSystemBooted = true; 3529 } 3530 } 3531 3532 ProgressDialog mBootMsgDialog = null; 3533 3534 /** {@inheritDoc} */ 3535 public void showBootMessage(final CharSequence msg, final boolean always) { 3536 if (mHeadless) return; 3537 mHandler.post(new Runnable() { 3538 @Override public void run() { 3539 if (mBootMsgDialog == null) { 3540 mBootMsgDialog = new ProgressDialog(mContext) { 3541 // This dialog will consume all events coming in to 3542 // it, to avoid it trying to do things too early in boot. 3543 @Override public boolean dispatchKeyEvent(KeyEvent event) { 3544 return true; 3545 } 3546 @Override public boolean dispatchKeyShortcutEvent(KeyEvent event) { 3547 return true; 3548 } 3549 @Override public boolean dispatchTouchEvent(MotionEvent ev) { 3550 return true; 3551 } 3552 @Override public boolean dispatchTrackballEvent(MotionEvent ev) { 3553 return true; 3554 } 3555 @Override public boolean dispatchGenericMotionEvent(MotionEvent ev) { 3556 return true; 3557 } 3558 @Override public boolean dispatchPopulateAccessibilityEvent( 3559 AccessibilityEvent event) { 3560 return true; 3561 } 3562 }; 3563 mBootMsgDialog.setTitle(R.string.android_upgrading_title); 3564 mBootMsgDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); 3565 mBootMsgDialog.setIndeterminate(true); 3566 mBootMsgDialog.getWindow().setType( 3567 WindowManager.LayoutParams.TYPE_BOOT_PROGRESS); 3568 mBootMsgDialog.getWindow().addFlags( 3569 WindowManager.LayoutParams.FLAG_DIM_BEHIND 3570 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); 3571 mBootMsgDialog.getWindow().setDimAmount(1); 3572 WindowManager.LayoutParams lp = mBootMsgDialog.getWindow().getAttributes(); 3573 lp.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR; 3574 mBootMsgDialog.getWindow().setAttributes(lp); 3575 mBootMsgDialog.setCancelable(false); 3576 mBootMsgDialog.show(); 3577 } 3578 mBootMsgDialog.setMessage(msg); 3579 } 3580 }); 3581 } 3582 3583 /** {@inheritDoc} */ 3584 public void hideBootMessages() { 3585 mHandler.post(new Runnable() { 3586 @Override public void run() { 3587 if (mBootMsgDialog != null) { 3588 mBootMsgDialog.dismiss(); 3589 mBootMsgDialog = null; 3590 } 3591 } 3592 }); 3593 } 3594 3595 /** {@inheritDoc} */ 3596 public void userActivity() { 3597 // *************************************** 3598 // NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE 3599 // *************************************** 3600 // THIS IS CALLED FROM DEEP IN THE POWER MANAGER 3601 // WITH ITS LOCKS HELD. 3602 // 3603 // This code must be VERY careful about the locks 3604 // it acquires. 3605 // In fact, the current code acquires way too many, 3606 // and probably has lurking deadlocks. 3607 3608 synchronized (mScreenLockTimeout) { 3609 if (mLockScreenTimerActive) { 3610 // reset the timer 3611 mHandler.removeCallbacks(mScreenLockTimeout); 3612 mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout); 3613 } 3614 } 3615 3616 synchronized (mLock) { 3617 // Only posts messages; holds no additional locks. 3618 updateScreenSaverTimeoutLocked(); 3619 } 3620 } 3621 3622 Runnable mScreenSaverActivator = new Runnable() { 3623 public void run() { 3624 if (!(mScreenSaverMayRun && mScreenOnEarly)) { 3625 Log.w(TAG, "mScreenSaverActivator ran, but the screensaver should not be showing. Who's driving this thing?"); 3626 return; 3627 } 3628 if (!mPluggedIn) { 3629 if (localLOGV) Log.v(TAG, "mScreenSaverActivator: not running screen saver when not plugged in"); 3630 return; 3631 } 3632 // Quick fix for automation tests. 3633 // The correct fix is to move this triggering logic to PowerManager, where more complete 3634 // information about wakelocks (including StayOnWhilePluggedIn) is available. 3635 if (Settings.System.getInt(mContext.getContentResolver(), 3636 Settings.System.STAY_ON_WHILE_PLUGGED_IN, 3637 BatteryManager.BATTERY_PLUGGED_AC) != 0) { 3638 Log.v(TAG, "mScreenSaverActivator: not running screen saver when STAY_ON_WHILE_PLUGGED_IN"); 3639 return; 3640 } 3641 3642 if (localLOGV) Log.v(TAG, "mScreenSaverActivator entering dreamland"); 3643 3644 try { 3645 String component = Settings.Secure.getString( 3646 mContext.getContentResolver(), Settings.Secure.SCREENSAVER_COMPONENT); 3647 if (component == null) { 3648 component = mContext.getResources().getString(R.string.config_defaultDreamComponent); 3649 } 3650 if (component != null) { 3651 // dismiss the notification shade, recents, etc. 3652 mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) 3653 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)); 3654 3655 ComponentName cn = ComponentName.unflattenFromString(component); 3656 Intent intent = new Intent(Intent.ACTION_MAIN) 3657 .setComponent(cn) 3658 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK 3659 | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS 3660 | Intent.FLAG_ACTIVITY_NO_USER_ACTION 3661 | Intent.FLAG_FROM_BACKGROUND 3662 | Intent.FLAG_ACTIVITY_NO_HISTORY 3663 ); 3664 mContext.startActivity(intent); 3665 } else { 3666 Log.e(TAG, "Couldn't start screen saver: none selected"); 3667 } 3668 } catch (android.content.ActivityNotFoundException exc) { 3669 // no screensaver? give up 3670 Log.e(TAG, "Couldn't start screen saver: none installed"); 3671 } 3672 } 3673 }; 3674 3675 // Must call while holding mLock 3676 private void updateScreenSaverTimeoutLocked() { 3677 if (mScreenSaverActivator == null) return; 3678 3679 mHandler.removeCallbacks(mScreenSaverActivator); 3680 if (mScreenSaverEnabledByUser && mScreenSaverMayRun && mScreenOnEarly && mScreenSaverTimeout > 0) { 3681 if (localLOGV) 3682 Log.v(TAG, "scheduling screensaver for " + mScreenSaverTimeout + "ms from now"); 3683 mHandler.postDelayed(mScreenSaverActivator, mScreenSaverTimeout); 3684 } else { 3685 if (localLOGV) { 3686 if (!mScreenSaverEnabledByUser || mScreenSaverTimeout == 0) 3687 Log.v(TAG, "screen saver disabled by user"); 3688 else if (!mScreenOnEarly) 3689 Log.v(TAG, "screen saver disabled while screen off"); 3690 else 3691 Log.v(TAG, "screen saver disabled by wakelock"); 3692 } 3693 } 3694 } 3695 3696 Runnable mScreenLockTimeout = new Runnable() { 3697 public void run() { 3698 synchronized (this) { 3699 if (localLOGV) Log.v(TAG, "mScreenLockTimeout activating keyguard"); 3700 if (mKeyguardMediator != null) { 3701 mKeyguardMediator.doKeyguardTimeout(); 3702 } 3703 mLockScreenTimerActive = false; 3704 } 3705 } 3706 }; 3707 3708 public void lockNow() { 3709 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); 3710 mHandler.removeCallbacks(mScreenLockTimeout); 3711 mHandler.post(mScreenLockTimeout); 3712 } 3713 3714 private void updateLockScreenTimeout() { 3715 synchronized (mScreenLockTimeout) { 3716 boolean enable = (mAllowLockscreenWhenOn && mScreenOnEarly && 3717 mKeyguardMediator != null && mKeyguardMediator.isSecure()); 3718 if (mLockScreenTimerActive != enable) { 3719 if (enable) { 3720 if (localLOGV) Log.v(TAG, "setting lockscreen timer"); 3721 mHandler.postDelayed(mScreenLockTimeout, mLockScreenTimeout); 3722 } else { 3723 if (localLOGV) Log.v(TAG, "clearing lockscreen timer"); 3724 mHandler.removeCallbacks(mScreenLockTimeout); 3725 } 3726 mLockScreenTimerActive = enable; 3727 } 3728 } 3729 } 3730 3731 /** {@inheritDoc} */ 3732 public void enableScreenAfterBoot() { 3733 readLidState(); 3734 updateKeyboardVisibility(); 3735 3736 updateRotation(true); 3737 } 3738 3739 private void updateKeyboardVisibility() { 3740 mPowerManager.setKeyboardVisibility(mLidOpen == LID_OPEN); 3741 } 3742 3743 void updateRotation(boolean alwaysSendConfiguration) { 3744 try { 3745 //set orientation on WindowManager 3746 mWindowManager.updateRotation(alwaysSendConfiguration); 3747 } catch (RemoteException e) { 3748 // Ignore 3749 } 3750 } 3751 3752 /** 3753 * Return an Intent to launch the currently active dock app as home. Returns 3754 * null if the standard home should be launched, which is the case if any of the following is 3755 * true: 3756 * <ul> 3757 * <li>The device is not in either car mode or desk mode 3758 * <li>The device is in car mode but ENABLE_CAR_DOCK_HOME_CAPTURE is false 3759 * <li>The device is in desk mode but ENABLE_DESK_DOCK_HOME_CAPTURE is false 3760 * <li>The device is in car mode but there's no CAR_DOCK app with METADATA_DOCK_HOME 3761 * <li>The device is in desk mode but there's no DESK_DOCK app with METADATA_DOCK_HOME 3762 * </ul> 3763 * @return 3764 */ 3765 Intent createHomeDockIntent() { 3766 Intent intent = null; 3767 3768 // What home does is based on the mode, not the dock state. That 3769 // is, when in car mode you should be taken to car home regardless 3770 // of whether we are actually in a car dock. 3771 if (mUiMode == Configuration.UI_MODE_TYPE_CAR) { 3772 if (ENABLE_CAR_DOCK_HOME_CAPTURE) { 3773 intent = mCarDockIntent; 3774 } 3775 } else if (mUiMode == Configuration.UI_MODE_TYPE_DESK) { 3776 if (ENABLE_DESK_DOCK_HOME_CAPTURE) { 3777 intent = mDeskDockIntent; 3778 } 3779 } 3780 3781 if (intent == null) { 3782 return null; 3783 } 3784 3785 ActivityInfo ai = intent.resolveActivityInfo( 3786 mContext.getPackageManager(), PackageManager.GET_META_DATA); 3787 if (ai == null) { 3788 return null; 3789 } 3790 3791 if (ai.metaData != null && ai.metaData.getBoolean(Intent.METADATA_DOCK_HOME)) { 3792 intent = new Intent(intent); 3793 intent.setClassName(ai.packageName, ai.name); 3794 return intent; 3795 } 3796 3797 return null; 3798 } 3799 3800 void startDockOrHome() { 3801 Intent dock = createHomeDockIntent(); 3802 if (dock != null) { 3803 try { 3804 mContext.startActivity(dock); 3805 return; 3806 } catch (ActivityNotFoundException e) { 3807 } 3808 } 3809 mContext.startActivity(mHomeIntent); 3810 } 3811 3812 /** 3813 * goes to the home screen 3814 * @return whether it did anything 3815 */ 3816 boolean goHome() { 3817 if (false) { 3818 // This code always brings home to the front. 3819 try { 3820 ActivityManagerNative.getDefault().stopAppSwitches(); 3821 } catch (RemoteException e) { 3822 } 3823 sendCloseSystemWindows(); 3824 startDockOrHome(); 3825 } else { 3826 // This code brings home to the front or, if it is already 3827 // at the front, puts the device to sleep. 3828 try { 3829 if (SystemProperties.getInt("persist.sys.uts-test-mode", 0) == 1) { 3830 /// Roll back EndcallBehavior as the cupcake design to pass P1 lab entry. 3831 Log.d(TAG, "UTS-TEST-MODE"); 3832 } else { 3833 ActivityManagerNative.getDefault().stopAppSwitches(); 3834 sendCloseSystemWindows(); 3835 Intent dock = createHomeDockIntent(); 3836 if (dock != null) { 3837 int result = ActivityManagerNative.getDefault() 3838 .startActivity(null, dock, 3839 dock.resolveTypeIfNeeded(mContext.getContentResolver()), 3840 null, null, 0, 3841 ActivityManager.START_FLAG_ONLY_IF_NEEDED, 3842 null, null, null); 3843 if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) { 3844 return false; 3845 } 3846 } 3847 } 3848 int result = ActivityManagerNative.getDefault() 3849 .startActivity(null, mHomeIntent, 3850 mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()), 3851 null, null, 0, 3852 ActivityManager.START_FLAG_ONLY_IF_NEEDED, 3853 null, null, null); 3854 if (result == ActivityManager.START_RETURN_INTENT_TO_CALLER) { 3855 return false; 3856 } 3857 } catch (RemoteException ex) { 3858 // bummer, the activity manager, which is in this process, is dead 3859 } 3860 } 3861 return true; 3862 } 3863 3864 public void setCurrentOrientationLw(int newOrientation) { 3865 synchronized (mLock) { 3866 if (newOrientation != mCurrentAppOrientation) { 3867 mCurrentAppOrientation = newOrientation; 3868 updateOrientationListenerLp(); 3869 } 3870 } 3871 } 3872 3873 public boolean performHapticFeedbackLw(WindowState win, int effectId, boolean always) { 3874 final boolean hapticsDisabled = Settings.System.getInt(mContext.getContentResolver(), 3875 Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0; 3876 if (!always && (hapticsDisabled || mKeyguardMediator.isShowingAndNotHidden())) { 3877 return false; 3878 } 3879 long[] pattern = null; 3880 switch (effectId) { 3881 case HapticFeedbackConstants.LONG_PRESS: 3882 pattern = mLongPressVibePattern; 3883 break; 3884 case HapticFeedbackConstants.VIRTUAL_KEY: 3885 pattern = mVirtualKeyVibePattern; 3886 break; 3887 case HapticFeedbackConstants.KEYBOARD_TAP: 3888 pattern = mKeyboardTapVibePattern; 3889 break; 3890 case HapticFeedbackConstants.SAFE_MODE_DISABLED: 3891 pattern = mSafeModeDisabledVibePattern; 3892 break; 3893 case HapticFeedbackConstants.SAFE_MODE_ENABLED: 3894 pattern = mSafeModeEnabledVibePattern; 3895 break; 3896 default: 3897 return false; 3898 } 3899 if (pattern.length == 1) { 3900 // One-shot vibration 3901 mVibrator.vibrate(pattern[0]); 3902 } else { 3903 // Pattern vibration 3904 mVibrator.vibrate(pattern, -1); 3905 } 3906 return true; 3907 } 3908 3909 public void screenOnStartedLw() { 3910 // The window manager has just grabbed a wake lock. This is our cue to disable the screen 3911 // saver. 3912 synchronized (mLock) { 3913 mScreenSaverMayRun = false; 3914 } 3915 } 3916 3917 public void screenOnStoppedLw() { 3918 if (mPowerManager.isScreenOn()) { 3919 if (mKeyguardMediator != null && !mKeyguardMediator.isShowingAndNotHidden()) { 3920 long curTime = SystemClock.uptimeMillis(); 3921 mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT); 3922 } 3923 3924 synchronized (mLock) { 3925 // even if the keyguard is up, now that all the wakelocks have been released, we 3926 // should re-enable the screen saver 3927 mScreenSaverMayRun = true; 3928 updateScreenSaverTimeoutLocked(); 3929 } 3930 } 3931 } 3932 3933 public boolean allowKeyRepeat() { 3934 // disable key repeat when screen is off 3935 return mScreenOnEarly; 3936 } 3937 3938 private int updateSystemUiVisibilityLw() { 3939 // If there is no window focused, there will be nobody to handle the events 3940 // anyway, so just hang on in whatever state we're in until things settle down. 3941 if (mFocusedWindow == null) { 3942 return 0; 3943 } 3944 final int visibility = mFocusedWindow.getSystemUiVisibility() 3945 & ~mResettingSystemUiFlags 3946 & ~mForceClearedSystemUiFlags; 3947 int diff = visibility ^ mLastSystemUiFlags; 3948 final boolean needsMenu = mFocusedWindow.getNeedsMenuLw(mTopFullscreenOpaqueWindowState); 3949 if (diff == 0 && mLastFocusNeedsMenu == needsMenu 3950 && mFocusedApp == mFocusedWindow.getAppToken()) { 3951 return 0; 3952 } 3953 mLastSystemUiFlags = visibility; 3954 mLastFocusNeedsMenu = needsMenu; 3955 mFocusedApp = mFocusedWindow.getAppToken(); 3956 mHandler.post(new Runnable() { 3957 public void run() { 3958 if (mStatusBarService == null) { 3959 mStatusBarService = IStatusBarService.Stub.asInterface( 3960 ServiceManager.getService("statusbar")); 3961 } 3962 if (mStatusBarService != null) { 3963 try { 3964 mStatusBarService.setSystemUiVisibility(visibility); 3965 mStatusBarService.topAppWindowChanged(needsMenu); 3966 } catch (RemoteException e) { 3967 // not much to be done 3968 mStatusBarService = null; 3969 } 3970 } 3971 } 3972 }); 3973 return diff; 3974 } 3975 3976 // Use this instead of checking config_showNavigationBar so that it can be consistently 3977 // overridden by qemu.hw.mainkeys in the emulator. 3978 public boolean hasNavigationBar() { 3979 return mHasNavigationBar; 3980 } 3981 3982 public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) { 3983 pw.print(prefix); pw.print("mSafeMode="); pw.print(mSafeMode); 3984 pw.print(" mSystemReady="); pw.print(mSystemReady); 3985 pw.print(" mSystemBooted="); pw.println(mSystemBooted); 3986 pw.print(prefix); pw.print("mLidOpen="); pw.print(mLidOpen); 3987 pw.print(" mLidOpenRotation="); pw.print(mLidOpenRotation); 3988 pw.print(" mHdmiPlugged="); pw.println(mHdmiPlugged); 3989 if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0 3990 || mForceClearedSystemUiFlags != 0) { 3991 pw.print(prefix); pw.print("mLastSystemUiFlags=0x"); 3992 pw.print(Integer.toHexString(mLastSystemUiFlags)); 3993 pw.print(" mResettingSystemUiFlags=0x"); 3994 pw.print(Integer.toHexString(mResettingSystemUiFlags)); 3995 pw.print(" mForceClearedSystemUiFlags=0x"); 3996 pw.println(Integer.toHexString(mForceClearedSystemUiFlags)); 3997 } 3998 if (mLastFocusNeedsMenu) { 3999 pw.print(prefix); pw.print("mLastFocusNeedsMenu="); 4000 pw.println(mLastFocusNeedsMenu); 4001 } 4002 pw.print(prefix); pw.print("mUiMode="); pw.print(mUiMode); 4003 pw.print(" mDockMode="); pw.print(mDockMode); 4004 pw.print(" mCarDockRotation="); pw.print(mCarDockRotation); 4005 pw.print(" mDeskDockRotation="); pw.println(mDeskDockRotation); 4006 pw.print(prefix); pw.print("mUserRotationMode="); pw.print(mUserRotationMode); 4007 pw.print(" mUserRotation="); pw.print(mUserRotation); 4008 pw.print(" mAllowAllRotations="); pw.println(mAllowAllRotations); 4009 pw.print(prefix); pw.print("mAccelerometerDefault="); pw.print(mAccelerometerDefault); 4010 pw.print(" mCurrentAppOrientation="); pw.println(mCurrentAppOrientation); 4011 pw.print(prefix); pw.print("mCarDockEnablesAccelerometer="); 4012 pw.print(mCarDockEnablesAccelerometer); 4013 pw.print(" mDeskDockEnablesAccelerometer="); 4014 pw.println(mDeskDockEnablesAccelerometer); 4015 pw.print(prefix); pw.print("mLidKeyboardAccessibility="); 4016 pw.print(mLidKeyboardAccessibility); 4017 pw.print(" mLidNavigationAccessibility="); pw.print(mLidNavigationAccessibility); 4018 pw.print(" mLongPressOnPowerBehavior="); pw.println(mLongPressOnPowerBehavior); 4019 pw.print(prefix); pw.print("mScreenOnEarly="); pw.print(mScreenOnEarly); 4020 pw.print(" mScreenOnFully="); pw.print(mScreenOnFully); 4021 pw.print(" mOrientationSensorEnabled="); pw.print(mOrientationSensorEnabled); 4022 pw.print(" mHasSoftInput="); pw.println(mHasSoftInput); 4023 pw.print(prefix); pw.print("mUnrestrictedScreen=("); pw.print(mUnrestrictedScreenLeft); 4024 pw.print(","); pw.print(mUnrestrictedScreenTop); 4025 pw.print(") "); pw.print(mUnrestrictedScreenWidth); 4026 pw.print("x"); pw.println(mUnrestrictedScreenHeight); 4027 pw.print(prefix); pw.print("mRestrictedScreen=("); pw.print(mRestrictedScreenLeft); 4028 pw.print(","); pw.print(mRestrictedScreenTop); 4029 pw.print(") "); pw.print(mRestrictedScreenWidth); 4030 pw.print("x"); pw.println(mRestrictedScreenHeight); 4031 pw.print(prefix); pw.print("mCur=("); pw.print(mCurLeft); 4032 pw.print(","); pw.print(mCurTop); 4033 pw.print(")-("); pw.print(mCurRight); 4034 pw.print(","); pw.print(mCurBottom); pw.println(")"); 4035 pw.print(prefix); pw.print("mContent=("); pw.print(mContentLeft); 4036 pw.print(","); pw.print(mContentTop); 4037 pw.print(")-("); pw.print(mContentRight); 4038 pw.print(","); pw.print(mContentBottom); pw.println(")"); 4039 pw.print(prefix); pw.print("mDock=("); pw.print(mDockLeft); 4040 pw.print(","); pw.print(mDockTop); 4041 pw.print(")-("); pw.print(mDockRight); 4042 pw.print(","); pw.print(mDockBottom); pw.println(")"); 4043 pw.print(prefix); pw.print("mDockLayer="); pw.println(mDockLayer); 4044 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState="); 4045 pw.println(mTopFullscreenOpaqueWindowState); 4046 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen); 4047 pw.print(" mForceStatusBar="); pw.print(mForceStatusBar); 4048 pw.print(" mHideLockScreen="); pw.println(mHideLockScreen); 4049 pw.print(prefix); pw.print("mDismissKeyguard="); pw.print(mDismissKeyguard); 4050 pw.print(" mHomePressed="); pw.println(mHomePressed); 4051 pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.print(mAllowLockscreenWhenOn); 4052 pw.print(" mLockScreenTimeout="); pw.print(mLockScreenTimeout); 4053 pw.print(" mLockScreenTimerActive="); pw.println(mLockScreenTimerActive); 4054 pw.print(prefix); pw.print("mEndcallBehavior="); pw.print(mEndcallBehavior); 4055 pw.print(" mIncallPowerBehavior="); pw.print(mIncallPowerBehavior); 4056 pw.print(" mLongPressOnHomeBehavior="); pw.println(mLongPressOnHomeBehavior); 4057 pw.print(prefix); pw.print("mLandscapeRotation="); pw.print(mLandscapeRotation); 4058 pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation); 4059 pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation); 4060 pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation); 4061 } 4062} 4063