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