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