WindowManagerService.java revision 5a052a4d19556700a21286029f37e1cc37f217b1
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.wm; 18 19import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 20import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; 21import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; 22import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; 23import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; 24import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 25import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; 26import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 27import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 28import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; 29import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 30import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 31import static android.view.WindowManager.LayoutParams.TYPE_DREAM; 32import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 33import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; 34import static android.view.WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND; 35import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 36 37import com.android.internal.app.IBatteryStats; 38import com.android.internal.policy.PolicyManager; 39import com.android.internal.policy.impl.PhoneWindowManager; 40import com.android.internal.view.IInputContext; 41import com.android.internal.view.IInputMethodClient; 42import com.android.internal.view.IInputMethodManager; 43import com.android.internal.view.WindowManagerPolicyThread; 44import com.android.server.AttributeCache; 45import com.android.server.EventLogTags; 46import com.android.server.Watchdog; 47import com.android.server.am.BatteryStatsService; 48import com.android.server.display.DisplayDeviceInfo; 49import com.android.server.display.DisplayManagerService; 50import com.android.server.input.InputManagerService; 51import com.android.server.power.PowerManagerService; 52import com.android.server.power.ShutdownThread; 53 54import android.Manifest; 55import android.app.ActivityManagerNative; 56import android.app.ActivityOptions; 57import android.app.IActivityManager; 58import android.app.StatusBarManager; 59import android.app.admin.DevicePolicyManager; 60import android.content.BroadcastReceiver; 61import android.content.Context; 62import android.content.Intent; 63import android.content.IntentFilter; 64import android.content.pm.ActivityInfo; 65import android.content.pm.PackageManager; 66import android.content.res.CompatibilityInfo; 67import android.content.res.Configuration; 68import android.graphics.Bitmap; 69import android.graphics.Canvas; 70import android.graphics.Matrix; 71import android.graphics.PixelFormat; 72import android.graphics.Point; 73import android.graphics.Rect; 74import android.graphics.RectF; 75import android.graphics.Region; 76import android.os.BatteryStats; 77import android.os.Binder; 78import android.os.Bundle; 79import android.os.Debug; 80import android.os.Handler; 81import android.os.IBinder; 82import android.os.IRemoteCallback; 83import android.os.Looper; 84import android.os.Message; 85import android.os.Parcel; 86import android.os.ParcelFileDescriptor; 87import android.os.PowerManager; 88import android.os.Process; 89import android.os.RemoteException; 90import android.os.ServiceManager; 91import android.os.StrictMode; 92import android.os.SystemClock; 93import android.os.SystemProperties; 94import android.os.TokenWatcher; 95import android.os.Trace; 96import android.provider.Settings; 97import android.util.DisplayMetrics; 98import android.util.EventLog; 99import android.util.FloatMath; 100import android.util.Log; 101import android.util.SparseArray; 102//import android.util.LogPrinter; 103import android.util.Pair; 104import android.util.Slog; 105import android.util.SparseIntArray; 106import android.util.TypedValue; 107import android.view.Choreographer; 108import android.view.Display; 109import android.view.DisplayInfo; 110import android.view.Gravity; 111import android.view.IApplicationToken; 112import android.view.IInputFilter; 113import android.view.IOnKeyguardExitResult; 114import android.view.IRotationWatcher; 115import android.view.IWindow; 116import android.view.IWindowManager; 117import android.view.IWindowSession; 118import android.view.InputChannel; 119import android.view.InputDevice; 120import android.view.InputEvent; 121import android.view.InputEventReceiver; 122import android.view.KeyEvent; 123import android.view.MotionEvent; 124import android.view.Surface; 125import android.view.SurfaceSession; 126import android.view.View; 127import android.view.ViewTreeObserver; 128import android.view.WindowManager; 129import android.view.WindowManagerImpl; 130import android.view.WindowManagerPolicy; 131import android.view.WindowManager.LayoutParams; 132import android.view.WindowManagerPolicy.FakeWindow; 133import android.view.animation.AlphaAnimation; 134import android.view.animation.Animation; 135import android.view.animation.AnimationSet; 136import android.view.animation.AnimationUtils; 137import android.view.animation.DecelerateInterpolator; 138import android.view.animation.Interpolator; 139import android.view.animation.ScaleAnimation; 140import android.view.animation.Transformation; 141 142import java.io.BufferedWriter; 143import java.io.DataInputStream; 144import java.io.File; 145import java.io.FileDescriptor; 146import java.io.FileInputStream; 147import java.io.FileNotFoundException; 148import java.io.IOException; 149import java.io.OutputStream; 150import java.io.OutputStreamWriter; 151import java.io.PrintWriter; 152import java.io.StringWriter; 153import java.net.Socket; 154import java.text.DateFormat; 155import java.util.ArrayList; 156import java.util.Date; 157import java.util.HashMap; 158import java.util.HashSet; 159import java.util.Iterator; 160import java.util.List; 161import java.util.NoSuchElementException; 162 163/** {@hide} */ 164public class WindowManagerService extends IWindowManager.Stub 165 implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { 166 static final String TAG = "WindowManager"; 167 static final boolean DEBUG = false; 168 static final boolean DEBUG_ADD_REMOVE = false; 169 static final boolean DEBUG_FOCUS = false; 170 static final boolean DEBUG_ANIM = false; 171 static final boolean DEBUG_LAYOUT = false; 172 static final boolean DEBUG_RESIZE = false; 173 static final boolean DEBUG_LAYERS = false; 174 static final boolean DEBUG_INPUT = false; 175 static final boolean DEBUG_INPUT_METHOD = false; 176 static final boolean DEBUG_VISIBILITY = false; 177 static final boolean DEBUG_WINDOW_MOVEMENT = false; 178 static final boolean DEBUG_TOKEN_MOVEMENT = false; 179 static final boolean DEBUG_ORIENTATION = false; 180 static final boolean DEBUG_APP_ORIENTATION = false; 181 static final boolean DEBUG_CONFIGURATION = false; 182 static final boolean DEBUG_APP_TRANSITIONS = false; 183 static final boolean DEBUG_STARTING_WINDOW = false; 184 static final boolean DEBUG_REORDER = false; 185 static final boolean DEBUG_WALLPAPER = false; 186 static final boolean DEBUG_DRAG = false; 187 static final boolean DEBUG_SCREEN_ON = false; 188 static final boolean DEBUG_SCREENSHOT = false; 189 static final boolean DEBUG_BOOT = false; 190 static final boolean DEBUG_LAYOUT_REPEATS = true; 191 static final boolean DEBUG_SURFACE_TRACE = false; 192 static final boolean DEBUG_WINDOW_TRACE = false; 193 static final boolean SHOW_SURFACE_ALLOC = false; 194 static final boolean SHOW_TRANSACTIONS = false; 195 static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS; 196 static final boolean HIDE_STACK_CRAWLS = true; 197 static final int LAYOUT_REPEAT_THRESHOLD = 4; 198 199 static final boolean PROFILE_ORIENTATION = false; 200 static final boolean localLOGV = DEBUG; 201 202 /** How much to multiply the policy's type layer, to reserve room 203 * for multiple windows of the same type and Z-ordering adjustment 204 * with TYPE_LAYER_OFFSET. */ 205 static final int TYPE_LAYER_MULTIPLIER = 10000; 206 207 /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above 208 * or below others in the same layer. */ 209 static final int TYPE_LAYER_OFFSET = 1000; 210 211 /** How much to increment the layer for each window, to reserve room 212 * for effect surfaces between them. 213 */ 214 static final int WINDOW_LAYER_MULTIPLIER = 5; 215 216 /** 217 * Dim surface layer is immediately below target window. 218 */ 219 static final int LAYER_OFFSET_DIM = 1; 220 221 /** 222 * Blur surface layer is immediately below dim layer. 223 */ 224 static final int LAYER_OFFSET_BLUR = 2; 225 226 /** 227 * Animation thumbnail is as far as possible below the window above 228 * the thumbnail (or in other words as far as possible above the window 229 * below it). 230 */ 231 static final int LAYER_OFFSET_THUMBNAIL = WINDOW_LAYER_MULTIPLIER-1; 232 233 /** 234 * Layer at which to put the rotation freeze snapshot. 235 */ 236 static final int FREEZE_LAYER = (TYPE_LAYER_MULTIPLIER * 200) + 1; 237 238 /** 239 * Layer at which to put the mask for emulated screen sizes. 240 */ 241 static final int MASK_LAYER = TYPE_LAYER_MULTIPLIER * 200; 242 243 /** The maximum length we will accept for a loaded animation duration: 244 * this is 10 seconds. 245 */ 246 static final int MAX_ANIMATION_DURATION = 10*1000; 247 248 /** Amount of time (in milliseconds) to animate the dim surface from one 249 * value to another, when no window animation is driving it. 250 */ 251 static final int DEFAULT_DIM_DURATION = 200; 252 253 /** Amount of time (in milliseconds) to animate the fade-in-out transition for 254 * compatible windows. 255 */ 256 static final int DEFAULT_FADE_IN_OUT_DURATION = 400; 257 258 /** 259 * If true, the window manager will do its own custom freezing and general 260 * management of the screen during rotation. 261 */ 262 static final boolean CUSTOM_SCREEN_ROTATION = true; 263 264 // Maximum number of milliseconds to wait for input devices to be enumerated before 265 // proceding with safe mode detection. 266 private static final int INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS = 1000; 267 268 // Default input dispatching timeout in nanoseconds. 269 static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L; 270 271 static final int UPDATE_FOCUS_NORMAL = 0; 272 static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1; 273 static final int UPDATE_FOCUS_PLACING_SURFACES = 2; 274 static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3; 275 276 private static final String SYSTEM_SECURE = "ro.secure"; 277 private static final String SYSTEM_DEBUGGABLE = "ro.debuggable"; 278 279 /** 280 * Condition waited on by {@link #reenableKeyguard} to know the call to 281 * the window policy has finished. 282 * This is set to true only if mKeyguardTokenWatcher.acquired() has 283 * actually disabled the keyguard. 284 */ 285 private boolean mKeyguardDisabled = false; 286 287 private final boolean mHeadless; 288 289 private static final int ALLOW_DISABLE_YES = 1; 290 private static final int ALLOW_DISABLE_NO = 0; 291 private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager 292 private int mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN; // sync'd by mKeyguardTokenWatcher 293 294 private static final float THUMBNAIL_ANIMATION_DECELERATE_FACTOR = 1.5f; 295 296 final TokenWatcher mKeyguardTokenWatcher = new TokenWatcher( 297 new Handler(), "WindowManagerService.mKeyguardTokenWatcher") { 298 @Override 299 public void acquired() { 300 if (shouldAllowDisableKeyguard()) { 301 mPolicy.enableKeyguard(false); 302 mKeyguardDisabled = true; 303 } else { 304 Log.v(TAG, "Not disabling keyguard since device policy is enforced"); 305 } 306 } 307 @Override 308 public void released() { 309 mPolicy.enableKeyguard(true); 310 synchronized (mKeyguardTokenWatcher) { 311 mKeyguardDisabled = false; 312 mKeyguardTokenWatcher.notifyAll(); 313 } 314 } 315 }; 316 317 final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 318 @Override 319 public void onReceive(Context context, Intent intent) { 320 mPolicy.enableKeyguard(true); 321 synchronized(mKeyguardTokenWatcher) { 322 // lazily evaluate this next time we're asked to disable keyguard 323 mAllowDisableKeyguard = ALLOW_DISABLE_UNKNOWN; 324 mKeyguardDisabled = false; 325 } 326 } 327 }; 328 329 final Context mContext; 330 331 final boolean mHaveInputMethods; 332 333 final boolean mAllowBootMessages; 334 335 final boolean mLimitedAlphaCompositing; 336 337 final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager(); 338 339 final IActivityManager mActivityManager; 340 341 final IBatteryStats mBatteryStats; 342 343 /** 344 * All currently active sessions with clients. 345 */ 346 final HashSet<Session> mSessions = new HashSet<Session>(); 347 348 /** 349 * Mapping from an IWindow IBinder to the server's Window object. 350 * This is also used as the lock for all of our state. 351 */ 352 final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>(); 353 354 /** 355 * Mapping from a token IBinder to a WindowToken object. 356 */ 357 final HashMap<IBinder, WindowToken> mTokenMap = 358 new HashMap<IBinder, WindowToken>(); 359 360 /** 361 * Window tokens that are in the process of exiting, but still 362 * on screen for animations. 363 */ 364 final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>(); 365 366 /** 367 * List controlling the ordering of windows in different applications which must 368 * be kept in sync with ActivityManager. 369 */ 370 final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>(); 371 372 /** 373 * AppWindowTokens in the Z order they were in at the start of an animation. Between 374 * animations this list is maintained in the exact order of mAppTokens. If tokens 375 * are added to mAppTokens during an animation an attempt is made to insert them at the same 376 * logical location in this list. Note that this list is always in sync with mWindows. 377 */ 378 ArrayList<AppWindowToken> mAnimatingAppTokens = new ArrayList<AppWindowToken>(); 379 380 /** 381 * Application tokens that are in the process of exiting, but still 382 * on screen for animations. 383 */ 384 final ArrayList<AppWindowToken> mExitingAppTokens = new ArrayList<AppWindowToken>(); 385 386 /** 387 * List of window tokens that have finished starting their application, 388 * and now need to have the policy remove their windows. 389 */ 390 final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>(); 391 392 /** 393 * Fake windows added to the window manager. Note: ordered from top to 394 * bottom, opposite of mWindows. 395 */ 396 final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<FakeWindowImpl>(); 397 398 /** 399 * Windows that are being resized. Used so we can tell the client about 400 * the resize after closing the transaction in which we resized the 401 * underlying surface. 402 */ 403 final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>(); 404 405 /** 406 * Windows whose animations have ended and now must be removed. 407 */ 408 final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>(); 409 410 /** 411 * Used when processing mPendingRemove to avoid working on the original array. 412 */ 413 WindowState[] mPendingRemoveTmp = new WindowState[20]; 414 415 /** 416 * Windows whose surface should be destroyed. 417 */ 418 final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>(); 419 420 /** 421 * Windows that have lost input focus and are waiting for the new 422 * focus window to be displayed before they are told about this. 423 */ 424 ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>(); 425 426 /** 427 * This is set when we have run out of memory, and will either be an empty 428 * list or contain windows that need to be force removed. 429 */ 430 ArrayList<WindowState> mForceRemoves; 431 432 /** 433 * Windows that clients are waiting to have drawn. 434 */ 435 ArrayList<Pair<WindowState, IRemoteCallback>> mWaitingForDrawn 436 = new ArrayList<Pair<WindowState, IRemoteCallback>>(); 437 438 /** 439 * Windows that have called relayout() while we were running animations, 440 * so we need to tell when the animation is done. 441 */ 442 final ArrayList<WindowState> mRelayoutWhileAnimating = new ArrayList<WindowState>(); 443 444 /** 445 * Used when rebuilding window list to keep track of windows that have 446 * been removed. 447 */ 448 WindowState[] mRebuildTmp = new WindowState[20]; 449 450 IInputMethodManager mInputMethodManager; 451 452 final SurfaceSession mFxSession; 453 Watermark mWatermark; 454 StrictModeFlash mStrictModeFlash; 455 456 BlackFrame mBlackFrame; 457 458 final float[] mTmpFloats = new float[9]; 459 460 boolean mSafeMode; 461 boolean mDisplayEnabled = false; 462 boolean mSystemBooted = false; 463 boolean mForceDisplayEnabled = false; 464 boolean mShowingBootMessages = false; 465 466 String mLastANRState; 467 468 /** All DisplayDontents in the world, kept here */ 469 private SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>(); 470 471 int mRotation = 0; 472 int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 473 boolean mAltOrientation = false; 474 ArrayList<IRotationWatcher> mRotationWatchers 475 = new ArrayList<IRotationWatcher>(); 476 int mDeferredRotationPauseCount; 477 478 final Rect mSystemDecorRect = new Rect(); 479 int mSystemDecorLayer = 0; 480 final Rect mScreenRect = new Rect(); 481 482 int mPendingLayoutChanges = 0; 483 boolean mLayoutNeeded = true; 484 boolean mTraversalScheduled = false; 485 boolean mDisplayFrozen = false; 486 boolean mWaitingForConfig = false; 487 boolean mWindowsFreezingScreen = false; 488 int mAppsFreezingScreen = 0; 489 int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 490 491 int mLayoutSeq = 0; 492 493 int mLastStatusBarVisibility = 0; 494 495 // State while inside of layoutAndPlaceSurfacesLocked(). 496 boolean mFocusMayChange; 497 498 Configuration mCurConfiguration = new Configuration(); 499 500 // This is held as long as we have the screen frozen, to give us time to 501 // perform a rotation animation when turning off shows the lock screen which 502 // changes the orientation. 503 PowerManager.WakeLock mScreenFrozenLock; 504 505 // State management of app transitions. When we are preparing for a 506 // transition, mNextAppTransition will be the kind of transition to 507 // perform or TRANSIT_NONE if we are not waiting. If we are waiting, 508 // mOpeningApps and mClosingApps are the lists of tokens that will be 509 // made visible or hidden at the next transition. 510 int mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET; 511 int mNextAppTransitionType = ActivityOptions.ANIM_NONE; 512 String mNextAppTransitionPackage; 513 Bitmap mNextAppTransitionThumbnail; 514 boolean mNextAppTransitionDelayed; 515 IRemoteCallback mNextAppTransitionCallback; 516 int mNextAppTransitionEnter; 517 int mNextAppTransitionExit; 518 int mNextAppTransitionStartX; 519 int mNextAppTransitionStartY; 520 int mNextAppTransitionStartWidth; 521 int mNextAppTransitionStartHeight; 522 boolean mAppTransitionReady = false; 523 boolean mAppTransitionRunning = false; 524 boolean mAppTransitionTimeout = false; 525 boolean mStartingIconInTransition = false; 526 boolean mSkipAppTransitionAnimation = false; 527 final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>(); 528 final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>(); 529 530 Display mDisplay; 531 532 boolean mIsTouchDevice; 533 534 final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); 535 final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics(); 536 final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics(); 537 final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics(); 538 539 final H mH = new H(); 540 541 final Choreographer mChoreographer = Choreographer.getInstance(); 542 543 WindowState mCurrentFocus = null; 544 WindowState mLastFocus = null; 545 546 /** This just indicates the window the input method is on top of, not 547 * necessarily the window its input is going to. */ 548 WindowState mInputMethodTarget = null; 549 550 /** If true hold off on modifying the animation layer of mInputMethodTarget */ 551 boolean mInputMethodTargetWaitingAnim; 552 int mInputMethodAnimLayerAdjustment; 553 554 WindowState mInputMethodWindow = null; 555 final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>(); 556 557 boolean mHardKeyboardAvailable; 558 boolean mHardKeyboardEnabled; 559 OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; 560 561 final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>(); 562 563 // If non-null, this is the currently visible window that is associated 564 // with the wallpaper. 565 WindowState mWallpaperTarget = null; 566 // If non-null, we are in the middle of animating from one wallpaper target 567 // to another, and this is the lower one in Z-order. 568 private WindowState mLowerWallpaperTarget = null; 569 // If non-null, we are in the middle of animating from one wallpaper target 570 // to another, and this is the higher one in Z-order. 571 private WindowState mUpperWallpaperTarget = null; 572 int mWallpaperAnimLayerAdjustment; 573 float mLastWallpaperX = -1; 574 float mLastWallpaperY = -1; 575 float mLastWallpaperXStep = -1; 576 float mLastWallpaperYStep = -1; 577 // This is set when we are waiting for a wallpaper to tell us it is done 578 // changing its scroll position. 579 WindowState mWaitingOnWallpaper; 580 // The last time we had a timeout when waiting for a wallpaper. 581 long mLastWallpaperTimeoutTime; 582 // We give a wallpaper up to 150ms to finish scrolling. 583 static final long WALLPAPER_TIMEOUT = 150; 584 // Time we wait after a timeout before trying to wait again. 585 static final long WALLPAPER_TIMEOUT_RECOVERY = 10000; 586 587 AppWindowToken mFocusedApp = null; 588 589 PowerManagerService mPowerManager; 590 591 float mWindowAnimationScale = 1.0f; 592 float mTransitionAnimationScale = 1.0f; 593 float mAnimatorDurationScale = 1.0f; 594 595 final InputManagerService mInputManager; 596 final DisplayManagerService mDisplayManager; 597 598 // Who is holding the screen on. 599 Session mHoldingScreenOn; 600 PowerManager.WakeLock mHoldingScreenWakeLock; 601 602 boolean mTurnOnScreen; 603 604 DragState mDragState = null; 605 606 /** Pulled out of performLayoutAndPlaceSurfacesLockedInner in order to refactor into multiple 607 * methods. */ 608 class LayoutFields { 609 static final int SET_UPDATE_ROTATION = 1 << 0; 610 static final int SET_WALLPAPER_MAY_CHANGE = 1 << 1; 611 static final int SET_FORCE_HIDING_CHANGED = 1 << 2; 612 static final int SET_ORIENTATION_CHANGE_COMPLETE = 1 << 3; 613 static final int SET_TURN_ON_SCREEN = 1 << 4; 614 615 boolean mWallpaperForceHidingChanged = false; 616 boolean mWallpaperMayChange = false; 617 boolean mOrientationChangeComplete = true; 618 int mAdjResult = 0; 619 private Session mHoldScreen = null; 620 private boolean mObscured = false; 621 boolean mDimming = false; 622 private boolean mSyswin = false; 623 private float mScreenBrightness = -1; 624 private float mButtonBrightness = -1; 625 private boolean mUpdateRotation = false; 626 } 627 final LayoutFields mInnerFields = new LayoutFields(); 628 629 static class AppWindowAnimParams { 630 AppWindowAnimator mAppAnimator; 631 ArrayList<WindowStateAnimator> mWinAnimators; 632 633 public AppWindowAnimParams(final AppWindowAnimator appAnimator) { 634 mAppAnimator = appAnimator; 635 636 final AppWindowToken wtoken = appAnimator.mAppToken; 637 mWinAnimators = new ArrayList<WindowStateAnimator>(); 638 final int N = wtoken.allAppWindows.size(); 639 for (int i = 0; i < N; i++) { 640 mWinAnimators.add(wtoken.allAppWindows.get(i).mWinAnimator); 641 } 642 } 643 } 644 645 static class LayoutToAnimatorParams { 646 boolean mParamsModified; 647 648 static final long WALLPAPER_TOKENS_CHANGED = 1 << 0; 649 long mChanges; 650 651 boolean mAnimationScheduled; 652 ArrayList<WinAnimatorList> mWinAnimatorLists = new ArrayList<WinAnimatorList>(); 653 WindowState mWallpaperTarget; 654 WindowState mLowerWallpaperTarget; 655 WindowState mUpperWallpaperTarget; 656 DimAnimator.Parameters mDimParams; 657 ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>(); 658 ArrayList<AppWindowAnimParams> mAppWindowAnimParams = new ArrayList<AppWindowAnimParams>(); 659 } 660 /** Params from WindowManagerService to WindowAnimator. Do not modify or read without first 661 * locking on either mWindowMap or mAnimator and then on mLayoutToAnim */ 662 final LayoutToAnimatorParams mLayoutToAnim = new LayoutToAnimatorParams(); 663 664 /** The lowest wallpaper target with a detached wallpaper animation on it. */ 665 WindowState mWindowDetachedWallpaper = null; 666 667 /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this 668 * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */ 669 private int mTransactionSequence; 670 671 /** Only do a maximum of 6 repeated layouts. After that quit */ 672 private int mLayoutRepeatCount; 673 674 final WindowAnimator mAnimator; 675 676 final class DragInputEventReceiver extends InputEventReceiver { 677 public DragInputEventReceiver(InputChannel inputChannel, Looper looper) { 678 super(inputChannel, looper); 679 } 680 681 @Override 682 public void onInputEvent(InputEvent event) { 683 boolean handled = false; 684 try { 685 if (event instanceof MotionEvent 686 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0 687 && mDragState != null) { 688 final MotionEvent motionEvent = (MotionEvent)event; 689 boolean endDrag = false; 690 final float newX = motionEvent.getRawX(); 691 final float newY = motionEvent.getRawY(); 692 693 switch (motionEvent.getAction()) { 694 case MotionEvent.ACTION_DOWN: { 695 if (DEBUG_DRAG) { 696 Slog.w(TAG, "Unexpected ACTION_DOWN in drag layer"); 697 } 698 } break; 699 700 case MotionEvent.ACTION_MOVE: { 701 synchronized (mWindowMap) { 702 // move the surface and tell the involved window(s) where we are 703 mDragState.notifyMoveLw(newX, newY); 704 } 705 } break; 706 707 case MotionEvent.ACTION_UP: { 708 if (DEBUG_DRAG) Slog.d(TAG, "Got UP on move channel; dropping at " 709 + newX + "," + newY); 710 synchronized (mWindowMap) { 711 endDrag = mDragState.notifyDropLw(newX, newY); 712 } 713 } break; 714 715 case MotionEvent.ACTION_CANCEL: { 716 if (DEBUG_DRAG) Slog.d(TAG, "Drag cancelled!"); 717 endDrag = true; 718 } break; 719 } 720 721 if (endDrag) { 722 if (DEBUG_DRAG) Slog.d(TAG, "Drag ended; tearing down state"); 723 // tell all the windows that the drag has ended 724 synchronized (mWindowMap) { 725 mDragState.endDragLw(); 726 } 727 } 728 729 handled = true; 730 } 731 } catch (Exception e) { 732 Slog.e(TAG, "Exception caught by drag handleMotion", e); 733 } finally { 734 finishInputEvent(event, handled); 735 } 736 } 737 } 738 739 /** 740 * Whether the UI is currently running in touch mode (not showing 741 * navigational focus because the user is directly pressing the screen). 742 */ 743 boolean mInTouchMode = true; 744 745 private ViewServer mViewServer; 746 private ArrayList<WindowChangeListener> mWindowChangeListeners = 747 new ArrayList<WindowChangeListener>(); 748 private boolean mWindowsChanged = false; 749 750 public interface WindowChangeListener { 751 public void windowsChanged(); 752 public void focusChanged(); 753 } 754 755 final Configuration mTempConfiguration = new Configuration(); 756 757 // The desired scaling factor for compatible apps. 758 float mCompatibleScreenScale; 759 760 // If true, only the core apps and services are being launched because the device 761 // is in a special boot mode, such as being encrypted or waiting for a decryption password. 762 // For example, when this flag is true, there will be no wallpaper service. 763 final boolean mOnlyCore; 764 765 public static WindowManagerService main(Context context, 766 PowerManagerService pm, DisplayManagerService dm, 767 boolean haveInputMethods, boolean allowBootMsgs, 768 boolean onlyCore) { 769 WMThread thr = new WMThread(context, pm, dm, haveInputMethods, allowBootMsgs, onlyCore); 770 thr.start(); 771 772 synchronized (thr) { 773 while (thr.mService == null) { 774 try { 775 thr.wait(); 776 } catch (InterruptedException e) { 777 } 778 } 779 return thr.mService; 780 } 781 } 782 783 static class WMThread extends Thread { 784 WindowManagerService mService; 785 786 private final Context mContext; 787 private final PowerManagerService mPM; 788 private final DisplayManagerService mDisplayManager; 789 private final boolean mHaveInputMethods; 790 private final boolean mAllowBootMessages; 791 private final boolean mOnlyCore; 792 793 public WMThread(Context context, PowerManagerService pm, 794 DisplayManagerService dm, 795 boolean haveInputMethods, boolean allowBootMsgs, boolean onlyCore) { 796 super("WindowManager"); 797 mContext = context; 798 mPM = pm; 799 mDisplayManager = dm; 800 mHaveInputMethods = haveInputMethods; 801 mAllowBootMessages = allowBootMsgs; 802 mOnlyCore = onlyCore; 803 } 804 805 @Override 806 public void run() { 807 Looper.prepare(); 808 //Looper.myLooper().setMessageLogging(new LogPrinter( 809 // android.util.Log.DEBUG, TAG, android.util.Log.LOG_ID_SYSTEM)); 810 WindowManagerService s = new WindowManagerService(mContext, mPM, mDisplayManager, 811 mHaveInputMethods, mAllowBootMessages, mOnlyCore); 812 android.os.Process.setThreadPriority( 813 android.os.Process.THREAD_PRIORITY_DISPLAY); 814 android.os.Process.setCanSelfBackground(false); 815 816 synchronized (this) { 817 mService = s; 818 notifyAll(); 819 } 820 821 // For debug builds, log event loop stalls to dropbox for analysis. 822 if (StrictMode.conditionallyEnableDebugLogging()) { 823 Slog.i(TAG, "Enabled StrictMode logging for WMThread's Looper"); 824 } 825 826 Looper.loop(); 827 } 828 } 829 830 static class PolicyThread extends Thread { 831 private final WindowManagerPolicy mPolicy; 832 private final WindowManagerService mService; 833 private final Context mContext; 834 private final PowerManagerService mPM; 835 boolean mRunning = false; 836 837 public PolicyThread(WindowManagerPolicy policy, 838 WindowManagerService service, Context context, 839 PowerManagerService pm) { 840 super("WindowManagerPolicy"); 841 mPolicy = policy; 842 mService = service; 843 mContext = context; 844 mPM = pm; 845 } 846 847 @Override 848 public void run() { 849 Looper.prepare(); 850 WindowManagerPolicyThread.set(this, Looper.myLooper()); 851 852 //Looper.myLooper().setMessageLogging(new LogPrinter( 853 // Log.VERBOSE, "WindowManagerPolicy", Log.LOG_ID_SYSTEM)); 854 android.os.Process.setThreadPriority( 855 android.os.Process.THREAD_PRIORITY_FOREGROUND); 856 android.os.Process.setCanSelfBackground(false); 857 mPolicy.init(mContext, mService, mService, mPM); 858 mService.mAnimator.mAboveUniverseLayer = mPolicy.getAboveUniverseLayer() 859 * TYPE_LAYER_MULTIPLIER 860 + TYPE_LAYER_OFFSET; 861 862 synchronized (this) { 863 mRunning = true; 864 notifyAll(); 865 } 866 867 // For debug builds, log event loop stalls to dropbox for analysis. 868 if (StrictMode.conditionallyEnableDebugLogging()) { 869 Slog.i(TAG, "Enabled StrictMode for PolicyThread's Looper"); 870 } 871 872 Looper.loop(); 873 } 874 } 875 876 private WindowManagerService(Context context, PowerManagerService pm, 877 DisplayManagerService displayManager, 878 boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) { 879 mContext = context; 880 mHaveInputMethods = haveInputMethods; 881 mAllowBootMessages = showBootMsgs; 882 mOnlyCore = onlyCore; 883 mLimitedAlphaCompositing = context.getResources().getBoolean( 884 com.android.internal.R.bool.config_sf_limitedAlpha); 885 mDisplayManager = displayManager; 886 mHeadless = displayManager.isHeadless(); 887 888 mPowerManager = pm; 889 mPowerManager.setPolicy(mPolicy); 890 PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 891 mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, 892 "SCREEN_FROZEN"); 893 mScreenFrozenLock.setReferenceCounted(false); 894 895 mActivityManager = ActivityManagerNative.getDefault(); 896 mBatteryStats = BatteryStatsService.getService(); 897 898 // Get persisted window scale setting 899 mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(), 900 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale); 901 mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(), 902 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale); 903 mAnimatorDurationScale = Settings.System.getFloat(context.getContentResolver(), 904 Settings.System.ANIMATOR_DURATION_SCALE, mTransitionAnimationScale); 905 906 // Track changes to DevicePolicyManager state so we can enable/disable keyguard. 907 IntentFilter filter = new IntentFilter(); 908 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 909 mContext.registerReceiver(mBroadcastReceiver, filter); 910 911 mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK 912 | PowerManager.ON_AFTER_RELEASE, "KEEP_SCREEN_ON_FLAG"); 913 mHoldingScreenWakeLock.setReferenceCounted(false); 914 915 mInputManager = new InputManagerService(context, mInputMonitor); 916 mFxSession = new SurfaceSession(); 917 mAnimator = new WindowAnimator(this); 918 919 PolicyThread thr = new PolicyThread(mPolicy, this, context, pm); 920 thr.start(); 921 922 synchronized (thr) { 923 while (!thr.mRunning) { 924 try { 925 thr.wait(); 926 } catch (InterruptedException e) { 927 } 928 } 929 } 930 931 mInputManager.start(); 932 933 // Add ourself to the Watchdog monitors. 934 Watchdog.getInstance().addMonitor(this); 935 936 Surface.openTransaction(); 937 createWatermark(); 938 Surface.closeTransaction(); 939 } 940 941 public InputManagerService getInputManagerService() { 942 return mInputManager; 943 } 944 945 @Override 946 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 947 throws RemoteException { 948 try { 949 return super.onTransact(code, data, reply, flags); 950 } catch (RuntimeException e) { 951 // The window manager only throws security exceptions, so let's 952 // log all others. 953 if (!(e instanceof SecurityException)) { 954 Log.wtf(TAG, "Window Manager Crash", e); 955 } 956 throw e; 957 } 958 } 959 960 private void placeWindowAfter(WindowState pos, WindowState window) { 961 final WindowList windows = pos.getWindowList(); 962 final int i = windows.indexOf(pos); 963 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v( 964 TAG, "Adding window " + window + " at " 965 + (i+1) + " of " + windows.size() + " (after " + pos + ")"); 966 windows.add(i+1, window); 967 mWindowsChanged = true; 968 } 969 970 private void placeWindowBefore(WindowState pos, WindowState window) { 971 final WindowList windows = pos.getWindowList(); 972 final int i = windows.indexOf(pos); 973 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v( 974 TAG, "Adding window " + window + " at " 975 + i + " of " + windows.size() + " (before " + pos + ")"); 976 windows.add(i, window); 977 mWindowsChanged = true; 978 } 979 980 //This method finds out the index of a window that has the same app token as 981 //win. used for z ordering the windows in mWindows 982 private int findIdxBasedOnAppTokens(WindowState win) { 983 WindowList windows = win.getWindowList(); 984 for(int j = windows.size() - 1; j >= 0; j--) { 985 WindowState wentry = windows.get(j); 986 if(wentry.mAppToken == win.mAppToken) { 987 return j; 988 } 989 } 990 return -1; 991 } 992 993 private void addWindowToListInOrderLocked(WindowState win, boolean addToToken) { 994 final IWindow client = win.mClient; 995 final WindowToken token = win.mToken; 996 997 final WindowList windows = win.getWindowList(); 998 final int N = windows.size(); 999 final WindowState attached = win.mAttachedWindow; 1000 int i; 1001 if (attached == null) { 1002 int tokenWindowsPos = token.windows.size(); 1003 if (token.appWindowToken != null) { 1004 int index = tokenWindowsPos-1; 1005 if (index >= 0) { 1006 // If this application has existing windows, we 1007 // simply place the new window on top of them... but 1008 // keep the starting window on top. 1009 if (win.mAttrs.type == TYPE_BASE_APPLICATION) { 1010 // Base windows go behind everything else. 1011 placeWindowBefore(token.windows.get(0), win); 1012 tokenWindowsPos = 0; 1013 } else { 1014 AppWindowToken atoken = win.mAppToken; 1015 if (atoken != null && 1016 token.windows.get(index) == atoken.startingWindow) { 1017 placeWindowBefore(token.windows.get(index), win); 1018 tokenWindowsPos--; 1019 } else { 1020 int newIdx = findIdxBasedOnAppTokens(win); 1021 if(newIdx != -1) { 1022 //there is a window above this one associated with the same 1023 //apptoken note that the window could be a floating window 1024 //that was created later or a window at the top of the list of 1025 //windows associated with this token. 1026 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) { 1027 Slog.v(TAG, "Adding window " + win + " at " 1028 + (newIdx+1) + " of " + N); 1029 } 1030 windows.add(newIdx+1, win); 1031 mWindowsChanged = true; 1032 } 1033 } 1034 } 1035 } else { 1036 if (localLOGV) Slog.v( 1037 TAG, "Figuring out where to add app window " 1038 + client.asBinder() + " (token=" + token + ")"); 1039 // Figure out where the window should go, based on the 1040 // order of applications. 1041 final int NA = mAnimatingAppTokens.size(); 1042 WindowState pos = null; 1043 for (i=NA-1; i>=0; i--) { 1044 AppWindowToken t = mAnimatingAppTokens.get(i); 1045 if (t == token) { 1046 i--; 1047 break; 1048 } 1049 1050 // We haven't reached the token yet; if this token 1051 // is not going to the bottom and has windows, we can 1052 // use it as an anchor for when we do reach the token. 1053 if (!t.sendingToBottom && t.windows.size() > 0) { 1054 pos = t.windows.get(0); 1055 } 1056 } 1057 // We now know the index into the apps. If we found 1058 // an app window above, that gives us the position; else 1059 // we need to look some more. 1060 if (pos != null) { 1061 // Move behind any windows attached to this one. 1062 WindowToken atoken = mTokenMap.get(pos.mClient.asBinder()); 1063 if (atoken != null) { 1064 final int NC = atoken.windows.size(); 1065 if (NC > 0) { 1066 WindowState bottom = atoken.windows.get(0); 1067 if (bottom.mSubLayer < 0) { 1068 pos = bottom; 1069 } 1070 } 1071 } 1072 placeWindowBefore(pos, win); 1073 } else { 1074 // Continue looking down until we find the first 1075 // token that has windows. 1076 while (i >= 0) { 1077 AppWindowToken t = mAnimatingAppTokens.get(i); 1078 final int NW = t.windows.size(); 1079 if (NW > 0) { 1080 pos = t.windows.get(NW-1); 1081 break; 1082 } 1083 i--; 1084 } 1085 if (pos != null) { 1086 // Move in front of any windows attached to this 1087 // one. 1088 WindowToken atoken = mTokenMap.get(pos.mClient.asBinder()); 1089 if (atoken != null) { 1090 final int NC = atoken.windows.size(); 1091 if (NC > 0) { 1092 WindowState top = atoken.windows.get(NC-1); 1093 if (top.mSubLayer >= 0) { 1094 pos = top; 1095 } 1096 } 1097 } 1098 placeWindowAfter(pos, win); 1099 } else { 1100 // Just search for the start of this layer. 1101 final int myLayer = win.mBaseLayer; 1102 for (i=0; i<N; i++) { 1103 WindowState w = windows.get(i); 1104 if (w.mBaseLayer > myLayer) { 1105 break; 1106 } 1107 } 1108 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) { 1109 Slog.v(TAG, "Adding window " + win + " at " 1110 + i + " of " + N); 1111 } 1112 windows.add(i, win); 1113 mWindowsChanged = true; 1114 } 1115 } 1116 } 1117 } else { 1118 // Figure out where window should go, based on layer. 1119 final int myLayer = win.mBaseLayer; 1120 for (i=N-1; i>=0; i--) { 1121 if (windows.get(i).mBaseLayer <= myLayer) { 1122 i++; 1123 break; 1124 } 1125 } 1126 if (i < 0) i = 0; 1127 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v( 1128 TAG, "Adding window " + win + " at " 1129 + i + " of " + N); 1130 windows.add(i, win); 1131 mWindowsChanged = true; 1132 } 1133 1134 if (addToToken) { 1135 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token); 1136 token.windows.add(tokenWindowsPos, win); 1137 } 1138 1139 } else { 1140 // Figure out this window's ordering relative to the window 1141 // it is attached to. 1142 final int NA = token.windows.size(); 1143 final int sublayer = win.mSubLayer; 1144 int largestSublayer = Integer.MIN_VALUE; 1145 WindowState windowWithLargestSublayer = null; 1146 for (i=0; i<NA; i++) { 1147 WindowState w = token.windows.get(i); 1148 final int wSublayer = w.mSubLayer; 1149 if (wSublayer >= largestSublayer) { 1150 largestSublayer = wSublayer; 1151 windowWithLargestSublayer = w; 1152 } 1153 if (sublayer < 0) { 1154 // For negative sublayers, we go below all windows 1155 // in the same sublayer. 1156 if (wSublayer >= sublayer) { 1157 if (addToToken) { 1158 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token); 1159 token.windows.add(i, win); 1160 } 1161 placeWindowBefore(wSublayer >= 0 ? attached : w, win); 1162 break; 1163 } 1164 } else { 1165 // For positive sublayers, we go above all windows 1166 // in the same sublayer. 1167 if (wSublayer > sublayer) { 1168 if (addToToken) { 1169 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token); 1170 token.windows.add(i, win); 1171 } 1172 placeWindowBefore(w, win); 1173 break; 1174 } 1175 } 1176 } 1177 if (i >= NA) { 1178 if (addToToken) { 1179 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token); 1180 token.windows.add(win); 1181 } 1182 if (sublayer < 0) { 1183 placeWindowBefore(attached, win); 1184 } else { 1185 placeWindowAfter(largestSublayer >= 0 1186 ? windowWithLargestSublayer 1187 : attached, 1188 win); 1189 } 1190 } 1191 } 1192 1193 if (win.mAppToken != null && addToToken) { 1194 win.mAppToken.allAppWindows.add(win); 1195 } 1196 } 1197 1198 /** TODO(cmautner): Is this the same as {@link WindowState#canReceiveKeys()} */ 1199 static boolean canBeImeTarget(WindowState w) { 1200 final int fl = w.mAttrs.flags 1201 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM); 1202 if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM) 1203 || w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) { 1204 if (DEBUG_INPUT_METHOD) { 1205 Slog.i(TAG, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding()); 1206 if (!w.isVisibleOrAdding()) { 1207 Slog.i(TAG, " mSurface=" + w.mWinAnimator.mSurface 1208 + " relayoutCalled=" + w.mRelayoutCalled + " viewVis=" + w.mViewVisibility 1209 + " policyVis=" + w.mPolicyVisibility 1210 + " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim 1211 + " attachHid=" + w.mAttachedHidden 1212 + " exiting=" + w.mExiting + " destroying=" + w.mDestroying); 1213 if (w.mAppToken != null) { 1214 Slog.i(TAG, " mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested); 1215 } 1216 } 1217 } 1218 return w.isVisibleOrAdding(); 1219 } 1220 return false; 1221 } 1222 1223 /** 1224 * Dig through the WindowStates and find the one that the Input Method will target. 1225 * @param willMove 1226 * @param windows TODO(cmautner): 1227 * @return The index+1 in mWindows of the discovered target. 1228 */ 1229 int findDesiredInputMethodWindowIndexLocked(boolean willMove) { 1230 // TODO(multidisplay): Needs some serious rethought when the target and IME are not on the 1231 // same display. Or even when the current IME/target are not on the same screen as the next 1232 // IME/target. For now only look for input windows on the main screen. 1233 WindowList windows = getDefaultWindowList(); 1234 final int N = windows.size(); 1235 WindowState w = null; 1236 int i = N; 1237 while (i > 0) { 1238 i--; 1239 w = windows.get(i); 1240 1241 if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG, "Checking window @" + i 1242 + " " + w + " fl=0x" + Integer.toHexString(w.mAttrs.flags)); 1243 if (canBeImeTarget(w)) { 1244 //Slog.i(TAG, "Putting input method here!"); 1245 1246 // Yet more tricksyness! If this window is a "starting" 1247 // window, we do actually want to be on top of it, but 1248 // it is not -really- where input will go. So if the caller 1249 // is not actually looking to move the IME, look down below 1250 // for a real window to target... 1251 if (!willMove 1252 && w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING 1253 && i > 0) { 1254 WindowState wb = windows.get(i-1); 1255 if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) { 1256 i--; 1257 w = wb; 1258 } 1259 } 1260 break; 1261 } 1262 } 1263 1264 // Now w is either mWindows[0] or an IME (or null if mWindows is empty). 1265 1266 if (DEBUG_INPUT_METHOD && willMove) Slog.v(TAG, "Proposed new IME target: " + w); 1267 1268 // Now, a special case -- if the last target's window is in the 1269 // process of exiting, and is above the new target, keep on the 1270 // last target to avoid flicker. Consider for example a Dialog with 1271 // the IME shown: when the Dialog is dismissed, we want to keep 1272 // the IME above it until it is completely gone so it doesn't drop 1273 // behind the dialog or its full-screen scrim. 1274 final WindowState curTarget = mInputMethodTarget; 1275 if (curTarget != null && w != null 1276 && curTarget.isDisplayedLw() 1277 && curTarget.mExiting) { 1278 if (curTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) { 1279 w = curTarget; 1280 i = windows.indexOf(w); 1281 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Current target higher, switching to: " + w); 1282 } 1283 } 1284 1285 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Desired input method target=" 1286 + w + " willMove=" + willMove); 1287 1288 if (willMove && w != null) { 1289 AppWindowToken token = curTarget == null ? null : curTarget.mAppToken; 1290 if (token != null) { 1291 1292 // Now some fun for dealing with window animations that 1293 // modify the Z order. We need to look at all windows below 1294 // the current target that are in this app, finding the highest 1295 // visible one in layering. 1296 WindowState highestTarget = null; 1297 int highestPos = 0; 1298 if (token.mAppAnimator.animating || token.mAppAnimator.animation != null) { 1299 WindowList curWindows = curTarget.getWindowList(); 1300 int pos = curWindows.indexOf(curTarget); 1301 while (pos >= 0) { 1302 WindowState win = curWindows.get(pos); 1303 if (win.mAppToken != token) { 1304 break; 1305 } 1306 if (!win.mRemoved) { 1307 if (highestTarget == null || win.mWinAnimator.mAnimLayer > 1308 highestTarget.mWinAnimator.mAnimLayer) { 1309 highestTarget = win; 1310 highestPos = pos; 1311 } 1312 } 1313 pos--; 1314 } 1315 } 1316 1317 if (highestTarget != null) { 1318 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "mNextAppTransition=" 1319 + mNextAppTransition + " " + highestTarget 1320 + " animating=" + highestTarget.mWinAnimator.isAnimating() 1321 + " layer=" + highestTarget.mWinAnimator.mAnimLayer 1322 + " new layer=" + w.mWinAnimator.mAnimLayer); 1323 1324 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 1325 // If we are currently setting up for an animation, 1326 // hold everything until we can find out what will happen. 1327 mInputMethodTargetWaitingAnim = true; 1328 mInputMethodTarget = highestTarget; 1329 return highestPos + 1; 1330 } else if (highestTarget.mWinAnimator.isAnimating() && 1331 highestTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) { 1332 // If the window we are currently targeting is involved 1333 // with an animation, and it is on top of the next target 1334 // we will be over, then hold off on moving until 1335 // that is done. 1336 mInputMethodTargetWaitingAnim = true; 1337 mInputMethodTarget = highestTarget; 1338 return highestPos + 1; 1339 } 1340 } 1341 } 1342 } 1343 1344 //Slog.i(TAG, "Placing input method @" + (i+1)); 1345 if (w != null) { 1346 if (willMove) { 1347 if (DEBUG_INPUT_METHOD) Slog.w(TAG, "Moving IM target from " + curTarget + " to " 1348 + w + (HIDE_STACK_CRAWLS ? "" : " Callers=" + Debug.getCallers(4))); 1349 mInputMethodTarget = w; 1350 mInputMethodTargetWaitingAnim = false; 1351 if (w.mAppToken != null) { 1352 setInputMethodAnimLayerAdjustment(w.mAppToken.mAppAnimator.animLayerAdjustment); 1353 } else { 1354 setInputMethodAnimLayerAdjustment(0); 1355 } 1356 } 1357 return i+1; 1358 } 1359 if (willMove) { 1360 if (DEBUG_INPUT_METHOD) Slog.w(TAG, "Moving IM target from " + curTarget + " to null." 1361 + (HIDE_STACK_CRAWLS ? "" : " Callers=" + Debug.getCallers(4))); 1362 mInputMethodTarget = null; 1363 setInputMethodAnimLayerAdjustment(0); 1364 } 1365 return -1; 1366 } 1367 1368 void addInputMethodWindowToListLocked(WindowState win) { 1369 int pos = findDesiredInputMethodWindowIndexLocked(true); 1370 if (pos >= 0) { 1371 win.mTargetAppToken = mInputMethodTarget.mAppToken; 1372 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v( 1373 TAG, "Adding input method window " + win + " at " + pos); 1374 // TODO(multidisplay): IMEs are only supported on the default display. 1375 getDefaultWindowList().add(pos, win); 1376 mWindowsChanged = true; 1377 moveInputMethodDialogsLocked(pos+1); 1378 return; 1379 } 1380 win.mTargetAppToken = null; 1381 addWindowToListInOrderLocked(win, true); 1382 moveInputMethodDialogsLocked(pos); 1383 } 1384 1385 void setInputMethodAnimLayerAdjustment(int adj) { 1386 if (DEBUG_LAYERS) Slog.v(TAG, "Setting im layer adj to " + adj); 1387 mInputMethodAnimLayerAdjustment = adj; 1388 WindowState imw = mInputMethodWindow; 1389 if (imw != null) { 1390 imw.mWinAnimator.mAnimLayer = imw.mLayer + adj; 1391 if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + imw 1392 + " anim layer: " + imw.mWinAnimator.mAnimLayer); 1393 int wi = imw.mChildWindows.size(); 1394 while (wi > 0) { 1395 wi--; 1396 WindowState cw = imw.mChildWindows.get(wi); 1397 cw.mWinAnimator.mAnimLayer = cw.mLayer + adj; 1398 if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + cw 1399 + " anim layer: " + cw.mWinAnimator.mAnimLayer); 1400 } 1401 } 1402 int di = mInputMethodDialogs.size(); 1403 while (di > 0) { 1404 di --; 1405 imw = mInputMethodDialogs.get(di); 1406 imw.mWinAnimator.mAnimLayer = imw.mLayer + adj; 1407 if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + imw 1408 + " anim layer: " + imw.mWinAnimator.mAnimLayer); 1409 } 1410 } 1411 1412 private int tmpRemoveWindowLocked(int interestingPos, WindowState win) { 1413 WindowList windows = win.getWindowList(); 1414 int wpos = windows.indexOf(win); 1415 if (wpos >= 0) { 1416 if (wpos < interestingPos) interestingPos--; 1417 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Temp removing at " + wpos + ": " + win); 1418 windows.remove(wpos); 1419 mWindowsChanged = true; 1420 int NC = win.mChildWindows.size(); 1421 while (NC > 0) { 1422 NC--; 1423 WindowState cw = win.mChildWindows.get(NC); 1424 int cpos = windows.indexOf(cw); 1425 if (cpos >= 0) { 1426 if (cpos < interestingPos) interestingPos--; 1427 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Temp removing child at " 1428 + cpos + ": " + cw); 1429 windows.remove(cpos); 1430 } 1431 } 1432 } 1433 return interestingPos; 1434 } 1435 1436 private void reAddWindowToListInOrderLocked(WindowState win) { 1437 addWindowToListInOrderLocked(win, false); 1438 // This is a hack to get all of the child windows added as well 1439 // at the right position. Child windows should be rare and 1440 // this case should be rare, so it shouldn't be that big a deal. 1441 WindowList windows = win.getWindowList(); 1442 int wpos = windows.indexOf(win); 1443 if (wpos >= 0) { 1444 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "ReAdd removing from " + wpos + ": " + win); 1445 windows.remove(wpos); 1446 mWindowsChanged = true; 1447 reAddWindowLocked(wpos, win); 1448 } 1449 } 1450 1451 void logWindowList(final WindowList windows, String prefix) { 1452 int N = windows.size(); 1453 while (N > 0) { 1454 N--; 1455 Slog.v(TAG, prefix + "#" + N + ": " + windows.get(N)); 1456 } 1457 } 1458 1459 void moveInputMethodDialogsLocked(int pos) { 1460 ArrayList<WindowState> dialogs = mInputMethodDialogs; 1461 1462 // TODO(multidisplay): IMEs are only supported on the default display. 1463 WindowList windows = getDefaultWindowList(); 1464 final int N = dialogs.size(); 1465 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Removing " + N + " dialogs w/pos=" + pos); 1466 for (int i=0; i<N; i++) { 1467 pos = tmpRemoveWindowLocked(pos, dialogs.get(i)); 1468 } 1469 if (DEBUG_INPUT_METHOD) { 1470 Slog.v(TAG, "Window list w/pos=" + pos); 1471 logWindowList(windows, " "); 1472 } 1473 1474 if (pos >= 0) { 1475 final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken; 1476 if (pos < windows.size()) { 1477 WindowState wp = windows.get(pos); 1478 if (wp == mInputMethodWindow) { 1479 pos++; 1480 } 1481 } 1482 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Adding " + N + " dialogs at pos=" + pos); 1483 for (int i=0; i<N; i++) { 1484 WindowState win = dialogs.get(i); 1485 win.mTargetAppToken = targetAppToken; 1486 pos = reAddWindowLocked(pos, win); 1487 } 1488 if (DEBUG_INPUT_METHOD) { 1489 Slog.v(TAG, "Final window list:"); 1490 logWindowList(windows, " "); 1491 } 1492 return; 1493 } 1494 for (int i=0; i<N; i++) { 1495 WindowState win = dialogs.get(i); 1496 win.mTargetAppToken = null; 1497 reAddWindowToListInOrderLocked(win); 1498 if (DEBUG_INPUT_METHOD) { 1499 Slog.v(TAG, "No IM target, final list:"); 1500 logWindowList(windows, " "); 1501 } 1502 } 1503 } 1504 1505 boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) { 1506 final WindowState imWin = mInputMethodWindow; 1507 final int DN = mInputMethodDialogs.size(); 1508 if (imWin == null && DN == 0) { 1509 return false; 1510 } 1511 1512 // TODO(multidisplay): IMEs are only supported on the default display. 1513 WindowList windows = getDefaultWindowList(); 1514 1515 int imPos = findDesiredInputMethodWindowIndexLocked(true); 1516 if (imPos >= 0) { 1517 // In this case, the input method windows are to be placed 1518 // immediately above the window they are targeting. 1519 1520 // First check to see if the input method windows are already 1521 // located here, and contiguous. 1522 final int N = windows.size(); 1523 WindowState firstImWin = imPos < N 1524 ? windows.get(imPos) : null; 1525 1526 // Figure out the actual input method window that should be 1527 // at the bottom of their stack. 1528 WindowState baseImWin = imWin != null 1529 ? imWin : mInputMethodDialogs.get(0); 1530 if (baseImWin.mChildWindows.size() > 0) { 1531 WindowState cw = baseImWin.mChildWindows.get(0); 1532 if (cw.mSubLayer < 0) baseImWin = cw; 1533 } 1534 1535 if (firstImWin == baseImWin) { 1536 // The windows haven't moved... but are they still contiguous? 1537 // First find the top IM window. 1538 int pos = imPos+1; 1539 while (pos < N) { 1540 if (!(windows.get(pos)).mIsImWindow) { 1541 break; 1542 } 1543 pos++; 1544 } 1545 pos++; 1546 // Now there should be no more input method windows above. 1547 while (pos < N) { 1548 if ((windows.get(pos)).mIsImWindow) { 1549 break; 1550 } 1551 pos++; 1552 } 1553 if (pos >= N) { 1554 // All is good! 1555 return false; 1556 } 1557 } 1558 1559 if (imWin != null) { 1560 if (DEBUG_INPUT_METHOD) { 1561 Slog.v(TAG, "Moving IM from " + imPos); 1562 logWindowList(windows, " "); 1563 } 1564 imPos = tmpRemoveWindowLocked(imPos, imWin); 1565 if (DEBUG_INPUT_METHOD) { 1566 Slog.v(TAG, "List after removing with new pos " + imPos + ":"); 1567 logWindowList(windows, " "); 1568 } 1569 imWin.mTargetAppToken = mInputMethodTarget.mAppToken; 1570 reAddWindowLocked(imPos, imWin); 1571 if (DEBUG_INPUT_METHOD) { 1572 Slog.v(TAG, "List after moving IM to " + imPos + ":"); 1573 logWindowList(windows, " "); 1574 } 1575 if (DN > 0) moveInputMethodDialogsLocked(imPos+1); 1576 } else { 1577 moveInputMethodDialogsLocked(imPos); 1578 } 1579 1580 } else { 1581 // In this case, the input method windows go in a fixed layer, 1582 // because they aren't currently associated with a focus window. 1583 1584 if (imWin != null) { 1585 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Moving IM from " + imPos); 1586 tmpRemoveWindowLocked(0, imWin); 1587 imWin.mTargetAppToken = null; 1588 reAddWindowToListInOrderLocked(imWin); 1589 if (DEBUG_INPUT_METHOD) { 1590 Slog.v(TAG, "List with no IM target:"); 1591 logWindowList(windows, " "); 1592 } 1593 if (DN > 0) moveInputMethodDialogsLocked(-1); 1594 } else { 1595 moveInputMethodDialogsLocked(-1); 1596 } 1597 1598 } 1599 1600 if (needAssignLayers) { 1601 assignLayersLocked(windows); 1602 } 1603 1604 return true; 1605 } 1606 1607 void adjustInputMethodDialogsLocked() { 1608 moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true)); 1609 } 1610 1611 final boolean isWallpaperVisible(WindowState wallpaperTarget) { 1612 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured=" 1613 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??") 1614 + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null) 1615 ? wallpaperTarget.mAppToken.mAppAnimator.animation : null) 1616 + " upper=" + mUpperWallpaperTarget 1617 + " lower=" + mLowerWallpaperTarget); 1618 return (wallpaperTarget != null 1619 && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null 1620 && wallpaperTarget.mAppToken.mAppAnimator.animation != null))) 1621 || mUpperWallpaperTarget != null 1622 || mLowerWallpaperTarget != null; 1623 } 1624 1625 static final int ADJUST_WALLPAPER_LAYERS_CHANGED = 1<<1; 1626 static final int ADJUST_WALLPAPER_VISIBILITY_CHANGED = 1<<2; 1627 1628 int adjustWallpaperWindowsLocked() { 1629 mInnerFields.mWallpaperMayChange = false; 1630 int changed = 0; 1631 1632 // TODO(multidisplay): Wallpapers on main screen only. 1633 final DisplayInfo displayInfo = getDefaultDisplayContent().getDisplayInfo(); 1634 final int dw = displayInfo.appWidth; 1635 final int dh = displayInfo.appHeight; 1636 1637 // First find top-most window that has asked to be on top of the 1638 // wallpaper; all wallpapers go behind it. 1639 final WindowList windows = getDefaultWindowList(); 1640 int N = windows.size(); 1641 WindowState w = null; 1642 WindowState foundW = null; 1643 int foundI = 0; 1644 WindowState topCurW = null; 1645 int topCurI = 0; 1646 int windowDetachedI = -1; 1647 int i = N; 1648 while (i > 0) { 1649 i--; 1650 w = windows.get(i); 1651 if ((w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER)) { 1652 if (topCurW == null) { 1653 topCurW = w; 1654 topCurI = i; 1655 } 1656 continue; 1657 } 1658 topCurW = null; 1659 if (w != mWindowDetachedWallpaper && w.mAppToken != null) { 1660 // If this window's app token is hidden and not animating, 1661 // it is of no interest to us. 1662 if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) { 1663 if (DEBUG_WALLPAPER) Slog.v(TAG, 1664 "Skipping hidden and not animating token: " + w); 1665 continue; 1666 } 1667 } 1668 if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": readyfordisplay=" 1669 + w.isReadyForDisplay() + " mDrawState=" + w.mWinAnimator.mDrawState); 1670 if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay() 1671 && (mWallpaperTarget == w || w.isDrawnLw())) { 1672 if (DEBUG_WALLPAPER) Slog.v(TAG, 1673 "Found wallpaper activity: #" + i + "=" + w); 1674 foundW = w; 1675 foundI = i; 1676 if (w == mWallpaperTarget && w.mWinAnimator.isAnimating()) { 1677 // The current wallpaper target is animating, so we'll 1678 // look behind it for another possible target and figure 1679 // out what is going on below. 1680 if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w 1681 + ": token animating, looking behind."); 1682 continue; 1683 } 1684 break; 1685 } else if (w == mWindowDetachedWallpaper) { 1686 windowDetachedI = i; 1687 } 1688 } 1689 1690 if (foundW == null && windowDetachedI >= 0) { 1691 if (DEBUG_WALLPAPER) Slog.v(TAG, 1692 "Found animating detached wallpaper activity: #" + i + "=" + w); 1693 foundW = w; 1694 foundI = windowDetachedI; 1695 } 1696 1697 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 1698 // If we are currently waiting for an app transition, and either 1699 // the current target or the next target are involved with it, 1700 // then hold off on doing anything with the wallpaper. 1701 // Note that we are checking here for just whether the target 1702 // is part of an app token... which is potentially overly aggressive 1703 // (the app token may not be involved in the transition), but good 1704 // enough (we'll just wait until whatever transition is pending 1705 // executes). 1706 if (mWallpaperTarget != null && mWallpaperTarget.mAppToken != null) { 1707 if (DEBUG_WALLPAPER) Slog.v(TAG, 1708 "Wallpaper not changing: waiting for app anim in current target"); 1709 return 0; 1710 } 1711 if (foundW != null && foundW.mAppToken != null) { 1712 if (DEBUG_WALLPAPER) Slog.v(TAG, 1713 "Wallpaper not changing: waiting for app anim in found target"); 1714 return 0; 1715 } 1716 } 1717 1718 if (mWallpaperTarget != foundW) { 1719 if (DEBUG_WALLPAPER) { 1720 Slog.v(TAG, "New wallpaper target: " + foundW 1721 + " oldTarget: " + mWallpaperTarget); 1722 } 1723 1724 mLowerWallpaperTarget = null; 1725 mUpperWallpaperTarget = null; 1726 1727 WindowState oldW = mWallpaperTarget; 1728 mWallpaperTarget = foundW; 1729 1730 // Now what is happening... if the current and new targets are 1731 // animating, then we are in our super special mode! 1732 if (foundW != null && oldW != null) { 1733 boolean oldAnim = oldW.mWinAnimator.mAnimation != null 1734 || (oldW.mAppToken != null 1735 && oldW.mAppToken.mAppAnimator.animation != null); 1736 boolean foundAnim = foundW.mWinAnimator.mAnimation != null 1737 || (foundW.mAppToken != null && 1738 foundW.mAppToken.mAppAnimator.animation != null); 1739 if (DEBUG_WALLPAPER) { 1740 Slog.v(TAG, "New animation: " + foundAnim 1741 + " old animation: " + oldAnim); 1742 } 1743 if (foundAnim && oldAnim) { 1744 int oldI = windows.indexOf(oldW); 1745 if (DEBUG_WALLPAPER) { 1746 Slog.v(TAG, "New i: " + foundI + " old i: " + oldI); 1747 } 1748 if (oldI >= 0) { 1749 if (DEBUG_WALLPAPER) { 1750 Slog.v(TAG, "Animating wallpapers: old#" + oldI 1751 + "=" + oldW + "; new#" + foundI 1752 + "=" + foundW); 1753 } 1754 1755 // Set the new target correctly. 1756 if (foundW.mAppToken != null && foundW.mAppToken.hiddenRequested) { 1757 if (DEBUG_WALLPAPER) { 1758 Slog.v(TAG, "Old wallpaper still the target."); 1759 } 1760 mWallpaperTarget = oldW; 1761 foundW = oldW; 1762 foundI = oldI; 1763 } 1764 // Now set the upper and lower wallpaper targets 1765 // correctly, and make sure that we are positioning 1766 // the wallpaper below the lower. 1767 else if (foundI > oldI) { 1768 // The new target is on top of the old one. 1769 if (DEBUG_WALLPAPER) { 1770 Slog.v(TAG, "Found target above old target."); 1771 } 1772 mUpperWallpaperTarget = foundW; 1773 mLowerWallpaperTarget = oldW; 1774 foundW = oldW; 1775 foundI = oldI; 1776 } else { 1777 // The new target is below the old one. 1778 if (DEBUG_WALLPAPER) { 1779 Slog.v(TAG, "Found target below old target."); 1780 } 1781 mUpperWallpaperTarget = oldW; 1782 mLowerWallpaperTarget = foundW; 1783 } 1784 } 1785 } 1786 } 1787 1788 } else if (mLowerWallpaperTarget != null) { 1789 // Is it time to stop animating? 1790 boolean lowerAnimating = mLowerWallpaperTarget.mWinAnimator.mAnimation != null 1791 || (mLowerWallpaperTarget.mAppToken != null 1792 && mLowerWallpaperTarget.mAppToken.mAppAnimator.animation != null); 1793 boolean upperAnimating = mUpperWallpaperTarget.mWinAnimator.mAnimation != null 1794 || (mUpperWallpaperTarget.mAppToken != null 1795 && mUpperWallpaperTarget.mAppToken.mAppAnimator.animation != null); 1796 if (!lowerAnimating || !upperAnimating) { 1797 if (DEBUG_WALLPAPER) { 1798 Slog.v(TAG, "No longer animating wallpaper targets!"); 1799 } 1800 mLowerWallpaperTarget = null; 1801 mUpperWallpaperTarget = null; 1802 } 1803 } 1804 1805 boolean visible = foundW != null; 1806 if (visible) { 1807 // The window is visible to the compositor... but is it visible 1808 // to the user? That is what the wallpaper cares about. 1809 visible = isWallpaperVisible(foundW); 1810 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible); 1811 1812 // If the wallpaper target is animating, we may need to copy 1813 // its layer adjustment. Only do this if we are not transfering 1814 // between two wallpaper targets. 1815 mWallpaperAnimLayerAdjustment = 1816 (mLowerWallpaperTarget == null && foundW.mAppToken != null) 1817 ? foundW.mAppToken.mAppAnimator.animLayerAdjustment : 0; 1818 1819 final int maxLayer = mPolicy.getMaxWallpaperLayer() 1820 * TYPE_LAYER_MULTIPLIER 1821 + TYPE_LAYER_OFFSET; 1822 1823 // Now w is the window we are supposed to be behind... but we 1824 // need to be sure to also be behind any of its attached windows, 1825 // AND any starting window associated with it, AND below the 1826 // maximum layer the policy allows for wallpapers. 1827 while (foundI > 0) { 1828 WindowState wb = windows.get(foundI-1); 1829 if (wb.mBaseLayer < maxLayer && 1830 wb.mAttachedWindow != foundW && 1831 (foundW.mAttachedWindow == null || 1832 wb.mAttachedWindow != foundW.mAttachedWindow) && 1833 (wb.mAttrs.type != TYPE_APPLICATION_STARTING || 1834 foundW.mToken == null || wb.mToken != foundW.mToken)) { 1835 // This window is not related to the previous one in any 1836 // interesting way, so stop here. 1837 break; 1838 } 1839 foundW = wb; 1840 foundI--; 1841 } 1842 } else { 1843 if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target"); 1844 } 1845 1846 if (foundW == null && topCurW != null) { 1847 // There is no wallpaper target, so it goes at the bottom. 1848 // We will assume it is the same place as last time, if known. 1849 foundW = topCurW; 1850 foundI = topCurI+1; 1851 } else { 1852 // Okay i is the position immediately above the wallpaper. Look at 1853 // what is below it for later. 1854 foundW = foundI > 0 ? windows.get(foundI-1) : null; 1855 } 1856 1857 if (visible) { 1858 if (mWallpaperTarget.mWallpaperX >= 0) { 1859 mLastWallpaperX = mWallpaperTarget.mWallpaperX; 1860 mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep; 1861 } 1862 if (mWallpaperTarget.mWallpaperY >= 0) { 1863 mLastWallpaperY = mWallpaperTarget.mWallpaperY; 1864 mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep; 1865 } 1866 } 1867 1868 // Start stepping backwards from here, ensuring that our wallpaper windows 1869 // are correctly placed. 1870 int curTokenIndex = mWallpaperTokens.size(); 1871 while (curTokenIndex > 0) { 1872 curTokenIndex--; 1873 WindowToken token = mWallpaperTokens.get(curTokenIndex); 1874 if (token.hidden == visible) { 1875 changed |= ADJUST_WALLPAPER_VISIBILITY_CHANGED; 1876 token.hidden = !visible; 1877 // Need to do a layout to ensure the wallpaper now has the 1878 // correct size. 1879 mLayoutNeeded = true; 1880 } 1881 1882 int curWallpaperIndex = token.windows.size(); 1883 while (curWallpaperIndex > 0) { 1884 curWallpaperIndex--; 1885 WindowState wallpaper = token.windows.get(curWallpaperIndex); 1886 1887 if (visible) { 1888 updateWallpaperOffsetLocked(wallpaper, dw, dh, false); 1889 } 1890 1891 // First, make sure the client has the current visibility 1892 // state. 1893 dispatchWallpaperVisibility(wallpaper, visible); 1894 1895 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment; 1896 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "adjustWallpaper win " 1897 + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); 1898 1899 // First, if this window is at the current index, then all 1900 // is well. 1901 if (wallpaper == foundW) { 1902 foundI--; 1903 foundW = foundI > 0 1904 ? windows.get(foundI-1) : null; 1905 continue; 1906 } 1907 1908 // The window didn't match... the current wallpaper window, 1909 // wherever it is, is in the wrong place, so make sure it is 1910 // not in the list. 1911 int oldIndex = windows.indexOf(wallpaper); 1912 if (oldIndex >= 0) { 1913 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Wallpaper removing at " 1914 + oldIndex + ": " + wallpaper); 1915 windows.remove(oldIndex); 1916 mWindowsChanged = true; 1917 if (oldIndex < foundI) { 1918 foundI--; 1919 } 1920 } 1921 1922 // Now stick it in. 1923 if (DEBUG_WALLPAPER || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) { 1924 Slog.v(TAG, "Moving wallpaper " + wallpaper 1925 + " from " + oldIndex + " to " + foundI); 1926 } 1927 1928 windows.add(foundI, wallpaper); 1929 mWindowsChanged = true; 1930 changed |= ADJUST_WALLPAPER_LAYERS_CHANGED; 1931 } 1932 } 1933 1934 return changed; 1935 } 1936 1937 void setWallpaperAnimLayerAdjustmentLocked(int adj) { 1938 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, 1939 "Setting wallpaper layer adj to " + adj); 1940 mWallpaperAnimLayerAdjustment = adj; 1941 int curTokenIndex = mWallpaperTokens.size(); 1942 while (curTokenIndex > 0) { 1943 curTokenIndex--; 1944 WindowToken token = mWallpaperTokens.get(curTokenIndex); 1945 int curWallpaperIndex = token.windows.size(); 1946 while (curWallpaperIndex > 0) { 1947 curWallpaperIndex--; 1948 WindowState wallpaper = token.windows.get(curWallpaperIndex); 1949 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj; 1950 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win " 1951 + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); 1952 } 1953 } 1954 } 1955 1956 boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh, 1957 boolean sync) { 1958 boolean changed = false; 1959 boolean rawChanged = false; 1960 float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f; 1961 float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f; 1962 int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw; 1963 int offset = availw > 0 ? -(int)(availw*wpx+.5f) : 0; 1964 changed = wallpaperWin.mXOffset != offset; 1965 if (changed) { 1966 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " 1967 + wallpaperWin + " x: " + offset); 1968 wallpaperWin.mXOffset = offset; 1969 } 1970 if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) { 1971 wallpaperWin.mWallpaperX = wpx; 1972 wallpaperWin.mWallpaperXStep = wpxs; 1973 rawChanged = true; 1974 } 1975 1976 float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f; 1977 float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f; 1978 int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh; 1979 offset = availh > 0 ? -(int)(availh*wpy+.5f) : 0; 1980 if (wallpaperWin.mYOffset != offset) { 1981 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " 1982 + wallpaperWin + " y: " + offset); 1983 changed = true; 1984 wallpaperWin.mYOffset = offset; 1985 } 1986 if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) { 1987 wallpaperWin.mWallpaperY = wpy; 1988 wallpaperWin.mWallpaperYStep = wpys; 1989 rawChanged = true; 1990 } 1991 1992 if (rawChanged && (wallpaperWin.mAttrs.privateFlags & 1993 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) { 1994 try { 1995 if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset " 1996 + wallpaperWin + " x=" + wallpaperWin.mWallpaperX 1997 + " y=" + wallpaperWin.mWallpaperY); 1998 if (sync) { 1999 mWaitingOnWallpaper = wallpaperWin; 2000 } 2001 wallpaperWin.mClient.dispatchWallpaperOffsets( 2002 wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY, 2003 wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync); 2004 if (sync) { 2005 if (mWaitingOnWallpaper != null) { 2006 long start = SystemClock.uptimeMillis(); 2007 if ((mLastWallpaperTimeoutTime+WALLPAPER_TIMEOUT_RECOVERY) 2008 < start) { 2009 try { 2010 if (DEBUG_WALLPAPER) Slog.v(TAG, 2011 "Waiting for offset complete..."); 2012 mWindowMap.wait(WALLPAPER_TIMEOUT); 2013 } catch (InterruptedException e) { 2014 } 2015 if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!"); 2016 if ((start+WALLPAPER_TIMEOUT) 2017 < SystemClock.uptimeMillis()) { 2018 Slog.i(TAG, "Timeout waiting for wallpaper to offset: " 2019 + wallpaperWin); 2020 mLastWallpaperTimeoutTime = start; 2021 } 2022 } 2023 mWaitingOnWallpaper = null; 2024 } 2025 } 2026 } catch (RemoteException e) { 2027 } 2028 } 2029 2030 return changed; 2031 } 2032 2033 void wallpaperOffsetsComplete(IBinder window) { 2034 synchronized (mWindowMap) { 2035 if (mWaitingOnWallpaper != null && 2036 mWaitingOnWallpaper.mClient.asBinder() == window) { 2037 mWaitingOnWallpaper = null; 2038 mWindowMap.notifyAll(); 2039 } 2040 } 2041 } 2042 2043 void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) { 2044 final DisplayContent displayContent = changingTarget.mDisplayContent; 2045 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 2046 final int dw = displayInfo.appWidth; 2047 final int dh = displayInfo.appHeight; 2048 2049 WindowState target = mWallpaperTarget; 2050 if (target != null) { 2051 if (target.mWallpaperX >= 0) { 2052 mLastWallpaperX = target.mWallpaperX; 2053 } else if (changingTarget.mWallpaperX >= 0) { 2054 mLastWallpaperX = changingTarget.mWallpaperX; 2055 } 2056 if (target.mWallpaperY >= 0) { 2057 mLastWallpaperY = target.mWallpaperY; 2058 } else if (changingTarget.mWallpaperY >= 0) { 2059 mLastWallpaperY = changingTarget.mWallpaperY; 2060 } 2061 } 2062 2063 int curTokenIndex = mWallpaperTokens.size(); 2064 while (curTokenIndex > 0) { 2065 curTokenIndex--; 2066 WindowToken token = mWallpaperTokens.get(curTokenIndex); 2067 int curWallpaperIndex = token.windows.size(); 2068 while (curWallpaperIndex > 0) { 2069 curWallpaperIndex--; 2070 WindowState wallpaper = token.windows.get(curWallpaperIndex); 2071 if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) { 2072 WindowStateAnimator winAnimator = wallpaper.mWinAnimator; 2073 winAnimator.computeShownFrameLocked(); 2074 // No need to lay out the windows - we can just set the wallpaper position 2075 // directly. 2076 // TODO(cmautner): Don't move this from here, just lock the WindowAnimator. 2077 if (winAnimator.mSurfaceX != wallpaper.mShownFrame.left 2078 || winAnimator.mSurfaceY != wallpaper.mShownFrame.top) { 2079 winAnimator.setWallpaperOffset((int) wallpaper.mShownFrame.left, 2080 (int) wallpaper.mShownFrame.top); 2081 } 2082 // We only want to be synchronous with one wallpaper. 2083 sync = false; 2084 } 2085 } 2086 } 2087 } 2088 2089 /** 2090 * Check wallpaper for visiblity change and notify window if so. 2091 * @param wallpaper The wallpaper to test and notify. 2092 * @param visible Current visibility. 2093 */ 2094 void dispatchWallpaperVisibility(final WindowState wallpaper, final boolean visible) { 2095 if (wallpaper.mWallpaperVisible != visible) { 2096 wallpaper.mWallpaperVisible = visible; 2097 try { 2098 if (DEBUG_VISIBILITY || DEBUG_WALLPAPER) Slog.v(TAG, 2099 "Updating visibility of wallpaper " + wallpaper 2100 + ": " + visible + " Callers=" + Debug.getCallers(2)); 2101 wallpaper.mClient.dispatchAppVisibility(visible); 2102 } catch (RemoteException e) { 2103 } 2104 } 2105 } 2106 2107 void updateWallpaperVisibilityLocked() { 2108 final boolean visible = isWallpaperVisible(mWallpaperTarget); 2109 final DisplayContent displayContent = mWallpaperTarget.mDisplayContent; 2110 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 2111 final int dw = displayInfo.appWidth; 2112 final int dh = displayInfo.appHeight; 2113 2114 int curTokenIndex = mWallpaperTokens.size(); 2115 while (curTokenIndex > 0) { 2116 curTokenIndex--; 2117 WindowToken token = mWallpaperTokens.get(curTokenIndex); 2118 if (token.hidden == visible) { 2119 token.hidden = !visible; 2120 // Need to do a layout to ensure the wallpaper now has the 2121 // correct size. 2122 mLayoutNeeded = true; 2123 } 2124 2125 int curWallpaperIndex = token.windows.size(); 2126 while (curWallpaperIndex > 0) { 2127 curWallpaperIndex--; 2128 WindowState wallpaper = token.windows.get(curWallpaperIndex); 2129 if (visible) { 2130 updateWallpaperOffsetLocked(wallpaper, dw, dh, false); 2131 } 2132 2133 dispatchWallpaperVisibility(wallpaper, visible); 2134 } 2135 } 2136 } 2137 2138 public int addWindow(Session session, IWindow client, int seq, 2139 WindowManager.LayoutParams attrs, int viewVisibility, int displayId, 2140 Rect outContentInsets, InputChannel outInputChannel) { 2141 int res = mPolicy.checkAddPermission(attrs); 2142 if (res != WindowManagerImpl.ADD_OKAY) { 2143 return res; 2144 } 2145 2146 boolean reportNewConfig = false; 2147 WindowState attachedWindow = null; 2148 WindowState win = null; 2149 long origId; 2150 2151 synchronized(mWindowMap) { 2152 if (mDisplay == null) { 2153 throw new IllegalStateException("Display has not been initialialized"); 2154 } 2155 2156 if (mWindowMap.containsKey(client.asBinder())) { 2157 Slog.w(TAG, "Window " + client + " is already added"); 2158 return WindowManagerImpl.ADD_DUPLICATE_ADD; 2159 } 2160 2161 if (attrs.type >= FIRST_SUB_WINDOW && attrs.type <= LAST_SUB_WINDOW) { 2162 attachedWindow = windowForClientLocked(null, attrs.token, false); 2163 if (attachedWindow == null) { 2164 Slog.w(TAG, "Attempted to add window with token that is not a window: " 2165 + attrs.token + ". Aborting."); 2166 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN; 2167 } 2168 if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW 2169 && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) { 2170 Slog.w(TAG, "Attempted to add window with token that is a sub-window: " 2171 + attrs.token + ". Aborting."); 2172 return WindowManagerImpl.ADD_BAD_SUBWINDOW_TOKEN; 2173 } 2174 } 2175 2176 boolean addToken = false; 2177 WindowToken token = mTokenMap.get(attrs.token); 2178 if (token == null) { 2179 if (attrs.type >= FIRST_APPLICATION_WINDOW 2180 && attrs.type <= LAST_APPLICATION_WINDOW) { 2181 Slog.w(TAG, "Attempted to add application window with unknown token " 2182 + attrs.token + ". Aborting."); 2183 return WindowManagerImpl.ADD_BAD_APP_TOKEN; 2184 } 2185 if (attrs.type == TYPE_INPUT_METHOD) { 2186 Slog.w(TAG, "Attempted to add input method window with unknown token " 2187 + attrs.token + ". Aborting."); 2188 return WindowManagerImpl.ADD_BAD_APP_TOKEN; 2189 } 2190 if (attrs.type == TYPE_WALLPAPER) { 2191 Slog.w(TAG, "Attempted to add wallpaper window with unknown token " 2192 + attrs.token + ". Aborting."); 2193 return WindowManagerImpl.ADD_BAD_APP_TOKEN; 2194 } 2195 if (attrs.type == TYPE_DREAM) { 2196 Slog.w(TAG, "Attempted to add Dream window with unknown token " 2197 + attrs.token + ". Aborting."); 2198 return WindowManagerImpl.ADD_BAD_APP_TOKEN; 2199 } 2200 token = new WindowToken(this, attrs.token, -1, false); 2201 addToken = true; 2202 } else if (attrs.type >= FIRST_APPLICATION_WINDOW 2203 && attrs.type <= LAST_APPLICATION_WINDOW) { 2204 AppWindowToken atoken = token.appWindowToken; 2205 if (atoken == null) { 2206 Slog.w(TAG, "Attempted to add window with non-application token " 2207 + token + ". Aborting."); 2208 return WindowManagerImpl.ADD_NOT_APP_TOKEN; 2209 } else if (atoken.removed) { 2210 Slog.w(TAG, "Attempted to add window with exiting application token " 2211 + token + ". Aborting."); 2212 return WindowManagerImpl.ADD_APP_EXITING; 2213 } 2214 if (attrs.type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) { 2215 // No need for this guy! 2216 if (localLOGV) Slog.v( 2217 TAG, "**** NO NEED TO START: " + attrs.getTitle()); 2218 return WindowManagerImpl.ADD_STARTING_NOT_NEEDED; 2219 } 2220 } else if (attrs.type == TYPE_INPUT_METHOD) { 2221 if (token.windowType != TYPE_INPUT_METHOD) { 2222 Slog.w(TAG, "Attempted to add input method window with bad token " 2223 + attrs.token + ". Aborting."); 2224 return WindowManagerImpl.ADD_BAD_APP_TOKEN; 2225 } 2226 } else if (attrs.type == TYPE_WALLPAPER) { 2227 if (token.windowType != TYPE_WALLPAPER) { 2228 Slog.w(TAG, "Attempted to add wallpaper window with bad token " 2229 + attrs.token + ". Aborting."); 2230 return WindowManagerImpl.ADD_BAD_APP_TOKEN; 2231 } 2232 } else if (attrs.type == TYPE_DREAM) { 2233 if (token.windowType != TYPE_DREAM) { 2234 Slog.w(TAG, "Attempted to add Dream window with bad token " 2235 + attrs.token + ". Aborting."); 2236 return WindowManagerImpl.ADD_BAD_APP_TOKEN; 2237 } 2238 } 2239 2240 final DisplayContent displayContent = getDisplayContent(displayId); 2241 win = new WindowState(this, session, client, token, 2242 attachedWindow, seq, attrs, viewVisibility, displayContent); 2243 if (win.mDeathRecipient == null) { 2244 // Client has apparently died, so there is no reason to 2245 // continue. 2246 Slog.w(TAG, "Adding window client " + client.asBinder() 2247 + " that is dead, aborting."); 2248 return WindowManagerImpl.ADD_APP_EXITING; 2249 } 2250 2251 mPolicy.adjustWindowParamsLw(win.mAttrs); 2252 2253 res = mPolicy.prepareAddWindowLw(win, attrs); 2254 if (res != WindowManagerImpl.ADD_OKAY) { 2255 return res; 2256 } 2257 2258 if (outInputChannel != null && (attrs.inputFeatures 2259 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { 2260 String name = win.makeInputChannelName(); 2261 InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); 2262 win.setInputChannel(inputChannels[0]); 2263 inputChannels[1].transferTo(outInputChannel); 2264 2265 mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle); 2266 } 2267 2268 // From now on, no exceptions or errors allowed! 2269 2270 res = WindowManagerImpl.ADD_OKAY; 2271 2272 origId = Binder.clearCallingIdentity(); 2273 2274 if (addToken) { 2275 mTokenMap.put(attrs.token, token); 2276 } 2277 win.attach(); 2278 mWindowMap.put(client.asBinder(), win); 2279 2280 if (attrs.type == TYPE_APPLICATION_STARTING && 2281 token.appWindowToken != null) { 2282 token.appWindowToken.startingWindow = win; 2283 if (DEBUG_STARTING_WINDOW) Slog.v (TAG, "addWindow: " + token.appWindowToken 2284 + " startingWindow=" + win); 2285 } 2286 2287 boolean imMayMove = true; 2288 2289 if (attrs.type == TYPE_INPUT_METHOD) { 2290 win.mGivenInsetsPending = true; 2291 mInputMethodWindow = win; 2292 addInputMethodWindowToListLocked(win); 2293 imMayMove = false; 2294 } else if (attrs.type == TYPE_INPUT_METHOD_DIALOG) { 2295 mInputMethodDialogs.add(win); 2296 addWindowToListInOrderLocked(win, true); 2297 adjustInputMethodDialogsLocked(); 2298 imMayMove = false; 2299 } else { 2300 addWindowToListInOrderLocked(win, true); 2301 if (attrs.type == TYPE_WALLPAPER) { 2302 mLastWallpaperTimeoutTime = 0; 2303 adjustWallpaperWindowsLocked(); 2304 } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) { 2305 adjustWallpaperWindowsLocked(); 2306 } 2307 } 2308 2309 win.mWinAnimator.mEnterAnimationPending = true; 2310 2311 mPolicy.getContentInsetHintLw(attrs, outContentInsets); 2312 2313 if (mInTouchMode) { 2314 res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE; 2315 } 2316 if (win.mAppToken == null || !win.mAppToken.clientHidden) { 2317 res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE; 2318 } 2319 2320 mInputMonitor.setUpdateInputWindowsNeededLw(); 2321 2322 boolean focusChanged = false; 2323 if (win.canReceiveKeys()) { 2324 focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS, 2325 false /*updateInputWindows*/); 2326 if (focusChanged) { 2327 imMayMove = false; 2328 } 2329 } 2330 2331 if (imMayMove) { 2332 moveInputMethodWindowsIfNeededLocked(false); 2333 } 2334 2335 assignLayersLocked(displayContent.getWindowList()); 2336 // Don't do layout here, the window must call 2337 // relayout to be displayed, so we'll do it there. 2338 2339 //dump(); 2340 2341 if (focusChanged) { 2342 finishUpdateFocusedWindowAfterAssignLayersLocked(false /*updateInputWindows*/); 2343 } 2344 mInputMonitor.updateInputWindowsLw(false /*force*/); 2345 2346 if (localLOGV) Slog.v( 2347 TAG, "New client " + client.asBinder() 2348 + ": window=" + win); 2349 2350 if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) { 2351 reportNewConfig = true; 2352 } 2353 } 2354 2355 if (reportNewConfig) { 2356 sendNewConfiguration(); 2357 } 2358 2359 Binder.restoreCallingIdentity(origId); 2360 2361 return res; 2362 } 2363 2364 public void removeWindow(Session session, IWindow client) { 2365 synchronized(mWindowMap) { 2366 WindowState win = windowForClientLocked(session, client, false); 2367 if (win == null) { 2368 return; 2369 } 2370 removeWindowLocked(session, win); 2371 } 2372 } 2373 2374 public void removeWindowLocked(Session session, WindowState win) { 2375 2376 if (localLOGV || DEBUG_FOCUS) Slog.v( 2377 TAG, "Remove " + win + " client=" 2378 + Integer.toHexString(System.identityHashCode( 2379 win.mClient.asBinder())) 2380 + ", surface=" + win.mWinAnimator.mSurface); 2381 2382 final long origId = Binder.clearCallingIdentity(); 2383 2384 win.disposeInputChannel(); 2385 2386 if (DEBUG_APP_TRANSITIONS) Slog.v( 2387 TAG, "Remove " + win + ": mSurface=" + win.mWinAnimator.mSurface 2388 + " mExiting=" + win.mExiting 2389 + " isAnimating=" + win.mWinAnimator.isAnimating() 2390 + " app-animation=" 2391 + (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null) 2392 + " inPendingTransaction=" 2393 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false) 2394 + " mDisplayFrozen=" + mDisplayFrozen); 2395 // Visibility of the removed window. Will be used later to update orientation later on. 2396 boolean wasVisible = false; 2397 // First, see if we need to run an animation. If we do, we have 2398 // to hold off on removing the window until the animation is done. 2399 // If the display is frozen, just remove immediately, since the 2400 // animation wouldn't be seen. 2401 if (win.mHasSurface && okToDisplay()) { 2402 // If we are not currently running the exit animation, we 2403 // need to see about starting one. 2404 wasVisible = win.isWinVisibleLw(); 2405 if (wasVisible) { 2406 2407 int transit = WindowManagerPolicy.TRANSIT_EXIT; 2408 if (win.mAttrs.type == TYPE_APPLICATION_STARTING) { 2409 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; 2410 } 2411 // Try starting an animation. 2412 if (win.mWinAnimator.applyAnimationLocked(transit, false)) { 2413 win.mExiting = true; 2414 } 2415 } 2416 if (win.mExiting || win.mWinAnimator.isAnimating()) { 2417 // The exit animation is running... wait for it! 2418 //Slog.i(TAG, "*** Running exit animation..."); 2419 win.mExiting = true; 2420 win.mRemoveOnExit = true; 2421 mLayoutNeeded = true; 2422 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 2423 false /*updateInputWindows*/); 2424 performLayoutAndPlaceSurfacesLocked(); 2425 mInputMonitor.updateInputWindowsLw(false /*force*/); 2426 if (win.mAppToken != null) { 2427 win.mAppToken.updateReportedVisibilityLocked(); 2428 } 2429 //dump(); 2430 Binder.restoreCallingIdentity(origId); 2431 return; 2432 } 2433 } 2434 2435 removeWindowInnerLocked(session, win); 2436 // Removing a visible window will effect the computed orientation 2437 // So just update orientation if needed. 2438 if (wasVisible && computeForcedAppOrientationLocked() 2439 != mForcedAppOrientation 2440 && updateOrientationFromAppTokensLocked(false)) { 2441 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 2442 } 2443 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); 2444 Binder.restoreCallingIdentity(origId); 2445 } 2446 2447 private void removeWindowInnerLocked(Session session, WindowState win) { 2448 if (win.mRemoved) { 2449 // Nothing to do. 2450 return; 2451 } 2452 2453 for (int i=win.mChildWindows.size()-1; i>=0; i--) { 2454 WindowState cwin = win.mChildWindows.get(i); 2455 Slog.w(TAG, "Force-removing child win " + cwin + " from container " 2456 + win); 2457 removeWindowInnerLocked(cwin.mSession, cwin); 2458 } 2459 2460 win.mRemoved = true; 2461 2462 if (mInputMethodTarget == win) { 2463 moveInputMethodWindowsIfNeededLocked(false); 2464 } 2465 2466 if (false) { 2467 RuntimeException e = new RuntimeException("here"); 2468 e.fillInStackTrace(); 2469 Slog.w(TAG, "Removing window " + win, e); 2470 } 2471 2472 mPolicy.removeWindowLw(win); 2473 win.removeLocked(); 2474 2475 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win); 2476 mWindowMap.remove(win.mClient.asBinder()); 2477 2478 final WindowList windows = win.getWindowList(); 2479 windows.remove(win); 2480 mPendingRemove.remove(win); 2481 mWindowsChanged = true; 2482 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win); 2483 2484 if (mInputMethodWindow == win) { 2485 mInputMethodWindow = null; 2486 } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) { 2487 mInputMethodDialogs.remove(win); 2488 } 2489 2490 final WindowToken token = win.mToken; 2491 final AppWindowToken atoken = win.mAppToken; 2492 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing " + win + " from " + token); 2493 token.windows.remove(win); 2494 if (atoken != null) { 2495 atoken.allAppWindows.remove(win); 2496 } 2497 if (localLOGV) Slog.v( 2498 TAG, "**** Removing window " + win + ": count=" 2499 + token.windows.size()); 2500 if (token.windows.size() == 0) { 2501 if (!token.explicit) { 2502 mTokenMap.remove(token.token); 2503 } else if (atoken != null) { 2504 atoken.firstWindowDrawn = false; 2505 } 2506 } 2507 2508 if (atoken != null) { 2509 if (atoken.startingWindow == win) { 2510 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Nulling startingWindow " + win); 2511 atoken.startingWindow = null; 2512 } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) { 2513 // If this is the last window and we had requested a starting 2514 // transition window, well there is no point now. 2515 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Nulling last startingWindow"); 2516 atoken.startingData = null; 2517 } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) { 2518 // If this is the last window except for a starting transition 2519 // window, we need to get rid of the starting transition. 2520 if (DEBUG_STARTING_WINDOW) { 2521 Slog.v(TAG, "Schedule remove starting " + token 2522 + ": no more real windows"); 2523 } 2524 Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken); 2525 mH.sendMessage(m); 2526 } 2527 } 2528 2529 if (win.mAttrs.type == TYPE_WALLPAPER) { 2530 mLastWallpaperTimeoutTime = 0; 2531 adjustWallpaperWindowsLocked(); 2532 } else if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) { 2533 adjustWallpaperWindowsLocked(); 2534 } 2535 2536 if (!mInLayout) { 2537 assignLayersLocked(windows); 2538 mLayoutNeeded = true; 2539 performLayoutAndPlaceSurfacesLocked(); 2540 if (win.mAppToken != null) { 2541 win.mAppToken.updateReportedVisibilityLocked(); 2542 } 2543 } 2544 2545 mInputMonitor.updateInputWindowsLw(true /*force*/); 2546 } 2547 2548 static void logSurface(WindowState w, String msg, RuntimeException where) { 2549 String str = " SURFACE " + msg + ": " + w; 2550 if (where != null) { 2551 Slog.i(TAG, str, where); 2552 } else { 2553 Slog.i(TAG, str); 2554 } 2555 } 2556 2557 static void logSurface(Surface s, String title, String msg, RuntimeException where) { 2558 String str = " SURFACE " + s + ": " + msg + " / " + title; 2559 if (where != null) { 2560 Slog.i(TAG, str, where); 2561 } else { 2562 Slog.i(TAG, str); 2563 } 2564 } 2565 2566 // TODO(cmautner): Move to WindowStateAnimator. 2567 void setTransparentRegionHint(final WindowStateAnimator winAnimator, final Region region) { 2568 mH.sendMessage(mH.obtainMessage(H.SET_TRANSPARENT_REGION, 2569 new Pair<WindowStateAnimator, Region>(winAnimator, region))); 2570 } 2571 2572 void setTransparentRegionWindow(Session session, IWindow client, Region region) { 2573 long origId = Binder.clearCallingIdentity(); 2574 try { 2575 synchronized (mWindowMap) { 2576 WindowState w = windowForClientLocked(session, client, false); 2577 if ((w != null) && w.mHasSurface) { 2578 setTransparentRegionHint(w.mWinAnimator, region); 2579 } 2580 } 2581 } finally { 2582 Binder.restoreCallingIdentity(origId); 2583 } 2584 } 2585 2586 void setInsetsWindow(Session session, IWindow client, 2587 int touchableInsets, Rect contentInsets, 2588 Rect visibleInsets, Region touchableRegion) { 2589 long origId = Binder.clearCallingIdentity(); 2590 try { 2591 synchronized (mWindowMap) { 2592 WindowState w = windowForClientLocked(session, client, false); 2593 if (w != null) { 2594 w.mGivenInsetsPending = false; 2595 w.mGivenContentInsets.set(contentInsets); 2596 w.mGivenVisibleInsets.set(visibleInsets); 2597 w.mGivenTouchableRegion.set(touchableRegion); 2598 w.mTouchableInsets = touchableInsets; 2599 if (w.mGlobalScale != 1) { 2600 w.mGivenContentInsets.scale(w.mGlobalScale); 2601 w.mGivenVisibleInsets.scale(w.mGlobalScale); 2602 w.mGivenTouchableRegion.scale(w.mGlobalScale); 2603 } 2604 mLayoutNeeded = true; 2605 performLayoutAndPlaceSurfacesLocked(); 2606 } 2607 } 2608 } finally { 2609 Binder.restoreCallingIdentity(origId); 2610 } 2611 } 2612 2613 public void getWindowDisplayFrame(Session session, IWindow client, 2614 Rect outDisplayFrame) { 2615 synchronized(mWindowMap) { 2616 WindowState win = windowForClientLocked(session, client, false); 2617 if (win == null) { 2618 outDisplayFrame.setEmpty(); 2619 return; 2620 } 2621 outDisplayFrame.set(win.mDisplayFrame); 2622 } 2623 } 2624 2625 public void setWindowWallpaperPositionLocked(WindowState window, float x, float y, 2626 float xStep, float yStep) { 2627 if (window.mWallpaperX != x || window.mWallpaperY != y) { 2628 window.mWallpaperX = x; 2629 window.mWallpaperY = y; 2630 window.mWallpaperXStep = xStep; 2631 window.mWallpaperYStep = yStep; 2632 updateWallpaperOffsetLocked(window, true); 2633 } 2634 } 2635 2636 void wallpaperCommandComplete(IBinder window, Bundle result) { 2637 synchronized (mWindowMap) { 2638 if (mWaitingOnWallpaper != null && 2639 mWaitingOnWallpaper.mClient.asBinder() == window) { 2640 mWaitingOnWallpaper = null; 2641 mWindowMap.notifyAll(); 2642 } 2643 } 2644 } 2645 2646 public Bundle sendWindowWallpaperCommandLocked(WindowState window, 2647 String action, int x, int y, int z, Bundle extras, boolean sync) { 2648 if (window == mWallpaperTarget || window == mLowerWallpaperTarget 2649 || window == mUpperWallpaperTarget) { 2650 boolean doWait = sync; 2651 int curTokenIndex = mWallpaperTokens.size(); 2652 while (curTokenIndex > 0) { 2653 curTokenIndex--; 2654 WindowToken token = mWallpaperTokens.get(curTokenIndex); 2655 int curWallpaperIndex = token.windows.size(); 2656 while (curWallpaperIndex > 0) { 2657 curWallpaperIndex--; 2658 WindowState wallpaper = token.windows.get(curWallpaperIndex); 2659 try { 2660 wallpaper.mClient.dispatchWallpaperCommand(action, 2661 x, y, z, extras, sync); 2662 // We only want to be synchronous with one wallpaper. 2663 sync = false; 2664 } catch (RemoteException e) { 2665 } 2666 } 2667 } 2668 2669 if (doWait) { 2670 // XXX Need to wait for result. 2671 } 2672 } 2673 2674 return null; 2675 } 2676 2677 public void setUniverseTransformLocked(WindowState window, float alpha, 2678 float offx, float offy, float dsdx, float dtdx, float dsdy, float dtdy) { 2679 Transformation transform = window.mWinAnimator.mUniverseTransform; 2680 transform.setAlpha(alpha); 2681 Matrix matrix = transform.getMatrix(); 2682 matrix.getValues(mTmpFloats); 2683 mTmpFloats[Matrix.MTRANS_X] = offx; 2684 mTmpFloats[Matrix.MTRANS_Y] = offy; 2685 mTmpFloats[Matrix.MSCALE_X] = dsdx; 2686 mTmpFloats[Matrix.MSKEW_Y] = dtdx; 2687 mTmpFloats[Matrix.MSKEW_X] = dsdy; 2688 mTmpFloats[Matrix.MSCALE_Y] = dtdy; 2689 matrix.setValues(mTmpFloats); 2690 final DisplayInfo displayInfo = window.mDisplayContent.getDisplayInfo(); 2691 final RectF dispRect = new RectF(0, 0, 2692 displayInfo.logicalWidth, displayInfo.logicalHeight); 2693 matrix.mapRect(dispRect); 2694 window.mGivenTouchableRegion.set(0, 0, 2695 displayInfo.logicalWidth, displayInfo.logicalHeight); 2696 window.mGivenTouchableRegion.op((int)dispRect.left, (int)dispRect.top, 2697 (int)dispRect.right, (int)dispRect.bottom, Region.Op.DIFFERENCE); 2698 window.mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; 2699 mLayoutNeeded = true; 2700 performLayoutAndPlaceSurfacesLocked(); 2701 } 2702 2703 public int relayoutWindow(Session session, IWindow client, int seq, 2704 WindowManager.LayoutParams attrs, int requestedWidth, 2705 int requestedHeight, int viewVisibility, int flags, 2706 Rect outFrame, Rect outContentInsets, 2707 Rect outVisibleInsets, Configuration outConfig, Surface outSurface) { 2708 boolean toBeDisplayed = false; 2709 boolean inTouchMode; 2710 boolean configChanged; 2711 boolean surfaceChanged = false; 2712 boolean animating; 2713 2714 // if they don't have this permission, mask out the status bar bits 2715 int systemUiVisibility = 0; 2716 if (attrs != null) { 2717 systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility); 2718 if ((systemUiVisibility & StatusBarManager.DISABLE_MASK) != 0) { 2719 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) 2720 != PackageManager.PERMISSION_GRANTED) { 2721 systemUiVisibility &= ~StatusBarManager.DISABLE_MASK; 2722 } 2723 } 2724 } 2725 long origId = Binder.clearCallingIdentity(); 2726 2727 synchronized(mWindowMap) { 2728 // TODO(cmautner): synchronize on mAnimator or win.mWinAnimator. 2729 WindowState win = windowForClientLocked(session, client, false); 2730 if (win == null) { 2731 return 0; 2732 } 2733 WindowStateAnimator winAnimator = win.mWinAnimator; 2734 if (win.mRequestedWidth != requestedWidth 2735 || win.mRequestedHeight != requestedHeight) { 2736 win.mLayoutNeeded = true; 2737 win.mRequestedWidth = requestedWidth; 2738 win.mRequestedHeight = requestedHeight; 2739 } 2740 if (attrs != null && seq == win.mSeq) { 2741 win.mSystemUiVisibility = systemUiVisibility; 2742 } 2743 2744 if (attrs != null) { 2745 mPolicy.adjustWindowParamsLw(attrs); 2746 } 2747 2748 winAnimator.mSurfaceDestroyDeferred = 2749 (flags&WindowManagerImpl.RELAYOUT_DEFER_SURFACE_DESTROY) != 0; 2750 2751 int attrChanges = 0; 2752 int flagChanges = 0; 2753 if (attrs != null) { 2754 if (win.mAttrs.type != attrs.type) { 2755 throw new IllegalArgumentException( 2756 "Window type can not be changed after the window is added."); 2757 } 2758 flagChanges = win.mAttrs.flags ^= attrs.flags; 2759 attrChanges = win.mAttrs.copyFrom(attrs); 2760 if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED 2761 | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) { 2762 win.mLayoutNeeded = true; 2763 } 2764 } 2765 2766 if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": " + win.mAttrs); 2767 2768 win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0; 2769 2770 if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) { 2771 winAnimator.mAlpha = attrs.alpha; 2772 } 2773 2774 final boolean scaledWindow = 2775 ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0); 2776 2777 if (scaledWindow) { 2778 // requested{Width|Height} Surface's physical size 2779 // attrs.{width|height} Size on screen 2780 win.mHScale = (attrs.width != requestedWidth) ? 2781 (attrs.width / (float)requestedWidth) : 1.0f; 2782 win.mVScale = (attrs.height != requestedHeight) ? 2783 (attrs.height / (float)requestedHeight) : 1.0f; 2784 } else { 2785 win.mHScale = win.mVScale = 1; 2786 } 2787 2788 boolean imMayMove = (flagChanges&( 2789 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM | 2790 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0; 2791 2792 boolean focusMayChange = win.mViewVisibility != viewVisibility 2793 || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0) 2794 || (!win.mRelayoutCalled); 2795 2796 boolean wallpaperMayMove = win.mViewVisibility != viewVisibility 2797 && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0; 2798 wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0; 2799 2800 win.mRelayoutCalled = true; 2801 final int oldVisibility = win.mViewVisibility; 2802 win.mViewVisibility = viewVisibility; 2803 if (DEBUG_SCREEN_ON) { 2804 RuntimeException stack = new RuntimeException(); 2805 stack.fillInStackTrace(); 2806 Slog.i(TAG, "Relayout " + win + ": oldVis=" + oldVisibility 2807 + " newVis=" + viewVisibility, stack); 2808 } 2809 if (viewVisibility == View.VISIBLE && 2810 (win.mAppToken == null || !win.mAppToken.clientHidden)) { 2811 toBeDisplayed = !win.isVisibleLw(); 2812 if (win.mExiting) { 2813 winAnimator.cancelExitAnimationForNextAnimationLocked(); 2814 win.mExiting = false; 2815 } 2816 if (win.mDestroying) { 2817 win.mDestroying = false; 2818 mDestroySurface.remove(win); 2819 } 2820 if (oldVisibility == View.GONE) { 2821 winAnimator.mEnterAnimationPending = true; 2822 } 2823 if (toBeDisplayed) { 2824 if (win.isDrawnLw() && okToDisplay()) { 2825 winAnimator.applyEnterAnimationLocked(); 2826 } 2827 if ((win.mAttrs.flags 2828 & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) { 2829 if (DEBUG_VISIBILITY) Slog.v(TAG, 2830 "Relayout window turning screen on: " + win); 2831 win.mTurnOnScreen = true; 2832 } 2833 int diff = 0; 2834 if (win.mConfiguration != mCurConfiguration 2835 && (win.mConfiguration == null 2836 || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0)) { 2837 win.mConfiguration = mCurConfiguration; 2838 if (DEBUG_CONFIGURATION) { 2839 Slog.i(TAG, "Window " + win + " visible with new config: " 2840 + win.mConfiguration + " / 0x" 2841 + Integer.toHexString(diff)); 2842 } 2843 outConfig.setTo(mCurConfiguration); 2844 } 2845 } 2846 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) { 2847 // To change the format, we need to re-build the surface. 2848 winAnimator.destroySurfaceLocked(); 2849 toBeDisplayed = true; 2850 surfaceChanged = true; 2851 } 2852 try { 2853 if (!win.mHasSurface) { 2854 surfaceChanged = true; 2855 } 2856 Surface surface = winAnimator.createSurfaceLocked(); 2857 if (surface != null) { 2858 outSurface.copyFrom(surface); 2859 if (SHOW_TRANSACTIONS) Slog.i(TAG, 2860 " OUT SURFACE " + outSurface + ": copied"); 2861 } else { 2862 // For some reason there isn't a surface. Clear the 2863 // caller's object so they see the same state. 2864 outSurface.release(); 2865 } 2866 } catch (Exception e) { 2867 mInputMonitor.updateInputWindowsLw(true /*force*/); 2868 2869 Slog.w(TAG, "Exception thrown when creating surface for client " 2870 + client + " (" + win.mAttrs.getTitle() + ")", 2871 e); 2872 Binder.restoreCallingIdentity(origId); 2873 return 0; 2874 } 2875 if (toBeDisplayed) { 2876 focusMayChange = true; 2877 } 2878 if (win.mAttrs.type == TYPE_INPUT_METHOD 2879 && mInputMethodWindow == null) { 2880 mInputMethodWindow = win; 2881 imMayMove = true; 2882 } 2883 if (win.mAttrs.type == TYPE_BASE_APPLICATION 2884 && win.mAppToken != null 2885 && win.mAppToken.startingWindow != null) { 2886 // Special handling of starting window over the base 2887 // window of the app: propagate lock screen flags to it, 2888 // to provide the correct semantics while starting. 2889 final int mask = 2890 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED 2891 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD 2892 | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; 2893 WindowManager.LayoutParams sa = win.mAppToken.startingWindow.mAttrs; 2894 sa.flags = (sa.flags&~mask) | (win.mAttrs.flags&mask); 2895 } 2896 } else { 2897 winAnimator.mEnterAnimationPending = false; 2898 if (winAnimator.mSurface != null) { 2899 if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win 2900 + ": mExiting=" + win.mExiting); 2901 // If we are not currently running the exit animation, we 2902 // need to see about starting one. 2903 if (!win.mExiting) { 2904 surfaceChanged = true; 2905 // Try starting an animation; if there isn't one, we 2906 // can destroy the surface right away. 2907 int transit = WindowManagerPolicy.TRANSIT_EXIT; 2908 if (win.mAttrs.type == TYPE_APPLICATION_STARTING) { 2909 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; 2910 } 2911 if (win.isWinVisibleLw() && 2912 winAnimator.applyAnimationLocked(transit, false)) { 2913 focusMayChange = true; 2914 win.mExiting = true; 2915 } else if (win.mWinAnimator.isAnimating()) { 2916 // Currently in a hide animation... turn this into 2917 // an exit. 2918 win.mExiting = true; 2919 } else if (win == mWallpaperTarget) { 2920 // If the wallpaper is currently behind this 2921 // window, we need to change both of them inside 2922 // of a transaction to avoid artifacts. 2923 win.mExiting = true; 2924 win.mWinAnimator.mAnimating = true; 2925 } else { 2926 if (mInputMethodWindow == win) { 2927 mInputMethodWindow = null; 2928 } 2929 winAnimator.destroySurfaceLocked(); 2930 } 2931 } 2932 } 2933 2934 outSurface.release(); 2935 if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win); 2936 } 2937 2938 if (focusMayChange) { 2939 //System.out.println("Focus may change: " + win.mAttrs.getTitle()); 2940 if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 2941 false /*updateInputWindows*/)) { 2942 imMayMove = false; 2943 } 2944 //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus); 2945 } 2946 2947 // updateFocusedWindowLocked() already assigned layers so we only need to 2948 // reassign them at this point if the IM window state gets shuffled 2949 boolean assignLayers = false; 2950 2951 if (imMayMove) { 2952 if (moveInputMethodWindowsIfNeededLocked(false) || toBeDisplayed) { 2953 // Little hack here -- we -should- be able to rely on the 2954 // function to return true if the IME has moved and needs 2955 // its layer recomputed. However, if the IME was hidden 2956 // and isn't actually moved in the list, its layer may be 2957 // out of data so we make sure to recompute it. 2958 assignLayers = true; 2959 } 2960 } 2961 if (wallpaperMayMove) { 2962 if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) { 2963 assignLayers = true; 2964 } 2965 } 2966 2967 mLayoutNeeded = true; 2968 win.mGivenInsetsPending = (flags&WindowManagerImpl.RELAYOUT_INSETS_PENDING) != 0; 2969 if (assignLayers) { 2970 assignLayersLocked(win.getWindowList()); 2971 } 2972 configChanged = updateOrientationFromAppTokensLocked(false); 2973 performLayoutAndPlaceSurfacesLocked(); 2974 if (toBeDisplayed && win.mIsWallpaper) { 2975 DisplayInfo displayInfo = getDefaultDisplayInfo(); 2976 updateWallpaperOffsetLocked(win, 2977 displayInfo.appWidth, displayInfo.appHeight, false); 2978 } 2979 if (win.mAppToken != null) { 2980 win.mAppToken.updateReportedVisibilityLocked(); 2981 } 2982 outFrame.set(win.mCompatFrame); 2983 outContentInsets.set(win.mContentInsets); 2984 outVisibleInsets.set(win.mVisibleInsets); 2985 if (localLOGV) Slog.v( 2986 TAG, "Relayout given client " + client.asBinder() 2987 + ", requestedWidth=" + requestedWidth 2988 + ", requestedHeight=" + requestedHeight 2989 + ", viewVisibility=" + viewVisibility 2990 + "\nRelayout returning frame=" + outFrame 2991 + ", surface=" + outSurface); 2992 2993 if (localLOGV || DEBUG_FOCUS) Slog.v( 2994 TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange); 2995 2996 inTouchMode = mInTouchMode; 2997 animating = mAnimator.mAnimating; 2998 if (animating && !mRelayoutWhileAnimating.contains(win)) { 2999 mRelayoutWhileAnimating.add(win); 3000 } 3001 3002 mInputMonitor.updateInputWindowsLw(true /*force*/); 3003 } 3004 3005 if (configChanged) { 3006 sendNewConfiguration(); 3007 } 3008 3009 Binder.restoreCallingIdentity(origId); 3010 3011 return (inTouchMode ? WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE : 0) 3012 | (toBeDisplayed ? WindowManagerImpl.RELAYOUT_RES_FIRST_TIME : 0) 3013 | (surfaceChanged ? WindowManagerImpl.RELAYOUT_RES_SURFACE_CHANGED : 0) 3014 | (animating ? WindowManagerImpl.RELAYOUT_RES_ANIMATING : 0); 3015 } 3016 3017 public void performDeferredDestroyWindow(Session session, IWindow client) { 3018 long origId = Binder.clearCallingIdentity(); 3019 3020 try { 3021 synchronized(mWindowMap) { 3022 WindowState win = windowForClientLocked(session, client, false); 3023 if (win == null) { 3024 return; 3025 } 3026 win.mWinAnimator.destroyDeferredSurfaceLocked(); 3027 } 3028 } finally { 3029 Binder.restoreCallingIdentity(origId); 3030 } 3031 } 3032 3033 public boolean outOfMemoryWindow(Session session, IWindow client) { 3034 long origId = Binder.clearCallingIdentity(); 3035 3036 try { 3037 synchronized(mWindowMap) { 3038 WindowState win = windowForClientLocked(session, client, false); 3039 if (win == null) { 3040 return false; 3041 } 3042 return reclaimSomeSurfaceMemoryLocked(win.mWinAnimator, "from-client", false); 3043 } 3044 } finally { 3045 Binder.restoreCallingIdentity(origId); 3046 } 3047 } 3048 3049 public void finishDrawingWindow(Session session, IWindow client) { 3050 final long origId = Binder.clearCallingIdentity(); 3051 synchronized(mWindowMap) { 3052 WindowState win = windowForClientLocked(session, client, false); 3053 if (win != null && win.mWinAnimator.finishDrawingLocked()) { 3054 if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) { 3055 adjustWallpaperWindowsLocked(); 3056 } 3057 mLayoutNeeded = true; 3058 performLayoutAndPlaceSurfacesLocked(); 3059 } 3060 } 3061 Binder.restoreCallingIdentity(origId); 3062 } 3063 3064 public float getWindowCompatibilityScale(IBinder windowToken) { 3065 if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO, 3066 "getWindowCompatibilityScale()")) { 3067 throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission."); 3068 } 3069 synchronized (mWindowMap) { 3070 WindowState windowState = mWindowMap.get(windowToken); 3071 return (windowState != null) ? windowState.mGlobalScale : 1.0f; 3072 } 3073 } 3074 3075 private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) { 3076 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg=" 3077 + (lp != null ? lp.packageName : null) 3078 + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null)); 3079 if (lp != null && lp.windowAnimations != 0) { 3080 // If this is a system resource, don't try to load it from the 3081 // application resources. It is nice to avoid loading application 3082 // resources if we can. 3083 String packageName = lp.packageName != null ? lp.packageName : "android"; 3084 int resId = lp.windowAnimations; 3085 if ((resId&0xFF000000) == 0x01000000) { 3086 packageName = "android"; 3087 } 3088 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 3089 + packageName); 3090 return AttributeCache.instance().get(packageName, resId, 3091 com.android.internal.R.styleable.WindowAnimation); 3092 } 3093 return null; 3094 } 3095 3096 private AttributeCache.Entry getCachedAnimations(String packageName, int resId) { 3097 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package=" 3098 + packageName + " resId=0x" + Integer.toHexString(resId)); 3099 if (packageName != null) { 3100 if ((resId&0xFF000000) == 0x01000000) { 3101 packageName = "android"; 3102 } 3103 if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package=" 3104 + packageName); 3105 return AttributeCache.instance().get(packageName, resId, 3106 com.android.internal.R.styleable.WindowAnimation); 3107 } 3108 return null; 3109 } 3110 3111 Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) { 3112 int anim = 0; 3113 Context context = mContext; 3114 if (animAttr >= 0) { 3115 AttributeCache.Entry ent = getCachedAnimations(lp); 3116 if (ent != null) { 3117 context = ent.context; 3118 anim = ent.array.getResourceId(animAttr, 0); 3119 } 3120 } 3121 if (anim != 0) { 3122 return AnimationUtils.loadAnimation(context, anim); 3123 } 3124 return null; 3125 } 3126 3127 private Animation loadAnimation(String packageName, int resId) { 3128 int anim = 0; 3129 Context context = mContext; 3130 if (resId >= 0) { 3131 AttributeCache.Entry ent = getCachedAnimations(packageName, resId); 3132 if (ent != null) { 3133 context = ent.context; 3134 anim = resId; 3135 } 3136 } 3137 if (anim != 0) { 3138 return AnimationUtils.loadAnimation(context, anim); 3139 } 3140 return null; 3141 } 3142 3143 private Animation createExitAnimationLocked(int transit, int duration) { 3144 if (transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN || 3145 transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE) { 3146 // If we are on top of the wallpaper, we need an animation that 3147 // correctly handles the wallpaper staying static behind all of 3148 // the animated elements. To do this, will just have the existing 3149 // element fade out. 3150 Animation a = new AlphaAnimation(1, 0); 3151 a.setDetachWallpaper(true); 3152 a.setDuration(duration); 3153 return a; 3154 } 3155 // For normal animations, the exiting element just holds in place. 3156 Animation a = new AlphaAnimation(1, 1); 3157 a.setDuration(duration); 3158 return a; 3159 } 3160 3161 /** 3162 * Compute the pivot point for an animation that is scaling from a small 3163 * rect on screen to a larger rect. The pivot point varies depending on 3164 * the distance between the inner and outer edges on both sides. This 3165 * function computes the pivot point for one dimension. 3166 * @param startPos Offset from left/top edge of outer rectangle to 3167 * left/top edge of inner rectangle. 3168 * @param finalScale The scaling factor between the size of the outer 3169 * and inner rectangles. 3170 */ 3171 private static float computePivot(int startPos, float finalScale) { 3172 final float denom = finalScale-1; 3173 if (Math.abs(denom) < .0001f) { 3174 return startPos; 3175 } 3176 return -startPos / denom; 3177 } 3178 3179 private Animation createScaleUpAnimationLocked(int transit, boolean enter) { 3180 Animation a; 3181 // Pick the desired duration. If this is an inter-activity transition, 3182 // it is the standard duration for that. Otherwise we use the longer 3183 // task transition duration. 3184 int duration; 3185 switch (transit) { 3186 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: 3187 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: 3188 duration = mContext.getResources().getInteger( 3189 com.android.internal.R.integer.config_shortAnimTime); 3190 break; 3191 default: 3192 duration = 300; 3193 break; 3194 } 3195 // TODO(multidisplay): For now assume all app animation is on main display. 3196 final DisplayInfo displayInfo = getDefaultDisplayInfo(); 3197 if (enter) { 3198 // Entering app zooms out from the center of the initial rect. 3199 float scaleW = mNextAppTransitionStartWidth / (float) displayInfo.appWidth; 3200 float scaleH = mNextAppTransitionStartHeight / (float) displayInfo.appHeight; 3201 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, 3202 computePivot(mNextAppTransitionStartX, scaleW), 3203 computePivot(mNextAppTransitionStartY, scaleH)); 3204 scale.setDuration(duration); 3205 AnimationSet set = new AnimationSet(true); 3206 Animation alpha = new AlphaAnimation(0, 1); 3207 scale.setDuration(duration); 3208 set.addAnimation(scale); 3209 alpha.setDuration(duration); 3210 set.addAnimation(alpha); 3211 set.setDetachWallpaper(true); 3212 a = set; 3213 } else { 3214 a = createExitAnimationLocked(transit, duration); 3215 } 3216 a.setFillAfter(true); 3217 final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext, 3218 com.android.internal.R.interpolator.decelerate_cubic); 3219 a.setInterpolator(interpolator); 3220 a.initialize(displayInfo.appWidth, displayInfo.appHeight, 3221 displayInfo.appWidth, displayInfo.appHeight); 3222 return a; 3223 } 3224 3225 private Animation createThumbnailAnimationLocked(int transit, 3226 boolean enter, boolean thumb, boolean delayed) { 3227 Animation a; 3228 final int thumbWidthI = mNextAppTransitionThumbnail.getWidth(); 3229 final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1; 3230 final int thumbHeightI = mNextAppTransitionThumbnail.getHeight(); 3231 final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1; 3232 // Pick the desired duration. If this is an inter-activity transition, 3233 // it is the standard duration for that. Otherwise we use the longer 3234 // task transition duration. 3235 int duration; 3236 int delayDuration = delayed ? 270 : 0; 3237 switch (transit) { 3238 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: 3239 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: 3240 duration = mContext.getResources().getInteger( 3241 com.android.internal.R.integer.config_shortAnimTime); 3242 break; 3243 default: 3244 duration = delayed ? 250 : 300; 3245 break; 3246 } 3247 // TOOD(multidisplay): For now assume all app animation is on the main screen. 3248 DisplayInfo displayInfo = getDefaultDisplayInfo(); 3249 if (thumb) { 3250 // Animation for zooming thumbnail from its initial size to 3251 // filling the screen. 3252 float scaleW = displayInfo.appWidth/thumbWidth; 3253 float scaleH = displayInfo.appHeight/thumbHeight; 3254 3255 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH, 3256 computePivot(mNextAppTransitionStartX, 1/scaleW), 3257 computePivot(mNextAppTransitionStartY, 1/scaleH)); 3258 AnimationSet set = new AnimationSet(true); 3259 Animation alpha = new AlphaAnimation(1, 0); 3260 scale.setDuration(duration); 3261 scale.setInterpolator( 3262 new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR)); 3263 set.addAnimation(scale); 3264 alpha.setDuration(duration); 3265 set.addAnimation(alpha); 3266 set.setFillBefore(true); 3267 if (delayDuration > 0) { 3268 set.setStartOffset(delayDuration); 3269 } 3270 a = set; 3271 } else if (enter) { 3272 // Entering app zooms out from the center of the thumbnail. 3273 float scaleW = thumbWidth / displayInfo.appWidth; 3274 float scaleH = thumbHeight / displayInfo.appHeight; 3275 Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1, 3276 computePivot(mNextAppTransitionStartX, scaleW), 3277 computePivot(mNextAppTransitionStartY, scaleH)); 3278 scale.setDuration(duration); 3279 scale.setInterpolator( 3280 new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR)); 3281 scale.setFillBefore(true); 3282 if (delayDuration > 0) { 3283 scale.setStartOffset(delayDuration); 3284 } 3285 a = scale; 3286 } else { 3287 if (delayed) { 3288 a = new AlphaAnimation(1, 0); 3289 a.setStartOffset(0); 3290 a.setDuration(delayDuration - 120); 3291 a.setBackgroundColor(0xFF000000); 3292 } else { 3293 a = createExitAnimationLocked(transit, duration); 3294 } 3295 } 3296 a.setFillAfter(true); 3297 final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext, 3298 com.android.internal.R.interpolator.decelerate_quad); 3299 a.setInterpolator(interpolator); 3300 a.initialize(displayInfo.appWidth, displayInfo.appHeight, 3301 displayInfo.appWidth, displayInfo.appHeight); 3302 return a; 3303 } 3304 3305 private boolean applyAnimationLocked(AppWindowToken wtoken, 3306 WindowManager.LayoutParams lp, int transit, boolean enter) { 3307 // Only apply an animation if the display isn't frozen. If it is 3308 // frozen, there is no reason to animate and it can cause strange 3309 // artifacts when we unfreeze the display if some different animation 3310 // is running. 3311 if (okToDisplay()) { 3312 Animation a; 3313 boolean initialized = false; 3314 if (mNextAppTransitionType == ActivityOptions.ANIM_CUSTOM) { 3315 a = loadAnimation(mNextAppTransitionPackage, enter ? 3316 mNextAppTransitionEnter : mNextAppTransitionExit); 3317 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 3318 "applyAnimation: wtoken=" + wtoken 3319 + " anim=" + a + " nextAppTransition=ANIM_CUSTOM" 3320 + " transit=" + transit + " Callers " + Debug.getCallers(3)); 3321 } else if (mNextAppTransitionType == ActivityOptions.ANIM_SCALE_UP) { 3322 a = createScaleUpAnimationLocked(transit, enter); 3323 initialized = true; 3324 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 3325 "applyAnimation: wtoken=" + wtoken 3326 + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP" 3327 + " transit=" + transit + " Callers " + Debug.getCallers(3)); 3328 } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL || 3329 mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_DELAYED) { 3330 boolean delayed = (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_DELAYED); 3331 a = createThumbnailAnimationLocked(transit, enter, false, delayed); 3332 initialized = true; 3333 3334 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) { 3335 String animName = delayed ? "ANIM_THUMBNAIL_DELAYED" : "ANIM_THUMBNAIL"; 3336 Slog.v(TAG, "applyAnimation: wtoken=" + wtoken 3337 + " anim=" + a + " nextAppTransition=" + animName 3338 + " transit=" + transit + " Callers " + Debug.getCallers(3)); 3339 } 3340 } else { 3341 int animAttr = 0; 3342 switch (transit) { 3343 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: 3344 animAttr = enter 3345 ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation 3346 : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation; 3347 break; 3348 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: 3349 animAttr = enter 3350 ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation 3351 : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation; 3352 break; 3353 case WindowManagerPolicy.TRANSIT_TASK_OPEN: 3354 animAttr = enter 3355 ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation 3356 : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation; 3357 break; 3358 case WindowManagerPolicy.TRANSIT_TASK_CLOSE: 3359 animAttr = enter 3360 ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation 3361 : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation; 3362 break; 3363 case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT: 3364 animAttr = enter 3365 ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation 3366 : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation; 3367 break; 3368 case WindowManagerPolicy.TRANSIT_TASK_TO_BACK: 3369 animAttr = enter 3370 ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation 3371 : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation; 3372 break; 3373 case WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN: 3374 animAttr = enter 3375 ? com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation 3376 : com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation; 3377 break; 3378 case WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE: 3379 animAttr = enter 3380 ? com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation 3381 : com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation; 3382 break; 3383 case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN: 3384 animAttr = enter 3385 ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation 3386 : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation; 3387 break; 3388 case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE: 3389 animAttr = enter 3390 ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation 3391 : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation; 3392 break; 3393 } 3394 a = animAttr != 0 ? loadAnimation(lp, animAttr) : null; 3395 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, 3396 "applyAnimation: wtoken=" + wtoken 3397 + " anim=" + a 3398 + " animAttr=0x" + Integer.toHexString(animAttr) 3399 + " transit=" + transit + " Callers " + Debug.getCallers(3)); 3400 } 3401 if (a != null) { 3402 if (DEBUG_ANIM) { 3403 RuntimeException e = null; 3404 if (!HIDE_STACK_CRAWLS) { 3405 e = new RuntimeException(); 3406 e.fillInStackTrace(); 3407 } 3408 Slog.v(TAG, "Loaded animation " + a + " for " + wtoken, e); 3409 } 3410 wtoken.mAppAnimator.setAnimation(a, initialized); 3411 } 3412 } else { 3413 wtoken.mAppAnimator.clearAnimation(); 3414 } 3415 3416 return wtoken.mAppAnimator.animation != null; 3417 } 3418 3419 // ------------------------------------------------------------- 3420 // Application Window Tokens 3421 // ------------------------------------------------------------- 3422 3423 public void validateAppTokens(List<IBinder> tokens) { 3424 int v = tokens.size()-1; 3425 int m = mAppTokens.size()-1; 3426 while (v >= 0 && m >= 0) { 3427 AppWindowToken wtoken = mAppTokens.get(m); 3428 if (wtoken.removed) { 3429 m--; 3430 continue; 3431 } 3432 if (tokens.get(v) != wtoken.token) { 3433 Slog.w(TAG, "Tokens out of sync: external is " + tokens.get(v) 3434 + " @ " + v + ", internal is " + wtoken.token + " @ " + m); 3435 } 3436 v--; 3437 m--; 3438 } 3439 while (v >= 0) { 3440 Slog.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v); 3441 v--; 3442 } 3443 while (m >= 0) { 3444 AppWindowToken wtoken = mAppTokens.get(m); 3445 if (!wtoken.removed) { 3446 Slog.w(TAG, "Invalid internal token: " + wtoken.token + " @ " + m); 3447 } 3448 m--; 3449 } 3450 } 3451 3452 boolean checkCallingPermission(String permission, String func) { 3453 // Quick check: if the calling permission is me, it's all okay. 3454 if (Binder.getCallingPid() == Process.myPid()) { 3455 return true; 3456 } 3457 3458 if (mContext.checkCallingPermission(permission) 3459 == PackageManager.PERMISSION_GRANTED) { 3460 return true; 3461 } 3462 String msg = "Permission Denial: " + func + " from pid=" 3463 + Binder.getCallingPid() 3464 + ", uid=" + Binder.getCallingUid() 3465 + " requires " + permission; 3466 Slog.w(TAG, msg); 3467 return false; 3468 } 3469 3470 boolean okToDisplay() { 3471 return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully(); 3472 } 3473 3474 AppWindowToken findAppWindowToken(IBinder token) { 3475 WindowToken wtoken = mTokenMap.get(token); 3476 if (wtoken == null) { 3477 return null; 3478 } 3479 return wtoken.appWindowToken; 3480 } 3481 3482 @Override 3483 public void addWindowToken(IBinder token, int type) { 3484 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3485 "addWindowToken()")) { 3486 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3487 } 3488 3489 synchronized(mWindowMap) { 3490 WindowToken wtoken = mTokenMap.get(token); 3491 if (wtoken != null) { 3492 Slog.w(TAG, "Attempted to add existing input method token: " + token); 3493 return; 3494 } 3495 wtoken = new WindowToken(this, token, type, true); 3496 mTokenMap.put(token, wtoken); 3497 if (type == TYPE_WALLPAPER) { 3498 mWallpaperTokens.add(wtoken); 3499 updateLayoutToAnimWallpaperTokens(); 3500 } 3501 } 3502 } 3503 3504 @Override 3505 public void removeWindowToken(IBinder token) { 3506 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3507 "removeWindowToken()")) { 3508 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3509 } 3510 3511 final long origId = Binder.clearCallingIdentity(); 3512 synchronized(mWindowMap) { 3513 WindowToken wtoken = mTokenMap.remove(token); 3514 if (wtoken != null) { 3515 boolean delayed = false; 3516 if (!wtoken.hidden) { 3517 wtoken.hidden = true; 3518 3519 final int N = wtoken.windows.size(); 3520 boolean changed = false; 3521 3522 for (int i=0; i<N; i++) { 3523 WindowState win = wtoken.windows.get(i); 3524 3525 if (win.mWinAnimator.isAnimating()) { 3526 delayed = true; 3527 } 3528 3529 if (win.isVisibleNow()) { 3530 win.mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT, 3531 false); 3532 changed = true; 3533 } 3534 } 3535 3536 if (changed) { 3537 mLayoutNeeded = true; 3538 performLayoutAndPlaceSurfacesLocked(); 3539 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, 3540 false /*updateInputWindows*/); 3541 } 3542 3543 if (delayed) { 3544 mExitingTokens.add(wtoken); 3545 } else if (wtoken.windowType == TYPE_WALLPAPER) { 3546 mWallpaperTokens.remove(wtoken); 3547 updateLayoutToAnimWallpaperTokens(); 3548 } 3549 } 3550 3551 mInputMonitor.updateInputWindowsLw(true /*force*/); 3552 } else { 3553 Slog.w(TAG, "Attempted to remove non-existing token: " + token); 3554 } 3555 } 3556 Binder.restoreCallingIdentity(origId); 3557 } 3558 3559 /** 3560 * Find the location to insert a new AppWindowToken into the window-ordered app token list. 3561 * Note that mAppTokens.size() == mAnimatingAppTokens.size() + 1. 3562 * @param addPos The location the token was inserted into in mAppTokens. 3563 * @param wtoken The token to insert. 3564 */ 3565 private void addAppTokenToAnimating(final int addPos, final AppWindowToken wtoken) { 3566 if (addPos == 0 || addPos == mAnimatingAppTokens.size()) { 3567 // It was inserted into the beginning or end of mAppTokens. Honor that. 3568 mAnimatingAppTokens.add(addPos, wtoken); 3569 return; 3570 } 3571 // Find the item immediately above the mAppTokens insertion point and put the token 3572 // immediately below that one in mAnimatingAppTokens. 3573 final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1); 3574 mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), wtoken); 3575 } 3576 3577 @Override 3578 public void addAppToken(int addPos, IApplicationToken token, 3579 int groupId, int requestedOrientation, boolean fullscreen) { 3580 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3581 "addAppToken()")) { 3582 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3583 } 3584 3585 // Get the dispatching timeout here while we are not holding any locks so that it 3586 // can be cached by the AppWindowToken. The timeout value is used later by the 3587 // input dispatcher in code that does hold locks. If we did not cache the value 3588 // here we would run the chance of introducing a deadlock between the window manager 3589 // (which holds locks while updating the input dispatcher state) and the activity manager 3590 // (which holds locks while querying the application token). 3591 long inputDispatchingTimeoutNanos; 3592 try { 3593 inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L; 3594 } catch (RemoteException ex) { 3595 Slog.w(TAG, "Could not get dispatching timeout.", ex); 3596 inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; 3597 } 3598 3599 synchronized(mWindowMap) { 3600 AppWindowToken wtoken = findAppWindowToken(token.asBinder()); 3601 if (wtoken != null) { 3602 Slog.w(TAG, "Attempted to add existing app token: " + token); 3603 return; 3604 } 3605 wtoken = new AppWindowToken(this, token); 3606 wtoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos; 3607 wtoken.groupId = groupId; 3608 wtoken.appFullscreen = fullscreen; 3609 wtoken.requestedOrientation = requestedOrientation; 3610 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + wtoken 3611 + " at " + addPos); 3612 mAppTokens.add(addPos, wtoken); 3613 addAppTokenToAnimating(addPos, wtoken); 3614 mTokenMap.put(token.asBinder(), wtoken); 3615 3616 // Application tokens start out hidden. 3617 wtoken.hidden = true; 3618 wtoken.hiddenRequested = true; 3619 3620 //dump(); 3621 } 3622 } 3623 3624 @Override 3625 public void setAppGroupId(IBinder token, int groupId) { 3626 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3627 "setAppGroupId()")) { 3628 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3629 } 3630 3631 synchronized(mWindowMap) { 3632 AppWindowToken wtoken = findAppWindowToken(token); 3633 if (wtoken == null) { 3634 Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token); 3635 return; 3636 } 3637 wtoken.groupId = groupId; 3638 } 3639 } 3640 3641 public int getOrientationFromWindowsLocked() { 3642 if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) { 3643 // If the display is frozen, some activities may be in the middle 3644 // of restarting, and thus have removed their old window. If the 3645 // window has the flag to hide the lock screen, then the lock screen 3646 // can re-appear and inflict its own orientation on us. Keep the 3647 // orientation stable until this all settles down. 3648 return mLastWindowForcedOrientation; 3649 } 3650 3651 // TODO(multidisplay): Change to the correct display. 3652 final WindowList windows = getDefaultWindowList(); 3653 int pos = windows.size() - 1; 3654 while (pos >= 0) { 3655 WindowState wtoken = windows.get(pos); 3656 pos--; 3657 if (wtoken.mAppToken != null) { 3658 // We hit an application window. so the orientation will be determined by the 3659 // app window. No point in continuing further. 3660 return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 3661 } 3662 if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) { 3663 continue; 3664 } 3665 int req = wtoken.mAttrs.screenOrientation; 3666 if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) || 3667 (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){ 3668 continue; 3669 } 3670 3671 return (mLastWindowForcedOrientation=req); 3672 } 3673 return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 3674 } 3675 3676 public int getOrientationFromAppTokensLocked() { 3677 int curGroup = 0; 3678 int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 3679 boolean findingBehind = false; 3680 boolean haveGroup = false; 3681 boolean lastFullscreen = false; 3682 for (int pos = mAppTokens.size() - 1; pos >= 0; pos--) { 3683 AppWindowToken wtoken = mAppTokens.get(pos); 3684 3685 if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + wtoken); 3686 3687 // if we're about to tear down this window and not seek for 3688 // the behind activity, don't use it for orientation 3689 if (!findingBehind 3690 && (!wtoken.hidden && wtoken.hiddenRequested)) { 3691 if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + wtoken 3692 + " -- going to hide"); 3693 continue; 3694 } 3695 3696 if (haveGroup == true && curGroup != wtoken.groupId) { 3697 // If we have hit a new application group, and the bottom 3698 // of the previous group didn't explicitly say to use 3699 // the orientation behind it, and the last app was 3700 // full screen, then we'll stick with the 3701 // user's orientation. 3702 if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND 3703 && lastFullscreen) { 3704 if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken 3705 + " -- end of group, return " + lastOrientation); 3706 return lastOrientation; 3707 } 3708 } 3709 3710 // We ignore any hidden applications on the top. 3711 if (wtoken.hiddenRequested || wtoken.willBeHidden) { 3712 if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + wtoken 3713 + " -- hidden on top"); 3714 continue; 3715 } 3716 3717 if (!haveGroup) { 3718 haveGroup = true; 3719 curGroup = wtoken.groupId; 3720 lastOrientation = wtoken.requestedOrientation; 3721 } 3722 3723 int or = wtoken.requestedOrientation; 3724 // If this application is fullscreen, and didn't explicitly say 3725 // to use the orientation behind it, then just take whatever 3726 // orientation it has and ignores whatever is under it. 3727 lastFullscreen = wtoken.appFullscreen; 3728 if (lastFullscreen 3729 && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { 3730 if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken 3731 + " -- full screen, return " + or); 3732 return or; 3733 } 3734 // If this application has requested an explicit orientation, 3735 // then use it. 3736 if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED 3737 && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { 3738 if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken 3739 + " -- explicitly set, return " + or); 3740 return or; 3741 } 3742 findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND); 3743 } 3744 if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation"); 3745 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 3746 } 3747 3748 @Override 3749 public Configuration updateOrientationFromAppTokens( 3750 Configuration currentConfig, IBinder freezeThisOneIfNeeded) { 3751 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3752 "updateOrientationFromAppTokens()")) { 3753 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3754 } 3755 3756 Configuration config = null; 3757 long ident = Binder.clearCallingIdentity(); 3758 3759 synchronized(mWindowMap) { 3760 config = updateOrientationFromAppTokensLocked(currentConfig, 3761 freezeThisOneIfNeeded); 3762 } 3763 3764 Binder.restoreCallingIdentity(ident); 3765 return config; 3766 } 3767 3768 private Configuration updateOrientationFromAppTokensLocked( 3769 Configuration currentConfig, IBinder freezeThisOneIfNeeded) { 3770 Configuration config = null; 3771 3772 if (updateOrientationFromAppTokensLocked(false)) { 3773 if (freezeThisOneIfNeeded != null) { 3774 AppWindowToken wtoken = findAppWindowToken( 3775 freezeThisOneIfNeeded); 3776 if (wtoken != null) { 3777 startAppFreezingScreenLocked(wtoken, 3778 ActivityInfo.CONFIG_ORIENTATION); 3779 } 3780 } 3781 config = computeNewConfigurationLocked(); 3782 3783 } else if (currentConfig != null) { 3784 // No obvious action we need to take, but if our current 3785 // state mismatches the activity manager's, update it, 3786 // disregarding font scale, which should remain set to 3787 // the value of the previous configuration. 3788 mTempConfiguration.setToDefaults(); 3789 mTempConfiguration.fontScale = currentConfig.fontScale; 3790 if (computeScreenConfigurationLocked(mTempConfiguration)) { 3791 if (currentConfig.diff(mTempConfiguration) != 0) { 3792 mWaitingForConfig = true; 3793 mLayoutNeeded = true; 3794 startFreezingDisplayLocked(false); 3795 config = new Configuration(mTempConfiguration); 3796 } 3797 } 3798 } 3799 3800 return config; 3801 } 3802 3803 /* 3804 * Determine the new desired orientation of the display, returning 3805 * a non-null new Configuration if it has changed from the current 3806 * orientation. IF TRUE IS RETURNED SOMEONE MUST CALL 3807 * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE 3808 * SCREEN. This will typically be done for you if you call 3809 * sendNewConfiguration(). 3810 * 3811 * The orientation is computed from non-application windows first. If none of 3812 * the non-application windows specify orientation, the orientation is computed from 3813 * application tokens. 3814 * @see android.view.IWindowManager#updateOrientationFromAppTokens( 3815 * android.os.IBinder) 3816 */ 3817 boolean updateOrientationFromAppTokensLocked(boolean inTransaction) { 3818 long ident = Binder.clearCallingIdentity(); 3819 try { 3820 int req = computeForcedAppOrientationLocked(); 3821 3822 if (req != mForcedAppOrientation) { 3823 mForcedAppOrientation = req; 3824 //send a message to Policy indicating orientation change to take 3825 //action like disabling/enabling sensors etc., 3826 mPolicy.setCurrentOrientationLw(req); 3827 if (updateRotationUncheckedLocked(inTransaction)) { 3828 // changed 3829 return true; 3830 } 3831 } 3832 3833 return false; 3834 } finally { 3835 Binder.restoreCallingIdentity(ident); 3836 } 3837 } 3838 3839 int computeForcedAppOrientationLocked() { 3840 int req = getOrientationFromWindowsLocked(); 3841 if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) { 3842 req = getOrientationFromAppTokensLocked(); 3843 } 3844 return req; 3845 } 3846 3847 @Override 3848 public void setNewConfiguration(Configuration config) { 3849 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3850 "setNewConfiguration()")) { 3851 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3852 } 3853 3854 synchronized(mWindowMap) { 3855 mCurConfiguration = new Configuration(config); 3856 mWaitingForConfig = false; 3857 performLayoutAndPlaceSurfacesLocked(); 3858 } 3859 } 3860 3861 @Override 3862 public void setAppOrientation(IApplicationToken token, int requestedOrientation) { 3863 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3864 "setAppOrientation()")) { 3865 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3866 } 3867 3868 synchronized(mWindowMap) { 3869 AppWindowToken wtoken = findAppWindowToken(token.asBinder()); 3870 if (wtoken == null) { 3871 Slog.w(TAG, "Attempted to set orientation of non-existing app token: " + token); 3872 return; 3873 } 3874 3875 wtoken.requestedOrientation = requestedOrientation; 3876 } 3877 } 3878 3879 public int getAppOrientation(IApplicationToken token) { 3880 synchronized(mWindowMap) { 3881 AppWindowToken wtoken = findAppWindowToken(token.asBinder()); 3882 if (wtoken == null) { 3883 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 3884 } 3885 3886 return wtoken.requestedOrientation; 3887 } 3888 } 3889 3890 public void setFocusedApp(IBinder token, boolean moveFocusNow) { 3891 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3892 "setFocusedApp()")) { 3893 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3894 } 3895 3896 synchronized(mWindowMap) { 3897 boolean changed = false; 3898 if (token == null) { 3899 if (DEBUG_FOCUS) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp); 3900 changed = mFocusedApp != null; 3901 mFocusedApp = null; 3902 if (changed) { 3903 mInputMonitor.setFocusedAppLw(null); 3904 } 3905 } else { 3906 AppWindowToken newFocus = findAppWindowToken(token); 3907 if (newFocus == null) { 3908 Slog.w(TAG, "Attempted to set focus to non-existing app token: " + token); 3909 return; 3910 } 3911 changed = mFocusedApp != newFocus; 3912 mFocusedApp = newFocus; 3913 if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp); 3914 if (changed) { 3915 mInputMonitor.setFocusedAppLw(newFocus); 3916 } 3917 } 3918 3919 if (moveFocusNow && changed) { 3920 final long origId = Binder.clearCallingIdentity(); 3921 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); 3922 Binder.restoreCallingIdentity(origId); 3923 } 3924 } 3925 } 3926 3927 public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) { 3928 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3929 "prepareAppTransition()")) { 3930 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3931 } 3932 3933 synchronized(mWindowMap) { 3934 if (DEBUG_APP_TRANSITIONS) Slog.v( 3935 TAG, "Prepare app transition: transit=" + transit 3936 + " mNextAppTransition=" + mNextAppTransition 3937 + " alwaysKeepCurrent=" + alwaysKeepCurrent 3938 + " Callers=" + Debug.getCallers(3)); 3939 if (okToDisplay()) { 3940 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET 3941 || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) { 3942 mNextAppTransition = transit; 3943 } else if (!alwaysKeepCurrent) { 3944 if (transit == WindowManagerPolicy.TRANSIT_TASK_OPEN 3945 && mNextAppTransition == WindowManagerPolicy.TRANSIT_TASK_CLOSE) { 3946 // Opening a new task always supersedes a close for the anim. 3947 mNextAppTransition = transit; 3948 } else if (transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN 3949 && mNextAppTransition == WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE) { 3950 // Opening a new activity always supersedes a close for the anim. 3951 mNextAppTransition = transit; 3952 } 3953 } 3954 mAppTransitionReady = false; 3955 mAppTransitionTimeout = false; 3956 mStartingIconInTransition = false; 3957 mSkipAppTransitionAnimation = false; 3958 mH.removeMessages(H.APP_TRANSITION_TIMEOUT); 3959 mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT), 3960 5000); 3961 } 3962 } 3963 } 3964 3965 public int getPendingAppTransition() { 3966 return mNextAppTransition; 3967 } 3968 3969 private void scheduleAnimationCallback(IRemoteCallback cb) { 3970 if (cb != null) { 3971 mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, cb)); 3972 } 3973 } 3974 3975 public void overridePendingAppTransition(String packageName, 3976 int enterAnim, int exitAnim, IRemoteCallback startedCallback) { 3977 synchronized(mWindowMap) { 3978 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 3979 mNextAppTransitionType = ActivityOptions.ANIM_CUSTOM; 3980 mNextAppTransitionPackage = packageName; 3981 mNextAppTransitionThumbnail = null; 3982 mNextAppTransitionEnter = enterAnim; 3983 mNextAppTransitionExit = exitAnim; 3984 scheduleAnimationCallback(mNextAppTransitionCallback); 3985 mNextAppTransitionCallback = startedCallback; 3986 } else { 3987 scheduleAnimationCallback(startedCallback); 3988 } 3989 } 3990 } 3991 3992 public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, 3993 int startHeight) { 3994 synchronized(mWindowMap) { 3995 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 3996 mNextAppTransitionType = ActivityOptions.ANIM_SCALE_UP; 3997 mNextAppTransitionPackage = null; 3998 mNextAppTransitionThumbnail = null; 3999 mNextAppTransitionStartX = startX; 4000 mNextAppTransitionStartY = startY; 4001 mNextAppTransitionStartWidth = startWidth; 4002 mNextAppTransitionStartHeight = startHeight; 4003 scheduleAnimationCallback(mNextAppTransitionCallback); 4004 mNextAppTransitionCallback = null; 4005 } 4006 } 4007 } 4008 4009 public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, 4010 int startY, IRemoteCallback startedCallback, boolean delayed) { 4011 synchronized(mWindowMap) { 4012 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 4013 mNextAppTransitionType = delayed 4014 ? ActivityOptions.ANIM_THUMBNAIL_DELAYED : ActivityOptions.ANIM_THUMBNAIL; 4015 mNextAppTransitionPackage = null; 4016 mNextAppTransitionThumbnail = srcThumb; 4017 mNextAppTransitionDelayed = delayed; 4018 mNextAppTransitionStartX = startX; 4019 mNextAppTransitionStartY = startY; 4020 scheduleAnimationCallback(mNextAppTransitionCallback); 4021 mNextAppTransitionCallback = startedCallback; 4022 } else { 4023 scheduleAnimationCallback(startedCallback); 4024 } 4025 } 4026 } 4027 4028 public void executeAppTransition() { 4029 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4030 "executeAppTransition()")) { 4031 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4032 } 4033 4034 synchronized(mWindowMap) { 4035 if (DEBUG_APP_TRANSITIONS) { 4036 RuntimeException e = new RuntimeException("here"); 4037 e.fillInStackTrace(); 4038 Slog.w(TAG, "Execute app transition: mNextAppTransition=" 4039 + mNextAppTransition, e); 4040 } 4041 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 4042 mAppTransitionReady = true; 4043 final long origId = Binder.clearCallingIdentity(); 4044 performLayoutAndPlaceSurfacesLocked(); 4045 Binder.restoreCallingIdentity(origId); 4046 } 4047 } 4048 } 4049 4050 public void setAppStartingWindow(IBinder token, String pkg, 4051 int theme, CompatibilityInfo compatInfo, 4052 CharSequence nonLocalizedLabel, int labelRes, int icon, 4053 int windowFlags, IBinder transferFrom, boolean createIfNeeded) { 4054 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4055 "setAppStartingWindow()")) { 4056 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4057 } 4058 4059 synchronized(mWindowMap) { 4060 if (DEBUG_STARTING_WINDOW) Slog.v( 4061 TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg 4062 + " transferFrom=" + transferFrom); 4063 4064 AppWindowToken wtoken = findAppWindowToken(token); 4065 if (wtoken == null) { 4066 Slog.w(TAG, "Attempted to set icon of non-existing app token: " + token); 4067 return; 4068 } 4069 4070 // If the display is frozen, we won't do anything until the 4071 // actual window is displayed so there is no reason to put in 4072 // the starting window. 4073 if (!okToDisplay()) { 4074 return; 4075 } 4076 4077 if (wtoken.startingData != null) { 4078 return; 4079 } 4080 4081 if (transferFrom != null) { 4082 AppWindowToken ttoken = findAppWindowToken(transferFrom); 4083 if (ttoken != null) { 4084 WindowState startingWindow = ttoken.startingWindow; 4085 if (startingWindow != null) { 4086 if (mStartingIconInTransition) { 4087 // In this case, the starting icon has already 4088 // been displayed, so start letting windows get 4089 // shown immediately without any more transitions. 4090 mSkipAppTransitionAnimation = true; 4091 } 4092 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, 4093 "Moving existing starting from " + ttoken 4094 + " to " + wtoken); 4095 final long origId = Binder.clearCallingIdentity(); 4096 4097 // Transfer the starting window over to the new 4098 // token. 4099 wtoken.startingData = ttoken.startingData; 4100 wtoken.startingView = ttoken.startingView; 4101 wtoken.startingDisplayed = ttoken.startingDisplayed; 4102 wtoken.startingWindow = startingWindow; 4103 wtoken.reportedVisible = ttoken.reportedVisible; 4104 ttoken.startingData = null; 4105 ttoken.startingView = null; 4106 ttoken.startingWindow = null; 4107 ttoken.startingMoved = true; 4108 startingWindow.mToken = wtoken; 4109 startingWindow.mRootToken = wtoken; 4110 startingWindow.mAppToken = wtoken; 4111 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) { 4112 Slog.v(TAG, "Removing starting window: " + startingWindow); 4113 } 4114 startingWindow.getWindowList().remove(startingWindow); 4115 mWindowsChanged = true; 4116 if (DEBUG_ADD_REMOVE) Slog.v(TAG, 4117 "Removing starting " + startingWindow + " from " + ttoken); 4118 ttoken.windows.remove(startingWindow); 4119 ttoken.allAppWindows.remove(startingWindow); 4120 addWindowToListInOrderLocked(startingWindow, true); 4121 4122 // Propagate other interesting state between the 4123 // tokens. If the old token is displayed, we should 4124 // immediately force the new one to be displayed. If 4125 // it is animating, we need to move that animation to 4126 // the new one. 4127 if (ttoken.allDrawn) { 4128 wtoken.allDrawn = true; 4129 } 4130 if (ttoken.firstWindowDrawn) { 4131 wtoken.firstWindowDrawn = true; 4132 } 4133 if (!ttoken.hidden) { 4134 wtoken.hidden = false; 4135 wtoken.hiddenRequested = false; 4136 wtoken.willBeHidden = false; 4137 } 4138 if (wtoken.clientHidden != ttoken.clientHidden) { 4139 wtoken.clientHidden = ttoken.clientHidden; 4140 wtoken.sendAppVisibilityToClients(); 4141 } 4142 final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator; 4143 final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator; 4144 if (tAppAnimator.animation != null) { 4145 wAppAnimator.animation = tAppAnimator.animation; 4146 wAppAnimator.animating = tAppAnimator.animating; 4147 wAppAnimator.animLayerAdjustment = tAppAnimator.animLayerAdjustment; 4148 tAppAnimator.animation = null; 4149 tAppAnimator.animLayerAdjustment = 0; 4150 wAppAnimator.updateLayers(); 4151 tAppAnimator.updateLayers(); 4152 } 4153 4154 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 4155 true /*updateInputWindows*/); 4156 mLayoutNeeded = true; 4157 performLayoutAndPlaceSurfacesLocked(); 4158 Binder.restoreCallingIdentity(origId); 4159 return; 4160 } else if (ttoken.startingData != null) { 4161 // The previous app was getting ready to show a 4162 // starting window, but hasn't yet done so. Steal it! 4163 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, 4164 "Moving pending starting from " + ttoken 4165 + " to " + wtoken); 4166 wtoken.startingData = ttoken.startingData; 4167 ttoken.startingData = null; 4168 ttoken.startingMoved = true; 4169 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken); 4170 // Note: we really want to do sendMessageAtFrontOfQueue() because we 4171 // want to process the message ASAP, before any other queued 4172 // messages. 4173 mH.sendMessageAtFrontOfQueue(m); 4174 return; 4175 } 4176 final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator; 4177 final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator; 4178 if (tAppAnimator.thumbnail != null) { 4179 // The old token is animating with a thumbnail, transfer 4180 // that to the new token. 4181 if (wAppAnimator.thumbnail != null) { 4182 wAppAnimator.thumbnail.destroy(); 4183 } 4184 wAppAnimator.thumbnail = tAppAnimator.thumbnail; 4185 wAppAnimator.thumbnailX = tAppAnimator.thumbnailX; 4186 wAppAnimator.thumbnailY = tAppAnimator.thumbnailY; 4187 wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer; 4188 wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation; 4189 tAppAnimator.thumbnail = null; 4190 } 4191 } 4192 } 4193 4194 // There is no existing starting window, and the caller doesn't 4195 // want us to create one, so that's it! 4196 if (!createIfNeeded) { 4197 return; 4198 } 4199 4200 // If this is a translucent window, then don't 4201 // show a starting window -- the current effect (a full-screen 4202 // opaque starting window that fades away to the real contents 4203 // when it is ready) does not work for this. 4204 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Checking theme of starting window: 0x" 4205 + Integer.toHexString(theme)); 4206 if (theme != 0) { 4207 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, 4208 com.android.internal.R.styleable.Window); 4209 if (ent == null) { 4210 // Whoops! App doesn't exist. Um. Okay. We'll just 4211 // pretend like we didn't see that. 4212 return; 4213 } 4214 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Translucent=" 4215 + ent.array.getBoolean( 4216 com.android.internal.R.styleable.Window_windowIsTranslucent, false) 4217 + " Floating=" 4218 + ent.array.getBoolean( 4219 com.android.internal.R.styleable.Window_windowIsFloating, false) 4220 + " ShowWallpaper=" 4221 + ent.array.getBoolean( 4222 com.android.internal.R.styleable.Window_windowShowWallpaper, false)); 4223 if (ent.array.getBoolean( 4224 com.android.internal.R.styleable.Window_windowIsTranslucent, false)) { 4225 return; 4226 } 4227 if (ent.array.getBoolean( 4228 com.android.internal.R.styleable.Window_windowIsFloating, false)) { 4229 return; 4230 } 4231 if (ent.array.getBoolean( 4232 com.android.internal.R.styleable.Window_windowShowWallpaper, false)) { 4233 if (mWallpaperTarget == null) { 4234 // If this theme is requesting a wallpaper, and the wallpaper 4235 // is not curently visible, then this effectively serves as 4236 // an opaque window and our starting window transition animation 4237 // can still work. We just need to make sure the starting window 4238 // is also showing the wallpaper. 4239 windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 4240 } else { 4241 return; 4242 } 4243 } 4244 } 4245 4246 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Creating StartingData"); 4247 mStartingIconInTransition = true; 4248 wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel, 4249 labelRes, icon, windowFlags); 4250 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken); 4251 // Note: we really want to do sendMessageAtFrontOfQueue() because we 4252 // want to process the message ASAP, before any other queued 4253 // messages. 4254 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING"); 4255 mH.sendMessageAtFrontOfQueue(m); 4256 } 4257 } 4258 4259 public void setAppWillBeHidden(IBinder token) { 4260 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4261 "setAppWillBeHidden()")) { 4262 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4263 } 4264 4265 AppWindowToken wtoken; 4266 4267 synchronized(mWindowMap) { 4268 wtoken = findAppWindowToken(token); 4269 if (wtoken == null) { 4270 Slog.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token); 4271 return; 4272 } 4273 wtoken.willBeHidden = true; 4274 } 4275 } 4276 4277 boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp, 4278 boolean visible, int transit, boolean performLayout) { 4279 boolean delayed = false; 4280 4281 if (wtoken.clientHidden == visible) { 4282 wtoken.clientHidden = !visible; 4283 wtoken.sendAppVisibilityToClients(); 4284 } 4285 4286 wtoken.willBeHidden = false; 4287 if (wtoken.hidden == visible) { 4288 boolean changed = false; 4289 if (DEBUG_APP_TRANSITIONS) Slog.v( 4290 TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden 4291 + " performLayout=" + performLayout); 4292 4293 boolean runningAppAnimation = false; 4294 4295 if (transit != WindowManagerPolicy.TRANSIT_UNSET) { 4296 if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) { 4297 wtoken.mAppAnimator.animation = null; 4298 } 4299 if (applyAnimationLocked(wtoken, lp, transit, visible)) { 4300 delayed = runningAppAnimation = true; 4301 } 4302 changed = true; 4303 } 4304 4305 final int N = wtoken.allAppWindows.size(); 4306 for (int i=0; i<N; i++) { 4307 WindowState win = wtoken.allAppWindows.get(i); 4308 if (win == wtoken.startingWindow) { 4309 continue; 4310 } 4311 4312 //Slog.i(TAG, "Window " + win + ": vis=" + win.isVisible()); 4313 //win.dump(" "); 4314 if (visible) { 4315 if (!win.isVisibleNow()) { 4316 if (!runningAppAnimation) { 4317 win.mWinAnimator.applyAnimationLocked( 4318 WindowManagerPolicy.TRANSIT_ENTER, true); 4319 } 4320 changed = true; 4321 } 4322 } else if (win.isVisibleNow()) { 4323 if (!runningAppAnimation) { 4324 win.mWinAnimator.applyAnimationLocked( 4325 WindowManagerPolicy.TRANSIT_EXIT, false); 4326 } 4327 changed = true; 4328 } 4329 } 4330 4331 wtoken.hidden = wtoken.hiddenRequested = !visible; 4332 if (!visible) { 4333 unsetAppFreezingScreenLocked(wtoken, true, true); 4334 } else { 4335 // If we are being set visible, and the starting window is 4336 // not yet displayed, then make sure it doesn't get displayed. 4337 WindowState swin = wtoken.startingWindow; 4338 if (swin != null && !swin.isDrawnLw()) { 4339 swin.mPolicyVisibility = false; 4340 swin.mPolicyVisibilityAfterAnim = false; 4341 } 4342 } 4343 4344 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "setTokenVisibilityLocked: " + wtoken 4345 + ": hidden=" + wtoken.hidden + " hiddenRequested=" 4346 + wtoken.hiddenRequested); 4347 4348 if (changed) { 4349 mLayoutNeeded = true; 4350 mInputMonitor.setUpdateInputWindowsNeededLw(); 4351 if (performLayout) { 4352 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 4353 false /*updateInputWindows*/); 4354 performLayoutAndPlaceSurfacesLocked(); 4355 } 4356 mInputMonitor.updateInputWindowsLw(false /*force*/); 4357 } 4358 } 4359 4360 if (wtoken.mAppAnimator.animation != null) { 4361 delayed = true; 4362 } 4363 4364 for (int i = wtoken.allAppWindows.size() - 1; i >= 0 && !delayed; i--) { 4365 if (wtoken.allAppWindows.get(i).mWinAnimator.isWindowAnimating()) { 4366 delayed = true; 4367 } 4368 } 4369 4370 return delayed; 4371 } 4372 4373 public void setAppVisibility(IBinder token, boolean visible) { 4374 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4375 "setAppVisibility()")) { 4376 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4377 } 4378 4379 AppWindowToken wtoken; 4380 4381 synchronized(mWindowMap) { 4382 wtoken = findAppWindowToken(token); 4383 if (wtoken == null) { 4384 Slog.w(TAG, "Attempted to set visibility of non-existing app token: " + token); 4385 return; 4386 } 4387 4388 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) { 4389 RuntimeException e = null; 4390 if (!HIDE_STACK_CRAWLS) { 4391 e = new RuntimeException(); 4392 e.fillInStackTrace(); 4393 } 4394 Slog.v(TAG, "setAppVisibility(" + token + ", visible=" + visible 4395 + "): mNextAppTransition=" + mNextAppTransition 4396 + " hidden=" + wtoken.hidden 4397 + " hiddenRequested=" + wtoken.hiddenRequested, e); 4398 } 4399 4400 // If we are preparing an app transition, then delay changing 4401 // the visibility of this token until we execute that transition. 4402 if (okToDisplay() && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 4403 // Already in requested state, don't do anything more. 4404 if (wtoken.hiddenRequested != visible) { 4405 return; 4406 } 4407 wtoken.hiddenRequested = !visible; 4408 4409 if (DEBUG_APP_TRANSITIONS) Slog.v( 4410 TAG, "Setting dummy animation on: " + wtoken); 4411 if (!wtoken.startingDisplayed) { 4412 wtoken.mAppAnimator.setDummyAnimation(); 4413 } 4414 mOpeningApps.remove(wtoken); 4415 mClosingApps.remove(wtoken); 4416 wtoken.waitingToShow = wtoken.waitingToHide = false; 4417 wtoken.inPendingTransaction = true; 4418 if (visible) { 4419 mOpeningApps.add(wtoken); 4420 wtoken.startingMoved = false; 4421 4422 // If the token is currently hidden (should be the 4423 // common case), then we need to set up to wait for 4424 // its windows to be ready. 4425 if (wtoken.hidden) { 4426 wtoken.allDrawn = false; 4427 wtoken.waitingToShow = true; 4428 4429 if (wtoken.clientHidden) { 4430 // In the case where we are making an app visible 4431 // but holding off for a transition, we still need 4432 // to tell the client to make its windows visible so 4433 // they get drawn. Otherwise, we will wait on 4434 // performing the transition until all windows have 4435 // been drawn, they never will be, and we are sad. 4436 wtoken.clientHidden = false; 4437 wtoken.sendAppVisibilityToClients(); 4438 } 4439 } 4440 } else { 4441 mClosingApps.add(wtoken); 4442 4443 // If the token is currently visible (should be the 4444 // common case), then set up to wait for it to be hidden. 4445 if (!wtoken.hidden) { 4446 wtoken.waitingToHide = true; 4447 } 4448 } 4449 return; 4450 } 4451 4452 final long origId = Binder.clearCallingIdentity(); 4453 setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET, 4454 true); 4455 wtoken.updateReportedVisibilityLocked(); 4456 Binder.restoreCallingIdentity(origId); 4457 } 4458 } 4459 4460 void unsetAppFreezingScreenLocked(AppWindowToken wtoken, 4461 boolean unfreezeSurfaceNow, boolean force) { 4462 if (wtoken.mAppAnimator.freezingScreen) { 4463 if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + wtoken 4464 + " force=" + force); 4465 final int N = wtoken.allAppWindows.size(); 4466 boolean unfrozeWindows = false; 4467 for (int i=0; i<N; i++) { 4468 WindowState w = wtoken.allAppWindows.get(i); 4469 if (w.mAppFreezing) { 4470 w.mAppFreezing = false; 4471 if (w.mHasSurface && !w.mOrientationChanging) { 4472 if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w); 4473 w.mOrientationChanging = true; 4474 mInnerFields.mOrientationChangeComplete = false; 4475 } 4476 unfrozeWindows = true; 4477 } 4478 } 4479 if (force || unfrozeWindows) { 4480 if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken); 4481 wtoken.mAppAnimator.freezingScreen = false; 4482 mAppsFreezingScreen--; 4483 } 4484 if (unfreezeSurfaceNow) { 4485 if (unfrozeWindows) { 4486 mLayoutNeeded = true; 4487 performLayoutAndPlaceSurfacesLocked(); 4488 } 4489 stopFreezingDisplayLocked(); 4490 } 4491 } 4492 } 4493 4494 public void startAppFreezingScreenLocked(AppWindowToken wtoken, 4495 int configChanges) { 4496 if (DEBUG_ORIENTATION) { 4497 RuntimeException e = null; 4498 if (!HIDE_STACK_CRAWLS) { 4499 e = new RuntimeException(); 4500 e.fillInStackTrace(); 4501 } 4502 Slog.i(TAG, "Set freezing of " + wtoken.appToken 4503 + ": hidden=" + wtoken.hidden + " freezing=" 4504 + wtoken.mAppAnimator.freezingScreen, e); 4505 } 4506 if (!wtoken.hiddenRequested) { 4507 if (!wtoken.mAppAnimator.freezingScreen) { 4508 wtoken.mAppAnimator.freezingScreen = true; 4509 mAppsFreezingScreen++; 4510 if (mAppsFreezingScreen == 1) { 4511 startFreezingDisplayLocked(false); 4512 mH.removeMessages(H.APP_FREEZE_TIMEOUT); 4513 mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT), 4514 5000); 4515 } 4516 } 4517 final int N = wtoken.allAppWindows.size(); 4518 for (int i=0; i<N; i++) { 4519 WindowState w = wtoken.allAppWindows.get(i); 4520 w.mAppFreezing = true; 4521 } 4522 } 4523 } 4524 4525 public void startAppFreezingScreen(IBinder token, int configChanges) { 4526 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4527 "setAppFreezingScreen()")) { 4528 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4529 } 4530 4531 synchronized(mWindowMap) { 4532 if (configChanges == 0 && okToDisplay()) { 4533 if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping set freeze of " + token); 4534 return; 4535 } 4536 4537 AppWindowToken wtoken = findAppWindowToken(token); 4538 if (wtoken == null || wtoken.appToken == null) { 4539 Slog.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken); 4540 return; 4541 } 4542 final long origId = Binder.clearCallingIdentity(); 4543 startAppFreezingScreenLocked(wtoken, configChanges); 4544 Binder.restoreCallingIdentity(origId); 4545 } 4546 } 4547 4548 public void stopAppFreezingScreen(IBinder token, boolean force) { 4549 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4550 "setAppFreezingScreen()")) { 4551 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4552 } 4553 4554 synchronized(mWindowMap) { 4555 AppWindowToken wtoken = findAppWindowToken(token); 4556 if (wtoken == null || wtoken.appToken == null) { 4557 return; 4558 } 4559 final long origId = Binder.clearCallingIdentity(); 4560 if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + token 4561 + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen); 4562 unsetAppFreezingScreenLocked(wtoken, true, force); 4563 Binder.restoreCallingIdentity(origId); 4564 } 4565 } 4566 4567 public void removeAppToken(IBinder token) { 4568 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4569 "removeAppToken()")) { 4570 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4571 } 4572 4573 AppWindowToken wtoken = null; 4574 AppWindowToken startingToken = null; 4575 boolean delayed = false; 4576 4577 final long origId = Binder.clearCallingIdentity(); 4578 synchronized(mWindowMap) { 4579 WindowToken basewtoken = mTokenMap.remove(token); 4580 if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) { 4581 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken); 4582 delayed = setTokenVisibilityLocked(wtoken, null, false, 4583 WindowManagerPolicy.TRANSIT_UNSET, true); 4584 wtoken.inPendingTransaction = false; 4585 mOpeningApps.remove(wtoken); 4586 wtoken.waitingToShow = false; 4587 if (mClosingApps.contains(wtoken)) { 4588 delayed = true; 4589 } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 4590 mClosingApps.add(wtoken); 4591 wtoken.waitingToHide = true; 4592 delayed = true; 4593 } 4594 if (DEBUG_APP_TRANSITIONS) Slog.v( 4595 TAG, "Removing app " + wtoken + " delayed=" + delayed 4596 + " animation=" + wtoken.mAppAnimator.animation 4597 + " animating=" + wtoken.mAppAnimator.animating); 4598 if (delayed) { 4599 // set the token aside because it has an active animation to be finished 4600 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, 4601 "removeAppToken make exiting: " + wtoken); 4602 mExitingAppTokens.add(wtoken); 4603 } else { 4604 // Make sure there is no animation running on this token, 4605 // so any windows associated with it will be removed as 4606 // soon as their animations are complete 4607 wtoken.mAppAnimator.clearAnimation(); 4608 wtoken.mAppAnimator.animating = false; 4609 } 4610 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, 4611 "removeAppToken: " + wtoken); 4612 mAppTokens.remove(wtoken); 4613 mAnimatingAppTokens.remove(wtoken); 4614 wtoken.removed = true; 4615 if (wtoken.startingData != null) { 4616 startingToken = wtoken; 4617 } 4618 unsetAppFreezingScreenLocked(wtoken, true, true); 4619 if (mFocusedApp == wtoken) { 4620 if (DEBUG_FOCUS) Slog.v(TAG, "Removing focused app token:" + wtoken); 4621 mFocusedApp = null; 4622 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); 4623 mInputMonitor.setFocusedAppLw(null); 4624 } 4625 } else { 4626 Slog.w(TAG, "Attempted to remove non-existing app token: " + token); 4627 } 4628 4629 if (!delayed && wtoken != null) { 4630 wtoken.updateReportedVisibilityLocked(); 4631 } 4632 } 4633 Binder.restoreCallingIdentity(origId); 4634 4635 if (startingToken != null) { 4636 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Schedule remove starting " 4637 + startingToken + ": app token removed"); 4638 Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken); 4639 mH.sendMessage(m); 4640 } 4641 } 4642 4643 private boolean tmpRemoveAppWindowsLocked(WindowToken token) { 4644 final int NW = token.windows.size(); 4645 if (NW > 0) { 4646 mWindowsChanged = true; 4647 } 4648 for (int i=0; i<NW; i++) { 4649 WindowState win = token.windows.get(i); 4650 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win); 4651 win.getWindowList().remove(win); 4652 int j = win.mChildWindows.size(); 4653 while (j > 0) { 4654 j--; 4655 WindowState cwin = win.mChildWindows.get(j); 4656 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, 4657 "Tmp removing child window " + cwin); 4658 cwin.getWindowList().remove(cwin); 4659 } 4660 } 4661 return NW > 0; 4662 } 4663 4664 void dumpAppTokensLocked() { 4665 for (int i=mAppTokens.size()-1; i>=0; i--) { 4666 Slog.v(TAG, " #" + i + ": " + mAppTokens.get(i).token); 4667 } 4668 } 4669 4670 void dumpAnimatingAppTokensLocked() { 4671 for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) { 4672 Slog.v(TAG, " #" + i + ": " + mAnimatingAppTokens.get(i).token); 4673 } 4674 } 4675 4676 void dumpWindowsLocked() { 4677 int i = 0; 4678 final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR); 4679 while (iterator.hasNext()) { 4680 final WindowState w = iterator.next(); 4681 Slog.v(TAG, " #" + i++ + ": " + w); 4682 } 4683 } 4684 4685 private int findWindowOffsetLocked(WindowList windows, int tokenPos) { 4686 final int NW = windows.size(); 4687 4688 if (tokenPos >= mAnimatingAppTokens.size()) { 4689 int i = NW; 4690 while (i > 0) { 4691 i--; 4692 WindowState win = windows.get(i); 4693 if (win.getAppToken() != null) { 4694 return i+1; 4695 } 4696 } 4697 } 4698 4699 while (tokenPos > 0) { 4700 // Find the first app token below the new position that has 4701 // a window displayed. 4702 final AppWindowToken wtoken = mAppTokens.get(tokenPos-1); 4703 if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ " 4704 + tokenPos + " -- " + wtoken.token); 4705 if (wtoken.sendingToBottom) { 4706 if (DEBUG_REORDER) Slog.v(TAG, 4707 "Skipping token -- currently sending to bottom"); 4708 tokenPos--; 4709 continue; 4710 } 4711 int i = wtoken.windows.size(); 4712 while (i > 0) { 4713 i--; 4714 WindowState win = wtoken.windows.get(i); 4715 int j = win.mChildWindows.size(); 4716 while (j > 0) { 4717 j--; 4718 WindowState cwin = win.mChildWindows.get(j); 4719 if (cwin.mSubLayer >= 0) { 4720 for (int pos=NW-1; pos>=0; pos--) { 4721 if (windows.get(pos) == cwin) { 4722 if (DEBUG_REORDER) Slog.v(TAG, 4723 "Found child win @" + (pos+1)); 4724 return pos+1; 4725 } 4726 } 4727 } 4728 } 4729 for (int pos=NW-1; pos>=0; pos--) { 4730 if (windows.get(pos) == win) { 4731 if (DEBUG_REORDER) Slog.v(TAG, "Found win @" + (pos+1)); 4732 return pos+1; 4733 } 4734 } 4735 } 4736 tokenPos--; 4737 } 4738 4739 return 0; 4740 } 4741 4742 private final int reAddWindowLocked(int index, WindowState win) { 4743 final WindowList windows = win.getWindowList(); 4744 final int NCW = win.mChildWindows.size(); 4745 boolean added = false; 4746 for (int j=0; j<NCW; j++) { 4747 WindowState cwin = win.mChildWindows.get(j); 4748 if (!added && cwin.mSubLayer >= 0) { 4749 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding child window at " 4750 + index + ": " + cwin); 4751 win.mRebuilding = false; 4752 windows.add(index, win); 4753 index++; 4754 added = true; 4755 } 4756 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at " 4757 + index + ": " + cwin); 4758 cwin.mRebuilding = false; 4759 windows.add(index, cwin); 4760 index++; 4761 } 4762 if (!added) { 4763 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at " 4764 + index + ": " + win); 4765 win.mRebuilding = false; 4766 windows.add(index, win); 4767 index++; 4768 } 4769 mWindowsChanged = true; 4770 return index; 4771 } 4772 4773 private final int reAddAppWindowsLocked(final DisplayContent displayContent, int index, 4774 WindowToken token) { 4775 final int NW = token.windows.size(); 4776 for (int i=0; i<NW; i++) { 4777 final WindowState win = token.windows.get(i); 4778 if (win.mDisplayContent == displayContent) { 4779 index = reAddWindowLocked(index, token.windows.get(i)); 4780 } 4781 } 4782 return index; 4783 } 4784 4785 public void moveAppToken(int index, IBinder token) { 4786 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4787 "moveAppToken()")) { 4788 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4789 } 4790 4791 synchronized(mWindowMap) { 4792 if (DEBUG_REORDER) Slog.v(TAG, "Initial app tokens:"); 4793 if (DEBUG_REORDER) dumpAppTokensLocked(); 4794 final AppWindowToken wtoken = findAppWindowToken(token); 4795 final int oldIndex = mAppTokens.indexOf(wtoken); 4796 if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG, 4797 "Start moving token " + wtoken + " initially at " 4798 + oldIndex); 4799 if (oldIndex > index && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET 4800 && !mAppTransitionRunning) { 4801 // animation towards back has not started, copy old list for duration of animation. 4802 mAnimatingAppTokens.clear(); 4803 mAnimatingAppTokens.addAll(mAppTokens); 4804 } 4805 if (wtoken == null || !mAppTokens.remove(wtoken)) { 4806 Slog.w(TAG, "Attempting to reorder token that doesn't exist: " 4807 + token + " (" + wtoken + ")"); 4808 return; 4809 } 4810 mAppTokens.add(index, wtoken); 4811 if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":"); 4812 else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index); 4813 if (DEBUG_REORDER) dumpAppTokensLocked(); 4814 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET && !mAppTransitionRunning) { 4815 // Not animating, bring animating app list in line with mAppTokens. 4816 mAnimatingAppTokens.clear(); 4817 mAnimatingAppTokens.addAll(mAppTokens); 4818 4819 // Bring window ordering, window focus and input window in line with new app token 4820 final long origId = Binder.clearCallingIdentity(); 4821 if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":"); 4822 if (DEBUG_REORDER) dumpWindowsLocked(); 4823 if (tmpRemoveAppWindowsLocked(wtoken)) { 4824 if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:"); 4825 if (DEBUG_REORDER) dumpWindowsLocked(); 4826 DisplayContentsIterator iterator = new DisplayContentsIterator(); 4827 while(iterator.hasNext()) { 4828 final DisplayContent displayContent = iterator.next(); 4829 final WindowList windows = displayContent.getWindowList(); 4830 final int pos = findWindowOffsetLocked(windows, index); 4831 reAddAppWindowsLocked(displayContent, pos, wtoken); 4832 } 4833 if (DEBUG_REORDER) Slog.v(TAG, "Final window list:"); 4834 if (DEBUG_REORDER) dumpWindowsLocked(); 4835 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 4836 false /*updateInputWindows*/); 4837 mLayoutNeeded = true; 4838 mInputMonitor.setUpdateInputWindowsNeededLw(); 4839 performLayoutAndPlaceSurfacesLocked(); 4840 mInputMonitor.updateInputWindowsLw(false /*force*/); 4841 } 4842 Binder.restoreCallingIdentity(origId); 4843 } 4844 } 4845 } 4846 4847 private void removeAppTokensLocked(List<IBinder> tokens) { 4848 // XXX This should be done more efficiently! 4849 // (take advantage of the fact that both lists should be 4850 // ordered in the same way.) 4851 int N = tokens.size(); 4852 for (int i=0; i<N; i++) { 4853 IBinder token = tokens.get(i); 4854 final AppWindowToken wtoken = findAppWindowToken(token); 4855 if (DEBUG_REORDER || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, 4856 "Temporarily removing " + wtoken + " from " + mAppTokens.indexOf(wtoken)); 4857 if (!mAppTokens.remove(wtoken)) { 4858 Slog.w(TAG, "Attempting to reorder token that doesn't exist: " 4859 + token + " (" + wtoken + ")"); 4860 i--; 4861 N--; 4862 } 4863 } 4864 } 4865 4866 private void moveAppWindowsLocked(AppWindowToken wtoken, int tokenPos, 4867 boolean updateFocusAndLayout) { 4868 // First remove all of the windows from the list. 4869 tmpRemoveAppWindowsLocked(wtoken); 4870 4871 // And now add them back at the correct place. 4872 DisplayContentsIterator iterator = new DisplayContentsIterator(); 4873 while (iterator.hasNext()) { 4874 final DisplayContent displayContent = iterator.next(); 4875 final WindowList windows = displayContent.getWindowList(); 4876 final int pos = findWindowOffsetLocked(windows, tokenPos); 4877 reAddAppWindowsLocked(displayContent, pos, wtoken); 4878 4879 if (updateFocusAndLayout && !updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 4880 false /*updateInputWindows*/)) { 4881 assignLayersLocked(windows); 4882 } 4883 } 4884 4885 if (updateFocusAndLayout) { 4886 mInputMonitor.setUpdateInputWindowsNeededLw(); 4887 4888 // Note that the above updateFocusedWindowLocked conditional used to sit here. 4889 4890 mLayoutNeeded = true; 4891 if (!mInLayout) { 4892 performLayoutAndPlaceSurfacesLocked(); 4893 } 4894 mInputMonitor.updateInputWindowsLw(false /*force*/); 4895 } 4896 } 4897 4898 private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) { 4899 // First remove all of the windows from the list. 4900 final int N = tokens.size(); 4901 int i; 4902 for (i=0; i<N; i++) { 4903 WindowToken token = mTokenMap.get(tokens.get(i)); 4904 if (token != null) { 4905 tmpRemoveAppWindowsLocked(token); 4906 } 4907 } 4908 4909 // And now add them back at the correct place. 4910 DisplayContentsIterator iterator = new DisplayContentsIterator(); 4911 while (iterator.hasNext()) { 4912 final DisplayContent displayContent = iterator.next(); 4913 final WindowList windows = displayContent.getWindowList(); 4914 // Where to start adding? 4915 int pos = findWindowOffsetLocked(windows, tokenPos); 4916 for (i=0; i<N; i++) { 4917 WindowToken token = mTokenMap.get(tokens.get(i)); 4918 if (token != null) { 4919 pos = reAddAppWindowsLocked(displayContent, pos, token); 4920 } 4921 } 4922 if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 4923 false /*updateInputWindows*/)) { 4924 assignLayersLocked(windows); 4925 } 4926 } 4927 4928 mInputMonitor.setUpdateInputWindowsNeededLw(); 4929 4930 // Note that the above updateFocusedWindowLocked used to sit here. 4931 4932 mLayoutNeeded = true; 4933 performLayoutAndPlaceSurfacesLocked(); 4934 mInputMonitor.updateInputWindowsLw(false /*force*/); 4935 4936 //dump(); 4937 } 4938 4939 public void moveAppTokensToTop(List<IBinder> tokens) { 4940 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4941 "moveAppTokensToTop()")) { 4942 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4943 } 4944 4945 final long origId = Binder.clearCallingIdentity(); 4946 synchronized(mWindowMap) { 4947 removeAppTokensLocked(tokens); 4948 final int N = tokens.size(); 4949 for (int i=0; i<N; i++) { 4950 AppWindowToken wt = findAppWindowToken(tokens.get(i)); 4951 if (wt != null) { 4952 if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG, 4953 "Adding next to top: " + wt); 4954 mAppTokens.add(wt); 4955 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 4956 wt.sendingToBottom = false; 4957 } 4958 } 4959 } 4960 4961 if (!mAppTransitionRunning) { 4962 mAnimatingAppTokens.clear(); 4963 mAnimatingAppTokens.addAll(mAppTokens); 4964 moveAppWindowsLocked(tokens, mAppTokens.size()); 4965 } 4966 } 4967 Binder.restoreCallingIdentity(origId); 4968 } 4969 4970 @Override 4971 public void moveAppTokensToBottom(List<IBinder> tokens) { 4972 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4973 "moveAppTokensToBottom()")) { 4974 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4975 } 4976 4977 final long origId = Binder.clearCallingIdentity(); 4978 synchronized(mWindowMap) { 4979 final int N = tokens.size(); 4980 if (N > 0 && !mAppTransitionRunning) { 4981 // animating towards back, hang onto old list for duration of animation. 4982 mAnimatingAppTokens.clear(); 4983 mAnimatingAppTokens.addAll(mAppTokens); 4984 } 4985 removeAppTokensLocked(tokens); 4986 int pos = 0; 4987 for (int i=0; i<N; i++) { 4988 AppWindowToken wt = findAppWindowToken(tokens.get(i)); 4989 if (wt != null) { 4990 if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, 4991 "Adding next to bottom: " + wt + " at " + pos); 4992 mAppTokens.add(pos, wt); 4993 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 4994 wt.sendingToBottom = true; 4995 } 4996 pos++; 4997 } 4998 } 4999 5000 if (!mAppTransitionRunning) { 5001 mAnimatingAppTokens.clear(); 5002 mAnimatingAppTokens.addAll(mAppTokens); 5003 moveAppWindowsLocked(tokens, 0); 5004 } 5005 } 5006 Binder.restoreCallingIdentity(origId); 5007 } 5008 5009 // ------------------------------------------------------------- 5010 // Misc IWindowSession methods 5011 // ------------------------------------------------------------- 5012 5013 private boolean shouldAllowDisableKeyguard() 5014 { 5015 // We fail safe and prevent disabling keyguard in the unlikely event this gets 5016 // called before DevicePolicyManagerService has started. 5017 if (mAllowDisableKeyguard == ALLOW_DISABLE_UNKNOWN) { 5018 DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService( 5019 Context.DEVICE_POLICY_SERVICE); 5020 if (dpm != null) { 5021 mAllowDisableKeyguard = dpm.getPasswordQuality(null) 5022 == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ? 5023 ALLOW_DISABLE_YES : ALLOW_DISABLE_NO; 5024 } 5025 } 5026 return mAllowDisableKeyguard == ALLOW_DISABLE_YES; 5027 } 5028 5029 public void disableKeyguard(IBinder token, String tag) { 5030 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) 5031 != PackageManager.PERMISSION_GRANTED) { 5032 throw new SecurityException("Requires DISABLE_KEYGUARD permission"); 5033 } 5034 5035 synchronized (mKeyguardTokenWatcher) { 5036 mKeyguardTokenWatcher.acquire(token, tag); 5037 } 5038 } 5039 5040 public void reenableKeyguard(IBinder token) { 5041 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) 5042 != PackageManager.PERMISSION_GRANTED) { 5043 throw new SecurityException("Requires DISABLE_KEYGUARD permission"); 5044 } 5045 5046 synchronized (mKeyguardTokenWatcher) { 5047 mKeyguardTokenWatcher.release(token); 5048 5049 if (!mKeyguardTokenWatcher.isAcquired()) { 5050 // If we are the last one to reenable the keyguard wait until 5051 // we have actually finished reenabling until returning. 5052 // It is possible that reenableKeyguard() can be called before 5053 // the previous disableKeyguard() is handled, in which case 5054 // neither mKeyguardTokenWatcher.acquired() or released() would 5055 // be called. In that case mKeyguardDisabled will be false here 5056 // and we have nothing to wait for. 5057 while (mKeyguardDisabled) { 5058 try { 5059 mKeyguardTokenWatcher.wait(); 5060 } catch (InterruptedException e) { 5061 Thread.currentThread().interrupt(); 5062 } 5063 } 5064 } 5065 } 5066 } 5067 5068 /** 5069 * @see android.app.KeyguardManager#exitKeyguardSecurely 5070 */ 5071 public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) { 5072 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) 5073 != PackageManager.PERMISSION_GRANTED) { 5074 throw new SecurityException("Requires DISABLE_KEYGUARD permission"); 5075 } 5076 mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() { 5077 public void onKeyguardExitResult(boolean success) { 5078 try { 5079 callback.onKeyguardExitResult(success); 5080 } catch (RemoteException e) { 5081 // Client has died, we don't care. 5082 } 5083 } 5084 }); 5085 } 5086 5087 public boolean inKeyguardRestrictedInputMode() { 5088 return mPolicy.inKeyguardRestrictedKeyInputMode(); 5089 } 5090 5091 public boolean isKeyguardLocked() { 5092 return mPolicy.isKeyguardLocked(); 5093 } 5094 5095 public boolean isKeyguardSecure() { 5096 return mPolicy.isKeyguardSecure(); 5097 } 5098 5099 public void dismissKeyguard() { 5100 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) 5101 != PackageManager.PERMISSION_GRANTED) { 5102 throw new SecurityException("Requires DISABLE_KEYGUARD permission"); 5103 } 5104 synchronized(mWindowMap) { 5105 mPolicy.dismissKeyguardLw(); 5106 } 5107 } 5108 5109 public void closeSystemDialogs(String reason) { 5110 synchronized(mWindowMap) { 5111 final AllWindowsIterator iterator = new AllWindowsIterator(); 5112 while (iterator.hasNext()) { 5113 final WindowState w = iterator.next(); 5114 if (w.mHasSurface) { 5115 try { 5116 w.mClient.closeSystemDialogs(reason); 5117 } catch (RemoteException e) { 5118 } 5119 } 5120 } 5121 } 5122 } 5123 5124 static float fixScale(float scale) { 5125 if (scale < 0) scale = 0; 5126 else if (scale > 20) scale = 20; 5127 return Math.abs(scale); 5128 } 5129 5130 public void setAnimationScale(int which, float scale) { 5131 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE, 5132 "setAnimationScale()")) { 5133 throw new SecurityException("Requires SET_ANIMATION_SCALE permission"); 5134 } 5135 5136 if (scale < 0) scale = 0; 5137 else if (scale > 20) scale = 20; 5138 scale = Math.abs(scale); 5139 switch (which) { 5140 case 0: mWindowAnimationScale = fixScale(scale); break; 5141 case 1: mTransitionAnimationScale = fixScale(scale); break; 5142 case 2: mAnimatorDurationScale = fixScale(scale); break; 5143 } 5144 5145 // Persist setting 5146 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget(); 5147 } 5148 5149 public void setAnimationScales(float[] scales) { 5150 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE, 5151 "setAnimationScale()")) { 5152 throw new SecurityException("Requires SET_ANIMATION_SCALE permission"); 5153 } 5154 5155 if (scales != null) { 5156 if (scales.length >= 1) { 5157 mWindowAnimationScale = fixScale(scales[0]); 5158 } 5159 if (scales.length >= 2) { 5160 mTransitionAnimationScale = fixScale(scales[1]); 5161 } 5162 if (scales.length >= 3) { 5163 mAnimatorDurationScale = fixScale(scales[2]); 5164 } 5165 } 5166 5167 // Persist setting 5168 mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget(); 5169 } 5170 5171 public float getAnimationScale(int which) { 5172 switch (which) { 5173 case 0: return mWindowAnimationScale; 5174 case 1: return mTransitionAnimationScale; 5175 case 2: return mAnimatorDurationScale; 5176 } 5177 return 0; 5178 } 5179 5180 public float[] getAnimationScales() { 5181 return new float[] { mWindowAnimationScale, mTransitionAnimationScale, 5182 mAnimatorDurationScale }; 5183 } 5184 5185 // Called by window manager policy. Not exposed externally. 5186 @Override 5187 public int getLidState() { 5188 int sw = mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, 5189 InputManagerService.SW_LID); 5190 if (sw > 0) { 5191 // Switch state: AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL. 5192 return LID_CLOSED; 5193 } else if (sw == 0) { 5194 // Switch state: AKEY_STATE_UP. 5195 return LID_OPEN; 5196 } else { 5197 // Switch state: AKEY_STATE_UNKNOWN. 5198 return LID_ABSENT; 5199 } 5200 } 5201 5202 // Called by window manager policy. Not exposed externally. 5203 @Override 5204 public InputChannel monitorInput(String inputChannelName) { 5205 return mInputManager.monitorInput(inputChannelName); 5206 } 5207 5208 // Called by window manager policy. Not exposed externally. 5209 @Override 5210 public void switchKeyboardLayout(int deviceId, int direction) { 5211 mInputManager.switchKeyboardLayout(deviceId, direction); 5212 } 5213 5214 // Called by window manager policy. Not exposed externally. 5215 @Override 5216 public void shutdown() { 5217 ShutdownThread.shutdown(mContext, true); 5218 } 5219 5220 // Called by window manager policy. Not exposed externally. 5221 @Override 5222 public void rebootSafeMode() { 5223 ShutdownThread.rebootSafeMode(mContext, true); 5224 } 5225 5226 public void setInputFilter(IInputFilter filter) { 5227 if (!checkCallingPermission(android.Manifest.permission.FILTER_EVENTS, "setInputFilter()")) { 5228 throw new SecurityException("Requires FILTER_EVENTS permission"); 5229 } 5230 mInputManager.setInputFilter(filter); 5231 } 5232 5233 public void enableScreenAfterBoot() { 5234 synchronized(mWindowMap) { 5235 if (DEBUG_BOOT) { 5236 RuntimeException here = new RuntimeException("here"); 5237 here.fillInStackTrace(); 5238 Slog.i(TAG, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled 5239 + " mForceDisplayEnabled=" + mForceDisplayEnabled 5240 + " mShowingBootMessages=" + mShowingBootMessages 5241 + " mSystemBooted=" + mSystemBooted, here); 5242 } 5243 if (mSystemBooted) { 5244 return; 5245 } 5246 mSystemBooted = true; 5247 hideBootMessagesLocked(); 5248 // If the screen still doesn't come up after 30 seconds, give 5249 // up and turn it on. 5250 Message msg = mH.obtainMessage(H.BOOT_TIMEOUT); 5251 mH.sendMessageDelayed(msg, 30*1000); 5252 } 5253 5254 mPolicy.systemBooted(); 5255 5256 performEnableScreen(); 5257 } 5258 5259 void enableScreenIfNeededLocked() { 5260 if (DEBUG_BOOT) { 5261 RuntimeException here = new RuntimeException("here"); 5262 here.fillInStackTrace(); 5263 Slog.i(TAG, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled 5264 + " mForceDisplayEnabled=" + mForceDisplayEnabled 5265 + " mShowingBootMessages=" + mShowingBootMessages 5266 + " mSystemBooted=" + mSystemBooted, here); 5267 } 5268 if (mDisplayEnabled) { 5269 return; 5270 } 5271 if (!mSystemBooted && !mShowingBootMessages) { 5272 return; 5273 } 5274 mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN)); 5275 } 5276 5277 public void performBootTimeout() { 5278 synchronized(mWindowMap) { 5279 if (mDisplayEnabled || mHeadless) { 5280 return; 5281 } 5282 Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled"); 5283 mForceDisplayEnabled = true; 5284 } 5285 performEnableScreen(); 5286 } 5287 5288 public void performEnableScreen() { 5289 synchronized(mWindowMap) { 5290 if (DEBUG_BOOT) { 5291 RuntimeException here = new RuntimeException("here"); 5292 here.fillInStackTrace(); 5293 Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled 5294 + " mForceDisplayEnabled=" + mForceDisplayEnabled 5295 + " mShowingBootMessages=" + mShowingBootMessages 5296 + " mSystemBooted=" + mSystemBooted 5297 + " mOnlyCore=" + mOnlyCore, here); 5298 } 5299 if (mDisplayEnabled) { 5300 return; 5301 } 5302 if (!mSystemBooted && !mShowingBootMessages) { 5303 return; 5304 } 5305 5306 if (!mForceDisplayEnabled) { 5307 // Don't enable the screen until all existing windows 5308 // have been drawn. 5309 boolean haveBootMsg = false; 5310 boolean haveApp = false; 5311 // if the wallpaper service is disabled on the device, we're never going to have 5312 // wallpaper, don't bother waiting for it 5313 boolean haveWallpaper = false; 5314 boolean wallpaperEnabled = mContext.getResources().getBoolean( 5315 com.android.internal.R.bool.config_enableWallpaperService) 5316 && !mOnlyCore; 5317 boolean haveKeyguard = true; 5318 // TODO(multidisplay): Expand to all displays? 5319 final WindowList windows = getDefaultWindowList(); 5320 final int N = windows.size(); 5321 for (int i=0; i<N; i++) { 5322 WindowState w = windows.get(i); 5323 if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) { 5324 // Only if there is a keyguard attached to the window manager 5325 // will we consider ourselves as having a keyguard. If it 5326 // isn't attached, we don't know if it wants to be shown or 5327 // hidden. If it is attached, we will say we have a keyguard 5328 // if the window doesn't want to be visible, because in that 5329 // case it explicitly doesn't want to be shown so we should 5330 // not delay turning the screen on for it. 5331 boolean vis = w.mViewVisibility == View.VISIBLE 5332 && w.mPolicyVisibility; 5333 haveKeyguard = !vis; 5334 } 5335 if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { 5336 return; 5337 } 5338 if (w.isDrawnLw()) { 5339 if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) { 5340 haveBootMsg = true; 5341 } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) { 5342 haveApp = true; 5343 } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) { 5344 haveWallpaper = true; 5345 } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) { 5346 haveKeyguard = true; 5347 } 5348 } 5349 } 5350 5351 if (DEBUG_SCREEN_ON || DEBUG_BOOT) { 5352 Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages 5353 + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp 5354 + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled 5355 + " haveKeyguard=" + haveKeyguard); 5356 } 5357 5358 // If we are turning on the screen to show the boot message, 5359 // don't do it until the boot message is actually displayed. 5360 if (!mSystemBooted && !haveBootMsg) { 5361 return; 5362 } 5363 5364 // If we are turning on the screen after the boot is completed 5365 // normally, don't do so until we have the application and 5366 // wallpaper. 5367 if (mSystemBooted && ((!haveApp && !haveKeyguard) || 5368 (wallpaperEnabled && !haveWallpaper))) { 5369 return; 5370 } 5371 } 5372 5373 mDisplayEnabled = true; 5374 if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!"); 5375 if (false) { 5376 StringWriter sw = new StringWriter(); 5377 PrintWriter pw = new PrintWriter(sw); 5378 this.dump(null, pw, null); 5379 Slog.i(TAG, sw.toString()); 5380 } 5381 try { 5382 IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger"); 5383 if (surfaceFlinger != null) { 5384 //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!"); 5385 Parcel data = Parcel.obtain(); 5386 data.writeInterfaceToken("android.ui.ISurfaceComposer"); 5387 surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED 5388 data, null, 0); 5389 data.recycle(); 5390 } 5391 } catch (RemoteException ex) { 5392 Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!"); 5393 } 5394 5395 // Enable input dispatch. 5396 mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled); 5397 } 5398 5399 mPolicy.enableScreenAfterBoot(); 5400 5401 // Make sure the last requested orientation has been applied. 5402 updateRotationUnchecked(false, false); 5403 } 5404 5405 public void showBootMessage(final CharSequence msg, final boolean always) { 5406 boolean first = false; 5407 synchronized(mWindowMap) { 5408 if (DEBUG_BOOT) { 5409 RuntimeException here = new RuntimeException("here"); 5410 here.fillInStackTrace(); 5411 Slog.i(TAG, "showBootMessage: msg=" + msg + " always=" + always 5412 + " mAllowBootMessages=" + mAllowBootMessages 5413 + " mShowingBootMessages=" + mShowingBootMessages 5414 + " mSystemBooted=" + mSystemBooted, here); 5415 } 5416 if (!mAllowBootMessages) { 5417 return; 5418 } 5419 if (!mShowingBootMessages) { 5420 if (!always) { 5421 return; 5422 } 5423 first = true; 5424 } 5425 if (mSystemBooted) { 5426 return; 5427 } 5428 mShowingBootMessages = true; 5429 mPolicy.showBootMessage(msg, always); 5430 } 5431 if (first) { 5432 performEnableScreen(); 5433 } 5434 } 5435 5436 public void hideBootMessagesLocked() { 5437 if (DEBUG_BOOT) { 5438 RuntimeException here = new RuntimeException("here"); 5439 here.fillInStackTrace(); 5440 Slog.i(TAG, "hideBootMessagesLocked: mDisplayEnabled=" + mDisplayEnabled 5441 + " mForceDisplayEnabled=" + mForceDisplayEnabled 5442 + " mShowingBootMessages=" + mShowingBootMessages 5443 + " mSystemBooted=" + mSystemBooted, here); 5444 } 5445 if (mShowingBootMessages) { 5446 mShowingBootMessages = false; 5447 mPolicy.hideBootMessages(); 5448 } 5449 } 5450 5451 public void setInTouchMode(boolean mode) { 5452 synchronized(mWindowMap) { 5453 mInTouchMode = mode; 5454 } 5455 } 5456 5457 // TODO: more accounting of which pid(s) turned it on, keep count, 5458 // only allow disables from pids which have count on, etc. 5459 @Override 5460 public void showStrictModeViolation(boolean on) { 5461 if (mHeadless) return; 5462 mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, 0)); 5463 } 5464 5465 private void showStrictModeViolation(int arg) { 5466 final boolean on = arg != 0; 5467 int pid = Binder.getCallingPid(); 5468 synchronized(mWindowMap) { 5469 // Ignoring requests to enable the red border from clients 5470 // which aren't on screen. (e.g. Broadcast Receivers in 5471 // the background..) 5472 if (on) { 5473 boolean isVisible = false; 5474 final AllWindowsIterator iterator = new AllWindowsIterator(); 5475 while (iterator.hasNext()) { 5476 final WindowState ws = iterator.next(); 5477 if (ws.mSession.mPid == pid && ws.isVisibleLw()) { 5478 isVisible = true; 5479 break; 5480 } 5481 } 5482 if (!isVisible) { 5483 return; 5484 } 5485 } 5486 5487 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, 5488 ">>> OPEN TRANSACTION showStrictModeViolation"); 5489 Surface.openTransaction(); 5490 try { 5491 if (mStrictModeFlash == null) { 5492 mStrictModeFlash = new StrictModeFlash(mDisplay, mFxSession); 5493 } 5494 mStrictModeFlash.setVisibility(on); 5495 } finally { 5496 Surface.closeTransaction(); 5497 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, 5498 "<<< CLOSE TRANSACTION showStrictModeViolation"); 5499 } 5500 } 5501 } 5502 5503 public void setStrictModeVisualIndicatorPreference(String value) { 5504 SystemProperties.set(StrictMode.VISUAL_PROPERTY, value); 5505 } 5506 5507 /** 5508 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. 5509 * In portrait mode, it grabs the upper region of the screen based on the vertical dimension 5510 * of the target image. 5511 * 5512 * @param displayId the Display to take a screenshot of. 5513 * @param width the width of the target bitmap 5514 * @param height the height of the target bitmap 5515 */ 5516 public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height) { 5517 if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER, 5518 "screenshotApplications()")) { 5519 throw new SecurityException("Requires READ_FRAME_BUFFER permission"); 5520 } 5521 5522 Bitmap rawss; 5523 5524 int maxLayer = 0; 5525 final Rect frame = new Rect(); 5526 5527 float scale; 5528 int dw, dh; 5529 int rot; 5530 5531 synchronized(mWindowMap) { 5532 long ident = Binder.clearCallingIdentity(); 5533 5534 final DisplayContent displayContent = getDisplayContent(displayId); 5535 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 5536 dw = displayInfo.logicalWidth; 5537 dh = displayInfo.logicalHeight; 5538 5539 int aboveAppLayer = mPolicy.windowTypeToLayerLw( 5540 WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER 5541 + TYPE_LAYER_OFFSET; 5542 aboveAppLayer += TYPE_LAYER_MULTIPLIER; 5543 5544 boolean isImeTarget = mInputMethodTarget != null 5545 && mInputMethodTarget.mAppToken != null 5546 && mInputMethodTarget.mAppToken.appToken != null 5547 && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken; 5548 5549 // Figure out the part of the screen that is actually the app. 5550 boolean including = false; 5551 final WindowList windows = displayContent.getWindowList(); 5552 for (int i = windows.size() - 1; i >= 0; i--) { 5553 WindowState ws = windows.get(i); 5554 if (!ws.mHasSurface) { 5555 continue; 5556 } 5557 if (ws.mLayer >= aboveAppLayer) { 5558 continue; 5559 } 5560 // When we will skip windows: when we are not including 5561 // ones behind a window we didn't skip, and we are actually 5562 // taking a screenshot of a specific app. 5563 if (!including && appToken != null) { 5564 // Also, we can possibly skip this window if it is not 5565 // an IME target or the application for the screenshot 5566 // is not the current IME target. 5567 if (!ws.mIsImWindow || !isImeTarget) { 5568 // And finally, this window is of no interest if it 5569 // is not associated with the screenshot app. 5570 if (ws.mAppToken == null || ws.mAppToken.token != appToken) { 5571 continue; 5572 } 5573 } 5574 } 5575 5576 // We keep on including windows until we go past a full-screen 5577 // window. 5578 including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh); 5579 5580 if (maxLayer < ws.mWinAnimator.mSurfaceLayer) { 5581 maxLayer = ws.mWinAnimator.mSurfaceLayer; 5582 } 5583 5584 // Don't include wallpaper in bounds calculation 5585 if (!ws.mIsWallpaper) { 5586 final Rect wf = ws.mFrame; 5587 final Rect cr = ws.mContentInsets; 5588 int left = wf.left + cr.left; 5589 int top = wf.top + cr.top; 5590 int right = wf.right - cr.right; 5591 int bottom = wf.bottom - cr.bottom; 5592 frame.union(left, top, right, bottom); 5593 } 5594 } 5595 Binder.restoreCallingIdentity(ident); 5596 5597 // Constrain frame to the screen size. 5598 frame.intersect(0, 0, dw, dh); 5599 5600 if (frame.isEmpty() || maxLayer == 0) { 5601 return null; 5602 } 5603 5604 // The screenshot API does not apply the current screen rotation. 5605 rot = mDisplay.getRotation(); 5606 int fw = frame.width(); 5607 int fh = frame.height(); 5608 5609 // Constrain thumbnail to smaller of screen width or height. Assumes aspect 5610 // of thumbnail is the same as the screen (in landscape) or square. 5611 float targetWidthScale = width / (float) fw; 5612 float targetHeightScale = height / (float) fh; 5613 if (dw <= dh) { 5614 scale = targetWidthScale; 5615 // If aspect of thumbnail is the same as the screen (in landscape), 5616 // select the slightly larger value so we fill the entire bitmap 5617 if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) { 5618 scale = targetHeightScale; 5619 } 5620 } else { 5621 scale = targetHeightScale; 5622 // If aspect of thumbnail is the same as the screen (in landscape), 5623 // select the slightly larger value so we fill the entire bitmap 5624 if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) { 5625 scale = targetWidthScale; 5626 } 5627 } 5628 5629 // The screen shot will contain the entire screen. 5630 dw = (int)(dw*scale); 5631 dh = (int)(dh*scale); 5632 if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { 5633 int tmp = dw; 5634 dw = dh; 5635 dh = tmp; 5636 rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90; 5637 } 5638 if (DEBUG_SCREENSHOT) { 5639 Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from 0 to " + maxLayer); 5640 for (int i = 0; i < windows.size(); i++) { 5641 WindowState win = windows.get(i); 5642 Slog.i(TAG, win + ": " + win.mLayer 5643 + " animLayer=" + win.mWinAnimator.mAnimLayer 5644 + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer); 5645 } 5646 } 5647 rawss = Surface.screenshot(dw, dh, 0, maxLayer); 5648 } 5649 5650 if (rawss == null) { 5651 Slog.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh 5652 + ") to layer " + maxLayer); 5653 return null; 5654 } 5655 5656 Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig()); 5657 Matrix matrix = new Matrix(); 5658 ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix); 5659 matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale)); 5660 Canvas canvas = new Canvas(bm); 5661 canvas.drawBitmap(rawss, matrix, null); 5662 canvas.setBitmap(null); 5663 5664 rawss.recycle(); 5665 return bm; 5666 } 5667 5668 /** 5669 * Freeze rotation changes. (Enable "rotation lock".) 5670 * Persists across reboots. 5671 * @param rotation The desired rotation to freeze to, or -1 to use the 5672 * current rotation. 5673 */ 5674 public void freezeRotation(int rotation) { 5675 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, 5676 "freezeRotation()")) { 5677 throw new SecurityException("Requires SET_ORIENTATION permission"); 5678 } 5679 if (rotation < -1 || rotation > Surface.ROTATION_270) { 5680 throw new IllegalArgumentException("Rotation argument must be -1 or a valid " 5681 + "rotation constant."); 5682 } 5683 5684 if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation); 5685 5686 mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED, 5687 rotation == -1 ? mRotation : rotation); 5688 updateRotationUnchecked(false, false); 5689 } 5690 5691 /** 5692 * Thaw rotation changes. (Disable "rotation lock".) 5693 * Persists across reboots. 5694 */ 5695 public void thawRotation() { 5696 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, 5697 "thawRotation()")) { 5698 throw new SecurityException("Requires SET_ORIENTATION permission"); 5699 } 5700 5701 if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation); 5702 5703 mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used 5704 updateRotationUnchecked(false, false); 5705 } 5706 5707 /** 5708 * Recalculate the current rotation. 5709 * 5710 * Called by the window manager policy whenever the state of the system changes 5711 * such that the current rotation might need to be updated, such as when the 5712 * device is docked or rotated into a new posture. 5713 */ 5714 public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) { 5715 updateRotationUnchecked(alwaysSendConfiguration, forceRelayout); 5716 } 5717 5718 /** 5719 * Temporarily pauses rotation changes until resumed. 5720 * 5721 * This can be used to prevent rotation changes from occurring while the user is 5722 * performing certain operations, such as drag and drop. 5723 * 5724 * This call nests and must be matched by an equal number of calls to {@link #resumeRotation}. 5725 */ 5726 void pauseRotationLocked() { 5727 mDeferredRotationPauseCount += 1; 5728 } 5729 5730 /** 5731 * Resumes normal rotation changes after being paused. 5732 */ 5733 void resumeRotationLocked() { 5734 if (mDeferredRotationPauseCount > 0) { 5735 mDeferredRotationPauseCount -= 1; 5736 if (mDeferredRotationPauseCount == 0) { 5737 boolean changed = updateRotationUncheckedLocked(false); 5738 if (changed) { 5739 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 5740 } 5741 } 5742 } 5743 } 5744 5745 public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) { 5746 if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked(" 5747 + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")"); 5748 5749 long origId = Binder.clearCallingIdentity(); 5750 boolean changed; 5751 synchronized(mWindowMap) { 5752 changed = updateRotationUncheckedLocked(false); 5753 if (!changed || forceRelayout) { 5754 mLayoutNeeded = true; 5755 performLayoutAndPlaceSurfacesLocked(); 5756 } 5757 } 5758 5759 if (changed || alwaysSendConfiguration) { 5760 sendNewConfiguration(); 5761 } 5762 5763 Binder.restoreCallingIdentity(origId); 5764 } 5765 5766 // TODO(multidisplay): Rotate any display? 5767 /** 5768 * Updates the current rotation. 5769 * 5770 * Returns true if the rotation has been changed. In this case YOU 5771 * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN. 5772 */ 5773 public boolean updateRotationUncheckedLocked(boolean inTransaction) { 5774 if (mDeferredRotationPauseCount > 0) { 5775 // Rotation updates have been paused temporarily. Defer the update until 5776 // updates have been resumed. 5777 if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused."); 5778 return false; 5779 } 5780 5781 if (mAnimator.mScreenRotationAnimation != null && 5782 mAnimator.mScreenRotationAnimation.isAnimating()) { 5783 // Rotation updates cannot be performed while the previous rotation change 5784 // animation is still in progress. Skip this update. We will try updating 5785 // again after the animation is finished and the display is unfrozen. 5786 if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress."); 5787 return false; 5788 } 5789 5790 if (!mDisplayEnabled) { 5791 // No point choosing a rotation if the display is not enabled. 5792 if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled."); 5793 return false; 5794 } 5795 5796 // TODO: Implement forced rotation changes. 5797 // Set mAltOrientation to indicate that the application is receiving 5798 // an orientation that has different metrics than it expected. 5799 // eg. Portrait instead of Landscape. 5800 5801 int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation); 5802 boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw( 5803 mForcedAppOrientation, rotation); 5804 5805 if (DEBUG_ORIENTATION) { 5806 Slog.v(TAG, "Application requested orientation " 5807 + mForcedAppOrientation + ", got rotation " + rotation 5808 + " which has " + (altOrientation ? "incompatible" : "compatible") 5809 + " metrics"); 5810 } 5811 5812 if (mRotation == rotation && mAltOrientation == altOrientation) { 5813 // No change. 5814 return false; 5815 } 5816 5817 if (DEBUG_ORIENTATION) { 5818 Slog.v(TAG, 5819 "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "") 5820 + " from " + mRotation + (mAltOrientation ? " (alt)" : "") 5821 + ", forceApp=" + mForcedAppOrientation); 5822 } 5823 5824 mRotation = rotation; 5825 mAltOrientation = altOrientation; 5826 mPolicy.setRotationLw(mRotation); 5827 5828 mWindowsFreezingScreen = true; 5829 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); 5830 mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), 2000); 5831 mWaitingForConfig = true; 5832 mLayoutNeeded = true; 5833 startFreezingDisplayLocked(inTransaction); 5834 mInputManager.setDisplayOrientation(0, rotation, Surface.ROTATION_0); 5835 5836 // We need to update our screen size information to match the new 5837 // rotation. Note that this is redundant with the later call to 5838 // sendNewConfiguration() that must be called after this function 5839 // returns... however we need to do the screen size part of that 5840 // before then so we have the correct size to use when initializiation 5841 // the rotation animation for the new rotation. 5842 computeScreenConfigurationLocked(null); 5843 5844 if (!inTransaction) { 5845 if (SHOW_TRANSACTIONS) Slog.i(TAG, 5846 ">>> OPEN TRANSACTION setRotationUnchecked"); 5847 Surface.openTransaction(); 5848 } 5849 final DisplayContent displayContent = getDefaultDisplayContent(); 5850 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 5851 try { 5852 // NOTE: We disable the rotation in the emulator because 5853 // it doesn't support hardware OpenGL emulation yet. 5854 if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null 5855 && mAnimator.mScreenRotationAnimation.hasScreenshot()) { 5856 if (mAnimator.mScreenRotationAnimation.setRotation(rotation, mFxSession, 5857 MAX_ANIMATION_DURATION, mTransitionAnimationScale, 5858 displayInfo.logicalWidth, displayInfo.logicalHeight)) { 5859 updateLayoutToAnimationLocked(); 5860 } 5861 } 5862 Surface.setOrientation(0, rotation); 5863 } finally { 5864 if (!inTransaction) { 5865 Surface.closeTransaction(); 5866 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, 5867 "<<< CLOSE TRANSACTION setRotationUnchecked"); 5868 } 5869 } 5870 5871 rebuildBlackFrameLocked(); 5872 5873 final WindowList windows = displayContent.getWindowList(); 5874 for (int i = windows.size() - 1; i >= 0; i--) { 5875 WindowState w = windows.get(i); 5876 if (w.mHasSurface) { 5877 if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w); 5878 w.mOrientationChanging = true; 5879 mInnerFields.mOrientationChangeComplete = false; 5880 } 5881 } 5882 for (int i=mRotationWatchers.size()-1; i>=0; i--) { 5883 try { 5884 mRotationWatchers.get(i).onRotationChanged(rotation); 5885 } catch (RemoteException e) { 5886 } 5887 } 5888 return true; 5889 } 5890 5891 public int getRotation() { 5892 return mRotation; 5893 } 5894 5895 public int watchRotation(IRotationWatcher watcher) { 5896 final IBinder watcherBinder = watcher.asBinder(); 5897 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() { 5898 public void binderDied() { 5899 synchronized (mWindowMap) { 5900 for (int i=0; i<mRotationWatchers.size(); i++) { 5901 if (watcherBinder == mRotationWatchers.get(i).asBinder()) { 5902 IRotationWatcher removed = mRotationWatchers.remove(i); 5903 if (removed != null) { 5904 removed.asBinder().unlinkToDeath(this, 0); 5905 } 5906 i--; 5907 } 5908 } 5909 } 5910 } 5911 }; 5912 5913 synchronized (mWindowMap) { 5914 try { 5915 watcher.asBinder().linkToDeath(dr, 0); 5916 mRotationWatchers.add(watcher); 5917 } catch (RemoteException e) { 5918 // Client died, no cleanup needed. 5919 } 5920 5921 return mRotation; 5922 } 5923 } 5924 5925 /** 5926 * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact 5927 * theme attribute) on devices that feature a physical options menu key attempt to position 5928 * their menu panel window along the edge of the screen nearest the physical menu key. 5929 * This lowers the travel distance between invoking the menu panel and selecting 5930 * a menu option. 5931 * 5932 * This method helps control where that menu is placed. Its current implementation makes 5933 * assumptions about the menu key and its relationship to the screen based on whether 5934 * the device's natural orientation is portrait (width < height) or landscape. 5935 * 5936 * The menu key is assumed to be located along the bottom edge of natural-portrait 5937 * devices and along the right edge of natural-landscape devices. If these assumptions 5938 * do not hold for the target device, this method should be changed to reflect that. 5939 * 5940 * @return A {@link Gravity} value for placing the options menu window 5941 */ 5942 public int getPreferredOptionsPanelGravity() { 5943 synchronized (mWindowMap) { 5944 final int rotation = getRotation(); 5945 5946 // TODO(multidisplay): Assume that such devices physical keys are on the main screen. 5947 final DisplayContent displayContent = getDefaultDisplayContent(); 5948 if (displayContent.mInitialDisplayWidth < displayContent.mInitialDisplayHeight) { 5949 // On devices with a natural orientation of portrait 5950 switch (rotation) { 5951 default: 5952 case Surface.ROTATION_0: 5953 return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 5954 case Surface.ROTATION_90: 5955 return Gravity.RIGHT | Gravity.BOTTOM; 5956 case Surface.ROTATION_180: 5957 return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 5958 case Surface.ROTATION_270: 5959 return Gravity.START | Gravity.BOTTOM; 5960 } 5961 } else { 5962 // On devices with a natural orientation of landscape 5963 switch (rotation) { 5964 default: 5965 case Surface.ROTATION_0: 5966 return Gravity.RIGHT | Gravity.BOTTOM; 5967 case Surface.ROTATION_90: 5968 return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 5969 case Surface.ROTATION_180: 5970 return Gravity.START | Gravity.BOTTOM; 5971 case Surface.ROTATION_270: 5972 return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 5973 } 5974 } 5975 } 5976 } 5977 5978 /** 5979 * Starts the view server on the specified port. 5980 * 5981 * @param port The port to listener to. 5982 * 5983 * @return True if the server was successfully started, false otherwise. 5984 * 5985 * @see com.android.server.wm.ViewServer 5986 * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT 5987 */ 5988 public boolean startViewServer(int port) { 5989 if (isSystemSecure()) { 5990 return false; 5991 } 5992 5993 if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) { 5994 return false; 5995 } 5996 5997 if (port < 1024) { 5998 return false; 5999 } 6000 6001 if (mViewServer != null) { 6002 if (!mViewServer.isRunning()) { 6003 try { 6004 return mViewServer.start(); 6005 } catch (IOException e) { 6006 Slog.w(TAG, "View server did not start"); 6007 } 6008 } 6009 return false; 6010 } 6011 6012 try { 6013 mViewServer = new ViewServer(this, port); 6014 return mViewServer.start(); 6015 } catch (IOException e) { 6016 Slog.w(TAG, "View server did not start"); 6017 } 6018 return false; 6019 } 6020 6021 private boolean isSystemSecure() { 6022 return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) && 6023 "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); 6024 } 6025 6026 /** 6027 * Stops the view server if it exists. 6028 * 6029 * @return True if the server stopped, false if it wasn't started or 6030 * couldn't be stopped. 6031 * 6032 * @see com.android.server.wm.ViewServer 6033 */ 6034 public boolean stopViewServer() { 6035 if (isSystemSecure()) { 6036 return false; 6037 } 6038 6039 if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) { 6040 return false; 6041 } 6042 6043 if (mViewServer != null) { 6044 return mViewServer.stop(); 6045 } 6046 return false; 6047 } 6048 6049 /** 6050 * Indicates whether the view server is running. 6051 * 6052 * @return True if the server is running, false otherwise. 6053 * 6054 * @see com.android.server.wm.ViewServer 6055 */ 6056 public boolean isViewServerRunning() { 6057 if (isSystemSecure()) { 6058 return false; 6059 } 6060 6061 if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) { 6062 return false; 6063 } 6064 6065 return mViewServer != null && mViewServer.isRunning(); 6066 } 6067 6068 /** 6069 * Lists all availble windows in the system. The listing is written in the 6070 * specified Socket's output stream with the following syntax: 6071 * windowHashCodeInHexadecimal windowName 6072 * Each line of the ouput represents a different window. 6073 * 6074 * @param client The remote client to send the listing to. 6075 * @return False if an error occured, true otherwise. 6076 */ 6077 boolean viewServerListWindows(Socket client) { 6078 if (isSystemSecure()) { 6079 return false; 6080 } 6081 6082 boolean result = true; 6083 6084 WindowList windows = new WindowList(); 6085 synchronized (mWindowMap) { 6086 //noinspection unchecked 6087 DisplayContentsIterator iterator = new DisplayContentsIterator(); 6088 while(iterator.hasNext()) { 6089 windows.addAll(iterator.next().getWindowList()); 6090 } 6091 } 6092 6093 BufferedWriter out = null; 6094 6095 // Any uncaught exception will crash the system process 6096 try { 6097 OutputStream clientStream = client.getOutputStream(); 6098 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024); 6099 6100 final int count = windows.size(); 6101 for (int i = 0; i < count; i++) { 6102 final WindowState w = windows.get(i); 6103 out.write(Integer.toHexString(System.identityHashCode(w))); 6104 out.write(' '); 6105 out.append(w.mAttrs.getTitle()); 6106 out.write('\n'); 6107 } 6108 6109 out.write("DONE.\n"); 6110 out.flush(); 6111 } catch (Exception e) { 6112 result = false; 6113 } finally { 6114 if (out != null) { 6115 try { 6116 out.close(); 6117 } catch (IOException e) { 6118 result = false; 6119 } 6120 } 6121 } 6122 6123 return result; 6124 } 6125 6126 // TODO(multidisplay): Extend to multiple displays. 6127 /** 6128 * Returns the focused window in the following format: 6129 * windowHashCodeInHexadecimal windowName 6130 * 6131 * @param client The remote client to send the listing to. 6132 * @return False if an error occurred, true otherwise. 6133 */ 6134 boolean viewServerGetFocusedWindow(Socket client) { 6135 if (isSystemSecure()) { 6136 return false; 6137 } 6138 6139 boolean result = true; 6140 6141 WindowState focusedWindow = getFocusedWindow(); 6142 6143 BufferedWriter out = null; 6144 6145 // Any uncaught exception will crash the system process 6146 try { 6147 OutputStream clientStream = client.getOutputStream(); 6148 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024); 6149 6150 if(focusedWindow != null) { 6151 out.write(Integer.toHexString(System.identityHashCode(focusedWindow))); 6152 out.write(' '); 6153 out.append(focusedWindow.mAttrs.getTitle()); 6154 } 6155 out.write('\n'); 6156 out.flush(); 6157 } catch (Exception e) { 6158 result = false; 6159 } finally { 6160 if (out != null) { 6161 try { 6162 out.close(); 6163 } catch (IOException e) { 6164 result = false; 6165 } 6166 } 6167 } 6168 6169 return result; 6170 } 6171 6172 /** 6173 * Sends a command to a target window. The result of the command, if any, will be 6174 * written in the output stream of the specified socket. 6175 * 6176 * The parameters must follow this syntax: 6177 * windowHashcode extra 6178 * 6179 * Where XX is the length in characeters of the windowTitle. 6180 * 6181 * The first parameter is the target window. The window with the specified hashcode 6182 * will be the target. If no target can be found, nothing happens. The extra parameters 6183 * will be delivered to the target window and as parameters to the command itself. 6184 * 6185 * @param client The remote client to sent the result, if any, to. 6186 * @param command The command to execute. 6187 * @param parameters The command parameters. 6188 * 6189 * @return True if the command was successfully delivered, false otherwise. This does 6190 * not indicate whether the command itself was successful. 6191 */ 6192 boolean viewServerWindowCommand(Socket client, String command, String parameters) { 6193 if (isSystemSecure()) { 6194 return false; 6195 } 6196 6197 boolean success = true; 6198 Parcel data = null; 6199 Parcel reply = null; 6200 6201 BufferedWriter out = null; 6202 6203 // Any uncaught exception will crash the system process 6204 try { 6205 // Find the hashcode of the window 6206 int index = parameters.indexOf(' '); 6207 if (index == -1) { 6208 index = parameters.length(); 6209 } 6210 final String code = parameters.substring(0, index); 6211 int hashCode = (int) Long.parseLong(code, 16); 6212 6213 // Extract the command's parameter after the window description 6214 if (index < parameters.length()) { 6215 parameters = parameters.substring(index + 1); 6216 } else { 6217 parameters = ""; 6218 } 6219 6220 final WindowState window = findWindow(hashCode); 6221 if (window == null) { 6222 return false; 6223 } 6224 6225 data = Parcel.obtain(); 6226 data.writeInterfaceToken("android.view.IWindow"); 6227 data.writeString(command); 6228 data.writeString(parameters); 6229 data.writeInt(1); 6230 ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0); 6231 6232 reply = Parcel.obtain(); 6233 6234 final IBinder binder = window.mClient.asBinder(); 6235 // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER 6236 binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0); 6237 6238 reply.readException(); 6239 6240 if (!client.isOutputShutdown()) { 6241 out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); 6242 out.write("DONE\n"); 6243 out.flush(); 6244 } 6245 6246 } catch (Exception e) { 6247 Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e); 6248 success = false; 6249 } finally { 6250 if (data != null) { 6251 data.recycle(); 6252 } 6253 if (reply != null) { 6254 reply.recycle(); 6255 } 6256 if (out != null) { 6257 try { 6258 out.close(); 6259 } catch (IOException e) { 6260 6261 } 6262 } 6263 } 6264 6265 return success; 6266 } 6267 6268 public void addWindowChangeListener(WindowChangeListener listener) { 6269 synchronized(mWindowMap) { 6270 mWindowChangeListeners.add(listener); 6271 } 6272 } 6273 6274 public void removeWindowChangeListener(WindowChangeListener listener) { 6275 synchronized(mWindowMap) { 6276 mWindowChangeListeners.remove(listener); 6277 } 6278 } 6279 6280 private void notifyWindowsChanged() { 6281 WindowChangeListener[] windowChangeListeners; 6282 synchronized(mWindowMap) { 6283 if(mWindowChangeListeners.isEmpty()) { 6284 return; 6285 } 6286 windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()]; 6287 windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners); 6288 } 6289 int N = windowChangeListeners.length; 6290 for(int i = 0; i < N; i++) { 6291 windowChangeListeners[i].windowsChanged(); 6292 } 6293 } 6294 6295 private void notifyFocusChanged() { 6296 WindowChangeListener[] windowChangeListeners; 6297 synchronized(mWindowMap) { 6298 if(mWindowChangeListeners.isEmpty()) { 6299 return; 6300 } 6301 windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()]; 6302 windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners); 6303 } 6304 int N = windowChangeListeners.length; 6305 for(int i = 0; i < N; i++) { 6306 windowChangeListeners[i].focusChanged(); 6307 } 6308 } 6309 6310 private WindowState findWindow(int hashCode) { 6311 if (hashCode == -1) { 6312 // TODO(multidisplay): Extend to multiple displays. 6313 return getFocusedWindow(); 6314 } 6315 6316 synchronized (mWindowMap) { 6317 final AllWindowsIterator iterator = new AllWindowsIterator(); 6318 while (iterator.hasNext()) { 6319 final WindowState w = iterator.next(); 6320 if (System.identityHashCode(w) == hashCode) { 6321 return w; 6322 } 6323 } 6324 } 6325 6326 return null; 6327 } 6328 6329 /* 6330 * Instruct the Activity Manager to fetch the current configuration and broadcast 6331 * that to config-changed listeners if appropriate. 6332 */ 6333 void sendNewConfiguration() { 6334 try { 6335 mActivityManager.updateConfiguration(null); 6336 } catch (RemoteException e) { 6337 } 6338 } 6339 6340 public Configuration computeNewConfiguration() { 6341 synchronized (mWindowMap) { 6342 Configuration config = computeNewConfigurationLocked(); 6343 if (config == null && mWaitingForConfig) { 6344 // Nothing changed but we are waiting for something... stop that! 6345 mWaitingForConfig = false; 6346 performLayoutAndPlaceSurfacesLocked(); 6347 } 6348 return config; 6349 } 6350 } 6351 6352 Configuration computeNewConfigurationLocked() { 6353 Configuration config = new Configuration(); 6354 config.fontScale = 0; 6355 if (!computeScreenConfigurationLocked(config)) { 6356 return null; 6357 } 6358 return config; 6359 } 6360 6361 private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) { 6362 final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation); 6363 if (width < displayInfo.smallestNominalAppWidth) { 6364 displayInfo.smallestNominalAppWidth = width; 6365 } 6366 if (width > displayInfo.largestNominalAppWidth) { 6367 displayInfo.largestNominalAppWidth = width; 6368 } 6369 final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation); 6370 if (height < displayInfo.smallestNominalAppHeight) { 6371 displayInfo.smallestNominalAppHeight = height; 6372 } 6373 if (height > displayInfo.largestNominalAppHeight) { 6374 displayInfo.largestNominalAppHeight = height; 6375 } 6376 } 6377 6378 private int reduceConfigLayout(int curLayout, int rotation, float density, 6379 int dw, int dh) { 6380 // Get the app screen size at this rotation. 6381 int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation); 6382 int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation); 6383 6384 // Compute the screen layout size class for this rotation. 6385 int screenLayoutSize; 6386 boolean screenLayoutLong; 6387 boolean screenLayoutCompatNeeded; 6388 int longSize = w; 6389 int shortSize = h; 6390 if (longSize < shortSize) { 6391 int tmp = longSize; 6392 longSize = shortSize; 6393 shortSize = tmp; 6394 } 6395 longSize = (int)(longSize/density); 6396 shortSize = (int)(shortSize/density); 6397 6398 // These semi-magic numbers define our compatibility modes for 6399 // applications with different screens. These are guarantees to 6400 // app developers about the space they can expect for a particular 6401 // configuration. DO NOT CHANGE! 6402 if (longSize < 470) { 6403 // This is shorter than an HVGA normal density screen (which 6404 // is 480 pixels on its long side). 6405 screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_SMALL; 6406 screenLayoutLong = false; 6407 screenLayoutCompatNeeded = false; 6408 } else { 6409 // What size is this screen screen? 6410 if (longSize >= 960 && shortSize >= 720) { 6411 // 1.5xVGA or larger screens at medium density are the point 6412 // at which we consider it to be an extra large screen. 6413 screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_XLARGE; 6414 } else if (longSize >= 640 && shortSize >= 480) { 6415 // VGA or larger screens at medium density are the point 6416 // at which we consider it to be a large screen. 6417 screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_LARGE; 6418 } else { 6419 screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_NORMAL; 6420 } 6421 6422 // If this screen is wider than normal HVGA, or taller 6423 // than FWVGA, then for old apps we want to run in size 6424 // compatibility mode. 6425 if (shortSize > 321 || longSize > 570) { 6426 screenLayoutCompatNeeded = true; 6427 } else { 6428 screenLayoutCompatNeeded = false; 6429 } 6430 6431 // Is this a long screen? 6432 if (((longSize*3)/5) >= (shortSize-1)) { 6433 // Anything wider than WVGA (5:3) is considering to be long. 6434 screenLayoutLong = true; 6435 } else { 6436 screenLayoutLong = false; 6437 } 6438 } 6439 6440 // Now reduce the last screenLayout to not be better than what we 6441 // have found. 6442 if (!screenLayoutLong) { 6443 curLayout = (curLayout&~Configuration.SCREENLAYOUT_LONG_MASK) 6444 | Configuration.SCREENLAYOUT_LONG_NO; 6445 } 6446 if (screenLayoutCompatNeeded) { 6447 curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED; 6448 } 6449 int curSize = curLayout&Configuration.SCREENLAYOUT_SIZE_MASK; 6450 if (screenLayoutSize < curSize) { 6451 curLayout = (curLayout&~Configuration.SCREENLAYOUT_SIZE_MASK) 6452 | screenLayoutSize; 6453 } 6454 return curLayout; 6455 } 6456 6457 private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated, 6458 int dw, int dh, float density, Configuration outConfig) { 6459 // We need to determine the smallest width that will occur under normal 6460 // operation. To this, start with the base screen size and compute the 6461 // width under the different possible rotations. We need to un-rotate 6462 // the current screen dimensions before doing this. 6463 int unrotDw, unrotDh; 6464 if (rotated) { 6465 unrotDw = dh; 6466 unrotDh = dw; 6467 } else { 6468 unrotDw = dw; 6469 unrotDh = dh; 6470 } 6471 displayInfo.smallestNominalAppWidth = 1<<30; 6472 displayInfo.smallestNominalAppHeight = 1<<30; 6473 displayInfo.largestNominalAppWidth = 0; 6474 displayInfo.largestNominalAppHeight = 0; 6475 adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh); 6476 adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw); 6477 adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh); 6478 adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw); 6479 int sl = Configuration.SCREENLAYOUT_SIZE_XLARGE 6480 | Configuration.SCREENLAYOUT_LONG_YES; 6481 sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh); 6482 sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw); 6483 sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh); 6484 sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw); 6485 outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density); 6486 outConfig.screenLayout = sl; 6487 } 6488 6489 private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm, 6490 int dw, int dh) { 6491 dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation); 6492 dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation); 6493 float scale = CompatibilityInfo.computeCompatibleScaling(dm, null); 6494 int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f); 6495 if (curSize == 0 || size < curSize) { 6496 curSize = size; 6497 } 6498 return curSize; 6499 } 6500 6501 private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) { 6502 mTmpDisplayMetrics.setTo(dm); 6503 dm = mTmpDisplayMetrics; 6504 int unrotDw, unrotDh; 6505 if (rotated) { 6506 unrotDw = dh; 6507 unrotDh = dw; 6508 } else { 6509 unrotDw = dw; 6510 unrotDh = dh; 6511 } 6512 int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, dm, unrotDw, unrotDh); 6513 sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, dm, unrotDh, unrotDw); 6514 sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, dm, unrotDw, unrotDh); 6515 sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, dm, unrotDh, unrotDw); 6516 return sw; 6517 } 6518 6519 boolean computeScreenConfigurationLocked(Configuration config) { 6520 if (mDisplay == null) { 6521 return false; 6522 } 6523 6524 // TODO(multidisplay): For now, apply Configuration to main screen only. 6525 final DisplayContent displayContent = getDefaultDisplayContent(); 6526 6527 // Use the effective "visual" dimensions based on current rotation 6528 final boolean rotated = (mRotation == Surface.ROTATION_90 6529 || mRotation == Surface.ROTATION_270); 6530 final int realdw = rotated ? 6531 displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth; 6532 final int realdh = rotated ? 6533 displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight; 6534 int dw = realdw; 6535 int dh = realdh; 6536 6537 if (mAltOrientation) { 6538 if (realdw > realdh) { 6539 // Turn landscape into portrait. 6540 int maxw = (int)(realdh/1.3f); 6541 if (maxw < realdw) { 6542 dw = maxw; 6543 } 6544 } else { 6545 // Turn portrait into landscape. 6546 int maxh = (int)(realdw/1.3f); 6547 if (maxh < realdh) { 6548 dh = maxh; 6549 } 6550 } 6551 } 6552 6553 if (config != null) { 6554 int orientation = Configuration.ORIENTATION_SQUARE; 6555 if (dw < dh) { 6556 orientation = Configuration.ORIENTATION_PORTRAIT; 6557 } else if (dw > dh) { 6558 orientation = Configuration.ORIENTATION_LANDSCAPE; 6559 } 6560 config.orientation = orientation; 6561 } 6562 6563 // Update application display metrics. 6564 final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation); 6565 final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation); 6566 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 6567 synchronized(displayContent.mDisplaySizeLock) { 6568 displayInfo.rotation = mRotation; 6569 displayInfo.logicalWidth = dw; 6570 displayInfo.logicalHeight = dh; 6571 displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity; 6572 displayInfo.appWidth = appWidth; 6573 displayInfo.appHeight = appHeight; 6574 displayInfo.getLogicalMetrics(mRealDisplayMetrics, null); 6575 displayInfo.getAppMetrics(mDisplayMetrics, null); 6576 mDisplayManager.setDisplayInfo(displayContent.getDisplayId(), displayInfo); 6577 6578 mAnimator.setDisplayDimensions(dw, dh, appWidth, appHeight); 6579 } 6580 if (false) { 6581 Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight); 6582 } 6583 6584 final DisplayMetrics dm = mDisplayMetrics; 6585 mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm, 6586 mCompatDisplayMetrics); 6587 6588 if (config != null) { 6589 config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation) 6590 / dm.density); 6591 config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation) 6592 / dm.density); 6593 computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config); 6594 6595 config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale); 6596 config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale); 6597 config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh); 6598 config.densityDpi = displayContent.mBaseDisplayDensity; 6599 6600 // Update the configuration based on available input devices, lid switch, 6601 // and platform configuration. 6602 config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH; 6603 config.keyboard = Configuration.KEYBOARD_NOKEYS; 6604 config.navigation = Configuration.NAVIGATION_NONAV; 6605 6606 int keyboardPresence = 0; 6607 int navigationPresence = 0; 6608 final InputDevice[] devices = mInputManager.getInputDevices(); 6609 final int len = devices.length; 6610 for (int i = 0; i < len; i++) { 6611 InputDevice device = devices[i]; 6612 if (!device.isVirtual()) { 6613 final int sources = device.getSources(); 6614 final int presenceFlag = device.isExternal() ? 6615 WindowManagerPolicy.PRESENCE_EXTERNAL : 6616 WindowManagerPolicy.PRESENCE_INTERNAL; 6617 6618 if (mIsTouchDevice) { 6619 if ((sources & InputDevice.SOURCE_TOUCHSCREEN) == 6620 InputDevice.SOURCE_TOUCHSCREEN) { 6621 config.touchscreen = Configuration.TOUCHSCREEN_FINGER; 6622 } 6623 } else { 6624 config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH; 6625 } 6626 6627 if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) { 6628 config.navigation = Configuration.NAVIGATION_TRACKBALL; 6629 navigationPresence |= presenceFlag; 6630 } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD 6631 && config.navigation == Configuration.NAVIGATION_NONAV) { 6632 config.navigation = Configuration.NAVIGATION_DPAD; 6633 navigationPresence |= presenceFlag; 6634 } 6635 6636 if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) { 6637 config.keyboard = Configuration.KEYBOARD_QWERTY; 6638 keyboardPresence |= presenceFlag; 6639 } 6640 } 6641 } 6642 6643 // Determine whether a hard keyboard is available and enabled. 6644 boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS; 6645 if (hardKeyboardAvailable != mHardKeyboardAvailable) { 6646 mHardKeyboardAvailable = hardKeyboardAvailable; 6647 mHardKeyboardEnabled = hardKeyboardAvailable; 6648 mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); 6649 mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); 6650 } 6651 if (!mHardKeyboardEnabled) { 6652 config.keyboard = Configuration.KEYBOARD_NOKEYS; 6653 } 6654 6655 // Let the policy update hidden states. 6656 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO; 6657 config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO; 6658 config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO; 6659 mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence); 6660 } 6661 6662 return true; 6663 } 6664 6665 public boolean isHardKeyboardAvailable() { 6666 synchronized (mWindowMap) { 6667 return mHardKeyboardAvailable; 6668 } 6669 } 6670 6671 public boolean isHardKeyboardEnabled() { 6672 synchronized (mWindowMap) { 6673 return mHardKeyboardEnabled; 6674 } 6675 } 6676 6677 public void setHardKeyboardEnabled(boolean enabled) { 6678 synchronized (mWindowMap) { 6679 if (mHardKeyboardEnabled != enabled) { 6680 mHardKeyboardEnabled = enabled; 6681 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 6682 } 6683 } 6684 } 6685 6686 public void setOnHardKeyboardStatusChangeListener( 6687 OnHardKeyboardStatusChangeListener listener) { 6688 synchronized (mWindowMap) { 6689 mHardKeyboardStatusChangeListener = listener; 6690 } 6691 } 6692 6693 void notifyHardKeyboardStatusChange() { 6694 final boolean available, enabled; 6695 final OnHardKeyboardStatusChangeListener listener; 6696 synchronized (mWindowMap) { 6697 listener = mHardKeyboardStatusChangeListener; 6698 available = mHardKeyboardAvailable; 6699 enabled = mHardKeyboardEnabled; 6700 } 6701 if (listener != null) { 6702 listener.onHardKeyboardStatusChange(available, enabled); 6703 } 6704 } 6705 6706 // ------------------------------------------------------------- 6707 // Drag and drop 6708 // ------------------------------------------------------------- 6709 6710 IBinder prepareDragSurface(IWindow window, SurfaceSession session, 6711 int flags, int width, int height, Surface outSurface) { 6712 if (DEBUG_DRAG) { 6713 Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height 6714 + " flags=" + Integer.toHexString(flags) + " win=" + window 6715 + " asbinder=" + window.asBinder()); 6716 } 6717 6718 final int callerPid = Binder.getCallingPid(); 6719 final long origId = Binder.clearCallingIdentity(); 6720 IBinder token = null; 6721 6722 try { 6723 synchronized (mWindowMap) { 6724 try { 6725 if (mDragState == null) { 6726 Surface surface = new Surface(session, callerPid, "drag surface", 6727 Display.DEFAULT_DISPLAY, 6728 width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN); 6729 if (SHOW_TRANSACTIONS) Slog.i(TAG, " DRAG " 6730 + surface + ": CREATE"); 6731 outSurface.copyFrom(surface); 6732 final IBinder winBinder = window.asBinder(); 6733 token = new Binder(); 6734 mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder); 6735 token = mDragState.mToken = new Binder(); 6736 6737 // 5 second timeout for this window to actually begin the drag 6738 mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder); 6739 Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder); 6740 mH.sendMessageDelayed(msg, 5000); 6741 } else { 6742 Slog.w(TAG, "Drag already in progress"); 6743 } 6744 } catch (Surface.OutOfResourcesException e) { 6745 Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e); 6746 if (mDragState != null) { 6747 mDragState.reset(); 6748 mDragState = null; 6749 } 6750 } 6751 } 6752 } finally { 6753 Binder.restoreCallingIdentity(origId); 6754 } 6755 6756 return token; 6757 } 6758 6759 // ------------------------------------------------------------- 6760 // Input Events and Focus Management 6761 // ------------------------------------------------------------- 6762 6763 final InputMonitor mInputMonitor = new InputMonitor(this); 6764 private boolean mEventDispatchingEnabled; 6765 6766 public void pauseKeyDispatching(IBinder _token) { 6767 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 6768 "pauseKeyDispatching()")) { 6769 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 6770 } 6771 6772 synchronized (mWindowMap) { 6773 WindowToken token = mTokenMap.get(_token); 6774 if (token != null) { 6775 mInputMonitor.pauseDispatchingLw(token); 6776 } 6777 } 6778 } 6779 6780 public void resumeKeyDispatching(IBinder _token) { 6781 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 6782 "resumeKeyDispatching()")) { 6783 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 6784 } 6785 6786 synchronized (mWindowMap) { 6787 WindowToken token = mTokenMap.get(_token); 6788 if (token != null) { 6789 mInputMonitor.resumeDispatchingLw(token); 6790 } 6791 } 6792 } 6793 6794 public void setEventDispatching(boolean enabled) { 6795 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 6796 "setEventDispatching()")) { 6797 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 6798 } 6799 6800 synchronized (mWindowMap) { 6801 mEventDispatchingEnabled = enabled; 6802 if (mDisplayEnabled) { 6803 mInputMonitor.setEventDispatchingLw(enabled); 6804 } 6805 sendScreenStatusToClientsLocked(); 6806 } 6807 } 6808 6809 public IBinder getFocusedWindowToken() { 6810 if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO, 6811 "getFocusedWindowToken()")) { 6812 throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission."); 6813 } 6814 synchronized (mWindowMap) { 6815 WindowState windowState = getFocusedWindowLocked(); 6816 if (windowState != null) { 6817 return windowState.mClient.asBinder(); 6818 } 6819 return null; 6820 } 6821 } 6822 6823 public boolean getWindowFrame(IBinder token, Rect outBounds) { 6824 if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO, 6825 "getWindowFrame()")) { 6826 throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission."); 6827 } 6828 synchronized (mWindowMap) { 6829 WindowState windowState = mWindowMap.get(token); 6830 if (windowState != null) { 6831 outBounds.set(windowState.getFrameLw()); 6832 return true; 6833 } 6834 } 6835 return false; 6836 } 6837 6838 private WindowState getFocusedWindow() { 6839 synchronized (mWindowMap) { 6840 return getFocusedWindowLocked(); 6841 } 6842 } 6843 6844 private WindowState getFocusedWindowLocked() { 6845 return mCurrentFocus; 6846 } 6847 6848 public boolean detectSafeMode() { 6849 if (!mInputMonitor.waitForInputDevicesReady( 6850 INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) { 6851 Slog.w(TAG, "Devices still not ready after waiting " 6852 + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS 6853 + " milliseconds before attempting to detect safe mode."); 6854 } 6855 6856 int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, 6857 KeyEvent.KEYCODE_MENU); 6858 int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S); 6859 int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD, 6860 KeyEvent.KEYCODE_DPAD_CENTER); 6861 int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL, 6862 InputManagerService.BTN_MOUSE); 6863 int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, 6864 KeyEvent.KEYCODE_VOLUME_DOWN); 6865 mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0 6866 || volumeDownState > 0; 6867 try { 6868 if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) { 6869 mSafeMode = true; 6870 SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, ""); 6871 } 6872 } catch (IllegalArgumentException e) { 6873 } 6874 if (mSafeMode) { 6875 Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState 6876 + " dpad=" + dpadState + " trackball=" + trackballState + ")"); 6877 } else { 6878 Log.i(TAG, "SAFE MODE not enabled"); 6879 } 6880 mPolicy.setSafeMode(mSafeMode); 6881 return mSafeMode; 6882 } 6883 6884 public void displayReady() { 6885 displayReady(Display.DEFAULT_DISPLAY); 6886 6887 synchronized(mWindowMap) { 6888 readForcedDisplaySizeAndDensityLocked(getDefaultDisplayContent()); 6889 6890 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); 6891 mDisplay = wm.getDefaultDisplay(); 6892 mIsTouchDevice = mContext.getPackageManager().hasSystemFeature( 6893 PackageManager.FEATURE_TOUCHSCREEN); 6894 6895 final DisplayInfo displayInfo = getDefaultDisplayInfo(); 6896 mAnimator.setDisplayDimensions(displayInfo.logicalWidth, displayInfo.logicalHeight, 6897 displayInfo.appWidth, displayInfo.appHeight); 6898 6899 DisplayDeviceInfo info = new DisplayDeviceInfo(); 6900 mDisplayManager.getDefaultExternalDisplayDeviceInfo(info); 6901 6902 final DisplayContent displayContent = getDefaultDisplayContent(); 6903 mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY, 6904 displayContent.mInitialDisplayWidth, displayContent.mInitialDisplayHeight, 6905 info.width, info.height); 6906 mInputManager.setDisplayOrientation(Display.DEFAULT_DISPLAY, 6907 mDisplay.getRotation(), Surface.ROTATION_0); 6908 mPolicy.setInitialDisplaySize(mDisplay, displayContent.mInitialDisplayWidth, 6909 displayContent.mInitialDisplayHeight, displayContent.mInitialDisplayDensity); 6910 } 6911 6912 try { 6913 mActivityManager.updateConfiguration(null); 6914 } catch (RemoteException e) { 6915 } 6916 } 6917 6918 public void displayReady(int displayId) { 6919 synchronized(mWindowMap) { 6920 final DisplayContent displayContent = getDisplayContent(displayId); 6921 final DisplayInfo displayInfo; 6922 synchronized(displayContent.mDisplaySizeLock) { 6923 // Bootstrap the default logical display from the display manager. 6924 displayInfo = displayContent.getDisplayInfo(); 6925 mDisplayManager.getDisplayInfo(displayId, displayInfo); 6926 displayContent.mInitialDisplayWidth = displayInfo.logicalWidth; 6927 displayContent.mInitialDisplayHeight = displayInfo.logicalHeight; 6928 displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi; 6929 displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth; 6930 displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight; 6931 displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity; 6932 } 6933 } 6934 } 6935 6936 public void systemReady() { 6937 mPolicy.systemReady(); 6938 } 6939 6940 // TODO(multidisplay): Call isScreenOn for each display. 6941 private void sendScreenStatusToClientsLocked() { 6942 final boolean on = mPowerManager.isScreenOn(); 6943 final AllWindowsIterator iterator = new AllWindowsIterator(); 6944 while (iterator.hasNext()) { 6945 try { 6946 iterator.next().mClient.dispatchScreenState(on); 6947 } catch (RemoteException e) { 6948 // Ignored 6949 } 6950 } 6951 } 6952 6953 // ------------------------------------------------------------- 6954 // Async Handler 6955 // ------------------------------------------------------------- 6956 6957 final class H extends Handler { 6958 public static final int REPORT_FOCUS_CHANGE = 2; 6959 public static final int REPORT_LOSING_FOCUS = 3; 6960 public static final int DO_TRAVERSAL = 4; 6961 public static final int ADD_STARTING = 5; 6962 public static final int REMOVE_STARTING = 6; 6963 public static final int FINISHED_STARTING = 7; 6964 public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8; 6965 public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9; 6966 public static final int WINDOW_FREEZE_TIMEOUT = 11; 6967 public static final int HOLD_SCREEN_CHANGED = 12; 6968 public static final int APP_TRANSITION_TIMEOUT = 13; 6969 public static final int PERSIST_ANIMATION_SCALE = 14; 6970 public static final int FORCE_GC = 15; 6971 public static final int ENABLE_SCREEN = 16; 6972 public static final int APP_FREEZE_TIMEOUT = 17; 6973 public static final int SEND_NEW_CONFIGURATION = 18; 6974 public static final int REPORT_WINDOWS_CHANGE = 19; 6975 public static final int DRAG_START_TIMEOUT = 20; 6976 public static final int DRAG_END_TIMEOUT = 21; 6977 public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22; 6978 public static final int BOOT_TIMEOUT = 23; 6979 public static final int WAITING_FOR_DRAWN_TIMEOUT = 24; 6980 public static final int UPDATE_ANIM_PARAMETERS = 25; 6981 public static final int SHOW_STRICT_MODE_VIOLATION = 26; 6982 public static final int DO_ANIMATION_CALLBACK = 27; 6983 6984 public static final int ANIMATOR_WHAT_OFFSET = 100000; 6985 public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1; 6986 public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2; 6987 6988 private Session mLastReportedHold; 6989 6990 public H() { 6991 } 6992 6993 @Override 6994 public void handleMessage(Message msg) { 6995 if (DEBUG_WINDOW_TRACE) { 6996 Slog.v(TAG, "handleMessage: entry what=" + msg.what); 6997 } 6998 switch (msg.what) { 6999 case REPORT_FOCUS_CHANGE: { 7000 WindowState lastFocus; 7001 WindowState newFocus; 7002 7003 synchronized(mWindowMap) { 7004 lastFocus = mLastFocus; 7005 newFocus = mCurrentFocus; 7006 if (lastFocus == newFocus) { 7007 // Focus is not changing, so nothing to do. 7008 return; 7009 } 7010 mLastFocus = newFocus; 7011 //Slog.i(TAG, "Focus moving from " + lastFocus 7012 // + " to " + newFocus); 7013 if (newFocus != null && lastFocus != null 7014 && !newFocus.isDisplayedLw()) { 7015 //Slog.i(TAG, "Delaying loss of focus..."); 7016 mLosingFocus.add(lastFocus); 7017 lastFocus = null; 7018 } 7019 } 7020 7021 if (lastFocus != newFocus) { 7022 //System.out.println("Changing focus from " + lastFocus 7023 // + " to " + newFocus); 7024 if (newFocus != null) { 7025 try { 7026 //Slog.i(TAG, "Gaining focus: " + newFocus); 7027 newFocus.mClient.windowFocusChanged(true, mInTouchMode); 7028 } catch (RemoteException e) { 7029 // Ignore if process has died. 7030 } 7031 notifyFocusChanged(); 7032 } 7033 7034 if (lastFocus != null) { 7035 try { 7036 //Slog.i(TAG, "Losing focus: " + lastFocus); 7037 lastFocus.mClient.windowFocusChanged(false, mInTouchMode); 7038 } catch (RemoteException e) { 7039 // Ignore if process has died. 7040 } 7041 } 7042 } 7043 } break; 7044 7045 case REPORT_LOSING_FOCUS: { 7046 ArrayList<WindowState> losers; 7047 7048 synchronized(mWindowMap) { 7049 losers = mLosingFocus; 7050 mLosingFocus = new ArrayList<WindowState>(); 7051 } 7052 7053 final int N = losers.size(); 7054 for (int i=0; i<N; i++) { 7055 try { 7056 //Slog.i(TAG, "Losing delayed focus: " + losers.get(i)); 7057 losers.get(i).mClient.windowFocusChanged(false, mInTouchMode); 7058 } catch (RemoteException e) { 7059 // Ignore if process has died. 7060 } 7061 } 7062 } break; 7063 7064 case DO_TRAVERSAL: { 7065 synchronized(mWindowMap) { 7066 mTraversalScheduled = false; 7067 performLayoutAndPlaceSurfacesLocked(); 7068 } 7069 } break; 7070 7071 case ADD_STARTING: { 7072 final AppWindowToken wtoken = (AppWindowToken)msg.obj; 7073 final StartingData sd = wtoken.startingData; 7074 7075 if (sd == null) { 7076 // Animation has been canceled... do nothing. 7077 return; 7078 } 7079 7080 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting " 7081 + wtoken + ": pkg=" + sd.pkg); 7082 7083 View view = null; 7084 try { 7085 view = mPolicy.addStartingWindow( 7086 wtoken.token, sd.pkg, sd.theme, sd.compatInfo, 7087 sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags); 7088 } catch (Exception e) { 7089 Slog.w(TAG, "Exception when adding starting window", e); 7090 } 7091 7092 if (view != null) { 7093 boolean abort = false; 7094 7095 synchronized(mWindowMap) { 7096 if (wtoken.removed || wtoken.startingData == null) { 7097 // If the window was successfully added, then 7098 // we need to remove it. 7099 if (wtoken.startingWindow != null) { 7100 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, 7101 "Aborted starting " + wtoken 7102 + ": removed=" + wtoken.removed 7103 + " startingData=" + wtoken.startingData); 7104 wtoken.startingWindow = null; 7105 wtoken.startingData = null; 7106 abort = true; 7107 } 7108 } else { 7109 wtoken.startingView = view; 7110 } 7111 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG, 7112 "Added starting " + wtoken 7113 + ": startingWindow=" 7114 + wtoken.startingWindow + " startingView=" 7115 + wtoken.startingView); 7116 } 7117 7118 if (abort) { 7119 try { 7120 mPolicy.removeStartingWindow(wtoken.token, view); 7121 } catch (Exception e) { 7122 Slog.w(TAG, "Exception when removing starting window", e); 7123 } 7124 } 7125 } 7126 } break; 7127 7128 case REMOVE_STARTING: { 7129 final AppWindowToken wtoken = (AppWindowToken)msg.obj; 7130 IBinder token = null; 7131 View view = null; 7132 synchronized (mWindowMap) { 7133 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting " 7134 + wtoken + ": startingWindow=" 7135 + wtoken.startingWindow + " startingView=" 7136 + wtoken.startingView); 7137 if (wtoken.startingWindow != null) { 7138 view = wtoken.startingView; 7139 token = wtoken.token; 7140 wtoken.startingData = null; 7141 wtoken.startingView = null; 7142 wtoken.startingWindow = null; 7143 wtoken.startingDisplayed = false; 7144 } 7145 } 7146 if (view != null) { 7147 try { 7148 mPolicy.removeStartingWindow(token, view); 7149 } catch (Exception e) { 7150 Slog.w(TAG, "Exception when removing starting window", e); 7151 } 7152 } 7153 } break; 7154 7155 case FINISHED_STARTING: { 7156 IBinder token = null; 7157 View view = null; 7158 while (true) { 7159 synchronized (mWindowMap) { 7160 final int N = mFinishedStarting.size(); 7161 if (N <= 0) { 7162 break; 7163 } 7164 AppWindowToken wtoken = mFinishedStarting.remove(N-1); 7165 7166 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, 7167 "Finished starting " + wtoken 7168 + ": startingWindow=" + wtoken.startingWindow 7169 + " startingView=" + wtoken.startingView); 7170 7171 if (wtoken.startingWindow == null) { 7172 continue; 7173 } 7174 7175 view = wtoken.startingView; 7176 token = wtoken.token; 7177 wtoken.startingData = null; 7178 wtoken.startingView = null; 7179 wtoken.startingWindow = null; 7180 wtoken.startingDisplayed = false; 7181 } 7182 7183 try { 7184 mPolicy.removeStartingWindow(token, view); 7185 } catch (Exception e) { 7186 Slog.w(TAG, "Exception when removing starting window", e); 7187 } 7188 } 7189 } break; 7190 7191 case REPORT_APPLICATION_TOKEN_DRAWN: { 7192 final AppWindowToken wtoken = (AppWindowToken)msg.obj; 7193 7194 try { 7195 if (DEBUG_VISIBILITY) Slog.v( 7196 TAG, "Reporting drawn in " + wtoken); 7197 wtoken.appToken.windowsDrawn(); 7198 } catch (RemoteException ex) { 7199 } 7200 } break; 7201 7202 case REPORT_APPLICATION_TOKEN_WINDOWS: { 7203 final AppWindowToken wtoken = (AppWindowToken)msg.obj; 7204 7205 boolean nowVisible = msg.arg1 != 0; 7206 boolean nowGone = msg.arg2 != 0; 7207 7208 try { 7209 if (DEBUG_VISIBILITY) Slog.v( 7210 TAG, "Reporting visible in " + wtoken 7211 + " visible=" + nowVisible 7212 + " gone=" + nowGone); 7213 if (nowVisible) { 7214 wtoken.appToken.windowsVisible(); 7215 } else { 7216 wtoken.appToken.windowsGone(); 7217 } 7218 } catch (RemoteException ex) { 7219 } 7220 } break; 7221 7222 case WINDOW_FREEZE_TIMEOUT: { 7223 // TODO(multidisplay): Can non-default displays rotate? 7224 synchronized (mWindowMap) { 7225 Slog.w(TAG, "Window freeze timeout expired."); 7226 final WindowList windows = getDefaultWindowList(); 7227 int i = windows.size(); 7228 while (i > 0) { 7229 i--; 7230 WindowState w = windows.get(i); 7231 if (w.mOrientationChanging) { 7232 w.mOrientationChanging = false; 7233 Slog.w(TAG, "Force clearing orientation change: " + w); 7234 } 7235 } 7236 performLayoutAndPlaceSurfacesLocked(); 7237 } 7238 break; 7239 } 7240 7241 case HOLD_SCREEN_CHANGED: { 7242 Session oldHold; 7243 Session newHold; 7244 synchronized (mWindowMap) { 7245 oldHold = mLastReportedHold; 7246 newHold = (Session)msg.obj; 7247 mLastReportedHold = newHold; 7248 } 7249 7250 if (oldHold != newHold) { 7251 try { 7252 if (oldHold != null) { 7253 mBatteryStats.noteStopWakelock(oldHold.mUid, -1, 7254 "window", 7255 BatteryStats.WAKE_TYPE_WINDOW); 7256 } 7257 if (newHold != null) { 7258 mBatteryStats.noteStartWakelock(newHold.mUid, -1, 7259 "window", 7260 BatteryStats.WAKE_TYPE_WINDOW); 7261 } 7262 } catch (RemoteException e) { 7263 } 7264 } 7265 break; 7266 } 7267 7268 case APP_TRANSITION_TIMEOUT: { 7269 synchronized (mWindowMap) { 7270 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 7271 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 7272 "*** APP TRANSITION TIMEOUT"); 7273 mAppTransitionReady = true; 7274 mAppTransitionTimeout = true; 7275 mAnimatingAppTokens.clear(); 7276 mAnimatingAppTokens.addAll(mAppTokens); 7277 performLayoutAndPlaceSurfacesLocked(); 7278 } 7279 } 7280 break; 7281 } 7282 7283 case PERSIST_ANIMATION_SCALE: { 7284 Settings.System.putFloat(mContext.getContentResolver(), 7285 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale); 7286 Settings.System.putFloat(mContext.getContentResolver(), 7287 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale); 7288 Settings.System.putFloat(mContext.getContentResolver(), 7289 Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale); 7290 break; 7291 } 7292 7293 case FORCE_GC: { 7294 synchronized (mWindowMap) { 7295 synchronized (mAnimator) { 7296 // Since we're holding both mWindowMap and mAnimator we don't need to 7297 // hold mAnimator.mLayoutToAnim. 7298 if (mAnimator.mAnimating || mLayoutToAnim.mAnimationScheduled) { 7299 // If we are animating, don't do the gc now but 7300 // delay a bit so we don't interrupt the animation. 7301 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC), 7302 2000); 7303 return; 7304 } 7305 // If we are currently rotating the display, it will 7306 // schedule a new message when done. 7307 if (mDisplayFrozen) { 7308 return; 7309 } 7310 } 7311 } 7312 Runtime.getRuntime().gc(); 7313 break; 7314 } 7315 7316 case ENABLE_SCREEN: { 7317 performEnableScreen(); 7318 break; 7319 } 7320 7321 case APP_FREEZE_TIMEOUT: { 7322 synchronized (mWindowMap) { 7323 synchronized (mAnimator) { 7324 Slog.w(TAG, "App freeze timeout expired."); 7325 int i = mAppTokens.size(); 7326 while (i > 0) { 7327 i--; 7328 AppWindowToken tok = mAppTokens.get(i); 7329 if (tok.mAppAnimator.freezingScreen) { 7330 Slog.w(TAG, "Force clearing freeze: " + tok); 7331 unsetAppFreezingScreenLocked(tok, true, true); 7332 } 7333 } 7334 } 7335 } 7336 break; 7337 } 7338 7339 case SEND_NEW_CONFIGURATION: { 7340 removeMessages(SEND_NEW_CONFIGURATION); 7341 sendNewConfiguration(); 7342 break; 7343 } 7344 7345 case REPORT_WINDOWS_CHANGE: { 7346 if (mWindowsChanged) { 7347 synchronized (mWindowMap) { 7348 mWindowsChanged = false; 7349 } 7350 notifyWindowsChanged(); 7351 } 7352 break; 7353 } 7354 7355 case DRAG_START_TIMEOUT: { 7356 IBinder win = (IBinder)msg.obj; 7357 if (DEBUG_DRAG) { 7358 Slog.w(TAG, "Timeout starting drag by win " + win); 7359 } 7360 synchronized (mWindowMap) { 7361 // !!! TODO: ANR the app that has failed to start the drag in time 7362 if (mDragState != null) { 7363 mDragState.unregister(); 7364 mInputMonitor.updateInputWindowsLw(true /*force*/); 7365 mDragState.reset(); 7366 mDragState = null; 7367 } 7368 } 7369 break; 7370 } 7371 7372 case DRAG_END_TIMEOUT: { 7373 IBinder win = (IBinder)msg.obj; 7374 if (DEBUG_DRAG) { 7375 Slog.w(TAG, "Timeout ending drag to win " + win); 7376 } 7377 synchronized (mWindowMap) { 7378 // !!! TODO: ANR the drag-receiving app 7379 if (mDragState != null) { 7380 mDragState.mDragResult = false; 7381 mDragState.endDragLw(); 7382 } 7383 } 7384 break; 7385 } 7386 7387 case REPORT_HARD_KEYBOARD_STATUS_CHANGE: { 7388 notifyHardKeyboardStatusChange(); 7389 break; 7390 } 7391 7392 case BOOT_TIMEOUT: { 7393 performBootTimeout(); 7394 break; 7395 } 7396 7397 case WAITING_FOR_DRAWN_TIMEOUT: { 7398 Pair<WindowState, IRemoteCallback> pair; 7399 synchronized (mWindowMap) { 7400 pair = (Pair<WindowState, IRemoteCallback>)msg.obj; 7401 Slog.w(TAG, "Timeout waiting for drawn: " + pair.first); 7402 if (!mWaitingForDrawn.remove(pair)) { 7403 return; 7404 } 7405 } 7406 try { 7407 pair.second.sendResult(null); 7408 } catch (RemoteException e) { 7409 } 7410 break; 7411 } 7412 7413 case UPDATE_ANIM_PARAMETERS: { 7414 // Used to send multiple changes from the animation side to the layout side. 7415 synchronized (mWindowMap) { 7416 if (copyAnimToLayoutParamsLocked()) { 7417 mH.sendEmptyMessage(CLEAR_PENDING_ACTIONS); 7418 performLayoutAndPlaceSurfacesLocked(); 7419 } 7420 } 7421 break; 7422 } 7423 7424 case SHOW_STRICT_MODE_VIOLATION: { 7425 showStrictModeViolation(msg.arg1); 7426 break; 7427 } 7428 7429 // Animation messages. Move to Window{State}Animator 7430 case SET_TRANSPARENT_REGION: { 7431 Pair<WindowStateAnimator, Region> pair = 7432 (Pair<WindowStateAnimator, Region>) msg.obj; 7433 final WindowStateAnimator winAnimator = pair.first; 7434 winAnimator.setTransparentRegionHint(pair.second); 7435 break; 7436 } 7437 7438 case CLEAR_PENDING_ACTIONS: { 7439 mAnimator.clearPendingActions(); 7440 break; 7441 } 7442 7443 case DO_ANIMATION_CALLBACK: { 7444 try { 7445 ((IRemoteCallback)msg.obj).sendResult(null); 7446 } catch (RemoteException e) { 7447 } 7448 break; 7449 } 7450 } 7451 if (DEBUG_WINDOW_TRACE) { 7452 Slog.v(TAG, "handleMessage: exit"); 7453 } 7454 } 7455 } 7456 7457 // ------------------------------------------------------------- 7458 // IWindowManager API 7459 // ------------------------------------------------------------- 7460 7461 @Override 7462 public IWindowSession openSession(IInputMethodClient client, 7463 IInputContext inputContext) { 7464 if (client == null) throw new IllegalArgumentException("null client"); 7465 if (inputContext == null) throw new IllegalArgumentException("null inputContext"); 7466 Session session = new Session(this, client, inputContext); 7467 return session; 7468 } 7469 7470 @Override 7471 public boolean inputMethodClientHasFocus(IInputMethodClient client) { 7472 synchronized (mWindowMap) { 7473 // The focus for the client is the window immediately below 7474 // where we would place the input method window. 7475 int idx = findDesiredInputMethodWindowIndexLocked(false); 7476 if (idx > 0) { 7477 // TODO(multidisplay): IMEs are only supported on the default display. 7478 WindowState imFocus = getDefaultWindowList().get(idx-1); 7479 if (DEBUG_INPUT_METHOD) { 7480 Slog.i(TAG, "Desired input method target: " + imFocus); 7481 Slog.i(TAG, "Current focus: " + mCurrentFocus); 7482 Slog.i(TAG, "Last focus: " + mLastFocus); 7483 } 7484 if (imFocus != null) { 7485 // This may be a starting window, in which case we still want 7486 // to count it as okay. 7487 if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING 7488 && imFocus.mAppToken != null) { 7489 // The client has definitely started, so it really should 7490 // have a window in this app token. Let's look for it. 7491 for (int i=0; i<imFocus.mAppToken.windows.size(); i++) { 7492 WindowState w = imFocus.mAppToken.windows.get(i); 7493 if (w != imFocus) { 7494 Log.i(TAG, "Switching to real app window: " + w); 7495 imFocus = w; 7496 break; 7497 } 7498 } 7499 } 7500 if (DEBUG_INPUT_METHOD) { 7501 Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient); 7502 if (imFocus.mSession.mClient != null) { 7503 Slog.i(TAG, "IM target client binder: " 7504 + imFocus.mSession.mClient.asBinder()); 7505 Slog.i(TAG, "Requesting client binder: " + client.asBinder()); 7506 } 7507 } 7508 if (imFocus.mSession.mClient != null && 7509 imFocus.mSession.mClient.asBinder() == client.asBinder()) { 7510 return true; 7511 } 7512 } 7513 } 7514 7515 // Okay, how about this... what is the current focus? 7516 // It seems in some cases we may not have moved the IM 7517 // target window, such as when it was in a pop-up window, 7518 // so let's also look at the current focus. (An example: 7519 // go to Gmail, start searching so the keyboard goes up, 7520 // press home. Sometimes the IME won't go down.) 7521 // Would be nice to fix this more correctly, but it's 7522 // way at the end of a release, and this should be good enough. 7523 if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null 7524 && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) { 7525 return true; 7526 } 7527 } 7528 return false; 7529 } 7530 7531 public void getInitialDisplaySize(int displayId, Point size) { 7532 // TODO(cmautner): Access to DisplayContent should be locked on mWindowMap. Doing that 7533 // could lead to deadlock since this is called from ActivityManager. 7534 final DisplayContent displayContent = getDisplayContent(displayId); 7535 synchronized(displayContent.mDisplaySizeLock) { 7536 size.x = displayContent.mInitialDisplayWidth; 7537 size.y = displayContent.mInitialDisplayHeight; 7538 } 7539 } 7540 7541 public void setForcedDisplaySize(int displayId, int longDimen, int shortDimen) { 7542 synchronized(mWindowMap) { 7543 final DisplayContent displayContent = getDisplayContent(displayId); 7544 int width, height; 7545 if (displayContent.mInitialDisplayWidth < displayContent.mInitialDisplayHeight) { 7546 width = shortDimen < displayContent.mInitialDisplayWidth 7547 ? shortDimen : displayContent.mInitialDisplayWidth; 7548 height = longDimen < displayContent.mInitialDisplayHeight 7549 ? longDimen : displayContent.mInitialDisplayHeight; 7550 } else { 7551 width = longDimen < displayContent.mInitialDisplayWidth 7552 ? longDimen : displayContent.mInitialDisplayWidth; 7553 height = shortDimen < displayContent.mInitialDisplayHeight 7554 ? shortDimen : displayContent.mInitialDisplayHeight; 7555 } 7556 setForcedDisplaySizeLocked(displayContent, width, height); 7557 Settings.Secure.putString(mContext.getContentResolver(), 7558 Settings.Secure.DISPLAY_SIZE_FORCED, width + "," + height); 7559 } 7560 } 7561 7562 private void rebuildBlackFrameLocked() { 7563 if (mBlackFrame != null) { 7564 mBlackFrame.kill(); 7565 mBlackFrame = null; 7566 } 7567 // TODO(multidisplay): For now rotations are only main screen. 7568 final DisplayContent displayContent = getDefaultDisplayContent(); 7569 if (displayContent.mBaseDisplayWidth < displayContent.mInitialDisplayWidth 7570 || displayContent.mBaseDisplayHeight < displayContent.mInitialDisplayHeight) { 7571 int initW, initH, baseW, baseH; 7572 final boolean rotated = (mRotation == Surface.ROTATION_90 7573 || mRotation == Surface.ROTATION_270); 7574 if (DEBUG_BOOT) { 7575 Slog.i(TAG, "BLACK FRAME: rotated=" + rotated + " init=" 7576 + displayContent.mInitialDisplayWidth + "x" 7577 + displayContent.mInitialDisplayHeight + " base=" 7578 + displayContent.mBaseDisplayWidth + "x" 7579 + displayContent.mBaseDisplayHeight); 7580 } 7581 if (rotated) { 7582 initW = displayContent.mInitialDisplayHeight; 7583 initH = displayContent.mInitialDisplayWidth; 7584 baseW = displayContent.mBaseDisplayHeight; 7585 baseH = displayContent.mBaseDisplayWidth; 7586 } else { 7587 initW = displayContent.mInitialDisplayWidth; 7588 initH = displayContent.mInitialDisplayHeight; 7589 baseW = displayContent.mBaseDisplayWidth; 7590 baseH = displayContent.mBaseDisplayHeight; 7591 } 7592 Rect outer = new Rect(0, 0, initW, initH); 7593 Rect inner = new Rect(0, 0, baseW, baseH); 7594 try { 7595 mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER); 7596 } catch (Surface.OutOfResourcesException e) { 7597 } 7598 } 7599 } 7600 7601 private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) { 7602 boolean changed = false; 7603 final String sizeStr = Settings.Secure.getString(mContext.getContentResolver(), 7604 Settings.Secure.DISPLAY_SIZE_FORCED); 7605 if (sizeStr != null && sizeStr.length() > 0) { 7606 final int pos = sizeStr.indexOf(','); 7607 if (pos > 0 && sizeStr.lastIndexOf(',') == pos) { 7608 int width, height; 7609 try { 7610 width = Integer.parseInt(sizeStr.substring(0, pos)); 7611 height = Integer.parseInt(sizeStr.substring(pos+1)); 7612 synchronized(displayContent.mDisplaySizeLock) { 7613 if (displayContent.mBaseDisplayWidth != width 7614 || displayContent.mBaseDisplayHeight != height) { 7615 changed = true; 7616 Slog.i(TAG, "FORCED DISPLAY SIZE: " + width + "x" + height); 7617 displayContent.mBaseDisplayWidth = width; 7618 displayContent.mBaseDisplayHeight = height; 7619 } 7620 } 7621 } catch (NumberFormatException ex) { 7622 } 7623 } 7624 } 7625 final String densityStr = Settings.Secure.getString(mContext.getContentResolver(), 7626 Settings.Secure.DISPLAY_DENSITY_FORCED); 7627 if (densityStr != null && densityStr.length() > 0) { 7628 int density; 7629 try { 7630 density = Integer.parseInt(densityStr); 7631 synchronized(displayContent.mDisplaySizeLock) { 7632 if (displayContent.mBaseDisplayDensity != density) { 7633 changed = true; 7634 Slog.i(TAG, "FORCED DISPLAY DENSITY: " + density); 7635 displayContent.mBaseDisplayDensity = density; 7636 } 7637 } 7638 } catch (NumberFormatException ex) { 7639 } 7640 } 7641 if (changed) { 7642 rebuildBlackFrameLocked(); 7643 } 7644 } 7645 7646 private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) { 7647 Slog.i(TAG, "Using new display size: " + width + "x" + height); 7648 7649 synchronized(displayContent.mDisplaySizeLock) { 7650 displayContent.mBaseDisplayWidth = width; 7651 displayContent.mBaseDisplayHeight = height; 7652 } 7653 reconfigureDisplayLocked(displayContent); 7654 } 7655 7656 public void clearForcedDisplaySize(int displayId) { 7657 synchronized(mWindowMap) { 7658 final DisplayContent displayContent = getDisplayContent(displayId); 7659 setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth, 7660 displayContent.mInitialDisplayHeight); 7661 Settings.Secure.putString(mContext.getContentResolver(), 7662 Settings.Secure.DISPLAY_SIZE_FORCED, ""); 7663 } 7664 } 7665 7666 public void setForcedDisplayDensity(int displayId, int density) { 7667 synchronized(mWindowMap) { 7668 final DisplayContent displayContent = getDisplayContent(displayId); 7669 setForcedDisplayDensityLocked(displayContent, density); 7670 Settings.Secure.putString(mContext.getContentResolver(), 7671 Settings.Secure.DISPLAY_DENSITY_FORCED, Integer.toString(density)); 7672 } 7673 } 7674 7675 private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) { 7676 Slog.i(TAG, "Using new display density: " + density); 7677 7678 synchronized(displayContent.mDisplaySizeLock) { 7679 displayContent.mBaseDisplayDensity = density; 7680 } 7681 reconfigureDisplayLocked(displayContent); 7682 } 7683 7684 public void clearForcedDisplayDensity(int displayId) { 7685 synchronized(mWindowMap) { 7686 final DisplayContent displayContent = getDisplayContent(displayId); 7687 setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity); 7688 Settings.Secure.putString(mContext.getContentResolver(), 7689 Settings.Secure.DISPLAY_DENSITY_FORCED, ""); 7690 } 7691 } 7692 7693 private void reconfigureDisplayLocked(DisplayContent displayContent) { 7694 mPolicy.setInitialDisplaySize(mDisplay, displayContent.mBaseDisplayWidth, 7695 displayContent.mBaseDisplayHeight, displayContent.mBaseDisplayDensity); 7696 7697 mLayoutNeeded = true; 7698 7699 boolean configChanged = updateOrientationFromAppTokensLocked(false); 7700 mTempConfiguration.setToDefaults(); 7701 mTempConfiguration.fontScale = mCurConfiguration.fontScale; 7702 if (computeScreenConfigurationLocked(mTempConfiguration)) { 7703 if (mCurConfiguration.diff(mTempConfiguration) != 0) { 7704 configChanged = true; 7705 } 7706 } 7707 7708 if (configChanged) { 7709 mWaitingForConfig = true; 7710 startFreezingDisplayLocked(false); 7711 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 7712 } 7713 7714 rebuildBlackFrameLocked(); 7715 7716 performLayoutAndPlaceSurfacesLocked(); 7717 } 7718 7719 public boolean hasSystemNavBar() { 7720 return mPolicy.hasSystemNavBar(); 7721 } 7722 7723 // ------------------------------------------------------------- 7724 // Internals 7725 // ------------------------------------------------------------- 7726 7727 final WindowState windowForClientLocked(Session session, IWindow client, 7728 boolean throwOnError) { 7729 return windowForClientLocked(session, client.asBinder(), throwOnError); 7730 } 7731 7732 final WindowState windowForClientLocked(Session session, IBinder client, 7733 boolean throwOnError) { 7734 WindowState win = mWindowMap.get(client); 7735 if (localLOGV) Slog.v( 7736 TAG, "Looking up client " + client + ": " + win); 7737 if (win == null) { 7738 RuntimeException ex = new IllegalArgumentException( 7739 "Requested window " + client + " does not exist"); 7740 if (throwOnError) { 7741 throw ex; 7742 } 7743 Slog.w(TAG, "Failed looking up window", ex); 7744 return null; 7745 } 7746 if (session != null && win.mSession != session) { 7747 RuntimeException ex = new IllegalArgumentException( 7748 "Requested window " + client + " is in session " + 7749 win.mSession + ", not " + session); 7750 if (throwOnError) { 7751 throw ex; 7752 } 7753 Slog.w(TAG, "Failed looking up window", ex); 7754 return null; 7755 } 7756 7757 return win; 7758 } 7759 7760 final void rebuildAppWindowListLocked() { 7761 DisplayContentsIterator iterator = new DisplayContentsIterator(); 7762 while (iterator.hasNext()) { 7763 rebuildAppWindowListLocked(iterator.next()); 7764 } 7765 } 7766 7767 private void rebuildAppWindowListLocked(final DisplayContent displayContent) { 7768 final WindowList windows = displayContent.getWindowList(); 7769 int NW = windows.size(); 7770 int i; 7771 int lastBelow = -1; 7772 int numRemoved = 0; 7773 7774 if (mRebuildTmp.length < NW) { 7775 mRebuildTmp = new WindowState[NW+10]; 7776 } 7777 7778 // First remove all existing app windows. 7779 i=0; 7780 while (i < NW) { 7781 WindowState w = windows.get(i); 7782 if (w.mAppToken != null) { 7783 WindowState win = windows.remove(i); 7784 win.mRebuilding = true; 7785 mRebuildTmp[numRemoved] = win; 7786 mWindowsChanged = true; 7787 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, 7788 "Rebuild removing window: " + win); 7789 NW--; 7790 numRemoved++; 7791 continue; 7792 } else if (lastBelow == i-1) { 7793 if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER 7794 || w.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND) { 7795 lastBelow = i; 7796 } 7797 } 7798 i++; 7799 } 7800 7801 // Keep whatever windows were below the app windows still below, 7802 // by skipping them. 7803 lastBelow++; 7804 i = lastBelow; 7805 7806 // First add all of the exiting app tokens... these are no longer 7807 // in the main app list, but still have windows shown. We put them 7808 // in the back because now that the animation is over we no longer 7809 // will care about them. 7810 int NT = mExitingAppTokens.size(); 7811 for (int j=0; j<NT; j++) { 7812 i = reAddAppWindowsLocked(displayContent, i, mExitingAppTokens.get(j)); 7813 } 7814 7815 // And add in the still active app tokens in Z order. 7816 NT = mAnimatingAppTokens.size(); 7817 for (int j=0; j<NT; j++) { 7818 i = reAddAppWindowsLocked(displayContent, i, mAnimatingAppTokens.get(j)); 7819 } 7820 7821 i -= lastBelow; 7822 if (i != numRemoved) { 7823 Slog.w(TAG, "Rebuild removed " + numRemoved 7824 + " windows but added " + i); 7825 for (i=0; i<numRemoved; i++) { 7826 WindowState ws = mRebuildTmp[i]; 7827 if (ws.mRebuilding) { 7828 StringWriter sw = new StringWriter(); 7829 PrintWriter pw = new PrintWriter(sw); 7830 ws.dump(pw, "", true); 7831 pw.flush(); 7832 Slog.w(TAG, "This window was lost: " + ws); 7833 Slog.w(TAG, sw.toString()); 7834 ws.mWinAnimator.destroySurfaceLocked(); 7835 } 7836 } 7837 Slog.w(TAG, "Current app token list:"); 7838 dumpAnimatingAppTokensLocked(); 7839 Slog.w(TAG, "Final window list:"); 7840 dumpWindowsLocked(); 7841 } 7842 } 7843 7844 private final void assignLayersLocked(WindowList windows) { 7845 int N = windows.size(); 7846 int curBaseLayer = 0; 7847 int curLayer = 0; 7848 int i; 7849 7850 if (DEBUG_LAYERS) { 7851 RuntimeException here = new RuntimeException("here"); 7852 here.fillInStackTrace(); 7853 Slog.v(TAG, "Assigning layers", here); 7854 } 7855 7856 for (i=0; i<N; i++) { 7857 final WindowState w = windows.get(i); 7858 final WindowStateAnimator winAnimator = w.mWinAnimator; 7859 boolean layerChanged = false; 7860 int oldLayer = w.mLayer; 7861 if (w.mBaseLayer == curBaseLayer || w.mIsImWindow 7862 || (i > 0 && w.mIsWallpaper)) { 7863 curLayer += WINDOW_LAYER_MULTIPLIER; 7864 w.mLayer = curLayer; 7865 } else { 7866 curBaseLayer = curLayer = w.mBaseLayer; 7867 w.mLayer = curLayer; 7868 } 7869 if (w.mLayer != oldLayer) { 7870 layerChanged = true; 7871 } 7872 oldLayer = winAnimator.mAnimLayer; 7873 if (w.mTargetAppToken != null) { 7874 winAnimator.mAnimLayer = 7875 w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment; 7876 } else if (w.mAppToken != null) { 7877 winAnimator.mAnimLayer = 7878 w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment; 7879 } else { 7880 winAnimator.mAnimLayer = w.mLayer; 7881 } 7882 if (w.mIsImWindow) { 7883 winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment; 7884 } else if (w.mIsWallpaper) { 7885 winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment; 7886 } 7887 if (winAnimator.mAnimLayer != oldLayer) { 7888 layerChanged = true; 7889 } 7890 if (layerChanged && mAnimator.isDimming(winAnimator)) { 7891 // Force an animation pass just to update the mDimAnimator layer. 7892 updateLayoutToAnimationLocked(); 7893 } 7894 if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": " 7895 + winAnimator.mAnimLayer); 7896 //System.out.println( 7897 // "Assigned layer " + curLayer + " to " + w.mClient.asBinder()); 7898 } 7899 } 7900 7901 private boolean mInLayout = false; 7902 private final void performLayoutAndPlaceSurfacesLocked() { 7903 if (mInLayout) { 7904 if (DEBUG) { 7905 throw new RuntimeException("Recursive call!"); 7906 } 7907 Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers=" 7908 + Debug.getCallers(3)); 7909 return; 7910 } 7911 7912 if (mWaitingForConfig) { 7913 // Our configuration has changed (most likely rotation), but we 7914 // don't yet have the complete configuration to report to 7915 // applications. Don't do any window layout until we have it. 7916 return; 7917 } 7918 7919 if (mDisplay == null) { 7920 // Not yet initialized, nothing to do. 7921 return; 7922 } 7923 7924 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout"); 7925 mInLayout = true; 7926 boolean recoveringMemory = false; 7927 7928 try { 7929 if (mForceRemoves != null) { 7930 recoveringMemory = true; 7931 // Wait a little bit for things to settle down, and off we go. 7932 for (int i=0; i<mForceRemoves.size(); i++) { 7933 WindowState ws = mForceRemoves.get(i); 7934 Slog.i(TAG, "Force removing: " + ws); 7935 removeWindowInnerLocked(ws.mSession, ws); 7936 } 7937 mForceRemoves = null; 7938 Slog.w(TAG, "Due to memory failure, waiting a bit for next layout"); 7939 Object tmp = new Object(); 7940 synchronized (tmp) { 7941 try { 7942 tmp.wait(250); 7943 } catch (InterruptedException e) { 7944 } 7945 } 7946 } 7947 } catch (RuntimeException e) { 7948 Log.wtf(TAG, "Unhandled exception while force removing for memory", e); 7949 } 7950 7951 try { 7952 DisplayContentsIterator iterator = new DisplayContentsIterator(); 7953 while (iterator.hasNext()) { 7954 final DisplayContent displayContent = iterator.next(); 7955 performLayoutAndPlaceSurfacesLockedInner(displayContent, recoveringMemory); 7956 7957 final int N = mPendingRemove.size(); 7958 if (N > 0) { 7959 if (mPendingRemoveTmp.length < N) { 7960 mPendingRemoveTmp = new WindowState[N+10]; 7961 } 7962 mPendingRemove.toArray(mPendingRemoveTmp); 7963 mPendingRemove.clear(); 7964 for (int i=0; i<N; i++) { 7965 WindowState w = mPendingRemoveTmp[i]; 7966 removeWindowInnerLocked(w.mSession, w); 7967 } 7968 7969 assignLayersLocked(displayContent.getWindowList()); 7970 mLayoutNeeded = true; 7971 } 7972 } 7973 7974 mInLayout = false; 7975 7976 if (mLayoutNeeded) { 7977 if (++mLayoutRepeatCount < 6) { 7978 requestTraversalLocked(); 7979 } else { 7980 Slog.e(TAG, "Performed 6 layouts in a row. Skipping"); 7981 mLayoutRepeatCount = 0; 7982 } 7983 } else { 7984 mLayoutRepeatCount = 0; 7985 } 7986 7987 if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) { 7988 mH.removeMessages(H.REPORT_WINDOWS_CHANGE); 7989 mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE)); 7990 } 7991 } catch (RuntimeException e) { 7992 mInLayout = false; 7993 Log.wtf(TAG, "Unhandled exception while laying out windows", e); 7994 } 7995 7996 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); 7997 } 7998 7999 private final void performLayoutLockedInner(final DisplayContent displayContent, 8000 boolean initial, boolean updateInputWindows) { 8001 if (!mLayoutNeeded) { 8002 return; 8003 } 8004 WindowList windows = displayContent.getWindowList(); 8005 mLayoutNeeded = false; 8006 8007 DisplayInfo displayInfo = displayContent.getDisplayInfo(); 8008 final int dw = displayInfo.logicalWidth; 8009 final int dh = displayInfo.logicalHeight; 8010 8011 final int NFW = mFakeWindows.size(); 8012 for (int i=0; i<NFW; i++) { 8013 mFakeWindows.get(i).layout(dw, dh); 8014 } 8015 8016 final int N = windows.size(); 8017 int i; 8018 8019 if (DEBUG_LAYOUT) { 8020 Slog.v(TAG, "-------------------------------------"); 8021 Slog.v(TAG, "performLayout: needed=" 8022 + mLayoutNeeded + " dw=" + dw + " dh=" + dh); 8023 } 8024 8025 WindowStateAnimator universeBackground = null; 8026 8027 mPolicy.beginLayoutLw(dw, dh, mRotation); 8028 mSystemDecorLayer = mPolicy.getSystemDecorRectLw(mSystemDecorRect); 8029 mScreenRect.set(0, 0, dw, dh); 8030 8031 int seq = mLayoutSeq+1; 8032 if (seq < 0) seq = 0; 8033 mLayoutSeq = seq; 8034 8035 // First perform layout of any root windows (not attached 8036 // to another window). 8037 int topAttached = -1; 8038 for (i = N-1; i >= 0; i--) { 8039 final WindowState win = windows.get(i); 8040 8041 // Don't do layout of a window if it is not visible, or 8042 // soon won't be visible, to avoid wasting time and funky 8043 // changes while a window is animating away. 8044 final boolean gone = win.isGoneForLayoutLw(); 8045 8046 if (DEBUG_LAYOUT && !win.mLayoutAttached) { 8047 Slog.v(TAG, "1ST PASS " + win 8048 + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame 8049 + " mLayoutAttached=" + win.mLayoutAttached); 8050 final AppWindowToken atoken = win.mAppToken; 8051 if (gone) Slog.v(TAG, " GONE: mViewVisibility=" 8052 + win.mViewVisibility + " mRelayoutCalled=" 8053 + win.mRelayoutCalled + " hidden=" 8054 + win.mRootToken.hidden + " hiddenRequested=" 8055 + (atoken != null && atoken.hiddenRequested) 8056 + " mAttachedHidden=" + win.mAttachedHidden); 8057 else Slog.v(TAG, " VIS: mViewVisibility=" 8058 + win.mViewVisibility + " mRelayoutCalled=" 8059 + win.mRelayoutCalled + " hidden=" 8060 + win.mRootToken.hidden + " hiddenRequested=" 8061 + (atoken != null && atoken.hiddenRequested) 8062 + " mAttachedHidden=" + win.mAttachedHidden); 8063 } 8064 8065 // If this view is GONE, then skip it -- keep the current 8066 // frame, and let the caller know so they can ignore it 8067 // if they want. (We do the normal layout for INVISIBLE 8068 // windows, since that means "perform layout as normal, 8069 // just don't display"). 8070 if (!gone || !win.mHaveFrame || win.mLayoutNeeded 8071 || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) { 8072 if (!win.mLayoutAttached) { 8073 if (initial) { 8074 //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); 8075 win.mContentChanged = false; 8076 } 8077 win.mLayoutNeeded = false; 8078 win.prelayout(); 8079 mPolicy.layoutWindowLw(win, win.mAttrs, null); 8080 win.mLayoutSeq = seq; 8081 if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" 8082 + win.mFrame + " mContainingFrame=" 8083 + win.mContainingFrame + " mDisplayFrame=" 8084 + win.mDisplayFrame); 8085 } else { 8086 if (topAttached < 0) topAttached = i; 8087 } 8088 } 8089 if (win.mViewVisibility == View.VISIBLE 8090 && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND 8091 && universeBackground == null) { 8092 universeBackground = win.mWinAnimator; 8093 } 8094 } 8095 8096 if (mAnimator.mUniverseBackground != universeBackground) { 8097 mFocusMayChange = true; 8098 mAnimator.mUniverseBackground = universeBackground; 8099 } 8100 8101 // Now perform layout of attached windows, which usually 8102 // depend on the position of the window they are attached to. 8103 // XXX does not deal with windows that are attached to windows 8104 // that are themselves attached. 8105 for (i = topAttached; i >= 0; i--) { 8106 final WindowState win = windows.get(i); 8107 8108 if (win.mLayoutAttached) { 8109 if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win 8110 + " mHaveFrame=" + win.mHaveFrame 8111 + " mViewVisibility=" + win.mViewVisibility 8112 + " mRelayoutCalled=" + win.mRelayoutCalled); 8113 // If this view is GONE, then skip it -- keep the current 8114 // frame, and let the caller know so they can ignore it 8115 // if they want. (We do the normal layout for INVISIBLE 8116 // windows, since that means "perform layout as normal, 8117 // just don't display"). 8118 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled) 8119 || !win.mHaveFrame || win.mLayoutNeeded) { 8120 if (initial) { 8121 //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); 8122 win.mContentChanged = false; 8123 } 8124 win.mLayoutNeeded = false; 8125 win.prelayout(); 8126 mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow); 8127 win.mLayoutSeq = seq; 8128 if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" 8129 + win.mFrame + " mContainingFrame=" 8130 + win.mContainingFrame + " mDisplayFrame=" 8131 + win.mDisplayFrame); 8132 } 8133 } 8134 } 8135 8136 // Window frames may have changed. Tell the input dispatcher about it. 8137 mInputMonitor.setUpdateInputWindowsNeededLw(); 8138 if (updateInputWindows) { 8139 mInputMonitor.updateInputWindowsLw(false /*force*/); 8140 } 8141 8142 mPolicy.finishLayoutLw(); 8143 } 8144 8145 void makeWindowFreezingScreenIfNeededLocked(WindowState w) { 8146 // If the screen is currently frozen or off, then keep 8147 // it frozen/off until this window draws at its new 8148 // orientation. 8149 if (!okToDisplay()) { 8150 if (DEBUG_ORIENTATION) Slog.v(TAG, 8151 "Changing surface while display frozen: " + w); 8152 w.mOrientationChanging = true; 8153 mInnerFields.mOrientationChangeComplete = false; 8154 if (!mWindowsFreezingScreen) { 8155 mWindowsFreezingScreen = true; 8156 // XXX should probably keep timeout from 8157 // when we first froze the display. 8158 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); 8159 mH.sendMessageDelayed(mH.obtainMessage( 8160 H.WINDOW_FREEZE_TIMEOUT), 2000); 8161 } 8162 } 8163 } 8164 8165 /** 8166 * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. 8167 * @param windows TODO(cmautner): 8168 * 8169 * @return bitmap indicating if another pass through layout must be made. 8170 */ 8171 public int handleAppTransitionReadyLocked(WindowList windows) { 8172 int changes = 0; 8173 int i; 8174 int NN = mOpeningApps.size(); 8175 boolean goodToGo = true; 8176 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 8177 "Checking " + NN + " opening apps (frozen=" 8178 + mDisplayFrozen + " timeout=" 8179 + mAppTransitionTimeout + ")..."); 8180 if (!mDisplayFrozen && !mAppTransitionTimeout) { 8181 // If the display isn't frozen, wait to do anything until 8182 // all of the apps are ready. Otherwise just go because 8183 // we'll unfreeze the display when everyone is ready. 8184 for (i=0; i<NN && goodToGo; i++) { 8185 AppWindowToken wtoken = mOpeningApps.get(i); 8186 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 8187 "Check opening app=" + wtoken + ": allDrawn=" 8188 + wtoken.allDrawn + " startingDisplayed=" 8189 + wtoken.startingDisplayed + " startingMoved=" 8190 + wtoken.startingMoved); 8191 if (!wtoken.allDrawn && !wtoken.startingDisplayed 8192 && !wtoken.startingMoved) { 8193 goodToGo = false; 8194 } 8195 } 8196 } 8197 if (goodToGo) { 8198 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO"); 8199 int transit = mNextAppTransition; 8200 if (mSkipAppTransitionAnimation) { 8201 transit = WindowManagerPolicy.TRANSIT_UNSET; 8202 } 8203 mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET; 8204 mAppTransitionReady = false; 8205 mAppTransitionRunning = true; 8206 mAppTransitionTimeout = false; 8207 mStartingIconInTransition = false; 8208 mSkipAppTransitionAnimation = false; 8209 8210 mH.removeMessages(H.APP_TRANSITION_TIMEOUT); 8211 8212 rebuildAppWindowListLocked(); 8213 8214 // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper 8215 WindowState oldWallpaper = 8216 mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating() 8217 && !mWallpaperTarget.mWinAnimator.isDummyAnimation() 8218 ? null : mWallpaperTarget; 8219 8220 adjustWallpaperWindowsLocked(); 8221 mInnerFields.mWallpaperMayChange = false; 8222 8223 // The top-most window will supply the layout params, 8224 // and we will determine it below. 8225 LayoutParams animLp = null; 8226 int bestAnimLayer = -1; 8227 boolean fullscreenAnim = false; 8228 8229 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 8230 "New wallpaper target=" + mWallpaperTarget 8231 + ", oldWallpaper=" + oldWallpaper 8232 + ", lower target=" + mLowerWallpaperTarget 8233 + ", upper target=" + mUpperWallpaperTarget); 8234 int foundWallpapers = 0; 8235 // Do a first pass through the tokens for two 8236 // things: 8237 // (1) Determine if both the closing and opening 8238 // app token sets are wallpaper targets, in which 8239 // case special animations are needed 8240 // (since the wallpaper needs to stay static 8241 // behind them). 8242 // (2) Find the layout params of the top-most 8243 // application window in the tokens, which is 8244 // what will control the animation theme. 8245 final int NC = mClosingApps.size(); 8246 NN = NC + mOpeningApps.size(); 8247 for (i=0; i<NN; i++) { 8248 AppWindowToken wtoken; 8249 int mode; 8250 if (i < NC) { 8251 wtoken = mClosingApps.get(i); 8252 mode = 1; 8253 } else { 8254 wtoken = mOpeningApps.get(i-NC); 8255 mode = 2; 8256 } 8257 if (mLowerWallpaperTarget != null) { 8258 if (mLowerWallpaperTarget.mAppToken == wtoken 8259 || mUpperWallpaperTarget.mAppToken == wtoken) { 8260 foundWallpapers |= mode; 8261 } 8262 } 8263 if (wtoken.appFullscreen) { 8264 WindowState ws = wtoken.findMainWindow(); 8265 if (ws != null) { 8266 animLp = ws.mAttrs; 8267 bestAnimLayer = ws.mLayer; 8268 fullscreenAnim = true; 8269 } 8270 } else if (!fullscreenAnim) { 8271 WindowState ws = wtoken.findMainWindow(); 8272 if (ws != null) { 8273 if (ws.mLayer > bestAnimLayer) { 8274 animLp = ws.mAttrs; 8275 bestAnimLayer = ws.mLayer; 8276 } 8277 } 8278 } 8279 } 8280 8281 if (foundWallpapers == 3) { 8282 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 8283 "Wallpaper animation!"); 8284 switch (transit) { 8285 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: 8286 case WindowManagerPolicy.TRANSIT_TASK_OPEN: 8287 case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT: 8288 transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN; 8289 break; 8290 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: 8291 case WindowManagerPolicy.TRANSIT_TASK_CLOSE: 8292 case WindowManagerPolicy.TRANSIT_TASK_TO_BACK: 8293 transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE; 8294 break; 8295 } 8296 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 8297 "New transit: " + transit); 8298 } else if ((oldWallpaper != null) && !mOpeningApps.contains(oldWallpaper.mAppToken)) { 8299 // We are transitioning from an activity with 8300 // a wallpaper to one without. 8301 transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE; 8302 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 8303 "New transit away from wallpaper: " + transit); 8304 } else if (mWallpaperTarget != null) { 8305 // We are transitioning from an activity without 8306 // a wallpaper to now showing the wallpaper 8307 transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN; 8308 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 8309 "New transit into wallpaper: " + transit); 8310 } 8311 8312 // If all closing windows are obscured, then there is 8313 // no need to do an animation. This is the case, for 8314 // example, when this transition is being done behind 8315 // the lock screen. 8316 if (!mPolicy.allowAppAnimationsLw()) { 8317 animLp = null; 8318 } 8319 8320 AppWindowToken topOpeningApp = null; 8321 int topOpeningLayer = 0; 8322 8323 NN = mOpeningApps.size(); 8324 for (i=0; i<NN; i++) { 8325 AppWindowToken wtoken = mOpeningApps.get(i); 8326 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken); 8327 wtoken.mAppAnimator.clearThumbnail(); 8328 wtoken.reportedVisible = false; 8329 wtoken.inPendingTransaction = false; 8330 wtoken.mAppAnimator.animation = null; 8331 setTokenVisibilityLocked(wtoken, animLp, true, transit, false); 8332 wtoken.updateReportedVisibilityLocked(); 8333 wtoken.waitingToShow = false; 8334 mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked(); 8335 if (animLp != null) { 8336 int layer = -1; 8337 for (int j=0; j<wtoken.windows.size(); j++) { 8338 WindowState win = wtoken.windows.get(j); 8339 if (win.mWinAnimator.mAnimLayer > layer) { 8340 layer = win.mWinAnimator.mAnimLayer; 8341 } 8342 } 8343 if (topOpeningApp == null || layer > topOpeningLayer) { 8344 topOpeningApp = wtoken; 8345 topOpeningLayer = layer; 8346 } 8347 } 8348 } 8349 NN = mClosingApps.size(); 8350 for (i=0; i<NN; i++) { 8351 AppWindowToken wtoken = mClosingApps.get(i); 8352 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 8353 "Now closing app" + wtoken); 8354 wtoken.mAppAnimator.clearThumbnail(); 8355 wtoken.inPendingTransaction = false; 8356 wtoken.mAppAnimator.animation = null; 8357 setTokenVisibilityLocked(wtoken, animLp, false, 8358 transit, false); 8359 wtoken.updateReportedVisibilityLocked(); 8360 wtoken.waitingToHide = false; 8361 // Force the allDrawn flag, because we want to start 8362 // this guy's animations regardless of whether it's 8363 // gotten drawn. 8364 wtoken.allDrawn = true; 8365 } 8366 8367 if (mNextAppTransitionThumbnail != null && topOpeningApp != null 8368 && topOpeningApp.mAppAnimator.animation != null) { 8369 // This thumbnail animation is very special, we need to have 8370 // an extra surface with the thumbnail included with the animation. 8371 Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(), 8372 mNextAppTransitionThumbnail.getHeight()); 8373 try { 8374 Surface surface = new Surface(mFxSession, Process.myPid(), 8375 "thumbnail anim", Display.DEFAULT_DISPLAY, 8376 dirty.width(), dirty.height(), 8377 PixelFormat.TRANSLUCENT, Surface.HIDDEN); 8378 topOpeningApp.mAppAnimator.thumbnail = surface; 8379 if (SHOW_TRANSACTIONS) Slog.i(TAG, " THUMBNAIL " 8380 + surface + ": CREATE"); 8381 Surface drawSurface = new Surface(); 8382 drawSurface.copyFrom(surface); 8383 Canvas c = drawSurface.lockCanvas(dirty); 8384 c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null); 8385 drawSurface.unlockCanvasAndPost(c); 8386 drawSurface.release(); 8387 topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer; 8388 Animation anim = createThumbnailAnimationLocked( 8389 transit, true, true, mNextAppTransitionDelayed); 8390 topOpeningApp.mAppAnimator.thumbnailAnimation = anim; 8391 anim.restrictDuration(MAX_ANIMATION_DURATION); 8392 anim.scaleCurrentDuration(mTransitionAnimationScale); 8393 topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX; 8394 topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY; 8395 } catch (Surface.OutOfResourcesException e) { 8396 Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width() 8397 + " h=" + dirty.height(), e); 8398 topOpeningApp.mAppAnimator.clearThumbnail(); 8399 } 8400 } 8401 8402 mNextAppTransitionType = ActivityOptions.ANIM_NONE; 8403 mNextAppTransitionPackage = null; 8404 mNextAppTransitionThumbnail = null; 8405 scheduleAnimationCallback(mNextAppTransitionCallback); 8406 mNextAppTransitionCallback = null; 8407 8408 mOpeningApps.clear(); 8409 mClosingApps.clear(); 8410 8411 // This has changed the visibility of windows, so perform 8412 // a new layout to get them all up-to-date. 8413 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT 8414 | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; 8415 mLayoutNeeded = true; 8416 8417 // TODO(multidisplay): IMEs are only supported on the default display. 8418 if (windows == getDefaultWindowList() && !moveInputMethodWindowsIfNeededLocked(true)) { 8419 assignLayersLocked(windows); 8420 } 8421 updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, false /*updateInputWindows*/); 8422 mFocusMayChange = false; 8423 } 8424 8425 return changes; 8426 } 8427 8428 /** 8429 * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. 8430 * @return bitmap indicating if another pass through layout must be made. 8431 */ 8432 private int handleAnimatingStoppedAndTransitionLocked() { 8433 int changes = 0; 8434 8435 mAppTransitionRunning = false; 8436 // Restore window app tokens to the ActivityManager views 8437 for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) { 8438 mAnimatingAppTokens.get(i).sendingToBottom = false; 8439 } 8440 mAnimatingAppTokens.clear(); 8441 mAnimatingAppTokens.addAll(mAppTokens); 8442 rebuildAppWindowListLocked(); 8443 8444 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; 8445 mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED; 8446 moveInputMethodWindowsIfNeededLocked(true); 8447 mInnerFields.mWallpaperMayChange = true; 8448 // Since the window list has been rebuilt, focus might 8449 // have to be recomputed since the actual order of windows 8450 // might have changed again. 8451 mFocusMayChange = true; 8452 8453 return changes; 8454 } 8455 8456 /** 8457 * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. 8458 * 8459 * @return bitmap indicating if another pass through layout must be made. 8460 */ 8461 private int animateAwayWallpaperLocked() { 8462 int changes = 0; 8463 WindowState oldWallpaper = mWallpaperTarget; 8464 if (mLowerWallpaperTarget != null 8465 && mLowerWallpaperTarget.mAppToken != null) { 8466 if (DEBUG_WALLPAPER) Slog.v(TAG, 8467 "wallpaperForceHiding changed with lower=" 8468 + mLowerWallpaperTarget); 8469 if (DEBUG_WALLPAPER) Slog.v(TAG, 8470 "hidden=" + mLowerWallpaperTarget.mAppToken.hidden + 8471 " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested); 8472 if (mLowerWallpaperTarget.mAppToken.hidden) { 8473 // The lower target has become hidden before we 8474 // actually started the animation... let's completely 8475 // re-evaluate everything. 8476 mLowerWallpaperTarget = mUpperWallpaperTarget = null; 8477 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM; 8478 } 8479 } 8480 mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked(); 8481 if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper 8482 + " NEW: " + mWallpaperTarget 8483 + " LOWER: " + mLowerWallpaperTarget); 8484 return changes; 8485 } 8486 8487 private void updateResizingWindows(final WindowState w) { 8488 final WindowStateAnimator winAnimator = w.mWinAnimator; 8489 if (w.mHasSurface && !w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) { 8490 w.mContentInsetsChanged |= 8491 !w.mLastContentInsets.equals(w.mContentInsets); 8492 w.mVisibleInsetsChanged |= 8493 !w.mLastVisibleInsets.equals(w.mVisibleInsets); 8494 boolean configChanged = 8495 w.mConfiguration != mCurConfiguration 8496 && (w.mConfiguration == null 8497 || mCurConfiguration.diff(w.mConfiguration) != 0); 8498 if (DEBUG_CONFIGURATION && configChanged) { 8499 Slog.v(TAG, "Win " + w + " config changed: " 8500 + mCurConfiguration); 8501 } 8502 if (localLOGV) Slog.v(TAG, "Resizing " + w 8503 + ": configChanged=" + configChanged 8504 + " last=" + w.mLastFrame + " frame=" + w.mFrame); 8505 w.mLastFrame.set(w.mFrame); 8506 if (w.mContentInsetsChanged 8507 || w.mVisibleInsetsChanged 8508 || winAnimator.mSurfaceResized 8509 || configChanged) { 8510 if (DEBUG_RESIZE || DEBUG_ORIENTATION) { 8511 Slog.v(TAG, "Resize reasons: " 8512 + " contentInsetsChanged=" + w.mContentInsetsChanged 8513 + " visibleInsetsChanged=" + w.mVisibleInsetsChanged 8514 + " surfaceResized=" + winAnimator.mSurfaceResized 8515 + " configChanged=" + configChanged); 8516 } 8517 8518 w.mLastContentInsets.set(w.mContentInsets); 8519 w.mLastVisibleInsets.set(w.mVisibleInsets); 8520 makeWindowFreezingScreenIfNeededLocked(w); 8521 // If the orientation is changing, then we need to 8522 // hold off on unfreezing the display until this 8523 // window has been redrawn; to do that, we need 8524 // to go through the process of getting informed 8525 // by the application when it has finished drawing. 8526 if (w.mOrientationChanging) { 8527 if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG, 8528 "Orientation start waiting for draw mDrawState=DRAW_PENDING in " 8529 + w + ", surface " + winAnimator.mSurface); 8530 winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING; 8531 if (w.mAppToken != null) { 8532 w.mAppToken.allDrawn = false; 8533 } 8534 } 8535 if (!mResizingWindows.contains(w)) { 8536 if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, 8537 "Resizing window " + w + " to " + winAnimator.mSurfaceW 8538 + "x" + winAnimator.mSurfaceH); 8539 mResizingWindows.add(w); 8540 } 8541 } else if (w.mOrientationChanging) { 8542 if (w.isDrawnLw()) { 8543 if (DEBUG_ORIENTATION) Slog.v(TAG, 8544 "Orientation not waiting for draw in " 8545 + w + ", surface " + winAnimator.mSurface); 8546 w.mOrientationChanging = false; 8547 } 8548 } 8549 } 8550 } 8551 8552 /** 8553 * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. 8554 * 8555 * @param w WindowState this method is applied to. 8556 * @param currentTime The time which animations use for calculating transitions. 8557 * @param innerDw Width of app window. 8558 * @param innerDh Height of app window. 8559 */ 8560 private void handleNotObscuredLocked(final WindowState w, final long currentTime, 8561 final int innerDw, final int innerDh) { 8562 final WindowManager.LayoutParams attrs = w.mAttrs; 8563 final int attrFlags = attrs.flags; 8564 final boolean canBeSeen = w.isDisplayedLw(); 8565 8566 if (w.mHasSurface) { 8567 if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) { 8568 mInnerFields.mHoldScreen = w.mSession; 8569 } 8570 if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0 8571 && mInnerFields.mScreenBrightness < 0) { 8572 mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness; 8573 } 8574 if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0 8575 && mInnerFields.mButtonBrightness < 0) { 8576 mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness; 8577 } 8578 if (canBeSeen 8579 && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG 8580 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD 8581 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) { 8582 mInnerFields.mSyswin = true; 8583 } 8584 } 8585 8586 boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn(); 8587 if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) { 8588 // This window completely covers everything behind it, 8589 // so we want to leave all of them as undimmed (for 8590 // performance reasons). 8591 mInnerFields.mObscured = true; 8592 } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0 8593 && !(w.mAppToken != null && w.mAppToken.hiddenRequested) 8594 && !w.mExiting) { 8595 if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured); 8596 if (!mInnerFields.mDimming) { 8597 //Slog.i(TAG, "DIM BEHIND: " + w); 8598 mInnerFields.mDimming = true; 8599 final WindowStateAnimator winAnimator = w.mWinAnimator; 8600 if (!mAnimator.isDimming(winAnimator)) { 8601 final int width, height; 8602 if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) { 8603 final DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo(); 8604 width = displayInfo.logicalWidth; 8605 height = displayInfo.logicalHeight; 8606 } else { 8607 width = innerDw; 8608 height = innerDh; 8609 } 8610 startDimming(winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount, width, height); 8611 } 8612 } 8613 } 8614 } 8615 8616 private void updateAllDrawnLocked() { 8617 // See if any windows have been drawn, so they (and others 8618 // associated with them) can now be shown. 8619 final ArrayList<AppWindowToken> appTokens = mAnimatingAppTokens; 8620 final int NT = appTokens.size(); 8621 for (int i=0; i<NT; i++) { 8622 AppWindowToken wtoken = appTokens.get(i); 8623 if (!wtoken.allDrawn) { 8624 int numInteresting = wtoken.numInterestingWindows; 8625 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { 8626 if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, 8627 "allDrawn: " + wtoken 8628 + " interesting=" + numInteresting 8629 + " drawn=" + wtoken.numDrawnWindows); 8630 wtoken.allDrawn = true; 8631 } 8632 } 8633 } 8634 } 8635 8636 // "Something has changed! Let's make it correct now." 8637 private final void performLayoutAndPlaceSurfacesLockedInner( 8638 final DisplayContent displayContent, boolean recoveringMemory) { 8639 if (DEBUG_WINDOW_TRACE) { 8640 Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by " 8641 + Debug.getCallers(3)); 8642 } 8643 if (mDisplay == null) { 8644 Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay"); 8645 return; 8646 } 8647 8648 final WindowList windows = displayContent.getWindowList(); 8649 final long currentTime = SystemClock.uptimeMillis(); 8650 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 8651 final int dw = displayInfo.logicalWidth; 8652 final int dh = displayInfo.logicalHeight; 8653 final int innerDw = displayInfo.appWidth; 8654 final int innerDh = displayInfo.appHeight; 8655 8656 int i; 8657 8658 if (mFocusMayChange) { 8659 mFocusMayChange = false; 8660 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 8661 false /*updateInputWindows*/); 8662 } 8663 8664 // Initialize state of exiting tokens. 8665 for (i=mExitingTokens.size()-1; i>=0; i--) { 8666 mExitingTokens.get(i).hasVisible = false; 8667 } 8668 8669 // Initialize state of exiting applications. 8670 for (i=mExitingAppTokens.size()-1; i>=0; i--) { 8671 mExitingAppTokens.get(i).hasVisible = false; 8672 } 8673 8674 mInnerFields.mHoldScreen = null; 8675 mInnerFields.mScreenBrightness = -1; 8676 mInnerFields.mButtonBrightness = -1; 8677 mTransactionSequence++; 8678 8679 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, 8680 ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces"); 8681 8682 Surface.openTransaction(); 8683 8684 if (mWatermark != null) { 8685 mWatermark.positionSurface(dw, dh); 8686 } 8687 if (mStrictModeFlash != null) { 8688 mStrictModeFlash.positionSurface(dw, dh); 8689 } 8690 8691 try { 8692 int repeats = 0; 8693 8694 do { 8695 repeats++; 8696 if (repeats > 6) { 8697 Slog.w(TAG, "Animation repeat aborted after too many iterations"); 8698 mLayoutNeeded = false; 8699 break; 8700 } 8701 8702 if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner", 8703 mPendingLayoutChanges); 8704 8705 if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) { 8706 if ((adjustWallpaperWindowsLocked() & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) { 8707 assignLayersLocked(windows); 8708 mLayoutNeeded = true; 8709 } 8710 } 8711 8712 if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) { 8713 if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout"); 8714 if (updateOrientationFromAppTokensLocked(true)) { 8715 mLayoutNeeded = true; 8716 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 8717 } 8718 } 8719 8720 if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) { 8721 mLayoutNeeded = true; 8722 } 8723 8724 // FIRST LOOP: Perform a layout, if needed. 8725 if (repeats < 4) { 8726 performLayoutLockedInner(displayContent, repeats == 1, false /*updateInputWindows*/); 8727 } else { 8728 Slog.w(TAG, "Layout repeat skipped after too many iterations"); 8729 } 8730 8731 // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think 8732 // it is animating. 8733 mPendingLayoutChanges = 0; 8734 if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number " + mLayoutRepeatCount, 8735 mPendingLayoutChanges); 8736 mPolicy.beginAnimationLw(dw, dh); 8737 for (i = windows.size() - 1; i >= 0; i--) { 8738 WindowState w = windows.get(i); 8739 if (w.mHasSurface) { 8740 mPolicy.animatingWindowLw(w, w.mAttrs); 8741 } 8742 } 8743 mPendingLayoutChanges |= mPolicy.finishAnimationLw(); 8744 if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishAnimationLw", 8745 mPendingLayoutChanges); 8746 } while (mPendingLayoutChanges != 0); 8747 8748 final boolean someoneLosingFocus = !mLosingFocus.isEmpty(); 8749 8750 mInnerFields.mObscured = false; 8751 mInnerFields.mDimming = false; 8752 mInnerFields.mSyswin = false; 8753 8754 boolean focusDisplayed = false; 8755 boolean updateAllDrawn = false; 8756 final int N = windows.size(); 8757 for (i=N-1; i>=0; i--) { 8758 WindowState w = windows.get(i); 8759 8760 final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured; 8761 8762 // Update effect. 8763 w.mObscured = mInnerFields.mObscured; 8764 if (!mInnerFields.mObscured) { 8765 handleNotObscuredLocked(w, currentTime, innerDw, innerDh); 8766 } 8767 8768 if (obscuredChanged && (mWallpaperTarget == w) && w.isVisibleLw()) { 8769 // This is the wallpaper target and its obscured state 8770 // changed... make sure the current wallaper's visibility 8771 // has been updated accordingly. 8772 updateWallpaperVisibilityLocked(); 8773 } 8774 8775 final WindowStateAnimator winAnimator = w.mWinAnimator; 8776 8777 // If the window has moved due to its containing 8778 // content frame changing, then we'd like to animate 8779 // it. 8780 if (w.mHasSurface && w.shouldAnimateMove()) { 8781 // Frame has moved, containing content frame 8782 // has also moved, and we're not currently animating... 8783 // let's do something. 8784 Animation a = AnimationUtils.loadAnimation(mContext, 8785 com.android.internal.R.anim.window_move_from_decor); 8786 winAnimator.setAnimation(a); 8787 winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left; 8788 winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top; 8789 try { 8790 w.mClient.moved(w.mFrame.left, w.mFrame.top); 8791 } catch (RemoteException e) { 8792 } 8793 } 8794 8795 //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); 8796 w.mContentChanged = false; 8797 8798 // Moved from updateWindowsAndWallpaperLocked(). 8799 if (w.mHasSurface) { 8800 // Take care of the window being ready to display. 8801 if (winAnimator.commitFinishDrawingLocked(currentTime)) { 8802 if ((w.mAttrs.flags 8803 & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { 8804 if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG, 8805 "First draw done in potential wallpaper target " + w); 8806 mInnerFields.mWallpaperMayChange = true; 8807 mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 8808 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { 8809 debugLayoutRepeats("wallpaper and commitFinishDrawingLocked true", 8810 mPendingLayoutChanges); 8811 } 8812 } 8813 } 8814 8815 winAnimator.setSurfaceBoundaries(recoveringMemory); 8816 8817 final AppWindowToken atoken = w.mAppToken; 8818 if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) { 8819 Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" 8820 + w.isOnScreen() + " allDrawn=" + atoken.allDrawn 8821 + " freezingScreen=" + atoken.mAppAnimator.freezingScreen); 8822 } 8823 if (atoken != null 8824 && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) { 8825 if (atoken.lastTransactionSequence != mTransactionSequence) { 8826 atoken.lastTransactionSequence = mTransactionSequence; 8827 atoken.numInterestingWindows = atoken.numDrawnWindows = 0; 8828 atoken.startingDisplayed = false; 8829 } 8830 if ((w.isOnScreen() || winAnimator.mAttrType 8831 == WindowManager.LayoutParams.TYPE_BASE_APPLICATION) 8832 && !w.mExiting && !w.mDestroying) { 8833 if (WindowManagerService.DEBUG_VISIBILITY || 8834 WindowManagerService.DEBUG_ORIENTATION) { 8835 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw() 8836 + ", isAnimating=" + winAnimator.isAnimating()); 8837 if (!w.isDrawnLw()) { 8838 Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface 8839 + " pv=" + w.mPolicyVisibility 8840 + " mDrawState=" + winAnimator.mDrawState 8841 + " ah=" + w.mAttachedHidden 8842 + " th=" + atoken.hiddenRequested 8843 + " a=" + winAnimator.mAnimating); 8844 } 8845 } 8846 if (w != atoken.startingWindow) { 8847 if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) { 8848 atoken.numInterestingWindows++; 8849 if (w.isDrawnLw()) { 8850 atoken.numDrawnWindows++; 8851 if (WindowManagerService.DEBUG_VISIBILITY || 8852 WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG, 8853 "tokenMayBeDrawn: " + atoken 8854 + " freezingScreen=" + atoken.mAppAnimator.freezingScreen 8855 + " mAppFreezing=" + w.mAppFreezing); 8856 updateAllDrawn = true; 8857 } 8858 } 8859 } else if (w.isDrawnLw()) { 8860 atoken.startingDisplayed = true; 8861 } 8862 } 8863 } 8864 } 8865 8866 if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) { 8867 focusDisplayed = true; 8868 } 8869 8870 updateResizingWindows(w); 8871 } 8872 8873 if (updateAllDrawn) { 8874 updateAllDrawnLocked(); 8875 } 8876 8877 if (focusDisplayed) { 8878 mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS); 8879 } 8880 8881 if (!mInnerFields.mDimming && mAnimator.isDimming()) { 8882 stopDimming(); 8883 } 8884 } catch (RuntimeException e) { 8885 Log.wtf(TAG, "Unhandled exception in Window Manager", e); 8886 } finally { 8887 Surface.closeTransaction(); 8888 } 8889 8890 // If we are ready to perform an app transition, check through 8891 // all of the app tokens to be shown and see if they are ready 8892 // to go. 8893 if (mAppTransitionReady) { 8894 mPendingLayoutChanges |= handleAppTransitionReadyLocked(windows); 8895 if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked", 8896 mPendingLayoutChanges); 8897 } 8898 8899 mInnerFields.mAdjResult = 0; 8900 8901 if (!mAnimator.mAnimating && mAppTransitionRunning) { 8902 // We have finished the animation of an app transition. To do 8903 // this, we have delayed a lot of operations like showing and 8904 // hiding apps, moving apps in Z-order, etc. The app token list 8905 // reflects the correct Z-order, but the window list may now 8906 // be out of sync with it. So here we will just rebuild the 8907 // entire app window list. Fun! 8908 mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked(); 8909 if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock", 8910 mPendingLayoutChanges); 8911 } 8912 8913 if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 && 8914 !mAppTransitionReady) { 8915 // At this point, there was a window with a wallpaper that 8916 // was force hiding other windows behind it, but now it 8917 // is going away. This may be simple -- just animate 8918 // away the wallpaper and its window -- or it may be 8919 // hard -- the wallpaper now needs to be shown behind 8920 // something that was hidden. 8921 mPendingLayoutChanges |= animateAwayWallpaperLocked(); 8922 if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked", 8923 mPendingLayoutChanges); 8924 } 8925 mInnerFields.mWallpaperForceHidingChanged = false; 8926 8927 if (mInnerFields.mWallpaperMayChange) { 8928 if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG, 8929 "Wallpaper may change! Adjusting"); 8930 mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked(); 8931 } 8932 8933 if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) { 8934 if (DEBUG_WALLPAPER) Slog.v(TAG, 8935 "Wallpaper layer changed: assigning layers + relayout"); 8936 mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; 8937 assignLayersLocked(windows); 8938 } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) { 8939 if (DEBUG_WALLPAPER) Slog.v(TAG, 8940 "Wallpaper visibility changed: relayout"); 8941 mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; 8942 } 8943 8944 if (mFocusMayChange) { 8945 mFocusMayChange = false; 8946 if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, 8947 false /*updateInputWindows*/)) { 8948 mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM; 8949 mInnerFields.mAdjResult = 0; 8950 } 8951 } 8952 8953 if (mLayoutNeeded) { 8954 mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; 8955 if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges); 8956 } 8957 8958 if (!mResizingWindows.isEmpty()) { 8959 for (i = mResizingWindows.size() - 1; i >= 0; i--) { 8960 WindowState win = mResizingWindows.get(i); 8961 final WindowStateAnimator winAnimator = win.mWinAnimator; 8962 try { 8963 if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, 8964 "Reporting new frame to " + win + ": " + win.mCompatFrame); 8965 int diff = 0; 8966 boolean configChanged = 8967 win.mConfiguration != mCurConfiguration 8968 && (win.mConfiguration == null 8969 || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0); 8970 if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) 8971 && configChanged) { 8972 Slog.i(TAG, "Sending new config to window " + win + ": " 8973 + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH 8974 + " / " + mCurConfiguration + " / 0x" 8975 + Integer.toHexString(diff)); 8976 } 8977 win.mConfiguration = mCurConfiguration; 8978 if (DEBUG_ORIENTATION && 8979 winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i( 8980 TAG, "Resizing " + win + " WITH DRAW PENDING"); 8981 win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets, 8982 winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING, 8983 configChanged ? win.mConfiguration : null); 8984 win.mContentInsetsChanged = false; 8985 win.mVisibleInsetsChanged = false; 8986 winAnimator.mSurfaceResized = false; 8987 } catch (RemoteException e) { 8988 win.mOrientationChanging = false; 8989 } 8990 } 8991 mResizingWindows.clear(); 8992 } 8993 8994 if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG, 8995 "With display frozen, orientationChangeComplete=" 8996 + mInnerFields.mOrientationChangeComplete); 8997 if (mInnerFields.mOrientationChangeComplete) { 8998 if (mWindowsFreezingScreen) { 8999 mWindowsFreezingScreen = false; 9000 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); 9001 } 9002 stopFreezingDisplayLocked(); 9003 } 9004 9005 // Destroy the surface of any windows that are no longer visible. 9006 boolean wallpaperDestroyed = false; 9007 i = mDestroySurface.size(); 9008 if (i > 0) { 9009 do { 9010 i--; 9011 WindowState win = mDestroySurface.get(i); 9012 win.mDestroying = false; 9013 if (mInputMethodWindow == win) { 9014 mInputMethodWindow = null; 9015 } 9016 if (win == mWallpaperTarget) { 9017 wallpaperDestroyed = true; 9018 } 9019 win.mWinAnimator.destroySurfaceLocked(); 9020 } while (i > 0); 9021 mDestroySurface.clear(); 9022 } 9023 9024 // Time to remove any exiting tokens? 9025 for (i=mExitingTokens.size()-1; i>=0; i--) { 9026 WindowToken token = mExitingTokens.get(i); 9027 if (!token.hasVisible) { 9028 mExitingTokens.remove(i); 9029 if (token.windowType == TYPE_WALLPAPER) { 9030 mWallpaperTokens.remove(token); 9031 updateLayoutToAnimWallpaperTokens(); 9032 } 9033 } 9034 } 9035 9036 // Time to remove any exiting applications? 9037 for (i=mExitingAppTokens.size()-1; i>=0; i--) { 9038 AppWindowToken token = mExitingAppTokens.get(i); 9039 if (!token.hasVisible && !mClosingApps.contains(token)) { 9040 // Make sure there is no animation running on this token, 9041 // so any windows associated with it will be removed as 9042 // soon as their animations are complete 9043 token.mAppAnimator.clearAnimation(); 9044 token.mAppAnimator.animating = false; 9045 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, 9046 "performLayout: App token exiting now removed" + token); 9047 mAppTokens.remove(token); 9048 mAnimatingAppTokens.remove(token); 9049 mExitingAppTokens.remove(i); 9050 } 9051 } 9052 9053 if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) { 9054 for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) { 9055 try { 9056 mRelayoutWhileAnimating.get(j).mClient.doneAnimating(); 9057 } catch (RemoteException e) { 9058 } 9059 } 9060 mRelayoutWhileAnimating.clear(); 9061 } 9062 9063 if (wallpaperDestroyed) { 9064 mLayoutNeeded |= adjustWallpaperWindowsLocked() != 0; 9065 } 9066 if (mPendingLayoutChanges != 0) { 9067 mLayoutNeeded = true; 9068 } 9069 9070 // Finally update all input windows now that the window changes have stabilized. 9071 mInputMonitor.updateInputWindowsLw(true /*force*/); 9072 9073 setHoldScreenLocked(mInnerFields.mHoldScreen != null); 9074 if (!mDisplayFrozen) { 9075 if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) { 9076 mPowerManager.setScreenBrightnessOverride(-1); 9077 } else { 9078 mPowerManager.setScreenBrightnessOverride((int) 9079 (mInnerFields.mScreenBrightness * PowerManager.BRIGHTNESS_ON)); 9080 } 9081 if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) { 9082 mPowerManager.setButtonBrightnessOverride(-1); 9083 } else { 9084 mPowerManager.setButtonBrightnessOverride((int) 9085 (mInnerFields.mButtonBrightness * PowerManager.BRIGHTNESS_ON)); 9086 } 9087 } 9088 if (mInnerFields.mHoldScreen != mHoldingScreenOn) { 9089 mHoldingScreenOn = mInnerFields.mHoldScreen; 9090 Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, mInnerFields.mHoldScreen); 9091 mH.sendMessage(m); 9092 } 9093 9094 if (mTurnOnScreen) { 9095 if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!"); 9096 mPowerManager.userActivity(SystemClock.uptimeMillis(), false, 9097 PowerManager.USER_ACTIVITY_EVENT_BUTTON, true); 9098 mTurnOnScreen = false; 9099 } 9100 9101 if (mInnerFields.mUpdateRotation) { 9102 if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); 9103 if (updateRotationUncheckedLocked(false)) { 9104 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 9105 } else { 9106 mInnerFields.mUpdateRotation = false; 9107 } 9108 } 9109 9110 if (mInnerFields.mOrientationChangeComplete && !mLayoutNeeded && 9111 !mInnerFields.mUpdateRotation) { 9112 checkDrawnWindowsLocked(); 9113 } 9114 9115 // Check to see if we are now in a state where the screen should 9116 // be enabled, because the window obscured flags have changed. 9117 enableScreenIfNeededLocked(); 9118 9119 updateLayoutToAnimationLocked(); 9120 9121 if (DEBUG_WINDOW_TRACE) { 9122 Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges=" 9123 + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded 9124 + " animating=" + mAnimator.mAnimating); 9125 } 9126 } 9127 9128 void checkDrawnWindowsLocked() { 9129 if (mWaitingForDrawn.size() > 0) { 9130 for (int j=mWaitingForDrawn.size()-1; j>=0; j--) { 9131 Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j); 9132 WindowState win = pair.first; 9133 //Slog.i(TAG, "Waiting for drawn " + win + ": removed=" 9134 // + win.mRemoved + " visible=" + win.isVisibleLw() 9135 // + " shown=" + win.mSurfaceShown); 9136 if (win.mRemoved || !win.isVisibleLw()) { 9137 // Window has been removed or made invisible; no draw 9138 // will now happen, so stop waiting. 9139 Slog.w(TAG, "Aborted waiting for drawn: " + pair.first); 9140 try { 9141 pair.second.sendResult(null); 9142 } catch (RemoteException e) { 9143 } 9144 mWaitingForDrawn.remove(pair); 9145 mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair); 9146 } else if (win.mWinAnimator.mSurfaceShown) { 9147 // Window is now drawn (and shown). 9148 try { 9149 pair.second.sendResult(null); 9150 } catch (RemoteException e) { 9151 } 9152 mWaitingForDrawn.remove(pair); 9153 mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair); 9154 } 9155 } 9156 } 9157 } 9158 9159 public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) { 9160 synchronized (mWindowMap) { 9161 WindowState win = windowForClientLocked(null, token, true); 9162 if (win != null) { 9163 Pair<WindowState, IRemoteCallback> pair = 9164 new Pair<WindowState, IRemoteCallback>(win, callback); 9165 Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair); 9166 mH.sendMessageDelayed(m, 2000); 9167 mWaitingForDrawn.add(pair); 9168 checkDrawnWindowsLocked(); 9169 } 9170 } 9171 } 9172 9173 /** 9174 * Must be called with the main window manager lock held. 9175 */ 9176 void setHoldScreenLocked(boolean holding) { 9177 boolean state = mHoldingScreenWakeLock.isHeld(); 9178 if (holding != state) { 9179 if (holding) { 9180 mPolicy.screenOnStartedLw(); 9181 mHoldingScreenWakeLock.acquire(); 9182 } else { 9183 mPolicy.screenOnStoppedLw(); 9184 mHoldingScreenWakeLock.release(); 9185 } 9186 } 9187 } 9188 9189 void requestTraversalLocked() { 9190 if (!mTraversalScheduled) { 9191 mTraversalScheduled = true; 9192 mH.sendEmptyMessage(H.DO_TRAVERSAL); 9193 } 9194 } 9195 9196 /** Note that Locked in this case is on mLayoutToAnim */ 9197 void scheduleAnimationLocked() { 9198 final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim; 9199 if (!layoutToAnim.mAnimationScheduled) { 9200 layoutToAnim.mAnimationScheduled = true; 9201 mChoreographer.postCallback( 9202 Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null); 9203 } 9204 } 9205 9206 void updateLayoutToAnimationLocked() { 9207 final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim; 9208 synchronized (layoutToAnim) { 9209 // Copy local params to transfer params. 9210 ArrayList<WinAnimatorList> allWinAnimatorLists = layoutToAnim.mWinAnimatorLists; 9211 allWinAnimatorLists.clear(); 9212 DisplayContentsIterator iterator = new DisplayContentsIterator(); 9213 while (iterator.hasNext()) { 9214 final DisplayContent displayContent = iterator.next(); 9215 WinAnimatorList winAnimatorList = new WinAnimatorList(); 9216 final WindowList windows = displayContent.getWindowList(); 9217 int N = windows.size(); 9218 for (int i = 0; i < N; i++) { 9219 final WindowStateAnimator winAnimator = windows.get(i).mWinAnimator; 9220 if (winAnimator.mSurface != null) { 9221 winAnimatorList.add(winAnimator); 9222 } 9223 } 9224 allWinAnimatorLists.add(winAnimatorList); 9225 } 9226 9227 layoutToAnim.mWallpaperTarget = mWallpaperTarget; 9228 layoutToAnim.mLowerWallpaperTarget = mLowerWallpaperTarget; 9229 layoutToAnim.mUpperWallpaperTarget = mUpperWallpaperTarget; 9230 9231 final ArrayList<AppWindowAnimParams> paramList = layoutToAnim.mAppWindowAnimParams; 9232 paramList.clear(); 9233 int N = mAnimatingAppTokens.size(); 9234 for (int i = 0; i < N; i++) { 9235 paramList.add(new AppWindowAnimParams(mAnimatingAppTokens.get(i).mAppAnimator)); 9236 } 9237 9238 layoutToAnim.mParamsModified = true; 9239 scheduleAnimationLocked(); 9240 } 9241 } 9242 9243 void updateLayoutToAnimWallpaperTokens() { 9244 synchronized(mLayoutToAnim) { 9245 mLayoutToAnim.mWallpaperTokens = new ArrayList<WindowToken>(mWallpaperTokens); 9246 mLayoutToAnim.mChanges |= LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED; 9247 } 9248 } 9249 9250 void setAnimDimParams(DimAnimator.Parameters params) { 9251 synchronized (mLayoutToAnim) { 9252 mLayoutToAnim.mDimParams = params; 9253 scheduleAnimationLocked(); 9254 } 9255 } 9256 9257 void startDimming(final WindowStateAnimator winAnimator, final float target, 9258 final int width, final int height) { 9259 setAnimDimParams(new DimAnimator.Parameters(winAnimator, width, height, target)); 9260 } 9261 9262 void stopDimming() { 9263 setAnimDimParams(null); 9264 } 9265 9266 private boolean copyAnimToLayoutParamsLocked() { 9267 boolean doRequest = false; 9268 final WindowAnimator.AnimatorToLayoutParams animToLayout = mAnimator.mAnimToLayout; 9269 synchronized (animToLayout) { 9270 animToLayout.mUpdateQueued = false; 9271 final int bulkUpdateParams = animToLayout.mBulkUpdateParams; 9272 // TODO(cmautner): As the number of bits grows, use masks of bit groups to 9273 // eliminate unnecessary tests. 9274 if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) { 9275 mInnerFields.mUpdateRotation = true; 9276 doRequest = true; 9277 } 9278 if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) { 9279 mInnerFields.mWallpaperMayChange = true; 9280 doRequest = true; 9281 } 9282 if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) { 9283 mInnerFields.mWallpaperForceHidingChanged = true; 9284 doRequest = true; 9285 } 9286 if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) { 9287 mInnerFields.mOrientationChangeComplete = false; 9288 } else { 9289 mInnerFields.mOrientationChangeComplete = true; 9290 if (mWindowsFreezingScreen) { 9291 doRequest = true; 9292 } 9293 } 9294 if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) { 9295 mTurnOnScreen = true; 9296 } 9297 9298 mPendingLayoutChanges |= animToLayout.mPendingLayoutChanges; 9299 if (mPendingLayoutChanges != 0) { 9300 doRequest = true; 9301 } 9302 9303 mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper; 9304 } 9305 return doRequest; 9306 } 9307 9308 boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation, 9309 boolean secure) { 9310 final Surface surface = winAnimator.mSurface; 9311 boolean leakedSurface = false; 9312 boolean killedApps = false; 9313 9314 EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(), 9315 winAnimator.mSession.mPid, operation); 9316 9317 if (mForceRemoves == null) { 9318 mForceRemoves = new ArrayList<WindowState>(); 9319 } 9320 9321 long callingIdentity = Binder.clearCallingIdentity(); 9322 try { 9323 // There was some problem... first, do a sanity check of the 9324 // window list to make sure we haven't left any dangling surfaces 9325 // around. 9326 9327 AllWindowsIterator iterator = new AllWindowsIterator(); 9328 Slog.i(TAG, "Out of memory for surface! Looking for leaks..."); 9329 while (iterator.hasNext()) { 9330 WindowState ws = iterator.next(); 9331 WindowStateAnimator wsa = ws.mWinAnimator; 9332 if (wsa.mSurface != null) { 9333 if (!mSessions.contains(wsa.mSession)) { 9334 Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): " 9335 + ws + " surface=" + wsa.mSurface 9336 + " token=" + ws.mToken 9337 + " pid=" + ws.mSession.mPid 9338 + " uid=" + ws.mSession.mUid); 9339 if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null); 9340 wsa.mSurface.destroy(); 9341 wsa.mSurfaceShown = false; 9342 wsa.mSurface = null; 9343 ws.mHasSurface = false; 9344 mForceRemoves.add(ws); 9345 leakedSurface = true; 9346 } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) { 9347 Slog.w(TAG, "LEAKED SURFACE (app token hidden): " 9348 + ws + " surface=" + wsa.mSurface 9349 + " token=" + ws.mAppToken); 9350 if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null); 9351 wsa.mSurface.destroy(); 9352 wsa.mSurfaceShown = false; 9353 wsa.mSurface = null; 9354 ws.mHasSurface = false; 9355 leakedSurface = true; 9356 } 9357 } 9358 } 9359 9360 if (!leakedSurface) { 9361 Slog.w(TAG, "No leaked surfaces; killing applicatons!"); 9362 SparseIntArray pidCandidates = new SparseIntArray(); 9363 iterator = new AllWindowsIterator(); 9364 while (iterator.hasNext()) { 9365 WindowState ws = iterator.next(); 9366 if (mForceRemoves.contains(ws)) { 9367 continue; 9368 } 9369 WindowStateAnimator wsa = ws.mWinAnimator; 9370 if (wsa.mSurface != null) { 9371 pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid); 9372 } 9373 } 9374 if (pidCandidates.size() > 0) { 9375 int[] pids = new int[pidCandidates.size()]; 9376 for (int i=0; i<pids.length; i++) { 9377 pids[i] = pidCandidates.keyAt(i); 9378 } 9379 try { 9380 if (mActivityManager.killPids(pids, "Free memory", secure)) { 9381 killedApps = true; 9382 } 9383 } catch (RemoteException e) { 9384 } 9385 } 9386 } 9387 9388 if (leakedSurface || killedApps) { 9389 // We managed to reclaim some memory, so get rid of the trouble 9390 // surface and ask the app to request another one. 9391 Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry."); 9392 if (surface != null) { 9393 if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin, 9394 "RECOVER DESTROY", null); 9395 surface.destroy(); 9396 winAnimator.mSurfaceShown = false; 9397 winAnimator.mSurface = null; 9398 winAnimator.mWin.mHasSurface = false; 9399 } 9400 9401 try { 9402 winAnimator.mWin.mClient.dispatchGetNewSurface(); 9403 } catch (RemoteException e) { 9404 } 9405 } 9406 } finally { 9407 Binder.restoreCallingIdentity(callingIdentity); 9408 } 9409 9410 return leakedSurface || killedApps; 9411 } 9412 9413 private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) { 9414 WindowState newFocus = computeFocusedWindowLocked(); 9415 if (mCurrentFocus != newFocus) { 9416 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus"); 9417 // This check makes sure that we don't already have the focus 9418 // change message pending. 9419 mH.removeMessages(H.REPORT_FOCUS_CHANGE); 9420 mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE); 9421 if (localLOGV) Slog.v( 9422 TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus); 9423 final WindowState oldFocus = mCurrentFocus; 9424 mCurrentFocus = newFocus; 9425 mAnimator.setCurrentFocus(newFocus); 9426 mLosingFocus.remove(newFocus); 9427 int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus); 9428 9429 // TODO(multidisplay): Focused windows on default display only. 9430 final DisplayContent displayContent = getDefaultDisplayContent(); 9431 9432 final WindowState imWindow = mInputMethodWindow; 9433 if (newFocus != imWindow && oldFocus != imWindow) { 9434 if (moveInputMethodWindowsIfNeededLocked( 9435 mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS && 9436 mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) { 9437 mLayoutNeeded = true; 9438 } 9439 if (mode == UPDATE_FOCUS_PLACING_SURFACES) { 9440 performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows); 9441 focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; 9442 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) { 9443 // Client will do the layout, but we need to assign layers 9444 // for handleNewWindowLocked() below. 9445 assignLayersLocked(displayContent.getWindowList()); 9446 } 9447 } 9448 9449 if ((focusChanged&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) { 9450 // The change in focus caused us to need to do a layout. Okay. 9451 mLayoutNeeded = true; 9452 if (mode == UPDATE_FOCUS_PLACING_SURFACES) { 9453 performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows); 9454 } 9455 } 9456 9457 if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) { 9458 // If we defer assigning layers, then the caller is responsible for 9459 // doing this part. 9460 finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows); 9461 } 9462 9463 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); 9464 return true; 9465 } 9466 return false; 9467 } 9468 9469 private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) { 9470 mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows); 9471 } 9472 9473 private WindowState computeFocusedWindowLocked() { 9474 WindowState result = null; 9475 WindowState win; 9476 9477 if (mAnimator.mUniverseBackground != null 9478 && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) { 9479 return mAnimator.mUniverseBackground.mWin; 9480 } 9481 9482 int nextAppIndex = mAppTokens.size()-1; 9483 WindowToken nextApp = nextAppIndex >= 0 9484 ? mAppTokens.get(nextAppIndex) : null; 9485 9486 // TODO(multidisplay): IMEs are only supported on the default display. 9487 WindowList windows = getDefaultWindowList(); 9488 for (int i = windows.size() - 1; i >= 0; i--) { 9489 win = windows.get(i); 9490 9491 if (localLOGV || DEBUG_FOCUS) Slog.v( 9492 TAG, "Looking for focus: " + i 9493 + " = " + win 9494 + ", flags=" + win.mAttrs.flags 9495 + ", canReceive=" + win.canReceiveKeys()); 9496 9497 AppWindowToken thisApp = win.mAppToken; 9498 9499 // If this window's application has been removed, just skip it. 9500 if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) { 9501 if (DEBUG_FOCUS) Slog.v(TAG, "Skipping app because " + (thisApp.removed 9502 ? "removed" : "sendingToBottom")); 9503 continue; 9504 } 9505 9506 // If there is a focused app, don't allow focus to go to any 9507 // windows below it. If this is an application window, step 9508 // through the app tokens until we find its app. 9509 if (thisApp != null && nextApp != null && thisApp != nextApp 9510 && win.mAttrs.type != TYPE_APPLICATION_STARTING) { 9511 int origAppIndex = nextAppIndex; 9512 while (nextAppIndex > 0) { 9513 if (nextApp == mFocusedApp) { 9514 // Whoops, we are below the focused app... no focus 9515 // for you! 9516 if (localLOGV || DEBUG_FOCUS) Slog.v( 9517 TAG, "Reached focused app: " + mFocusedApp); 9518 return null; 9519 } 9520 nextAppIndex--; 9521 nextApp = mAppTokens.get(nextAppIndex); 9522 if (nextApp == thisApp) { 9523 break; 9524 } 9525 } 9526 if (thisApp != nextApp) { 9527 // Uh oh, the app token doesn't exist! This shouldn't 9528 // happen, but if it does we can get totally hosed... 9529 // so restart at the original app. 9530 nextAppIndex = origAppIndex; 9531 nextApp = mAppTokens.get(nextAppIndex); 9532 } 9533 } 9534 9535 // Dispatch to this window if it is wants key events. 9536 if (win.canReceiveKeys()) { 9537 if (DEBUG_FOCUS) Slog.v( 9538 TAG, "Found focus @ " + i + " = " + win); 9539 result = win; 9540 break; 9541 } 9542 } 9543 9544 return result; 9545 } 9546 9547 private void startFreezingDisplayLocked(boolean inTransaction) { 9548 if (mDisplayFrozen) { 9549 return; 9550 } 9551 9552 if (mDisplay == null || !mPolicy.isScreenOnFully()) { 9553 // No need to freeze the screen before the system is ready or if 9554 // the screen is off. 9555 return; 9556 } 9557 9558 mScreenFrozenLock.acquire(); 9559 9560 mDisplayFrozen = true; 9561 9562 mInputMonitor.freezeInputDispatchingLw(); 9563 9564 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 9565 mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET; 9566 mNextAppTransitionType = ActivityOptions.ANIM_NONE; 9567 mNextAppTransitionPackage = null; 9568 mNextAppTransitionThumbnail = null; 9569 mAppTransitionReady = true; 9570 } 9571 9572 if (PROFILE_ORIENTATION) { 9573 File file = new File("/data/system/frozen"); 9574 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024); 9575 } 9576 9577 if (CUSTOM_SCREEN_ROTATION) { 9578 if (mAnimator.mScreenRotationAnimation != null) { 9579 mAnimator.mScreenRotationAnimation.kill(); 9580 mAnimator.mScreenRotationAnimation = null; 9581 } 9582 9583 // TODO(multidisplay): rotation on main screen only. 9584 DisplayInfo displayInfo = getDefaultDisplayContent().getDisplayInfo(); 9585 mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext, 9586 mFxSession, inTransaction, displayInfo.logicalWidth, displayInfo.logicalHeight, 9587 mDisplay.getRotation()); 9588 } 9589 } 9590 9591 private void stopFreezingDisplayLocked() { 9592 if (!mDisplayFrozen) { 9593 return; 9594 } 9595 9596 if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) { 9597 if (DEBUG_ORIENTATION) Slog.d(TAG, 9598 "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig 9599 + ", mAppsFreezingScreen=" + mAppsFreezingScreen 9600 + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen); 9601 return; 9602 } 9603 9604 mDisplayFrozen = false; 9605 mH.removeMessages(H.APP_FREEZE_TIMEOUT); 9606 if (PROFILE_ORIENTATION) { 9607 Debug.stopMethodTracing(); 9608 } 9609 9610 boolean updateRotation = false; 9611 9612 if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null 9613 && mAnimator.mScreenRotationAnimation.hasScreenshot()) { 9614 if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation"); 9615 // TODO(multidisplay): rotation on main screen only. 9616 DisplayInfo displayInfo = getDefaultDisplayContent().getDisplayInfo(); 9617 if (mAnimator.mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION, 9618 mTransitionAnimationScale, displayInfo.logicalWidth, 9619 displayInfo.logicalHeight)) { 9620 updateLayoutToAnimationLocked(); 9621 } else { 9622 mAnimator.mScreenRotationAnimation.kill(); 9623 mAnimator.mScreenRotationAnimation = null; 9624 updateRotation = true; 9625 } 9626 } else { 9627 if (mAnimator.mScreenRotationAnimation != null) { 9628 mAnimator.mScreenRotationAnimation.kill(); 9629 mAnimator.mScreenRotationAnimation = null; 9630 } 9631 updateRotation = true; 9632 } 9633 9634 mInputMonitor.thawInputDispatchingLw(); 9635 9636 boolean configChanged; 9637 9638 // While the display is frozen we don't re-compute the orientation 9639 // to avoid inconsistent states. However, something interesting 9640 // could have actually changed during that time so re-evaluate it 9641 // now to catch that. 9642 configChanged = updateOrientationFromAppTokensLocked(false); 9643 9644 // A little kludge: a lot could have happened while the 9645 // display was frozen, so now that we are coming back we 9646 // do a gc so that any remote references the system 9647 // processes holds on others can be released if they are 9648 // no longer needed. 9649 mH.removeMessages(H.FORCE_GC); 9650 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC), 9651 2000); 9652 9653 mScreenFrozenLock.release(); 9654 9655 if (updateRotation) { 9656 if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); 9657 configChanged |= updateRotationUncheckedLocked(false); 9658 } 9659 9660 if (configChanged) { 9661 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 9662 } 9663 } 9664 9665 static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps, 9666 DisplayMetrics dm) { 9667 if (index < tokens.length) { 9668 String str = tokens[index]; 9669 if (str != null && str.length() > 0) { 9670 try { 9671 int val = Integer.parseInt(str); 9672 return val; 9673 } catch (Exception e) { 9674 } 9675 } 9676 } 9677 if (defUnits == TypedValue.COMPLEX_UNIT_PX) { 9678 return defDps; 9679 } 9680 int val = (int)TypedValue.applyDimension(defUnits, defDps, dm); 9681 return val; 9682 } 9683 9684 void createWatermark() { 9685 if (mWatermark != null) { 9686 return; 9687 } 9688 9689 File file = new File("/system/etc/setup.conf"); 9690 FileInputStream in = null; 9691 try { 9692 in = new FileInputStream(file); 9693 DataInputStream ind = new DataInputStream(in); 9694 String line = ind.readLine(); 9695 if (line != null) { 9696 String[] toks = line.split("%"); 9697 if (toks != null && toks.length > 0) { 9698 mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks); 9699 } 9700 } 9701 } catch (FileNotFoundException e) { 9702 } catch (IOException e) { 9703 } finally { 9704 if (in != null) { 9705 try { 9706 in.close(); 9707 } catch (IOException e) { 9708 } 9709 } 9710 } 9711 } 9712 9713 @Override 9714 public void statusBarVisibilityChanged(int visibility) { 9715 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) 9716 != PackageManager.PERMISSION_GRANTED) { 9717 throw new SecurityException("Caller does not hold permission " 9718 + android.Manifest.permission.STATUS_BAR); 9719 } 9720 9721 synchronized (mWindowMap) { 9722 mLastStatusBarVisibility = visibility; 9723 visibility = mPolicy.adjustSystemUiVisibilityLw(visibility); 9724 updateStatusBarVisibilityLocked(visibility); 9725 } 9726 } 9727 9728 // TOOD(multidisplay): StatusBar on multiple screens? 9729 void updateStatusBarVisibilityLocked(int visibility) { 9730 mInputManager.setSystemUiVisibility(visibility); 9731 final WindowList windows = getDefaultWindowList(); 9732 final int N = windows.size(); 9733 for (int i = 0; i < N; i++) { 9734 WindowState ws = windows.get(i); 9735 try { 9736 int curValue = ws.mSystemUiVisibility; 9737 int diff = curValue ^ visibility; 9738 // We are only interested in differences of one of the 9739 // clearable flags... 9740 diff &= View.SYSTEM_UI_CLEARABLE_FLAGS; 9741 // ...if it has actually been cleared. 9742 diff &= ~visibility; 9743 int newValue = (curValue&~diff) | (visibility&diff); 9744 if (newValue != curValue) { 9745 ws.mSeq++; 9746 ws.mSystemUiVisibility = newValue; 9747 } 9748 if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) { 9749 ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq, 9750 visibility, newValue, diff); 9751 } 9752 } catch (RemoteException e) { 9753 // so sorry 9754 } 9755 } 9756 } 9757 9758 @Override 9759 public void reevaluateStatusBarVisibility() { 9760 synchronized (mWindowMap) { 9761 int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility); 9762 updateStatusBarVisibilityLocked(visibility); 9763 performLayoutAndPlaceSurfacesLocked(); 9764 } 9765 } 9766 9767 @Override 9768 public FakeWindow addFakeWindow(Looper looper, 9769 InputEventReceiver.Factory inputEventReceiverFactory, 9770 String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys, 9771 boolean hasFocus, boolean touchFullscreen) { 9772 synchronized (mWindowMap) { 9773 FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory, 9774 name, windowType, 9775 layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen); 9776 int i=0; 9777 while (i<mFakeWindows.size()) { 9778 if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) { 9779 break; 9780 } 9781 } 9782 mFakeWindows.add(i, fw); 9783 mInputMonitor.updateInputWindowsLw(true); 9784 return fw; 9785 } 9786 } 9787 9788 boolean removeFakeWindowLocked(FakeWindow window) { 9789 synchronized (mWindowMap) { 9790 if (mFakeWindows.remove(window)) { 9791 mInputMonitor.updateInputWindowsLw(true); 9792 return true; 9793 } 9794 return false; 9795 } 9796 } 9797 9798 // It is assumed that this method is called only by InputMethodManagerService. 9799 public void saveLastInputMethodWindowForTransition() { 9800 synchronized (mWindowMap) { 9801 // TODO(multidisplay): Pass in the displayID. 9802 DisplayContent displayContent = getDefaultDisplayContent(); 9803 if (mInputMethodWindow != null) { 9804 mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget); 9805 } 9806 } 9807 } 9808 9809 @Override 9810 public boolean hasNavigationBar() { 9811 return mPolicy.hasNavigationBar(); 9812 } 9813 9814 public void lockNow() { 9815 mPolicy.lockNow(); 9816 } 9817 9818 void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) { 9819 pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)"); 9820 mPolicy.dump(" ", pw, args); 9821 } 9822 9823 void dumpTokensLocked(PrintWriter pw, boolean dumpAll) { 9824 pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)"); 9825 if (mTokenMap.size() > 0) { 9826 pw.println(" All tokens:"); 9827 Iterator<WindowToken> it = mTokenMap.values().iterator(); 9828 while (it.hasNext()) { 9829 WindowToken token = it.next(); 9830 pw.print(" Token "); pw.print(token.token); 9831 if (dumpAll) { 9832 pw.println(':'); 9833 token.dump(pw, " "); 9834 } else { 9835 pw.println(); 9836 } 9837 } 9838 } 9839 if (mWallpaperTokens.size() > 0) { 9840 pw.println(); 9841 pw.println(" Wallpaper tokens:"); 9842 for (int i=mWallpaperTokens.size()-1; i>=0; i--) { 9843 WindowToken token = mWallpaperTokens.get(i); 9844 pw.print(" Wallpaper #"); pw.print(i); 9845 pw.print(' '); pw.print(token); 9846 if (dumpAll) { 9847 pw.println(':'); 9848 token.dump(pw, " "); 9849 } else { 9850 pw.println(); 9851 } 9852 } 9853 } 9854 if (mAppTokens.size() > 0) { 9855 pw.println(); 9856 pw.println(" Application tokens in Z order:"); 9857 for (int i=mAppTokens.size()-1; i>=0; i--) { 9858 pw.print(" App #"); pw.print(i); pw.println(": "); 9859 mAppTokens.get(i).dump(pw, " "); 9860 } 9861 } 9862 if (mFinishedStarting.size() > 0) { 9863 pw.println(); 9864 pw.println(" Finishing start of application tokens:"); 9865 for (int i=mFinishedStarting.size()-1; i>=0; i--) { 9866 WindowToken token = mFinishedStarting.get(i); 9867 pw.print(" Finished Starting #"); pw.print(i); 9868 pw.print(' '); pw.print(token); 9869 if (dumpAll) { 9870 pw.println(':'); 9871 token.dump(pw, " "); 9872 } else { 9873 pw.println(); 9874 } 9875 } 9876 } 9877 if (mExitingTokens.size() > 0) { 9878 pw.println(); 9879 pw.println(" Exiting tokens:"); 9880 for (int i=mExitingTokens.size()-1; i>=0; i--) { 9881 WindowToken token = mExitingTokens.get(i); 9882 pw.print(" Exiting #"); pw.print(i); 9883 pw.print(' '); pw.print(token); 9884 if (dumpAll) { 9885 pw.println(':'); 9886 token.dump(pw, " "); 9887 } else { 9888 pw.println(); 9889 } 9890 } 9891 } 9892 if (mExitingAppTokens.size() > 0) { 9893 pw.println(); 9894 pw.println(" Exiting application tokens:"); 9895 for (int i=mExitingAppTokens.size()-1; i>=0; i--) { 9896 WindowToken token = mExitingAppTokens.get(i); 9897 pw.print(" Exiting App #"); pw.print(i); 9898 pw.print(' '); pw.print(token); 9899 if (dumpAll) { 9900 pw.println(':'); 9901 token.dump(pw, " "); 9902 } else { 9903 pw.println(); 9904 } 9905 } 9906 } 9907 if (mAppTransitionRunning && mAnimatingAppTokens.size() > 0) { 9908 pw.println(); 9909 pw.println(" Application tokens during animation:"); 9910 for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) { 9911 WindowToken token = mAnimatingAppTokens.get(i); 9912 pw.print(" App moving to bottom #"); pw.print(i); 9913 pw.print(' '); pw.print(token); 9914 if (dumpAll) { 9915 pw.println(':'); 9916 token.dump(pw, " "); 9917 } else { 9918 pw.println(); 9919 } 9920 } 9921 } 9922 if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) { 9923 pw.println(); 9924 if (mOpeningApps.size() > 0) { 9925 pw.print(" mOpeningApps="); pw.println(mOpeningApps); 9926 } 9927 if (mClosingApps.size() > 0) { 9928 pw.print(" mClosingApps="); pw.println(mClosingApps); 9929 } 9930 } 9931 } 9932 9933 void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) { 9934 pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)"); 9935 if (mSessions.size() > 0) { 9936 Iterator<Session> it = mSessions.iterator(); 9937 while (it.hasNext()) { 9938 Session s = it.next(); 9939 pw.print(" Session "); pw.print(s); pw.println(':'); 9940 s.dump(pw, " "); 9941 } 9942 } 9943 } 9944 9945 void dumpWindowsLocked(PrintWriter pw, boolean dumpAll, 9946 ArrayList<WindowState> windows) { 9947 pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)"); 9948 dumpWindowsNoHeaderLocked(pw, dumpAll, windows); 9949 } 9950 9951 void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll, 9952 ArrayList<WindowState> windows) { 9953 int j = 0; 9954 final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR); 9955 while (iterator.hasNext()) { 9956 final WindowState w = iterator.next(); 9957 if (windows == null || windows.contains(w)) { 9958 pw.print(" Window #"); pw.print(j++); pw.print(' '); 9959 pw.print(w); pw.println(":"); 9960 w.dump(pw, " ", dumpAll || windows != null); 9961 } 9962 } 9963 if (mInputMethodDialogs.size() > 0) { 9964 pw.println(); 9965 pw.println(" Input method dialogs:"); 9966 for (int i=mInputMethodDialogs.size()-1; i>=0; i--) { 9967 WindowState w = mInputMethodDialogs.get(i); 9968 if (windows == null || windows.contains(w)) { 9969 pw.print(" IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w); 9970 } 9971 } 9972 } 9973 if (mPendingRemove.size() > 0) { 9974 pw.println(); 9975 pw.println(" Remove pending for:"); 9976 for (int i=mPendingRemove.size()-1; i>=0; i--) { 9977 WindowState w = mPendingRemove.get(i); 9978 if (windows == null || windows.contains(w)) { 9979 pw.print(" Remove #"); pw.print(i); pw.print(' '); 9980 pw.print(w); 9981 if (dumpAll) { 9982 pw.println(":"); 9983 w.dump(pw, " ", true); 9984 } else { 9985 pw.println(); 9986 } 9987 } 9988 } 9989 } 9990 if (mForceRemoves != null && mForceRemoves.size() > 0) { 9991 pw.println(); 9992 pw.println(" Windows force removing:"); 9993 for (int i=mForceRemoves.size()-1; i>=0; i--) { 9994 WindowState w = mForceRemoves.get(i); 9995 pw.print(" Removing #"); pw.print(i); pw.print(' '); 9996 pw.print(w); 9997 if (dumpAll) { 9998 pw.println(":"); 9999 w.dump(pw, " ", true); 10000 } else { 10001 pw.println(); 10002 } 10003 } 10004 } 10005 if (mDestroySurface.size() > 0) { 10006 pw.println(); 10007 pw.println(" Windows waiting to destroy their surface:"); 10008 for (int i=mDestroySurface.size()-1; i>=0; i--) { 10009 WindowState w = mDestroySurface.get(i); 10010 if (windows == null || windows.contains(w)) { 10011 pw.print(" Destroy #"); pw.print(i); pw.print(' '); 10012 pw.print(w); 10013 if (dumpAll) { 10014 pw.println(":"); 10015 w.dump(pw, " ", true); 10016 } else { 10017 pw.println(); 10018 } 10019 } 10020 } 10021 } 10022 if (mLosingFocus.size() > 0) { 10023 pw.println(); 10024 pw.println(" Windows losing focus:"); 10025 for (int i=mLosingFocus.size()-1; i>=0; i--) { 10026 WindowState w = mLosingFocus.get(i); 10027 if (windows == null || windows.contains(w)) { 10028 pw.print(" Losing #"); pw.print(i); pw.print(' '); 10029 pw.print(w); 10030 if (dumpAll) { 10031 pw.println(":"); 10032 w.dump(pw, " ", true); 10033 } else { 10034 pw.println(); 10035 } 10036 } 10037 } 10038 } 10039 if (mResizingWindows.size() > 0) { 10040 pw.println(); 10041 pw.println(" Windows waiting to resize:"); 10042 for (int i=mResizingWindows.size()-1; i>=0; i--) { 10043 WindowState w = mResizingWindows.get(i); 10044 if (windows == null || windows.contains(w)) { 10045 pw.print(" Resizing #"); pw.print(i); pw.print(' '); 10046 pw.print(w); 10047 if (dumpAll) { 10048 pw.println(":"); 10049 w.dump(pw, " ", true); 10050 } else { 10051 pw.println(); 10052 } 10053 } 10054 } 10055 } 10056 if (mWaitingForDrawn.size() > 0) { 10057 pw.println(); 10058 pw.println(" Clients waiting for these windows to be drawn:"); 10059 for (int i=mWaitingForDrawn.size()-1; i>=0; i--) { 10060 Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i); 10061 pw.print(" Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first); 10062 pw.print(": "); pw.println(pair.second); 10063 } 10064 } 10065 pw.println(); 10066 if (mDisplay != null) { 10067 DisplayContentsIterator dCIterator = new DisplayContentsIterator(); 10068 while (dCIterator.hasNext()) { 10069 dCIterator.next().dump(pw); 10070 } 10071 } else { 10072 pw.println(" NO DISPLAY"); 10073 } 10074 pw.print(" mCurConfiguration="); pw.println(this.mCurConfiguration); 10075 pw.print(" mCurrentFocus="); pw.println(mCurrentFocus); 10076 if (mLastFocus != mCurrentFocus) { 10077 pw.print(" mLastFocus="); pw.println(mLastFocus); 10078 } 10079 pw.print(" mFocusedApp="); pw.println(mFocusedApp); 10080 if (mInputMethodTarget != null) { 10081 pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget); 10082 } 10083 pw.print(" mInTouchMode="); pw.print(mInTouchMode); 10084 pw.print(" mLayoutSeq="); pw.println(mLayoutSeq); 10085 if (dumpAll) { 10086 pw.print(" mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString()); 10087 pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer); 10088 pw.print(" mScreenRecr="); pw.println(mScreenRect.toShortString()); 10089 if (mLastStatusBarVisibility != 0) { 10090 pw.print(" mLastStatusBarVisibility=0x"); 10091 pw.println(Integer.toHexString(mLastStatusBarVisibility)); 10092 } 10093 if (mInputMethodWindow != null) { 10094 pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow); 10095 } 10096 pw.print(" mWallpaperTarget="); pw.println(mWallpaperTarget); 10097 if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) { 10098 pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget); 10099 pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget); 10100 } 10101 pw.print(" mLastWallpaperX="); pw.print(mLastWallpaperX); 10102 pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); 10103 if (mInputMethodAnimLayerAdjustment != 0 || 10104 mWallpaperAnimLayerAdjustment != 0) { 10105 pw.print(" mInputMethodAnimLayerAdjustment="); 10106 pw.print(mInputMethodAnimLayerAdjustment); 10107 pw.print(" mWallpaperAnimLayerAdjustment="); 10108 pw.println(mWallpaperAnimLayerAdjustment); 10109 } 10110 pw.print(" mSystemBooted="); pw.print(mSystemBooted); 10111 pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled); 10112 pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded); 10113 pw.print("mTransactionSequence="); pw.println(mTransactionSequence); 10114 pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen); 10115 pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen); 10116 pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen); 10117 pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig); 10118 pw.print(" mRotation="); pw.print(mRotation); 10119 pw.print(" mAltOrientation="); pw.println(mAltOrientation); 10120 pw.print(" mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation); 10121 pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation); 10122 pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount); 10123 if (mAnimator.mScreenRotationAnimation != null) { 10124 pw.println(" mScreenRotationAnimation:"); 10125 mAnimator.mScreenRotationAnimation.printTo(" ", pw); 10126 } 10127 pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale); 10128 pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale); 10129 pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale); 10130 pw.print(" mTraversalScheduled="); pw.print(mTraversalScheduled); 10131 pw.print(" mNextAppTransition=0x"); 10132 pw.print(Integer.toHexString(mNextAppTransition)); 10133 pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady); 10134 pw.print(" mAppTransitionRunning="); pw.print(mAppTransitionRunning); 10135 pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout); 10136 if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) { 10137 pw.print(" mNextAppTransitionType="); pw.println(mNextAppTransitionType); 10138 } 10139 switch (mNextAppTransitionType) { 10140 case ActivityOptions.ANIM_CUSTOM: 10141 pw.print(" mNextAppTransitionPackage="); 10142 pw.println(mNextAppTransitionPackage); 10143 pw.print(" mNextAppTransitionEnter=0x"); 10144 pw.print(Integer.toHexString(mNextAppTransitionEnter)); 10145 pw.print(" mNextAppTransitionExit=0x"); 10146 pw.println(Integer.toHexString(mNextAppTransitionExit)); 10147 break; 10148 case ActivityOptions.ANIM_SCALE_UP: 10149 pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX); 10150 pw.print(" mNextAppTransitionStartY="); 10151 pw.println(mNextAppTransitionStartY); 10152 pw.print(" mNextAppTransitionStartWidth="); 10153 pw.print(mNextAppTransitionStartWidth); 10154 pw.print(" mNextAppTransitionStartHeight="); 10155 pw.println(mNextAppTransitionStartHeight); 10156 break; 10157 case ActivityOptions.ANIM_THUMBNAIL: 10158 case ActivityOptions.ANIM_THUMBNAIL_DELAYED: 10159 pw.print(" mNextAppTransitionThumbnail="); 10160 pw.print(mNextAppTransitionThumbnail); 10161 pw.print(" mNextAppTransitionStartX="); 10162 pw.print(mNextAppTransitionStartX); 10163 pw.print(" mNextAppTransitionStartY="); 10164 pw.println(mNextAppTransitionStartY); 10165 pw.print(" mNextAppTransitionDelayed="); pw.println(mNextAppTransitionDelayed); 10166 break; 10167 } 10168 if (mNextAppTransitionCallback != null) { 10169 pw.print(" mNextAppTransitionCallback="); 10170 pw.println(mNextAppTransitionCallback); 10171 } 10172 pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition); 10173 pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation); 10174 pw.println(" Window Animator:"); 10175 mAnimator.dump(pw, " ", dumpAll); 10176 } 10177 } 10178 10179 boolean dumpWindows(PrintWriter pw, String name, String[] args, 10180 int opti, boolean dumpAll) { 10181 ArrayList<WindowState> windows = new ArrayList<WindowState>(); 10182 if ("visible".equals(name)) { 10183 synchronized(mWindowMap) { 10184 final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR); 10185 while (iterator.hasNext()) { 10186 final WindowState w = iterator.next(); 10187 if (w.mWinAnimator.mSurfaceShown) { 10188 windows.add(w); 10189 } 10190 } 10191 } 10192 } else { 10193 int objectId = 0; 10194 // See if this is an object ID. 10195 try { 10196 objectId = Integer.parseInt(name, 16); 10197 name = null; 10198 } catch (RuntimeException e) { 10199 } 10200 synchronized(mWindowMap) { 10201 final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR); 10202 while (iterator.hasNext()) { 10203 final WindowState w = iterator.next(); 10204 if (name != null) { 10205 if (w.mAttrs.getTitle().toString().contains(name)) { 10206 windows.add(w); 10207 } 10208 } else if (System.identityHashCode(w) == objectId) { 10209 windows.add(w); 10210 } 10211 } 10212 } 10213 } 10214 10215 if (windows.size() <= 0) { 10216 return false; 10217 } 10218 10219 synchronized(mWindowMap) { 10220 dumpWindowsLocked(pw, dumpAll, windows); 10221 } 10222 return true; 10223 } 10224 10225 void dumpLastANRLocked(PrintWriter pw) { 10226 pw.println("WINDOW MANAGER LAST ANR (dumpsys window lastanr)"); 10227 if (mLastANRState == null) { 10228 pw.println(" <no ANR has occurred since boot>"); 10229 } else { 10230 pw.println(mLastANRState); 10231 } 10232 } 10233 10234 /** 10235 * Saves information about the state of the window manager at 10236 * the time an ANR occurred before anything else in the system changes 10237 * in response. 10238 * 10239 * @param appWindowToken The application that ANR'd, may be null. 10240 * @param windowState The window that ANR'd, may be null. 10241 */ 10242 public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState) { 10243 StringWriter sw = new StringWriter(); 10244 PrintWriter pw = new PrintWriter(sw); 10245 pw.println(" ANR time: " + DateFormat.getInstance().format(new Date())); 10246 if (appWindowToken != null) { 10247 pw.println(" Application at fault: " + appWindowToken.stringName); 10248 } 10249 if (windowState != null) { 10250 pw.println(" Window at fault: " + windowState.mAttrs.getTitle()); 10251 } 10252 pw.println(); 10253 dumpWindowsNoHeaderLocked(pw, true, null); 10254 pw.close(); 10255 mLastANRState = sw.toString(); 10256 } 10257 10258 @Override 10259 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 10260 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP") 10261 != PackageManager.PERMISSION_GRANTED) { 10262 pw.println("Permission Denial: can't dump WindowManager from from pid=" 10263 + Binder.getCallingPid() 10264 + ", uid=" + Binder.getCallingUid()); 10265 return; 10266 } 10267 10268 boolean dumpAll = false; 10269 10270 int opti = 0; 10271 while (opti < args.length) { 10272 String opt = args[opti]; 10273 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { 10274 break; 10275 } 10276 opti++; 10277 if ("-a".equals(opt)) { 10278 dumpAll = true; 10279 } else if ("-h".equals(opt)) { 10280 pw.println("Window manager dump options:"); 10281 pw.println(" [-a] [-h] [cmd] ..."); 10282 pw.println(" cmd may be one of:"); 10283 pw.println(" l[astanr]: last ANR information"); 10284 pw.println(" p[policy]: policy state"); 10285 pw.println(" s[essions]: active sessions"); 10286 pw.println(" t[okens]: token list"); 10287 pw.println(" w[indows]: window list"); 10288 pw.println(" cmd may also be a NAME to dump windows. NAME may"); 10289 pw.println(" be a partial substring in a window name, a"); 10290 pw.println(" Window hex object identifier, or"); 10291 pw.println(" \"all\" for all windows, or"); 10292 pw.println(" \"visible\" for the visible windows."); 10293 pw.println(" -a: include all available server state."); 10294 return; 10295 } else { 10296 pw.println("Unknown argument: " + opt + "; use -h for help"); 10297 } 10298 } 10299 10300 // Is the caller requesting to dump a particular piece of data? 10301 if (opti < args.length) { 10302 String cmd = args[opti]; 10303 opti++; 10304 if ("lastanr".equals(cmd) || "l".equals(cmd)) { 10305 synchronized(mWindowMap) { 10306 dumpLastANRLocked(pw); 10307 } 10308 return; 10309 } else if ("policy".equals(cmd) || "p".equals(cmd)) { 10310 synchronized(mWindowMap) { 10311 dumpPolicyLocked(pw, args, true); 10312 } 10313 return; 10314 } else if ("sessions".equals(cmd) || "s".equals(cmd)) { 10315 synchronized(mWindowMap) { 10316 dumpSessionsLocked(pw, true); 10317 } 10318 return; 10319 } else if ("tokens".equals(cmd) || "t".equals(cmd)) { 10320 synchronized(mWindowMap) { 10321 dumpTokensLocked(pw, true); 10322 } 10323 return; 10324 } else if ("windows".equals(cmd) || "w".equals(cmd)) { 10325 synchronized(mWindowMap) { 10326 dumpWindowsLocked(pw, true, null); 10327 } 10328 return; 10329 } else if ("all".equals(cmd) || "a".equals(cmd)) { 10330 synchronized(mWindowMap) { 10331 dumpWindowsLocked(pw, true, null); 10332 } 10333 return; 10334 } else { 10335 // Dumping a single name? 10336 if (!dumpWindows(pw, cmd, args, opti, dumpAll)) { 10337 pw.println("Bad window command, or no windows match: " + cmd); 10338 pw.println("Use -h for help."); 10339 } 10340 return; 10341 } 10342 } 10343 10344 synchronized(mWindowMap) { 10345 pw.println(); 10346 if (dumpAll) { 10347 pw.println("-------------------------------------------------------------------------------"); 10348 } 10349 dumpLastANRLocked(pw); 10350 pw.println(); 10351 if (dumpAll) { 10352 pw.println("-------------------------------------------------------------------------------"); 10353 } 10354 dumpPolicyLocked(pw, args, dumpAll); 10355 pw.println(); 10356 if (dumpAll) { 10357 pw.println("-------------------------------------------------------------------------------"); 10358 } 10359 dumpSessionsLocked(pw, dumpAll); 10360 pw.println(); 10361 if (dumpAll) { 10362 pw.println("-------------------------------------------------------------------------------"); 10363 } 10364 dumpTokensLocked(pw, dumpAll); 10365 pw.println(); 10366 if (dumpAll) { 10367 pw.println("-------------------------------------------------------------------------------"); 10368 } 10369 dumpWindowsLocked(pw, dumpAll, null); 10370 } 10371 } 10372 10373 // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection). 10374 public void monitor() { 10375 synchronized (mWindowMap) { } 10376 synchronized (mKeyguardTokenWatcher) { } 10377 } 10378 10379 public interface OnHardKeyboardStatusChangeListener { 10380 public void onHardKeyboardStatusChange(boolean available, boolean enabled); 10381 } 10382 10383 void debugLayoutRepeats(final String msg, int pendingLayoutChanges) { 10384 if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) { 10385 Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" + 10386 Integer.toHexString(pendingLayoutChanges)); 10387 } 10388 } 10389 10390 public DisplayContent getDisplayContent(final int displayId) { 10391 DisplayContent displayContent = mDisplayContents.get(displayId); 10392 if (displayContent == null) { 10393 displayContent = new DisplayContent(mDisplayManager, displayId); 10394 mDisplayContents.put(displayId, displayContent); 10395 } 10396 return displayContent; 10397 } 10398 10399 class DisplayContentsIterator implements Iterator<DisplayContent> { 10400 private int cur; 10401 10402 @Override 10403 public boolean hasNext() { 10404 return cur < mDisplayContents.size(); 10405 } 10406 10407 @Override 10408 public DisplayContent next() { 10409 if (hasNext()) { 10410 return mDisplayContents.valueAt(cur++); 10411 } 10412 throw new NoSuchElementException(); 10413 } 10414 10415 @Override 10416 public void remove() { 10417 throw new IllegalArgumentException("AllDisplayContentIterator.remove not implemented"); 10418 } 10419 } 10420 10421 boolean REVERSE_ITERATOR = true; 10422 class AllWindowsIterator implements Iterator<WindowState> { 10423 private DisplayContent mDisplayContent; 10424 private DisplayContentsIterator mDisplayContentsIterator; 10425 private WindowList mWindowList; 10426 private int mWindowListIndex; 10427 private boolean mReverse; 10428 10429 AllWindowsIterator() { 10430 mDisplayContentsIterator = new DisplayContentsIterator(); 10431 mDisplayContent = mDisplayContentsIterator.next(); 10432 mWindowList = mDisplayContent.getWindowList(); 10433 } 10434 10435 AllWindowsIterator(boolean reverse) { 10436 this(); 10437 mReverse = reverse; 10438 mWindowListIndex = reverse ? mWindowList.size() - 1 : 0; 10439 } 10440 10441 @Override 10442 public boolean hasNext() { 10443 if (mReverse) { 10444 return mWindowListIndex >= 0; 10445 } 10446 return mWindowListIndex < mWindowList.size(); 10447 } 10448 10449 @Override 10450 public WindowState next() { 10451 if (hasNext()) { 10452 WindowState win = mWindowList.get(mWindowListIndex); 10453 if (mReverse) { 10454 mWindowListIndex--; 10455 if (mWindowListIndex < 0 && mDisplayContentsIterator.hasNext()) { 10456 mDisplayContent = mDisplayContentsIterator.next(); 10457 mWindowList = mDisplayContent.getWindowList(); 10458 mWindowListIndex = mWindowList.size() - 1; 10459 } 10460 } else { 10461 mWindowListIndex++; 10462 if (mWindowListIndex >= mWindowList.size() && mDisplayContentsIterator.hasNext()) { 10463 mDisplayContent = mDisplayContentsIterator.next(); 10464 mWindowList = mDisplayContent.getWindowList(); 10465 mWindowListIndex = 0; 10466 } 10467 } 10468 return win; 10469 } 10470 throw new NoSuchElementException(); 10471 } 10472 10473 @Override 10474 public void remove() { 10475 throw new IllegalArgumentException("AllWindowsIterator.remove not implemented"); 10476 } 10477 } 10478 10479 public DisplayContent getDefaultDisplayContent() { 10480 return getDisplayContent(Display.DEFAULT_DISPLAY); 10481 } 10482 10483 public WindowList getDefaultWindowList() { 10484 return getDefaultDisplayContent().getWindowList(); 10485 } 10486 10487 public DisplayInfo getDefaultDisplayInfo() { 10488 return getDefaultDisplayContent().getDisplayInfo(); 10489 } 10490 10491} 10492