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