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