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 17 package com.android.server.wm; 18 19 import static android.view.WindowManager.LayoutParams.*; 20 21 import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID; 22 23 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 24 25 import android.app.AppOpsManager; 26 import android.util.TimeUtils; 27 import android.view.IWindowId; 28 29 import com.android.internal.app.IBatteryStats; 30 import com.android.internal.policy.PolicyManager; 31 import com.android.internal.policy.impl.PhoneWindowManager; 32 import com.android.internal.util.FastPrintWriter; 33 import com.android.internal.view.IInputContext; 34 import com.android.internal.view.IInputMethodClient; 35 import com.android.internal.view.IInputMethodManager; 36 import com.android.internal.view.WindowManagerPolicyThread; 37 import com.android.server.AttributeCache; 38 import com.android.server.EventLogTags; 39 import com.android.server.UiThread; 40 import com.android.server.Watchdog; 41 import com.android.server.am.BatteryStatsService; 42 import com.android.server.display.DisplayManagerService; 43 import com.android.server.input.InputManagerService; 44 import com.android.server.power.PowerManagerService; 45 import com.android.server.power.ShutdownThread; 46 47 import android.Manifest; 48 import android.app.ActivityManager.StackBoxInfo; 49 import android.app.ActivityManagerNative; 50 import android.app.IActivityManager; 51 import android.app.StatusBarManager; 52 import android.app.admin.DevicePolicyManager; 53 import android.animation.ValueAnimator; 54 import android.content.BroadcastReceiver; 55 import android.content.Context; 56 import android.content.Intent; 57 import android.content.IntentFilter; 58 import android.content.pm.ActivityInfo; 59 import android.content.pm.PackageManager; 60 import android.content.res.CompatibilityInfo; 61 import android.content.res.Configuration; 62 import android.graphics.Bitmap; 63 import android.graphics.Bitmap.Config; 64 import android.graphics.Canvas; 65 import android.graphics.Matrix; 66 import android.graphics.PixelFormat; 67 import android.graphics.Point; 68 import android.graphics.Rect; 69 import android.graphics.RectF; 70 import android.graphics.Region; 71 import android.hardware.display.DisplayManager; 72 import android.os.Binder; 73 import android.os.Bundle; 74 import android.os.Debug; 75 import android.os.Handler; 76 import android.os.IBinder; 77 import android.os.IRemoteCallback; 78 import android.os.Looper; 79 import android.os.Message; 80 import android.os.Parcel; 81 import android.os.ParcelFileDescriptor; 82 import android.os.PowerManager; 83 import android.os.Process; 84 import android.os.RemoteException; 85 import android.os.ServiceManager; 86 import android.os.StrictMode; 87 import android.os.SystemClock; 88 import android.os.SystemProperties; 89 import android.os.Trace; 90 import android.os.WorkSource; 91 import android.provider.Settings; 92 import android.util.DisplayMetrics; 93 import android.util.EventLog; 94 import android.util.FloatMath; 95 import android.util.Log; 96 import android.util.SparseArray; 97 import android.util.Pair; 98 import android.util.Slog; 99 import android.util.SparseIntArray; 100 import android.util.TypedValue; 101 import android.view.Choreographer; 102 import android.view.Display; 103 import android.view.DisplayInfo; 104 import android.view.Gravity; 105 import android.view.IApplicationToken; 106 import android.view.IInputFilter; 107 import android.view.IMagnificationCallbacks; 108 import android.view.IOnKeyguardExitResult; 109 import android.view.IRotationWatcher; 110 import android.view.IWindow; 111 import android.view.IWindowManager; 112 import android.view.IWindowSession; 113 import android.view.InputChannel; 114 import android.view.InputDevice; 115 import android.view.InputEvent; 116 import android.view.InputEventReceiver; 117 import android.view.KeyEvent; 118 import android.view.MagnificationSpec; 119 import android.view.MotionEvent; 120 import android.view.Surface.OutOfResourcesException; 121 import android.view.Surface; 122 import android.view.SurfaceControl; 123 import android.view.SurfaceSession; 124 import android.view.View; 125 import android.view.ViewTreeObserver; 126 import android.view.WindowManager; 127 import android.view.WindowManagerGlobal; 128 import android.view.WindowManagerPolicy; 129 import android.view.WindowManager.LayoutParams; 130 import android.view.WindowManagerPolicy.FakeWindow; 131 import android.view.WindowManagerPolicy.PointerEventListener; 132 import android.view.animation.Animation; 133 import android.view.animation.AnimationUtils; 134 import android.view.animation.Transformation; 135 136 import java.io.BufferedWriter; 137 import java.io.DataInputStream; 138 import java.io.File; 139 import java.io.FileDescriptor; 140 import java.io.FileInputStream; 141 import java.io.FileNotFoundException; 142 import java.io.IOException; 143 import java.io.OutputStream; 144 import java.io.OutputStreamWriter; 145 import java.io.PrintWriter; 146 import java.io.StringWriter; 147 import java.net.Socket; 148 import java.text.DateFormat; 149 import java.util.ArrayList; 150 import java.util.Date; 151 import java.util.HashMap; 152 import java.util.HashSet; 153 import java.util.Iterator; 154 import java.util.List; 155 156 /** {@hide} */ 157 public class WindowManagerService extends IWindowManager.Stub 158 implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs, 159 DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener { 160 static final String TAG = "WindowManager"; 161 static final boolean DEBUG = false; 162 static final boolean DEBUG_ADD_REMOVE = false; 163 static final boolean DEBUG_FOCUS = false; 164 static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false; 165 static final boolean DEBUG_ANIM = false; 166 static final boolean DEBUG_LAYOUT = false; 167 static final boolean DEBUG_RESIZE = false; 168 static final boolean DEBUG_LAYERS = false; 169 static final boolean DEBUG_INPUT = false; 170 static final boolean DEBUG_INPUT_METHOD = false; 171 static final boolean DEBUG_VISIBILITY = false; 172 static final boolean DEBUG_WINDOW_MOVEMENT = false; 173 static final boolean DEBUG_TOKEN_MOVEMENT = false; 174 static final boolean DEBUG_ORIENTATION = false; 175 static final boolean DEBUG_APP_ORIENTATION = false; 176 static final boolean DEBUG_CONFIGURATION = false; 177 static final boolean DEBUG_APP_TRANSITIONS = false; 178 static final boolean DEBUG_STARTING_WINDOW = false; 179 static final boolean DEBUG_REORDER = false; 180 static final boolean DEBUG_WALLPAPER = false; 181 static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER; 182 static final boolean DEBUG_DRAG = false; 183 static final boolean DEBUG_SCREEN_ON = false; 184 static final boolean DEBUG_SCREENSHOT = false; 185 static final boolean DEBUG_BOOT = false; 186 static final boolean DEBUG_LAYOUT_REPEATS = true; 187 static final boolean DEBUG_SURFACE_TRACE = false; 188 static final boolean DEBUG_WINDOW_TRACE = false; 189 static final boolean DEBUG_TASK_MOVEMENT = false; 190 static final boolean DEBUG_STACK = false; 191 static final boolean SHOW_SURFACE_ALLOC = false; 192 static final boolean SHOW_TRANSACTIONS = false; 193 static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS; 194 static final boolean HIDE_STACK_CRAWLS = true; 195 static final int LAYOUT_REPEAT_THRESHOLD = 4; 196 197 static final boolean PROFILE_ORIENTATION = false; 198 static final boolean localLOGV = DEBUG; 199 200 /** How much to multiply the policy's type layer, to reserve room 201 * for multiple windows of the same type and Z-ordering adjustment 202 * with TYPE_LAYER_OFFSET. */ 203 static final int TYPE_LAYER_MULTIPLIER = 10000; 204 205 /** Offset from TYPE_LAYER_MULTIPLIER for moving a group of windows above 206 * or below others in the same layer. */ 207 static final int TYPE_LAYER_OFFSET = 1000; 208 209 /** How much to increment the layer for each window, to reserve room 210 * for effect surfaces between them. 211 */ 212 static final int WINDOW_LAYER_MULTIPLIER = 5; 213 214 /** 215 * Dim surface layer is immediately below target window. 216 */ 217 static final int LAYER_OFFSET_DIM = 1; 218 219 /** 220 * Blur surface layer is immediately below dim layer. 221 */ 222 static final int LAYER_OFFSET_BLUR = 2; 223 224 /** 225 * FocusedStackFrame layer is immediately above focused window. 226 */ 227 static final int LAYER_OFFSET_FOCUSED_STACK = 1; 228 229 /** 230 * Animation thumbnail is as far as possible below the window above 231 * the thumbnail (or in other words as far as possible above the window 232 * below it). 233 */ 234 static final int LAYER_OFFSET_THUMBNAIL = WINDOW_LAYER_MULTIPLIER-1; 235 236 /** 237 * Layer at which to put the rotation freeze snapshot. 238 */ 239 static final int FREEZE_LAYER = (TYPE_LAYER_MULTIPLIER * 200) + 1; 240 241 /** 242 * Layer at which to put the mask for emulated screen sizes. 243 */ 244 static final int MASK_LAYER = TYPE_LAYER_MULTIPLIER * 200; 245 246 /** The maximum length we will accept for a loaded animation duration: 247 * this is 10 seconds. 248 */ 249 static final int MAX_ANIMATION_DURATION = 10*1000; 250 251 /** Amount of time (in milliseconds) to animate the fade-in-out transition for 252 * compatible windows. 253 */ 254 static final int DEFAULT_FADE_IN_OUT_DURATION = 400; 255 256 /** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */ 257 static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000; 258 259 /** Amount of time (in milliseconds) to delay before declaring a starting window leaked. */ 260 static final int STARTING_WINDOW_TIMEOUT_DURATION = 10000; 261 262 /** 263 * If true, the window manager will do its own custom freezing and general 264 * management of the screen during rotation. 265 */ 266 static final boolean CUSTOM_SCREEN_ROTATION = true; 267 268 // Maximum number of milliseconds to wait for input devices to be enumerated before 269 // proceding with safe mode detection. 270 private static final int INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS = 1000; 271 272 // Default input dispatching timeout in nanoseconds. 273 static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L; 274 275 /** Minimum value for createStack and resizeStack weight value */ 276 public static final float STACK_WEIGHT_MIN = 0.2f; 277 278 /** Maximum value for createStack and resizeStack weight value */ 279 public static final float STACK_WEIGHT_MAX = 0.8f; 280 281 static final int UPDATE_FOCUS_NORMAL = 0; 282 static final int UPDATE_FOCUS_WILL_ASSIGN_LAYERS = 1; 283 static final int UPDATE_FOCUS_PLACING_SURFACES = 2; 284 static final int UPDATE_FOCUS_WILL_PLACE_SURFACES = 3; 285 286 private static final String SYSTEM_SECURE = "ro.secure"; 287 private static final String SYSTEM_DEBUGGABLE = "ro.debuggable"; 288 289 private static final String DENSITY_OVERRIDE = "ro.config.density_override"; 290 private static final String SIZE_OVERRIDE = "ro.config.size_override"; 291 292 private static final int MAX_SCREENSHOT_RETRIES = 3; 293 294 final private KeyguardDisableHandler mKeyguardDisableHandler; 295 296 private final boolean mHeadless; 297 298 final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 299 @Override 300 public void onReceive(Context context, Intent intent) { 301 final String action = intent.getAction(); 302 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) { 303 mKeyguardDisableHandler.sendEmptyMessage( 304 KeyguardDisableHandler.KEYGUARD_POLICY_CHANGED); 305 } 306 } 307 }; 308 309 // Current user when multi-user is enabled. Don't show windows of non-current user. 310 int mCurrentUserId; 311 312 final Context mContext; 313 314 final boolean mHaveInputMethods; 315 316 final boolean mAllowBootMessages; 317 318 final boolean mLimitedAlphaCompositing; 319 320 final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager(); 321 322 final IActivityManager mActivityManager; 323 324 final IBatteryStats mBatteryStats; 325 326 final AppOpsManager mAppOps; 327 328 final DisplaySettings mDisplaySettings; 329 330 /** 331 * All currently active sessions with clients. 332 */ 333 final HashSet<Session> mSessions = new HashSet<Session>(); 334 335 /** 336 * Mapping from an IWindow IBinder to the server's Window object. 337 * This is also used as the lock for all of our state. 338 * NOTE: Never call into methods that lock ActivityManagerService while holding this object. 339 */ 340 final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>(); 341 342 /** 343 * Mapping from a token IBinder to a WindowToken object. 344 */ 345 final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<IBinder, WindowToken>(); 346 347 /** 348 * List of window tokens that have finished starting their application, 349 * and now need to have the policy remove their windows. 350 */ 351 final ArrayList<AppWindowToken> mFinishedStarting = new ArrayList<AppWindowToken>(); 352 353 /** 354 * Fake windows added to the window manager. Note: ordered from top to 355 * bottom, opposite of mWindows. 356 */ 357 final ArrayList<FakeWindowImpl> mFakeWindows = new ArrayList<FakeWindowImpl>(); 358 359 /** 360 * Windows that are being resized. Used so we can tell the client about 361 * the resize after closing the transaction in which we resized the 362 * underlying surface. 363 */ 364 final ArrayList<WindowState> mResizingWindows = new ArrayList<WindowState>(); 365 366 /** 367 * Windows whose animations have ended and now must be removed. 368 */ 369 final ArrayList<WindowState> mPendingRemove = new ArrayList<WindowState>(); 370 371 /** 372 * Used when processing mPendingRemove to avoid working on the original array. 373 */ 374 WindowState[] mPendingRemoveTmp = new WindowState[20]; 375 376 /** 377 * Windows whose surface should be destroyed. 378 */ 379 final ArrayList<WindowState> mDestroySurface = new ArrayList<WindowState>(); 380 381 /** 382 * Windows that have lost input focus and are waiting for the new 383 * focus window to be displayed before they are told about this. 384 */ 385 ArrayList<WindowState> mLosingFocus = new ArrayList<WindowState>(); 386 387 /** 388 * This is set when we have run out of memory, and will either be an empty 389 * list or contain windows that need to be force removed. 390 */ 391 ArrayList<WindowState> mForceRemoves; 392 393 /** 394 * Windows that clients are waiting to have drawn. 395 */ 396 ArrayList<Pair<WindowState, IRemoteCallback>> mWaitingForDrawn 397 = new ArrayList<Pair<WindowState, IRemoteCallback>>(); 398 399 /** 400 * Windows that have called relayout() while we were running animations, 401 * so we need to tell when the animation is done. 402 */ 403 final ArrayList<WindowState> mRelayoutWhileAnimating = new ArrayList<WindowState>(); 404 405 /** 406 * Used when rebuilding window list to keep track of windows that have 407 * been removed. 408 */ 409 WindowState[] mRebuildTmp = new WindowState[20]; 410 411 IInputMethodManager mInputMethodManager; 412 413 DisplayMagnifier mDisplayMagnifier; 414 415 final SurfaceSession mFxSession; 416 Watermark mWatermark; 417 StrictModeFlash mStrictModeFlash; 418 FocusedStackFrame mFocusedStackFrame; 419 420 int mFocusedStackLayer; 421 422 final float[] mTmpFloats = new float[9]; 423 final Rect mTmpContentRect = new Rect(); 424 425 boolean mDisplayReady; 426 boolean mSafeMode; 427 boolean mDisplayEnabled = false; 428 boolean mSystemBooted = false; 429 boolean mForceDisplayEnabled = false; 430 boolean mShowingBootMessages = false; 431 432 String mLastANRState; 433 434 /** All DisplayContents in the world, kept here */ 435 SparseArray<DisplayContent> mDisplayContents = new SparseArray<DisplayContent>(2); 436 437 int mRotation = 0; 438 int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 439 boolean mAltOrientation = false; 440 class RotationWatcher { 441 IRotationWatcher watcher; 442 IBinder.DeathRecipient dr; 443 RotationWatcher(IRotationWatcher w, IBinder.DeathRecipient d) { 444 watcher = w; 445 dr = d; 446 } 447 } 448 ArrayList<RotationWatcher> mRotationWatchers = new ArrayList<RotationWatcher>(); 449 int mDeferredRotationPauseCount; 450 451 int mSystemDecorLayer = 0; 452 final Rect mScreenRect = new Rect(); 453 454 boolean mTraversalScheduled = false; 455 boolean mDisplayFrozen = false; 456 long mDisplayFreezeTime = 0; 457 int mLastDisplayFreezeDuration = 0; 458 Object mLastFinishedFreezeSource = null; 459 boolean mWaitingForConfig = false; 460 boolean mWindowsFreezingScreen = false; 461 boolean mClientFreezingScreen = false; 462 int mAppsFreezingScreen = 0; 463 int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 464 465 int mLayoutSeq = 0; 466 467 int mLastStatusBarVisibility = 0; 468 469 // State while inside of layoutAndPlaceSurfacesLocked(). 470 boolean mFocusMayChange; 471 472 Configuration mCurConfiguration = new Configuration(); 473 474 // This is held as long as we have the screen frozen, to give us time to 475 // perform a rotation animation when turning off shows the lock screen which 476 // changes the orientation. 477 private final PowerManager.WakeLock mScreenFrozenLock; 478 479 final AppTransition mAppTransition; 480 boolean mStartingIconInTransition = false; 481 boolean mSkipAppTransitionAnimation = false; 482 483 final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>(); 484 final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>(); 485 486 boolean mIsTouchDevice; 487 488 final DisplayMetrics mDisplayMetrics = new DisplayMetrics(); 489 final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics(); 490 final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics(); 491 final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics(); 492 493 final H mH = new H(); 494 495 final Choreographer mChoreographer = Choreographer.getInstance(); 496 497 WindowState mCurrentFocus = null; 498 WindowState mLastFocus = null; 499 500 /** This just indicates the window the input method is on top of, not 501 * necessarily the window its input is going to. */ 502 WindowState mInputMethodTarget = null; 503 504 /** If true hold off on modifying the animation layer of mInputMethodTarget */ 505 boolean mInputMethodTargetWaitingAnim; 506 int mInputMethodAnimLayerAdjustment; 507 508 WindowState mInputMethodWindow = null; 509 final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>(); 510 511 boolean mHardKeyboardAvailable; 512 boolean mHardKeyboardEnabled; 513 OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; 514 515 final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>(); 516 517 // If non-null, this is the currently visible window that is associated 518 // with the wallpaper. 519 WindowState mWallpaperTarget = null; 520 // If non-null, we are in the middle of animating from one wallpaper target 521 // to another, and this is the lower one in Z-order. 522 WindowState mLowerWallpaperTarget = null; 523 // If non-null, we are in the middle of animating from one wallpaper target 524 // to another, and this is the higher one in Z-order. 525 WindowState mUpperWallpaperTarget = null; 526 int mWallpaperAnimLayerAdjustment; 527 float mLastWallpaperX = -1; 528 float mLastWallpaperY = -1; 529 float mLastWallpaperXStep = -1; 530 float mLastWallpaperYStep = -1; 531 // This is set when we are waiting for a wallpaper to tell us it is done 532 // changing its scroll position. 533 WindowState mWaitingOnWallpaper; 534 // The last time we had a timeout when waiting for a wallpaper. 535 long mLastWallpaperTimeoutTime; 536 // We give a wallpaper up to 150ms to finish scrolling. 537 static final long WALLPAPER_TIMEOUT = 150; 538 // Time we wait after a timeout before trying to wait again. 539 static final long WALLPAPER_TIMEOUT_RECOVERY = 10000; 540 boolean mAnimateWallpaperWithTarget; 541 542 AppWindowToken mFocusedApp = null; 543 544 PowerManagerService mPowerManager; 545 546 float mWindowAnimationScale = 1.0f; 547 float mTransitionAnimationScale = 1.0f; 548 float mAnimatorDurationScale = 1.0f; 549 550 final InputManagerService mInputManager; 551 final DisplayManagerService mDisplayManagerService; 552 final DisplayManager mDisplayManager; 553 554 // Who is holding the screen on. 555 Session mHoldingScreenOn; 556 PowerManager.WakeLock mHoldingScreenWakeLock; 557 558 boolean mTurnOnScreen; 559 560 DragState mDragState = null; 561 562 // For frozen screen animations. 563 int mExitAnimId, mEnterAnimId; 564 565 /** Pulled out of performLayoutAndPlaceSurfacesLockedInner in order to refactor into multiple 566 * methods. */ 567 class LayoutFields { 568 static final int SET_UPDATE_ROTATION = 1 << 0; 569 static final int SET_WALLPAPER_MAY_CHANGE = 1 << 1; 570 static final int SET_FORCE_HIDING_CHANGED = 1 << 2; 571 static final int SET_ORIENTATION_CHANGE_COMPLETE = 1 << 3; 572 static final int SET_TURN_ON_SCREEN = 1 << 4; 573 static final int SET_WALLPAPER_ACTION_PENDING = 1 << 5; 574 575 boolean mWallpaperForceHidingChanged = false; 576 boolean mWallpaperMayChange = false; 577 boolean mOrientationChangeComplete = true; 578 Object mLastWindowFreezeSource = null; 579 private Session mHoldScreen = null; 580 private boolean mObscured = false; 581 private boolean mSyswin = false; 582 private float mScreenBrightness = -1; 583 private float mButtonBrightness = -1; 584 private long mUserActivityTimeout = -1; 585 private boolean mUpdateRotation = false; 586 boolean mWallpaperActionPending = false; 587 588 // Set to true when the display contains content to show the user. 589 // When false, the display manager may choose to mirror or blank the display. 590 boolean mDisplayHasContent = false; 591 592 // Only set while traversing the default display based on its content. 593 // Affects the behavior of mirroring on secondary displays. 594 boolean mObscureApplicationContentOnSecondaryDisplays = false; 595 } 596 final LayoutFields mInnerFields = new LayoutFields(); 597 598 boolean mAnimationScheduled; 599 600 /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this 601 * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */ 602 private int mTransactionSequence; 603 604 /** Only do a maximum of 6 repeated layouts. After that quit */ 605 private int mLayoutRepeatCount; 606 607 final WindowAnimator mAnimator; 608 609 SparseArray<Task> mTaskIdToTask = new SparseArray<Task>(); 610 SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>(); 611 612 private final PointerEventDispatcher mPointerEventDispatcher; 613 614 final class DragInputEventReceiver extends InputEventReceiver { 615 public DragInputEventReceiver(InputChannel inputChannel, Looper looper) { 616 super(inputChannel, looper); 617 } 618 619 @Override 620 public void onInputEvent(InputEvent event) { 621 boolean handled = false; 622 try { 623 if (event instanceof MotionEvent 624 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0 625 && mDragState != null) { 626 final MotionEvent motionEvent = (MotionEvent)event; 627 boolean endDrag = false; 628 final float newX = motionEvent.getRawX(); 629 final float newY = motionEvent.getRawY(); 630 631 switch (motionEvent.getAction()) { 632 case MotionEvent.ACTION_DOWN: { 633 if (DEBUG_DRAG) { 634 Slog.w(TAG, "Unexpected ACTION_DOWN in drag layer"); 635 } 636 } break; 637 638 case MotionEvent.ACTION_MOVE: { 639 synchronized (mWindowMap) { 640 // move the surface and tell the involved window(s) where we are 641 mDragState.notifyMoveLw(newX, newY); 642 } 643 } break; 644 645 case MotionEvent.ACTION_UP: { 646 if (DEBUG_DRAG) Slog.d(TAG, "Got UP on move channel; dropping at " 647 + newX + "," + newY); 648 synchronized (mWindowMap) { 649 endDrag = mDragState.notifyDropLw(newX, newY); 650 } 651 } break; 652 653 case MotionEvent.ACTION_CANCEL: { 654 if (DEBUG_DRAG) Slog.d(TAG, "Drag cancelled!"); 655 endDrag = true; 656 } break; 657 } 658 659 if (endDrag) { 660 if (DEBUG_DRAG) Slog.d(TAG, "Drag ended; tearing down state"); 661 // tell all the windows that the drag has ended 662 synchronized (mWindowMap) { 663 mDragState.endDragLw(); 664 } 665 } 666 667 handled = true; 668 } 669 } catch (Exception e) { 670 Slog.e(TAG, "Exception caught by drag handleMotion", e); 671 } finally { 672 finishInputEvent(event, handled); 673 } 674 } 675 } 676 677 /** 678 * Whether the UI is currently running in touch mode (not showing 679 * navigational focus because the user is directly pressing the screen). 680 */ 681 boolean mInTouchMode = true; 682 683 private ViewServer mViewServer; 684 private final ArrayList<WindowChangeListener> mWindowChangeListeners = 685 new ArrayList<WindowChangeListener>(); 686 private boolean mWindowsChanged = false; 687 688 public interface WindowChangeListener { 689 public void windowsChanged(); 690 public void focusChanged(); 691 } 692 693 final Configuration mTempConfiguration = new Configuration(); 694 695 // The desired scaling factor for compatible apps. 696 float mCompatibleScreenScale; 697 698 // If true, only the core apps and services are being launched because the device 699 // is in a special boot mode, such as being encrypted or waiting for a decryption password. 700 // For example, when this flag is true, there will be no wallpaper service. 701 final boolean mOnlyCore; 702 703 public static WindowManagerService main(final Context context, 704 final PowerManagerService pm, final DisplayManagerService dm, 705 final InputManagerService im, final Handler wmHandler, 706 final boolean haveInputMethods, final boolean showBootMsgs, 707 final boolean onlyCore) { 708 final WindowManagerService[] holder = new WindowManagerService[1]; 709 wmHandler.runWithScissors(new Runnable() { 710 @Override 711 public void run() { 712 holder[0] = new WindowManagerService(context, pm, dm, im, 713 haveInputMethods, showBootMsgs, onlyCore); 714 } 715 }, 0); 716 return holder[0]; 717 } 718 719 private void initPolicy(Handler uiHandler) { 720 uiHandler.runWithScissors(new Runnable() { 721 @Override 722 public void run() { 723 WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper()); 724 725 mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this); 726 mAnimator.mAboveUniverseLayer = mPolicy.getAboveUniverseLayer() 727 * TYPE_LAYER_MULTIPLIER 728 + TYPE_LAYER_OFFSET; 729 } 730 }, 0); 731 } 732 733 private WindowManagerService(Context context, PowerManagerService pm, 734 DisplayManagerService displayManager, InputManagerService inputManager, 735 boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) { 736 mContext = context; 737 mHaveInputMethods = haveInputMethods; 738 mAllowBootMessages = showBootMsgs; 739 mOnlyCore = onlyCore; 740 mLimitedAlphaCompositing = context.getResources().getBoolean( 741 com.android.internal.R.bool.config_sf_limitedAlpha); 742 mInputManager = inputManager; // Must be before createDisplayContentLocked. 743 mDisplayManagerService = displayManager; 744 mHeadless = displayManager.isHeadless(); 745 mDisplaySettings = new DisplaySettings(context); 746 mDisplaySettings.readSettingsLocked(); 747 748 mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG)); 749 750 mFxSession = new SurfaceSession(); 751 mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); 752 mDisplayManager.registerDisplayListener(this, null); 753 Display[] displays = mDisplayManager.getDisplays(); 754 for (Display display : displays) { 755 createDisplayContentLocked(display); 756 } 757 758 mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy); 759 760 mPowerManager = pm; 761 mPowerManager.setPolicy(mPolicy); 762 PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 763 mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN"); 764 mScreenFrozenLock.setReferenceCounted(false); 765 766 mAppTransition = new AppTransition(context, mH); 767 768 mActivityManager = ActivityManagerNative.getDefault(); 769 mBatteryStats = BatteryStatsService.getService(); 770 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE); 771 mAppOps.startWatchingMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, null, 772 new AppOpsManager.OnOpChangedInternalListener() { 773 @Override 774 public void onOpChanged(int op, String packageName) { 775 updateAppOpsState(); 776 } 777 } 778 ); 779 780 // Get persisted window scale setting 781 mWindowAnimationScale = Settings.Global.getFloat(context.getContentResolver(), 782 Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScale); 783 mTransitionAnimationScale = Settings.Global.getFloat(context.getContentResolver(), 784 Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale); 785 setAnimatorDurationScale(Settings.Global.getFloat(context.getContentResolver(), 786 Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale)); 787 788 // Track changes to DevicePolicyManager state so we can enable/disable keyguard. 789 IntentFilter filter = new IntentFilter(); 790 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); 791 mContext.registerReceiver(mBroadcastReceiver, filter); 792 793 mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK 794 | PowerManager.ON_AFTER_RELEASE, TAG); 795 mHoldingScreenWakeLock.setReferenceCounted(false); 796 797 mAnimator = new WindowAnimator(this); 798 799 initPolicy(UiThread.getHandler()); 800 801 // Add ourself to the Watchdog monitors. 802 Watchdog.getInstance().addMonitor(this); 803 804 SurfaceControl.openTransaction(); 805 try { 806 createWatermarkInTransaction(); 807 mFocusedStackFrame = new FocusedStackFrame( 808 getDefaultDisplayContentLocked().getDisplay(), mFxSession); 809 } finally { 810 SurfaceControl.closeTransaction(); 811 } 812 } 813 814 public InputMonitor getInputMonitor() { 815 return mInputMonitor; 816 } 817 818 @Override 819 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 820 throws RemoteException { 821 try { 822 return super.onTransact(code, data, reply, flags); 823 } catch (RuntimeException e) { 824 // The window manager only throws security exceptions, so let's 825 // log all others. 826 if (!(e instanceof SecurityException)) { 827 Slog.wtf(TAG, "Window Manager Crash", e); 828 } 829 throw e; 830 } 831 } 832 833 private void placeWindowAfter(WindowState pos, WindowState window) { 834 final WindowList windows = pos.getWindowList(); 835 final int i = windows.indexOf(pos); 836 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v( 837 TAG, "Adding window " + window + " at " 838 + (i+1) + " of " + windows.size() + " (after " + pos + ")"); 839 windows.add(i+1, window); 840 mWindowsChanged = true; 841 } 842 843 private void placeWindowBefore(WindowState pos, WindowState window) { 844 final WindowList windows = pos.getWindowList(); 845 int i = windows.indexOf(pos); 846 if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v( 847 TAG, "Adding window " + window + " at " 848 + i + " of " + windows.size() + " (before " + pos + ")"); 849 if (i < 0) { 850 Slog.w(TAG, "placeWindowBefore: Unable to find " + pos + " in " + windows); 851 i = 0; 852 } 853 windows.add(i, window); 854 mWindowsChanged = true; 855 } 856 857 //This method finds out the index of a window that has the same app token as 858 //win. used for z ordering the windows in mWindows 859 private int findIdxBasedOnAppTokens(WindowState win) { 860 WindowList windows = win.getWindowList(); 861 for(int j = windows.size() - 1; j >= 0; j--) { 862 WindowState wentry = windows.get(j); 863 if(wentry.mAppToken == win.mAppToken) { 864 return j; 865 } 866 } 867 return -1; 868 } 869 870 /** 871 * Return the list of Windows from the passed token on the given Display. 872 * @param token The token with all the windows. 873 * @param displayContent The display we are interested in. 874 * @return List of windows from token that are on displayContent. 875 */ 876 WindowList getTokenWindowsOnDisplay(WindowToken token, DisplayContent displayContent) { 877 final WindowList windowList = new WindowList(); 878 final int count = token.windows.size(); 879 for (int i = 0; i < count; i++) { 880 final WindowState win = token.windows.get(i); 881 if (win.mDisplayContent == displayContent) { 882 windowList.add(win); 883 } 884 } 885 return windowList; 886 } 887 888 /** 889 * Recursive search through a WindowList and all of its windows' children. 890 * @param targetWin The window to search for. 891 * @param windows The list to search. 892 * @return The index of win in windows or of the window that is an ancestor of win. 893 */ 894 private int indexOfWinInWindowList(WindowState targetWin, WindowList windows) { 895 for (int i = windows.size() - 1; i >= 0; i--) { 896 final WindowState w = windows.get(i); 897 if (w == targetWin) { 898 return i; 899 } 900 if (!w.mChildWindows.isEmpty()) { 901 if (indexOfWinInWindowList(targetWin, w.mChildWindows) >= 0) { 902 return i; 903 } 904 } 905 } 906 return -1; 907 } 908 909 private int addAppWindowToListLocked(final WindowState win) { 910 final IWindow client = win.mClient; 911 final WindowToken token = win.mToken; 912 final DisplayContent displayContent = win.mDisplayContent; 913 914 final WindowList windows = win.getWindowList(); 915 final int N = windows.size(); 916 WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent); 917 int tokenWindowsPos = 0; 918 int windowListPos = tokenWindowList.size(); 919 if (!tokenWindowList.isEmpty()) { 920 // If this application has existing windows, we 921 // simply place the new window on top of them... but 922 // keep the starting window on top. 923 if (win.mAttrs.type == TYPE_BASE_APPLICATION) { 924 // Base windows go behind everything else. 925 WindowState lowestWindow = tokenWindowList.get(0); 926 placeWindowBefore(lowestWindow, win); 927 tokenWindowsPos = indexOfWinInWindowList(lowestWindow, token.windows); 928 } else { 929 AppWindowToken atoken = win.mAppToken; 930 WindowState lastWindow = tokenWindowList.get(windowListPos - 1); 931 if (atoken != null && lastWindow == atoken.startingWindow) { 932 placeWindowBefore(lastWindow, win); 933 tokenWindowsPos = indexOfWinInWindowList(lastWindow, token.windows); 934 } else { 935 int newIdx = findIdxBasedOnAppTokens(win); 936 //there is a window above this one associated with the same 937 //apptoken note that the window could be a floating window 938 //that was created later or a window at the top of the list of 939 //windows associated with this token. 940 if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, 941 "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of " + 942 N); 943 windows.add(newIdx + 1, win); 944 if (newIdx < 0) { 945 // No window from token found on win's display. 946 tokenWindowsPos = 0; 947 } else { 948 tokenWindowsPos = indexOfWinInWindowList( 949 windows.get(newIdx), token.windows) + 1; 950 } 951 mWindowsChanged = true; 952 } 953 } 954 return tokenWindowsPos; 955 } 956 957 // No windows from this token on this display 958 if (localLOGV) Slog.v(TAG, "Figuring out where to add app window " + client.asBinder() 959 + " (token=" + token + ")"); 960 // Figure out where the window should go, based on the 961 // order of applications. 962 WindowState pos = null; 963 964 final ArrayList<Task> tasks = displayContent.getTasks(); 965 int taskNdx; 966 int tokenNdx = -1; 967 for (taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { 968 AppTokenList tokens = tasks.get(taskNdx).mAppTokens; 969 for (tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { 970 final AppWindowToken t = tokens.get(tokenNdx); 971 if (t == token) { 972 --tokenNdx; 973 if (tokenNdx < 0) { 974 --taskNdx; 975 if (taskNdx >= 0) { 976 tokenNdx = tasks.get(taskNdx).mAppTokens.size() - 1; 977 } 978 } 979 break; 980 } 981 982 // We haven't reached the token yet; if this token 983 // is not going to the bottom and has windows on this display, we can 984 // use it as an anchor for when we do reach the token. 985 tokenWindowList = getTokenWindowsOnDisplay(t, displayContent); 986 if (!t.sendingToBottom && tokenWindowList.size() > 0) { 987 pos = tokenWindowList.get(0); 988 } 989 } 990 if (tokenNdx >= 0) { 991 // early exit 992 break; 993 } 994 } 995 996 // We now know the index into the apps. If we found 997 // an app window above, that gives us the position; else 998 // we need to look some more. 999 if (pos != null) { 1000 // Move behind any windows attached to this one. 1001 WindowToken atoken = mTokenMap.get(pos.mClient.asBinder()); 1002 if (atoken != null) { 1003 tokenWindowList = 1004 getTokenWindowsOnDisplay(atoken, displayContent); 1005 final int NC = tokenWindowList.size(); 1006 if (NC > 0) { 1007 WindowState bottom = tokenWindowList.get(0); 1008 if (bottom.mSubLayer < 0) { 1009 pos = bottom; 1010 } 1011 } 1012 } 1013 placeWindowBefore(pos, win); 1014 return tokenWindowsPos; 1015 } 1016 1017 // Continue looking down until we find the first 1018 // token that has windows on this display. 1019 for ( ; taskNdx >= 0; --taskNdx) { 1020 AppTokenList tokens = tasks.get(taskNdx).mAppTokens; 1021 for ( ; tokenNdx >= 0; --tokenNdx) { 1022 final AppWindowToken t = tokens.get(tokenNdx); 1023 tokenWindowList = getTokenWindowsOnDisplay(t, displayContent); 1024 final int NW = tokenWindowList.size(); 1025 if (NW > 0) { 1026 pos = tokenWindowList.get(NW-1); 1027 break; 1028 } 1029 } 1030 if (tokenNdx >= 0) { 1031 // found 1032 break; 1033 } 1034 } 1035 1036 if (pos != null) { 1037 // Move in front of any windows attached to this 1038 // one. 1039 WindowToken atoken = mTokenMap.get(pos.mClient.asBinder()); 1040 if (atoken != null) { 1041 final int NC = atoken.windows.size(); 1042 if (NC > 0) { 1043 WindowState top = atoken.windows.get(NC-1); 1044 if (top.mSubLayer >= 0) { 1045 pos = top; 1046 } 1047 } 1048 } 1049 placeWindowAfter(pos, win); 1050 return tokenWindowsPos; 1051 } 1052 1053 // Just search for the start of this layer. 1054 final int myLayer = win.mBaseLayer; 1055 int i; 1056 for (i = 0; i < N; i++) { 1057 WindowState w = windows.get(i); 1058 if (w.mBaseLayer > myLayer) { 1059 break; 1060 } 1061 } 1062 if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, 1063 "Based on layer: Adding window " + win + " at " + i + " of " + N); 1064 windows.add(i, win); 1065 mWindowsChanged = true; 1066 return tokenWindowsPos; 1067 } 1068 1069 private void addFreeWindowToListLocked(final WindowState win) { 1070 final WindowList windows = win.getWindowList(); 1071 1072 // Figure out where window should go, based on layer. 1073 final int myLayer = win.mBaseLayer; 1074 int i; 1075 for (i = windows.size() - 1; i >= 0; i--) { 1076 if (windows.get(i).mBaseLayer <= myLayer) { 1077 break; 1078 } 1079 } 1080 i++; 1081 if (DEBUG_FOCUS_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, 1082 "Free window: Adding window " + win + " at " + i + " of " + windows.size()); 1083 windows.add(i, win); 1084 mWindowsChanged = true; 1085 } 1086 1087 private void addAttachedWindowToListLocked(final WindowState win, boolean addToToken) { 1088 final WindowToken token = win.mToken; 1089 final DisplayContent displayContent = win.mDisplayContent; 1090 final WindowState attached = win.mAttachedWindow; 1091 1092 WindowList tokenWindowList = getTokenWindowsOnDisplay(token, displayContent); 1093 1094 // Figure out this window's ordering relative to the window 1095 // it is attached to. 1096 final int NA = tokenWindowList.size(); 1097 final int sublayer = win.mSubLayer; 1098 int largestSublayer = Integer.MIN_VALUE; 1099 WindowState windowWithLargestSublayer = null; 1100 int i; 1101 for (i = 0; i < NA; i++) { 1102 WindowState w = tokenWindowList.get(i); 1103 final int wSublayer = w.mSubLayer; 1104 if (wSublayer >= largestSublayer) { 1105 largestSublayer = wSublayer; 1106 windowWithLargestSublayer = w; 1107 } 1108 if (sublayer < 0) { 1109 // For negative sublayers, we go below all windows 1110 // in the same sublayer. 1111 if (wSublayer >= sublayer) { 1112 if (addToToken) { 1113 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token); 1114 token.windows.add(i, win); 1115 } 1116 placeWindowBefore(wSublayer >= 0 ? attached : w, win); 1117 break; 1118 } 1119 } else { 1120 // For positive sublayers, we go above all windows 1121 // in the same sublayer. 1122 if (wSublayer > sublayer) { 1123 if (addToToken) { 1124 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token); 1125 token.windows.add(i, win); 1126 } 1127 placeWindowBefore(w, win); 1128 break; 1129 } 1130 } 1131 } 1132 if (i >= NA) { 1133 if (addToToken) { 1134 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token); 1135 token.windows.add(win); 1136 } 1137 if (sublayer < 0) { 1138 placeWindowBefore(attached, win); 1139 } else { 1140 placeWindowAfter(largestSublayer >= 0 1141 ? windowWithLargestSublayer 1142 : attached, 1143 win); 1144 } 1145 } 1146 } 1147 1148 private void addWindowToListInOrderLocked(final WindowState win, boolean addToToken) { 1149 if (DEBUG_FOCUS_LIGHT) Slog.d(TAG, "addWindowToListInOrderLocked: win=" + win + 1150 " Callers=" + Debug.getCallers(4)); 1151 if (win.mAttachedWindow == null) { 1152 final WindowToken token = win.mToken; 1153 int tokenWindowsPos = 0; 1154 if (token.appWindowToken != null) { 1155 tokenWindowsPos = addAppWindowToListLocked(win); 1156 } else { 1157 addFreeWindowToListLocked(win); 1158 } 1159 if (addToToken) { 1160 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + win + " to " + token); 1161 token.windows.add(tokenWindowsPos, win); 1162 } 1163 } else { 1164 addAttachedWindowToListLocked(win, addToToken); 1165 } 1166 1167 if (win.mAppToken != null && addToToken) { 1168 win.mAppToken.allAppWindows.add(win); 1169 } 1170 } 1171 1172 static boolean canBeImeTarget(WindowState w) { 1173 final int fl = w.mAttrs.flags 1174 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM); 1175 if (fl == 0 || fl == (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM) 1176 || w.mAttrs.type == TYPE_APPLICATION_STARTING) { 1177 if (DEBUG_INPUT_METHOD) { 1178 Slog.i(TAG, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding()); 1179 if (!w.isVisibleOrAdding()) { 1180 Slog.i(TAG, " mSurface=" + w.mWinAnimator.mSurfaceControl 1181 + " relayoutCalled=" + w.mRelayoutCalled + " viewVis=" + w.mViewVisibility 1182 + " policyVis=" + w.mPolicyVisibility 1183 + " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim 1184 + " attachHid=" + w.mAttachedHidden 1185 + " exiting=" + w.mExiting + " destroying=" + w.mDestroying); 1186 if (w.mAppToken != null) { 1187 Slog.i(TAG, " mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested); 1188 } 1189 } 1190 } 1191 return w.isVisibleOrAdding(); 1192 } 1193 return false; 1194 } 1195 1196 /** 1197 * Dig through the WindowStates and find the one that the Input Method will target. 1198 * @param willMove 1199 * @return The index+1 in mWindows of the discovered target. 1200 */ 1201 int findDesiredInputMethodWindowIndexLocked(boolean willMove) { 1202 // TODO(multidisplay): Needs some serious rethought when the target and IME are not on the 1203 // same display. Or even when the current IME/target are not on the same screen as the next 1204 // IME/target. For now only look for input windows on the main screen. 1205 WindowList windows = getDefaultWindowListLocked(); 1206 WindowState w = null; 1207 int i; 1208 for (i = windows.size() - 1; i >= 0; --i) { 1209 WindowState win = windows.get(i); 1210 1211 if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG, "Checking window @" + i 1212 + " " + win + " fl=0x" + Integer.toHexString(win.mAttrs.flags)); 1213 if (canBeImeTarget(win)) { 1214 w = win; 1215 //Slog.i(TAG, "Putting input method here!"); 1216 1217 // Yet more tricksyness! If this window is a "starting" 1218 // window, we do actually want to be on top of it, but 1219 // it is not -really- where input will go. So if the caller 1220 // is not actually looking to move the IME, look down below 1221 // for a real window to target... 1222 if (!willMove 1223 && w.mAttrs.type == TYPE_APPLICATION_STARTING 1224 && i > 0) { 1225 WindowState wb = windows.get(i-1); 1226 if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) { 1227 i--; 1228 w = wb; 1229 } 1230 } 1231 break; 1232 } 1233 } 1234 1235 // Now w is either mWindows[0] or an IME (or null if mWindows is empty). 1236 1237 if (DEBUG_INPUT_METHOD && willMove) Slog.v(TAG, "Proposed new IME target: " + w); 1238 1239 // Now, a special case -- if the last target's window is in the 1240 // process of exiting, and is above the new target, keep on the 1241 // last target to avoid flicker. Consider for example a Dialog with 1242 // the IME shown: when the Dialog is dismissed, we want to keep 1243 // the IME above it until it is completely gone so it doesn't drop 1244 // behind the dialog or its full-screen scrim. 1245 final WindowState curTarget = mInputMethodTarget; 1246 if (curTarget != null 1247 && curTarget.isDisplayedLw() 1248 && curTarget.isClosing() 1249 && (w == null || curTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer)) { 1250 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Current target higher, not changing"); 1251 return windows.indexOf(curTarget) + 1; 1252 } 1253 1254 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Desired input method target=" 1255 + w + " willMove=" + willMove); 1256 1257 if (willMove && w != null) { 1258 AppWindowToken token = curTarget == null ? null : curTarget.mAppToken; 1259 if (token != null) { 1260 1261 // Now some fun for dealing with window animations that 1262 // modify the Z order. We need to look at all windows below 1263 // the current target that are in this app, finding the highest 1264 // visible one in layering. 1265 WindowState highestTarget = null; 1266 int highestPos = 0; 1267 if (token.mAppAnimator.animating || token.mAppAnimator.animation != null) { 1268 WindowList curWindows = curTarget.getWindowList(); 1269 int pos = curWindows.indexOf(curTarget); 1270 while (pos >= 0) { 1271 WindowState win = curWindows.get(pos); 1272 if (win.mAppToken != token) { 1273 break; 1274 } 1275 if (!win.mRemoved) { 1276 if (highestTarget == null || win.mWinAnimator.mAnimLayer > 1277 highestTarget.mWinAnimator.mAnimLayer) { 1278 highestTarget = win; 1279 highestPos = pos; 1280 } 1281 } 1282 pos--; 1283 } 1284 } 1285 1286 if (highestTarget != null) { 1287 if (DEBUG_INPUT_METHOD) Slog.v(TAG, mAppTransition + " " + highestTarget 1288 + " animating=" + highestTarget.mWinAnimator.isAnimating() 1289 + " layer=" + highestTarget.mWinAnimator.mAnimLayer 1290 + " new layer=" + w.mWinAnimator.mAnimLayer); 1291 1292 if (mAppTransition.isTransitionSet()) { 1293 // If we are currently setting up for an animation, 1294 // hold everything until we can find out what will happen. 1295 mInputMethodTargetWaitingAnim = true; 1296 mInputMethodTarget = highestTarget; 1297 return highestPos + 1; 1298 } else if (highestTarget.mWinAnimator.isAnimating() && 1299 highestTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) { 1300 // If the window we are currently targeting is involved 1301 // with an animation, and it is on top of the next target 1302 // we will be over, then hold off on moving until 1303 // that is done. 1304 mInputMethodTargetWaitingAnim = true; 1305 mInputMethodTarget = highestTarget; 1306 return highestPos + 1; 1307 } 1308 } 1309 } 1310 } 1311 1312 //Slog.i(TAG, "Placing input method @" + (i+1)); 1313 if (w != null) { 1314 if (willMove) { 1315 if (DEBUG_INPUT_METHOD) Slog.w(TAG, "Moving IM target from " + curTarget + " to " 1316 + w + (HIDE_STACK_CRAWLS ? "" : " Callers=" + Debug.getCallers(4))); 1317 mInputMethodTarget = w; 1318 mInputMethodTargetWaitingAnim = false; 1319 if (w.mAppToken != null) { 1320 setInputMethodAnimLayerAdjustment(w.mAppToken.mAppAnimator.animLayerAdjustment); 1321 } else { 1322 setInputMethodAnimLayerAdjustment(0); 1323 } 1324 } 1325 return i+1; 1326 } 1327 if (willMove) { 1328 if (DEBUG_INPUT_METHOD) Slog.w(TAG, "Moving IM target from " + curTarget + " to null." 1329 + (HIDE_STACK_CRAWLS ? "" : " Callers=" + Debug.getCallers(4))); 1330 mInputMethodTarget = null; 1331 setInputMethodAnimLayerAdjustment(0); 1332 } 1333 return -1; 1334 } 1335 1336 void addInputMethodWindowToListLocked(WindowState win) { 1337 int pos = findDesiredInputMethodWindowIndexLocked(true); 1338 if (pos >= 0) { 1339 win.mTargetAppToken = mInputMethodTarget.mAppToken; 1340 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v( 1341 TAG, "Adding input method window " + win + " at " + pos); 1342 // TODO(multidisplay): IMEs are only supported on the default display. 1343 getDefaultWindowListLocked().add(pos, win); 1344 mWindowsChanged = true; 1345 moveInputMethodDialogsLocked(pos+1); 1346 return; 1347 } 1348 win.mTargetAppToken = null; 1349 addWindowToListInOrderLocked(win, true); 1350 moveInputMethodDialogsLocked(pos); 1351 } 1352 1353 void setInputMethodAnimLayerAdjustment(int adj) { 1354 if (DEBUG_LAYERS) Slog.v(TAG, "Setting im layer adj to " + adj); 1355 mInputMethodAnimLayerAdjustment = adj; 1356 WindowState imw = mInputMethodWindow; 1357 if (imw != null) { 1358 imw.mWinAnimator.mAnimLayer = imw.mLayer + adj; 1359 if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + imw 1360 + " anim layer: " + imw.mWinAnimator.mAnimLayer); 1361 int wi = imw.mChildWindows.size(); 1362 while (wi > 0) { 1363 wi--; 1364 WindowState cw = imw.mChildWindows.get(wi); 1365 cw.mWinAnimator.mAnimLayer = cw.mLayer + adj; 1366 if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + cw 1367 + " anim layer: " + cw.mWinAnimator.mAnimLayer); 1368 } 1369 } 1370 int di = mInputMethodDialogs.size(); 1371 while (di > 0) { 1372 di --; 1373 imw = mInputMethodDialogs.get(di); 1374 imw.mWinAnimator.mAnimLayer = imw.mLayer + adj; 1375 if (DEBUG_LAYERS) Slog.v(TAG, "IM win " + imw 1376 + " anim layer: " + imw.mWinAnimator.mAnimLayer); 1377 } 1378 } 1379 1380 private int tmpRemoveWindowLocked(int interestingPos, WindowState win) { 1381 WindowList windows = win.getWindowList(); 1382 int wpos = windows.indexOf(win); 1383 if (wpos >= 0) { 1384 if (wpos < interestingPos) interestingPos--; 1385 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Temp removing at " + wpos + ": " + win); 1386 windows.remove(wpos); 1387 mWindowsChanged = true; 1388 int NC = win.mChildWindows.size(); 1389 while (NC > 0) { 1390 NC--; 1391 WindowState cw = win.mChildWindows.get(NC); 1392 int cpos = windows.indexOf(cw); 1393 if (cpos >= 0) { 1394 if (cpos < interestingPos) interestingPos--; 1395 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Temp removing child at " 1396 + cpos + ": " + cw); 1397 windows.remove(cpos); 1398 } 1399 } 1400 } 1401 return interestingPos; 1402 } 1403 1404 private void reAddWindowToListInOrderLocked(WindowState win) { 1405 addWindowToListInOrderLocked(win, false); 1406 // This is a hack to get all of the child windows added as well 1407 // at the right position. Child windows should be rare and 1408 // this case should be rare, so it shouldn't be that big a deal. 1409 WindowList windows = win.getWindowList(); 1410 int wpos = windows.indexOf(win); 1411 if (wpos >= 0) { 1412 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "ReAdd removing from " + wpos + ": " + win); 1413 windows.remove(wpos); 1414 mWindowsChanged = true; 1415 reAddWindowLocked(wpos, win); 1416 } 1417 } 1418 1419 void logWindowList(final WindowList windows, String prefix) { 1420 int N = windows.size(); 1421 while (N > 0) { 1422 N--; 1423 Slog.v(TAG, prefix + "#" + N + ": " + windows.get(N)); 1424 } 1425 } 1426 1427 void moveInputMethodDialogsLocked(int pos) { 1428 ArrayList<WindowState> dialogs = mInputMethodDialogs; 1429 1430 // TODO(multidisplay): IMEs are only supported on the default display. 1431 WindowList windows = getDefaultWindowListLocked(); 1432 final int N = dialogs.size(); 1433 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Removing " + N + " dialogs w/pos=" + pos); 1434 for (int i=0; i<N; i++) { 1435 pos = tmpRemoveWindowLocked(pos, dialogs.get(i)); 1436 } 1437 if (DEBUG_INPUT_METHOD) { 1438 Slog.v(TAG, "Window list w/pos=" + pos); 1439 logWindowList(windows, " "); 1440 } 1441 1442 if (pos >= 0) { 1443 final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken; 1444 if (pos < windows.size()) { 1445 WindowState wp = windows.get(pos); 1446 if (wp == mInputMethodWindow) { 1447 pos++; 1448 } 1449 } 1450 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Adding " + N + " dialogs at pos=" + pos); 1451 for (int i=0; i<N; i++) { 1452 WindowState win = dialogs.get(i); 1453 win.mTargetAppToken = targetAppToken; 1454 pos = reAddWindowLocked(pos, win); 1455 } 1456 if (DEBUG_INPUT_METHOD) { 1457 Slog.v(TAG, "Final window list:"); 1458 logWindowList(windows, " "); 1459 } 1460 return; 1461 } 1462 for (int i=0; i<N; i++) { 1463 WindowState win = dialogs.get(i); 1464 win.mTargetAppToken = null; 1465 reAddWindowToListInOrderLocked(win); 1466 if (DEBUG_INPUT_METHOD) { 1467 Slog.v(TAG, "No IM target, final list:"); 1468 logWindowList(windows, " "); 1469 } 1470 } 1471 } 1472 1473 boolean moveInputMethodWindowsIfNeededLocked(boolean needAssignLayers) { 1474 final WindowState imWin = mInputMethodWindow; 1475 final int DN = mInputMethodDialogs.size(); 1476 if (imWin == null && DN == 0) { 1477 return false; 1478 } 1479 1480 // TODO(multidisplay): IMEs are only supported on the default display. 1481 WindowList windows = getDefaultWindowListLocked(); 1482 1483 int imPos = findDesiredInputMethodWindowIndexLocked(true); 1484 if (imPos >= 0) { 1485 // In this case, the input method windows are to be placed 1486 // immediately above the window they are targeting. 1487 1488 // First check to see if the input method windows are already 1489 // located here, and contiguous. 1490 final int N = windows.size(); 1491 WindowState firstImWin = imPos < N 1492 ? windows.get(imPos) : null; 1493 1494 // Figure out the actual input method window that should be 1495 // at the bottom of their stack. 1496 WindowState baseImWin = imWin != null 1497 ? imWin : mInputMethodDialogs.get(0); 1498 if (baseImWin.mChildWindows.size() > 0) { 1499 WindowState cw = baseImWin.mChildWindows.get(0); 1500 if (cw.mSubLayer < 0) baseImWin = cw; 1501 } 1502 1503 if (firstImWin == baseImWin) { 1504 // The windows haven't moved... but are they still contiguous? 1505 // First find the top IM window. 1506 int pos = imPos+1; 1507 while (pos < N) { 1508 if (!(windows.get(pos)).mIsImWindow) { 1509 break; 1510 } 1511 pos++; 1512 } 1513 pos++; 1514 // Now there should be no more input method windows above. 1515 while (pos < N) { 1516 if ((windows.get(pos)).mIsImWindow) { 1517 break; 1518 } 1519 pos++; 1520 } 1521 if (pos >= N) { 1522 // Z order is good. 1523 // The IM target window may be changed, so update the mTargetAppToken. 1524 if (imWin != null) { 1525 imWin.mTargetAppToken = mInputMethodTarget.mAppToken; 1526 } 1527 return false; 1528 } 1529 } 1530 1531 if (imWin != null) { 1532 if (DEBUG_INPUT_METHOD) { 1533 Slog.v(TAG, "Moving IM from " + imPos); 1534 logWindowList(windows, " "); 1535 } 1536 imPos = tmpRemoveWindowLocked(imPos, imWin); 1537 if (DEBUG_INPUT_METHOD) { 1538 Slog.v(TAG, "List after removing with new pos " + imPos + ":"); 1539 logWindowList(windows, " "); 1540 } 1541 imWin.mTargetAppToken = mInputMethodTarget.mAppToken; 1542 reAddWindowLocked(imPos, imWin); 1543 if (DEBUG_INPUT_METHOD) { 1544 Slog.v(TAG, "List after moving IM to " + imPos + ":"); 1545 logWindowList(windows, " "); 1546 } 1547 if (DN > 0) moveInputMethodDialogsLocked(imPos+1); 1548 } else { 1549 moveInputMethodDialogsLocked(imPos); 1550 } 1551 1552 } else { 1553 // In this case, the input method windows go in a fixed layer, 1554 // because they aren't currently associated with a focus window. 1555 1556 if (imWin != null) { 1557 if (DEBUG_INPUT_METHOD) Slog.v(TAG, "Moving IM from " + imPos); 1558 tmpRemoveWindowLocked(0, imWin); 1559 imWin.mTargetAppToken = null; 1560 reAddWindowToListInOrderLocked(imWin); 1561 if (DEBUG_INPUT_METHOD) { 1562 Slog.v(TAG, "List with no IM target:"); 1563 logWindowList(windows, " "); 1564 } 1565 if (DN > 0) moveInputMethodDialogsLocked(-1); 1566 } else { 1567 moveInputMethodDialogsLocked(-1); 1568 } 1569 1570 } 1571 1572 if (needAssignLayers) { 1573 assignLayersLocked(windows); 1574 } 1575 1576 return true; 1577 } 1578 1579 final boolean isWallpaperVisible(WindowState wallpaperTarget) { 1580 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured=" 1581 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??") 1582 + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null) 1583 ? wallpaperTarget.mAppToken.mAppAnimator.animation : null) 1584 + " upper=" + mUpperWallpaperTarget 1585 + " lower=" + mLowerWallpaperTarget); 1586 return (wallpaperTarget != null 1587 && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null 1588 && wallpaperTarget.mAppToken.mAppAnimator.animation != null))) 1589 || mUpperWallpaperTarget != null 1590 || mLowerWallpaperTarget != null; 1591 } 1592 1593 static final int ADJUST_WALLPAPER_LAYERS_CHANGED = 1<<1; 1594 static final int ADJUST_WALLPAPER_VISIBILITY_CHANGED = 1<<2; 1595 1596 int adjustWallpaperWindowsLocked() { 1597 mInnerFields.mWallpaperMayChange = false; 1598 boolean targetChanged = false; 1599 1600 // TODO(multidisplay): Wallpapers on main screen only. 1601 final DisplayInfo displayInfo = getDefaultDisplayContentLocked().getDisplayInfo(); 1602 final int dw = displayInfo.logicalWidth; 1603 final int dh = displayInfo.logicalHeight; 1604 1605 // First find top-most window that has asked to be on top of the 1606 // wallpaper; all wallpapers go behind it. 1607 final WindowList windows = getDefaultWindowListLocked(); 1608 int N = windows.size(); 1609 WindowState w = null; 1610 WindowState foundW = null; 1611 int foundI = 0; 1612 WindowState topCurW = null; 1613 int topCurI = 0; 1614 int windowDetachedI = -1; 1615 int i = N; 1616 while (i > 0) { 1617 i--; 1618 w = windows.get(i); 1619 if ((w.mAttrs.type == TYPE_WALLPAPER)) { 1620 if (topCurW == null) { 1621 topCurW = w; 1622 topCurI = i; 1623 } 1624 continue; 1625 } 1626 topCurW = null; 1627 if (w != mAnimator.mWindowDetachedWallpaper && w.mAppToken != null) { 1628 // If this window's app token is hidden and not animating, 1629 // it is of no interest to us. 1630 if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) { 1631 if (DEBUG_WALLPAPER) Slog.v(TAG, 1632 "Skipping hidden and not animating token: " + w); 1633 continue; 1634 } 1635 } 1636 if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen=" 1637 + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState); 1638 if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isOnScreen() 1639 && (mWallpaperTarget == w || w.isDrawFinishedLw())) { 1640 if (DEBUG_WALLPAPER) Slog.v(TAG, 1641 "Found wallpaper target: #" + i + "=" + w); 1642 foundW = w; 1643 foundI = i; 1644 if (w == mWallpaperTarget && w.mWinAnimator.isAnimating()) { 1645 // The current wallpaper target is animating, so we'll 1646 // look behind it for another possible target and figure 1647 // out what is going on below. 1648 if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w 1649 + ": token animating, looking behind."); 1650 continue; 1651 } 1652 break; 1653 } else if (w == mAnimator.mWindowDetachedWallpaper) { 1654 windowDetachedI = i; 1655 } 1656 } 1657 1658 if (foundW == null && windowDetachedI >= 0) { 1659 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 1660 "Found animating detached wallpaper activity: #" + i + "=" + w); 1661 foundW = w; 1662 foundI = windowDetachedI; 1663 } 1664 1665 if (mWallpaperTarget != foundW 1666 && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != foundW)) { 1667 if (DEBUG_WALLPAPER_LIGHT) { 1668 Slog.v(TAG, "New wallpaper target: " + foundW 1669 + " oldTarget: " + mWallpaperTarget); 1670 } 1671 1672 mLowerWallpaperTarget = null; 1673 mUpperWallpaperTarget = null; 1674 1675 WindowState oldW = mWallpaperTarget; 1676 mWallpaperTarget = foundW; 1677 targetChanged = true; 1678 1679 // Now what is happening... if the current and new targets are 1680 // animating, then we are in our super special mode! 1681 if (foundW != null && oldW != null) { 1682 boolean oldAnim = oldW.isAnimatingLw(); 1683 boolean foundAnim = foundW.isAnimatingLw(); 1684 if (DEBUG_WALLPAPER_LIGHT) { 1685 Slog.v(TAG, "New animation: " + foundAnim 1686 + " old animation: " + oldAnim); 1687 } 1688 if (foundAnim && oldAnim) { 1689 int oldI = windows.indexOf(oldW); 1690 if (DEBUG_WALLPAPER_LIGHT) { 1691 Slog.v(TAG, "New i: " + foundI + " old i: " + oldI); 1692 } 1693 if (oldI >= 0) { 1694 if (DEBUG_WALLPAPER_LIGHT) { 1695 Slog.v(TAG, "Animating wallpapers: old#" + oldI 1696 + "=" + oldW + "; new#" + foundI 1697 + "=" + foundW); 1698 } 1699 1700 // Set the new target correctly. 1701 if (foundW.mAppToken != null && foundW.mAppToken.hiddenRequested) { 1702 if (DEBUG_WALLPAPER_LIGHT) { 1703 Slog.v(TAG, "Old wallpaper still the target."); 1704 } 1705 mWallpaperTarget = oldW; 1706 foundW = oldW; 1707 foundI = oldI; 1708 } 1709 // Now set the upper and lower wallpaper targets 1710 // correctly, and make sure that we are positioning 1711 // the wallpaper below the lower. 1712 else if (foundI > oldI) { 1713 // The new target is on top of the old one. 1714 if (DEBUG_WALLPAPER_LIGHT) { 1715 Slog.v(TAG, "Found target above old target."); 1716 } 1717 mUpperWallpaperTarget = foundW; 1718 mLowerWallpaperTarget = oldW; 1719 foundW = oldW; 1720 foundI = oldI; 1721 } else { 1722 // The new target is below the old one. 1723 if (DEBUG_WALLPAPER_LIGHT) { 1724 Slog.v(TAG, "Found target below old target."); 1725 } 1726 mUpperWallpaperTarget = oldW; 1727 mLowerWallpaperTarget = foundW; 1728 } 1729 } 1730 } 1731 } 1732 1733 } else if (mLowerWallpaperTarget != null) { 1734 // Is it time to stop animating? 1735 if (!mLowerWallpaperTarget.isAnimatingLw() || !mUpperWallpaperTarget.isAnimatingLw()) { 1736 if (DEBUG_WALLPAPER_LIGHT) { 1737 Slog.v(TAG, "No longer animating wallpaper targets!"); 1738 } 1739 mLowerWallpaperTarget = null; 1740 mUpperWallpaperTarget = null; 1741 mWallpaperTarget = foundW; 1742 targetChanged = true; 1743 } 1744 } 1745 1746 boolean visible = foundW != null; 1747 if (visible) { 1748 // The window is visible to the compositor... but is it visible 1749 // to the user? That is what the wallpaper cares about. 1750 visible = isWallpaperVisible(foundW); 1751 if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible); 1752 1753 // If the wallpaper target is animating, we may need to copy 1754 // its layer adjustment. Only do this if we are not transfering 1755 // between two wallpaper targets. 1756 mWallpaperAnimLayerAdjustment = 1757 (mLowerWallpaperTarget == null && foundW.mAppToken != null) 1758 ? foundW.mAppToken.mAppAnimator.animLayerAdjustment : 0; 1759 1760 final int maxLayer = mPolicy.getMaxWallpaperLayer() 1761 * TYPE_LAYER_MULTIPLIER 1762 + TYPE_LAYER_OFFSET; 1763 1764 // Now w is the window we are supposed to be behind... but we 1765 // need to be sure to also be behind any of its attached windows, 1766 // AND any starting window associated with it, AND below the 1767 // maximum layer the policy allows for wallpapers. 1768 while (foundI > 0) { 1769 WindowState wb = windows.get(foundI-1); 1770 if (wb.mBaseLayer < maxLayer && 1771 wb.mAttachedWindow != foundW && 1772 (foundW.mAttachedWindow == null || 1773 wb.mAttachedWindow != foundW.mAttachedWindow) && 1774 (wb.mAttrs.type != TYPE_APPLICATION_STARTING || 1775 foundW.mToken == null || wb.mToken != foundW.mToken)) { 1776 // This window is not related to the previous one in any 1777 // interesting way, so stop here. 1778 break; 1779 } 1780 foundW = wb; 1781 foundI--; 1782 } 1783 } else { 1784 if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target"); 1785 } 1786 1787 if (foundW == null && topCurW != null) { 1788 // There is no wallpaper target, so it goes at the bottom. 1789 // We will assume it is the same place as last time, if known. 1790 foundW = topCurW; 1791 foundI = topCurI+1; 1792 } else { 1793 // Okay i is the position immediately above the wallpaper. Look at 1794 // what is below it for later. 1795 foundW = foundI > 0 ? windows.get(foundI-1) : null; 1796 } 1797 1798 if (visible) { 1799 if (mWallpaperTarget.mWallpaperX >= 0) { 1800 mLastWallpaperX = mWallpaperTarget.mWallpaperX; 1801 mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep; 1802 } 1803 if (mWallpaperTarget.mWallpaperY >= 0) { 1804 mLastWallpaperY = mWallpaperTarget.mWallpaperY; 1805 mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep; 1806 } 1807 } 1808 1809 // Start stepping backwards from here, ensuring that our wallpaper windows 1810 // are correctly placed. 1811 int changed = 0; 1812 int curTokenIndex = mWallpaperTokens.size(); 1813 while (curTokenIndex > 0) { 1814 curTokenIndex--; 1815 WindowToken token = mWallpaperTokens.get(curTokenIndex); 1816 if (token.hidden == visible) { 1817 if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG, 1818 "Wallpaper token " + token + " hidden=" + !visible); 1819 changed |= ADJUST_WALLPAPER_VISIBILITY_CHANGED; 1820 token.hidden = !visible; 1821 // Need to do a layout to ensure the wallpaper now has the 1822 // correct size. 1823 getDefaultDisplayContentLocked().layoutNeeded = true; 1824 } 1825 1826 int curWallpaperIndex = token.windows.size(); 1827 while (curWallpaperIndex > 0) { 1828 curWallpaperIndex--; 1829 WindowState wallpaper = token.windows.get(curWallpaperIndex); 1830 1831 if (visible) { 1832 updateWallpaperOffsetLocked(wallpaper, dw, dh, false); 1833 } 1834 1835 // First, make sure the client has the current visibility 1836 // state. 1837 dispatchWallpaperVisibility(wallpaper, visible); 1838 1839 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment; 1840 if (DEBUG_LAYERS || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "adjustWallpaper win " 1841 + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); 1842 1843 // First, if this window is at the current index, then all 1844 // is well. 1845 if (wallpaper == foundW) { 1846 foundI--; 1847 foundW = foundI > 0 1848 ? windows.get(foundI-1) : null; 1849 continue; 1850 } 1851 1852 // The window didn't match... the current wallpaper window, 1853 // wherever it is, is in the wrong place, so make sure it is 1854 // not in the list. 1855 int oldIndex = windows.indexOf(wallpaper); 1856 if (oldIndex >= 0) { 1857 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Wallpaper removing at " 1858 + oldIndex + ": " + wallpaper); 1859 windows.remove(oldIndex); 1860 mWindowsChanged = true; 1861 if (oldIndex < foundI) { 1862 foundI--; 1863 } 1864 } 1865 1866 // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost 1867 // layer. For keyguard over wallpaper put the wallpaper under the keyguard. 1868 int insertionIndex = 0; 1869 if (visible && foundW != null) { 1870 final int type = foundW.mAttrs.type; 1871 if (type == TYPE_KEYGUARD || type == TYPE_KEYGUARD_SCRIM) { 1872 insertionIndex = windows.indexOf(foundW); 1873 } 1874 } 1875 if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) { 1876 Slog.v(TAG, "Moving wallpaper " + wallpaper 1877 + " from " + oldIndex + " to " + insertionIndex); 1878 } 1879 1880 windows.add(insertionIndex, wallpaper); 1881 mWindowsChanged = true; 1882 changed |= ADJUST_WALLPAPER_LAYERS_CHANGED; 1883 } 1884 } 1885 1886 /* 1887 final TaskStack targetStack = 1888 mWallpaperTarget == null ? null : mWallpaperTarget.getStack(); 1889 if ((changed & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0 && 1890 targetStack != null && !targetStack.isHomeStack()) { 1891 // If the wallpaper target is not on the home stack then make sure that all windows 1892 // from other non-home stacks are above the wallpaper. 1893 for (i = foundI - 1; i >= 0; --i) { 1894 WindowState win = windows.get(i); 1895 if (!win.isVisibleLw()) { 1896 continue; 1897 } 1898 final TaskStack winStack = win.getStack(); 1899 if (winStack != null && !winStack.isHomeStack() && winStack != targetStack) { 1900 windows.remove(i); 1901 windows.add(foundI + 1, win); 1902 } 1903 } 1904 } 1905 */ 1906 1907 if (targetChanged && DEBUG_WALLPAPER_LIGHT) { 1908 Slog.d(TAG, "New wallpaper: target=" + mWallpaperTarget 1909 + " lower=" + mLowerWallpaperTarget + " upper=" 1910 + mUpperWallpaperTarget); 1911 } 1912 1913 return changed; 1914 } 1915 1916 void setWallpaperAnimLayerAdjustmentLocked(int adj) { 1917 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, 1918 "Setting wallpaper layer adj to " + adj); 1919 mWallpaperAnimLayerAdjustment = adj; 1920 int curTokenIndex = mWallpaperTokens.size(); 1921 while (curTokenIndex > 0) { 1922 curTokenIndex--; 1923 WindowToken token = mWallpaperTokens.get(curTokenIndex); 1924 int curWallpaperIndex = token.windows.size(); 1925 while (curWallpaperIndex > 0) { 1926 curWallpaperIndex--; 1927 WindowState wallpaper = token.windows.get(curWallpaperIndex); 1928 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj; 1929 if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win " 1930 + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer); 1931 } 1932 } 1933 } 1934 1935 boolean updateWallpaperOffsetLocked(WindowState wallpaperWin, int dw, int dh, 1936 boolean sync) { 1937 boolean changed = false; 1938 boolean rawChanged = false; 1939 float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : 0.5f; 1940 float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f; 1941 int availw = wallpaperWin.mFrame.right-wallpaperWin.mFrame.left-dw; 1942 int offset = availw > 0 ? -(int)(availw*wpx+.5f) : 0; 1943 changed = wallpaperWin.mXOffset != offset; 1944 if (changed) { 1945 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " 1946 + wallpaperWin + " x: " + offset); 1947 wallpaperWin.mXOffset = offset; 1948 } 1949 if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) { 1950 wallpaperWin.mWallpaperX = wpx; 1951 wallpaperWin.mWallpaperXStep = wpxs; 1952 rawChanged = true; 1953 } 1954 1955 float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f; 1956 float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f; 1957 int availh = wallpaperWin.mFrame.bottom-wallpaperWin.mFrame.top-dh; 1958 offset = availh > 0 ? -(int)(availh*wpy+.5f) : 0; 1959 if (wallpaperWin.mYOffset != offset) { 1960 if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " 1961 + wallpaperWin + " y: " + offset); 1962 changed = true; 1963 wallpaperWin.mYOffset = offset; 1964 } 1965 if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) { 1966 wallpaperWin.mWallpaperY = wpy; 1967 wallpaperWin.mWallpaperYStep = wpys; 1968 rawChanged = true; 1969 } 1970 1971 if (rawChanged && (wallpaperWin.mAttrs.privateFlags & 1972 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) { 1973 try { 1974 if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset " 1975 + wallpaperWin + " x=" + wallpaperWin.mWallpaperX 1976 + " y=" + wallpaperWin.mWallpaperY); 1977 if (sync) { 1978 mWaitingOnWallpaper = wallpaperWin; 1979 } 1980 wallpaperWin.mClient.dispatchWallpaperOffsets( 1981 wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY, 1982 wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync); 1983 if (sync) { 1984 if (mWaitingOnWallpaper != null) { 1985 long start = SystemClock.uptimeMillis(); 1986 if ((mLastWallpaperTimeoutTime+WALLPAPER_TIMEOUT_RECOVERY) 1987 < start) { 1988 try { 1989 if (DEBUG_WALLPAPER) Slog.v(TAG, 1990 "Waiting for offset complete..."); 1991 mWindowMap.wait(WALLPAPER_TIMEOUT); 1992 } catch (InterruptedException e) { 1993 } 1994 if (DEBUG_WALLPAPER) Slog.v(TAG, "Offset complete!"); 1995 if ((start+WALLPAPER_TIMEOUT) 1996 < SystemClock.uptimeMillis()) { 1997 Slog.i(TAG, "Timeout waiting for wallpaper to offset: " 1998 + wallpaperWin); 1999 mLastWallpaperTimeoutTime = start; 2000 } 2001 } 2002 mWaitingOnWallpaper = null; 2003 } 2004 } 2005 } catch (RemoteException e) { 2006 } 2007 } 2008 2009 return changed; 2010 } 2011 2012 void wallpaperOffsetsComplete(IBinder window) { 2013 synchronized (mWindowMap) { 2014 if (mWaitingOnWallpaper != null && 2015 mWaitingOnWallpaper.mClient.asBinder() == window) { 2016 mWaitingOnWallpaper = null; 2017 mWindowMap.notifyAll(); 2018 } 2019 } 2020 } 2021 2022 void updateWallpaperOffsetLocked(WindowState changingTarget, boolean sync) { 2023 final DisplayContent displayContent = changingTarget.mDisplayContent; 2024 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 2025 final int dw = displayInfo.logicalWidth; 2026 final int dh = displayInfo.logicalHeight; 2027 2028 WindowState target = mWallpaperTarget; 2029 if (target != null) { 2030 if (target.mWallpaperX >= 0) { 2031 mLastWallpaperX = target.mWallpaperX; 2032 } else if (changingTarget.mWallpaperX >= 0) { 2033 mLastWallpaperX = changingTarget.mWallpaperX; 2034 } 2035 if (target.mWallpaperY >= 0) { 2036 mLastWallpaperY = target.mWallpaperY; 2037 } else if (changingTarget.mWallpaperY >= 0) { 2038 mLastWallpaperY = changingTarget.mWallpaperY; 2039 } 2040 } 2041 2042 int curTokenIndex = mWallpaperTokens.size(); 2043 while (curTokenIndex > 0) { 2044 curTokenIndex--; 2045 WindowToken token = mWallpaperTokens.get(curTokenIndex); 2046 int curWallpaperIndex = token.windows.size(); 2047 while (curWallpaperIndex > 0) { 2048 curWallpaperIndex--; 2049 WindowState wallpaper = token.windows.get(curWallpaperIndex); 2050 if (updateWallpaperOffsetLocked(wallpaper, dw, dh, sync)) { 2051 WindowStateAnimator winAnimator = wallpaper.mWinAnimator; 2052 winAnimator.computeShownFrameLocked(); 2053 // No need to lay out the windows - we can just set the wallpaper position 2054 // directly. 2055 winAnimator.setWallpaperOffset(wallpaper.mShownFrame); 2056 // We only want to be synchronous with one wallpaper. 2057 sync = false; 2058 } 2059 } 2060 } 2061 } 2062 2063 /** 2064 * Check wallpaper for visiblity change and notify window if so. 2065 * @param wallpaper The wallpaper to test and notify. 2066 * @param visible Current visibility. 2067 */ 2068 void dispatchWallpaperVisibility(final WindowState wallpaper, final boolean visible) { 2069 if (wallpaper.mWallpaperVisible != visible) { 2070 wallpaper.mWallpaperVisible = visible; 2071 try { 2072 if (DEBUG_VISIBILITY || DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, 2073 "Updating vis of wallpaper " + wallpaper 2074 + ": " + visible + " from:\n" + Debug.getCallers(4, " ")); 2075 wallpaper.mClient.dispatchAppVisibility(visible); 2076 } catch (RemoteException e) { 2077 } 2078 } 2079 } 2080 2081 void updateWallpaperVisibilityLocked() { 2082 final boolean visible = isWallpaperVisible(mWallpaperTarget); 2083 final DisplayContent displayContent = mWallpaperTarget.mDisplayContent; 2084 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 2085 final int dw = displayInfo.logicalWidth; 2086 final int dh = displayInfo.logicalHeight; 2087 2088 int curTokenIndex = mWallpaperTokens.size(); 2089 while (curTokenIndex > 0) { 2090 curTokenIndex--; 2091 WindowToken token = mWallpaperTokens.get(curTokenIndex); 2092 if (token.hidden == visible) { 2093 token.hidden = !visible; 2094 // Need to do a layout to ensure the wallpaper now has the 2095 // correct size. 2096 getDefaultDisplayContentLocked().layoutNeeded = true; 2097 } 2098 2099 int curWallpaperIndex = token.windows.size(); 2100 while (curWallpaperIndex > 0) { 2101 curWallpaperIndex--; 2102 WindowState wallpaper = token.windows.get(curWallpaperIndex); 2103 if (visible) { 2104 updateWallpaperOffsetLocked(wallpaper, dw, dh, false); 2105 } 2106 2107 dispatchWallpaperVisibility(wallpaper, visible); 2108 } 2109 } 2110 } 2111 2112 public int addWindow(Session session, IWindow client, int seq, 2113 WindowManager.LayoutParams attrs, int viewVisibility, int displayId, 2114 Rect outContentInsets, InputChannel outInputChannel) { 2115 int[] appOp = new int[1]; 2116 int res = mPolicy.checkAddPermission(attrs, appOp); 2117 if (res != WindowManagerGlobal.ADD_OKAY) { 2118 return res; 2119 } 2120 2121 boolean reportNewConfig = false; 2122 WindowState attachedWindow = null; 2123 WindowState win = null; 2124 long origId; 2125 final int type = attrs.type; 2126 2127 synchronized(mWindowMap) { 2128 if (!mDisplayReady) { 2129 throw new IllegalStateException("Display has not been initialialized"); 2130 } 2131 2132 final DisplayContent displayContent = getDisplayContentLocked(displayId); 2133 if (displayContent == null) { 2134 Slog.w(TAG, "Attempted to add window to a display that does not exist: " 2135 + displayId + ". Aborting."); 2136 return WindowManagerGlobal.ADD_INVALID_DISPLAY; 2137 } 2138 if (!displayContent.hasAccess(session.mUid)) { 2139 Slog.w(TAG, "Attempted to add window to a display for which the application " 2140 + "does not have access: " + displayId + ". Aborting."); 2141 return WindowManagerGlobal.ADD_INVALID_DISPLAY; 2142 } 2143 2144 if (mWindowMap.containsKey(client.asBinder())) { 2145 Slog.w(TAG, "Window " + client + " is already added"); 2146 return WindowManagerGlobal.ADD_DUPLICATE_ADD; 2147 } 2148 2149 if (type >= FIRST_SUB_WINDOW && type <= LAST_SUB_WINDOW) { 2150 attachedWindow = windowForClientLocked(null, attrs.token, false); 2151 if (attachedWindow == null) { 2152 Slog.w(TAG, "Attempted to add window with token that is not a window: " 2153 + attrs.token + ". Aborting."); 2154 return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; 2155 } 2156 if (attachedWindow.mAttrs.type >= FIRST_SUB_WINDOW 2157 && attachedWindow.mAttrs.type <= LAST_SUB_WINDOW) { 2158 Slog.w(TAG, "Attempted to add window with token that is a sub-window: " 2159 + attrs.token + ". Aborting."); 2160 return WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN; 2161 } 2162 } 2163 2164 if (type == TYPE_PRIVATE_PRESENTATION && !displayContent.isPrivate()) { 2165 Slog.w(TAG, "Attempted to add private presentation window to a non-private display. Aborting."); 2166 return WindowManagerGlobal.ADD_PERMISSION_DENIED; 2167 } 2168 2169 boolean addToken = false; 2170 WindowToken token = mTokenMap.get(attrs.token); 2171 if (token == null) { 2172 if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { 2173 Slog.w(TAG, "Attempted to add application window with unknown token " 2174 + attrs.token + ". Aborting."); 2175 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 2176 } 2177 if (type == TYPE_INPUT_METHOD) { 2178 Slog.w(TAG, "Attempted to add input method window with unknown token " 2179 + attrs.token + ". Aborting."); 2180 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 2181 } 2182 if (type == TYPE_WALLPAPER) { 2183 Slog.w(TAG, "Attempted to add wallpaper window with unknown token " 2184 + attrs.token + ". Aborting."); 2185 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 2186 } 2187 if (type == TYPE_DREAM) { 2188 Slog.w(TAG, "Attempted to add Dream window with unknown token " 2189 + attrs.token + ". Aborting."); 2190 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 2191 } 2192 token = new WindowToken(this, attrs.token, -1, false); 2193 addToken = true; 2194 } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { 2195 AppWindowToken atoken = token.appWindowToken; 2196 if (atoken == null) { 2197 Slog.w(TAG, "Attempted to add window with non-application token " 2198 + token + ". Aborting."); 2199 return WindowManagerGlobal.ADD_NOT_APP_TOKEN; 2200 } else if (atoken.removed) { 2201 Slog.w(TAG, "Attempted to add window with exiting application token " 2202 + token + ". Aborting."); 2203 return WindowManagerGlobal.ADD_APP_EXITING; 2204 } 2205 if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) { 2206 // No need for this guy! 2207 if (localLOGV) Slog.v( 2208 TAG, "**** NO NEED TO START: " + attrs.getTitle()); 2209 return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED; 2210 } 2211 } else if (type == TYPE_INPUT_METHOD) { 2212 if (token.windowType != TYPE_INPUT_METHOD) { 2213 Slog.w(TAG, "Attempted to add input method window with bad token " 2214 + attrs.token + ". Aborting."); 2215 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 2216 } 2217 } else if (type == TYPE_WALLPAPER) { 2218 if (token.windowType != TYPE_WALLPAPER) { 2219 Slog.w(TAG, "Attempted to add wallpaper window with bad token " 2220 + attrs.token + ". Aborting."); 2221 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 2222 } 2223 } else if (type == TYPE_DREAM) { 2224 if (token.windowType != TYPE_DREAM) { 2225 Slog.w(TAG, "Attempted to add Dream window with bad token " 2226 + attrs.token + ". Aborting."); 2227 return WindowManagerGlobal.ADD_BAD_APP_TOKEN; 2228 } 2229 } 2230 2231 win = new WindowState(this, session, client, token, 2232 attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent); 2233 if (win.mDeathRecipient == null) { 2234 // Client has apparently died, so there is no reason to 2235 // continue. 2236 Slog.w(TAG, "Adding window client " + client.asBinder() 2237 + " that is dead, aborting."); 2238 return WindowManagerGlobal.ADD_APP_EXITING; 2239 } 2240 2241 mPolicy.adjustWindowParamsLw(win.mAttrs); 2242 win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs)); 2243 2244 res = mPolicy.prepareAddWindowLw(win, attrs); 2245 if (res != WindowManagerGlobal.ADD_OKAY) { 2246 return res; 2247 } 2248 2249 if (outInputChannel != null && (attrs.inputFeatures 2250 & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) { 2251 String name = win.makeInputChannelName(); 2252 InputChannel[] inputChannels = InputChannel.openInputChannelPair(name); 2253 win.setInputChannel(inputChannels[0]); 2254 inputChannels[1].transferTo(outInputChannel); 2255 2256 mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle); 2257 } 2258 2259 // From now on, no exceptions or errors allowed! 2260 2261 res = WindowManagerGlobal.ADD_OKAY; 2262 2263 origId = Binder.clearCallingIdentity(); 2264 2265 if (addToken) { 2266 mTokenMap.put(attrs.token, token); 2267 } 2268 win.attach(); 2269 mWindowMap.put(client.asBinder(), win); 2270 if (win.mAppOp != AppOpsManager.OP_NONE) { 2271 if (mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage()) 2272 != AppOpsManager.MODE_ALLOWED) { 2273 win.setAppOpVisibilityLw(false); 2274 } 2275 } 2276 2277 if (type == TYPE_APPLICATION_STARTING && token.appWindowToken != null) { 2278 token.appWindowToken.startingWindow = win; 2279 if (DEBUG_STARTING_WINDOW) Slog.v (TAG, "addWindow: " + token.appWindowToken 2280 + " startingWindow=" + win); 2281 Message m = mH.obtainMessage(H.REMOVE_STARTING_TIMEOUT, token.appWindowToken); 2282 mH.sendMessageDelayed(m, STARTING_WINDOW_TIMEOUT_DURATION); 2283 } 2284 2285 boolean imMayMove = true; 2286 2287 if (type == TYPE_INPUT_METHOD) { 2288 win.mGivenInsetsPending = true; 2289 mInputMethodWindow = win; 2290 addInputMethodWindowToListLocked(win); 2291 imMayMove = false; 2292 } else if (type == TYPE_INPUT_METHOD_DIALOG) { 2293 mInputMethodDialogs.add(win); 2294 addWindowToListInOrderLocked(win, true); 2295 moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true)); 2296 imMayMove = false; 2297 } else { 2298 addWindowToListInOrderLocked(win, true); 2299 if (type == TYPE_WALLPAPER) { 2300 mLastWallpaperTimeoutTime = 0; 2301 displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; 2302 } else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) { 2303 displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; 2304 } else if (mWallpaperTarget != null 2305 && mWallpaperTarget.mLayer >= win.mBaseLayer) { 2306 // If there is currently a wallpaper being shown, and 2307 // the base layer of the new window is below the current 2308 // layer of the target window, then adjust the wallpaper. 2309 // This is to avoid a new window being placed between the 2310 // wallpaper and its target. 2311 displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER; 2312 } 2313 } 2314 2315 win.mWinAnimator.mEnterAnimationPending = true; 2316 2317 if (displayContent.isDefaultDisplay) { 2318 mPolicy.getContentInsetHintLw(attrs, outContentInsets); 2319 } else { 2320 outContentInsets.setEmpty(); 2321 } 2322 2323 if (mInTouchMode) { 2324 res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE; 2325 } 2326 if (win.mAppToken == null || !win.mAppToken.clientHidden) { 2327 res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; 2328 } 2329 2330 mInputMonitor.setUpdateInputWindowsNeededLw(); 2331 2332 boolean focusChanged = false; 2333 if (win.canReceiveKeys()) { 2334 focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS, 2335 false /*updateInputWindows*/); 2336 if (focusChanged) { 2337 imMayMove = false; 2338 } 2339 } 2340 2341 if (imMayMove) { 2342 moveInputMethodWindowsIfNeededLocked(false); 2343 } 2344 2345 assignLayersLocked(displayContent.getWindowList()); 2346 // Don't do layout here, the window must call 2347 // relayout to be displayed, so we'll do it there. 2348 2349 if (focusChanged) { 2350 finishUpdateFocusedWindowAfterAssignLayersLocked(false /*updateInputWindows*/); 2351 } 2352 mInputMonitor.updateInputWindowsLw(false /*force*/); 2353 2354 if (localLOGV) Slog.v( 2355 TAG, "New client " + client.asBinder() 2356 + ": window=" + win); 2357 2358 if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) { 2359 reportNewConfig = true; 2360 } 2361 } 2362 2363 if (reportNewConfig) { 2364 sendNewConfiguration(); 2365 } 2366 2367 Binder.restoreCallingIdentity(origId); 2368 2369 return res; 2370 } 2371 2372 public void removeWindow(Session session, IWindow client) { 2373 synchronized(mWindowMap) { 2374 WindowState win = windowForClientLocked(session, client, false); 2375 if (win == null) { 2376 return; 2377 } 2378 removeWindowLocked(session, win); 2379 } 2380 } 2381 2382 public void removeWindowLocked(Session session, WindowState win) { 2383 removeWindowLocked(session, win, false); 2384 } 2385 2386 private void removeWindowLocked(Session session, WindowState win, 2387 boolean forceRemove) { 2388 if (win.mAttrs.type == TYPE_APPLICATION_STARTING) { 2389 if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Starting window removed " + win); 2390 removeStartingWindowTimeout(win.mAppToken); 2391 } 2392 2393 if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win==mCurrentFocus) Slog.v( 2394 TAG, "Remove " + win + " client=" 2395 + Integer.toHexString(System.identityHashCode(win.mClient.asBinder())) 2396 + ", surface=" + win.mWinAnimator.mSurfaceControl + " Callers=" 2397 + Debug.getCallers(4)); 2398 2399 final long origId = Binder.clearCallingIdentity(); 2400 2401 win.disposeInputChannel(); 2402 2403 if (DEBUG_APP_TRANSITIONS) Slog.v( 2404 TAG, "Remove " + win + ": mSurface=" + win.mWinAnimator.mSurfaceControl 2405 + " mExiting=" + win.mExiting 2406 + " isAnimating=" + win.mWinAnimator.isAnimating() 2407 + " app-animation=" 2408 + (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null) 2409 + " inPendingTransaction=" 2410 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false) 2411 + " mDisplayFrozen=" + mDisplayFrozen); 2412 // Visibility of the removed window. Will be used later to update orientation later on. 2413 boolean wasVisible = false; 2414 // First, see if we need to run an animation. If we do, we have 2415 // to hold off on removing the window until the animation is done. 2416 // If the display is frozen, just remove immediately, since the 2417 // animation wouldn't be seen. 2418 if (win.mHasSurface && okToDisplay()) { 2419 // If we are not currently running the exit animation, we 2420 // need to see about starting one. 2421 wasVisible = win.isWinVisibleLw(); 2422 if (wasVisible) { 2423 2424 int transit = WindowManagerPolicy.TRANSIT_EXIT; 2425 if (win.mAttrs.type == TYPE_APPLICATION_STARTING) { 2426 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; 2427 } 2428 // Try starting an animation. 2429 if (win.mWinAnimator.applyAnimationLocked(transit, false)) { 2430 win.mExiting = true; 2431 } 2432 //TODO (multidisplay): Magnification is supported only for the default display. 2433 if (mDisplayMagnifier != null 2434 && win.getDisplayId() == Display.DEFAULT_DISPLAY) { 2435 mDisplayMagnifier.onWindowTransitionLocked(win, transit); 2436 } 2437 } 2438 if (!forceRemove && (win.mExiting || win.mWinAnimator.isAnimating())) { 2439 // The exit animation is running... wait for it! 2440 //Slog.i(TAG, "*** Running exit animation..."); 2441 win.mExiting = true; 2442 win.mRemoveOnExit = true; 2443 win.mDisplayContent.layoutNeeded = true; 2444 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 2445 false /*updateInputWindows*/); 2446 performLayoutAndPlaceSurfacesLocked(); 2447 if (win.mAppToken != null) { 2448 win.mAppToken.updateReportedVisibilityLocked(); 2449 } 2450 //dump(); 2451 Binder.restoreCallingIdentity(origId); 2452 return; 2453 } 2454 } 2455 2456 removeWindowInnerLocked(session, win); 2457 // Removing a visible window will effect the computed orientation 2458 // So just update orientation if needed. 2459 if (wasVisible && updateOrientationFromAppTokensLocked(false)) { 2460 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 2461 } 2462 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); 2463 Binder.restoreCallingIdentity(origId); 2464 } 2465 2466 private void removeWindowInnerLocked(Session session, WindowState win) { 2467 if (win.mRemoved) { 2468 // Nothing to do. 2469 return; 2470 } 2471 2472 for (int i=win.mChildWindows.size()-1; i>=0; i--) { 2473 WindowState cwin = win.mChildWindows.get(i); 2474 Slog.w(TAG, "Force-removing child win " + cwin + " from container " 2475 + win); 2476 removeWindowInnerLocked(cwin.mSession, cwin); 2477 } 2478 2479 win.mRemoved = true; 2480 2481 if (mInputMethodTarget == win) { 2482 moveInputMethodWindowsIfNeededLocked(false); 2483 } 2484 2485 if (false) { 2486 RuntimeException e = new RuntimeException("here"); 2487 e.fillInStackTrace(); 2488 Slog.w(TAG, "Removing window " + win, e); 2489 } 2490 2491 mPolicy.removeWindowLw(win); 2492 win.removeLocked(); 2493 2494 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win); 2495 mWindowMap.remove(win.mClient.asBinder()); 2496 if (win.mAppOp != AppOpsManager.OP_NONE) { 2497 mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage()); 2498 } 2499 2500 final WindowList windows = win.getWindowList(); 2501 windows.remove(win); 2502 mPendingRemove.remove(win); 2503 mResizingWindows.remove(win); 2504 mWindowsChanged = true; 2505 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win); 2506 2507 if (mInputMethodWindow == win) { 2508 mInputMethodWindow = null; 2509 } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) { 2510 mInputMethodDialogs.remove(win); 2511 } 2512 2513 final WindowToken token = win.mToken; 2514 final AppWindowToken atoken = win.mAppToken; 2515 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing " + win + " from " + token); 2516 token.windows.remove(win); 2517 if (atoken != null) { 2518 atoken.allAppWindows.remove(win); 2519 } 2520 if (localLOGV) Slog.v( 2521 TAG, "**** Removing window " + win + ": count=" 2522 + token.windows.size()); 2523 if (token.windows.size() == 0) { 2524 if (!token.explicit) { 2525 mTokenMap.remove(token.token); 2526 } else if (atoken != null) { 2527 atoken.firstWindowDrawn = false; 2528 } 2529 } 2530 2531 if (atoken != null) { 2532 if (atoken.startingWindow == win) { 2533 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Nulling startingWindow " + win); 2534 removeStartingWindowTimeout(atoken); 2535 atoken.startingWindow = null; 2536 } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) { 2537 // If this is the last window and we had requested a starting 2538 // transition window, well there is no point now. 2539 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Nulling last startingWindow"); 2540 atoken.startingData = null; 2541 } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) { 2542 // If this is the last window except for a starting transition 2543 // window, we need to get rid of the starting transition. 2544 scheduleRemoveStartingWindow(atoken); 2545 } 2546 } 2547 2548 if (win.mAttrs.type == TYPE_WALLPAPER) { 2549 mLastWallpaperTimeoutTime = 0; 2550 getDefaultDisplayContentLocked().pendingLayoutChanges |= 2551 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 2552 } else if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) { 2553 getDefaultDisplayContentLocked().pendingLayoutChanges |= 2554 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 2555 } 2556 2557 if (!mInLayout) { 2558 assignLayersLocked(windows); 2559 win.mDisplayContent.layoutNeeded = true; 2560 performLayoutAndPlaceSurfacesLocked(); 2561 if (win.mAppToken != null) { 2562 win.mAppToken.updateReportedVisibilityLocked(); 2563 } 2564 } 2565 2566 mInputMonitor.updateInputWindowsLw(true /*force*/); 2567 } 2568 2569 public void updateAppOpsState() { 2570 synchronized(mWindowMap) { 2571 final int numDisplays = mDisplayContents.size(); 2572 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 2573 final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); 2574 final int numWindows = windows.size(); 2575 for (int winNdx = 0; winNdx < numWindows; ++winNdx) { 2576 final WindowState win = windows.get(winNdx); 2577 if (win.mAppOp != AppOpsManager.OP_NONE) { 2578 final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(), 2579 win.getOwningPackage()); 2580 win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED); 2581 } 2582 } 2583 } 2584 } 2585 } 2586 2587 static void logSurface(WindowState w, String msg, RuntimeException where) { 2588 String str = " SURFACE " + msg + ": " + w; 2589 if (where != null) { 2590 Slog.i(TAG, str, where); 2591 } else { 2592 Slog.i(TAG, str); 2593 } 2594 } 2595 2596 static void logSurface(SurfaceControl s, String title, String msg, RuntimeException where) { 2597 String str = " SURFACE " + s + ": " + msg + " / " + title; 2598 if (where != null) { 2599 Slog.i(TAG, str, where); 2600 } else { 2601 Slog.i(TAG, str); 2602 } 2603 } 2604 2605 void setTransparentRegionWindow(Session session, IWindow client, Region region) { 2606 long origId = Binder.clearCallingIdentity(); 2607 try { 2608 synchronized (mWindowMap) { 2609 WindowState w = windowForClientLocked(session, client, false); 2610 if ((w != null) && w.mHasSurface) { 2611 w.mWinAnimator.setTransparentRegionHintLocked(region); 2612 } 2613 } 2614 } finally { 2615 Binder.restoreCallingIdentity(origId); 2616 } 2617 } 2618 2619 void setInsetsWindow(Session session, IWindow client, 2620 int touchableInsets, Rect contentInsets, 2621 Rect visibleInsets, Region touchableRegion) { 2622 long origId = Binder.clearCallingIdentity(); 2623 try { 2624 synchronized (mWindowMap) { 2625 WindowState w = windowForClientLocked(session, client, false); 2626 if (w != null) { 2627 w.mGivenInsetsPending = false; 2628 w.mGivenContentInsets.set(contentInsets); 2629 w.mGivenVisibleInsets.set(visibleInsets); 2630 w.mGivenTouchableRegion.set(touchableRegion); 2631 w.mTouchableInsets = touchableInsets; 2632 if (w.mGlobalScale != 1) { 2633 w.mGivenContentInsets.scale(w.mGlobalScale); 2634 w.mGivenVisibleInsets.scale(w.mGlobalScale); 2635 w.mGivenTouchableRegion.scale(w.mGlobalScale); 2636 } 2637 w.mDisplayContent.layoutNeeded = true; 2638 performLayoutAndPlaceSurfacesLocked(); 2639 } 2640 } 2641 } finally { 2642 Binder.restoreCallingIdentity(origId); 2643 } 2644 } 2645 2646 public void getWindowDisplayFrame(Session session, IWindow client, 2647 Rect outDisplayFrame) { 2648 synchronized(mWindowMap) { 2649 WindowState win = windowForClientLocked(session, client, false); 2650 if (win == null) { 2651 outDisplayFrame.setEmpty(); 2652 return; 2653 } 2654 outDisplayFrame.set(win.mDisplayFrame); 2655 } 2656 } 2657 2658 public void setWindowWallpaperPositionLocked(WindowState window, float x, float y, 2659 float xStep, float yStep) { 2660 if (window.mWallpaperX != x || window.mWallpaperY != y) { 2661 window.mWallpaperX = x; 2662 window.mWallpaperY = y; 2663 window.mWallpaperXStep = xStep; 2664 window.mWallpaperYStep = yStep; 2665 updateWallpaperOffsetLocked(window, true); 2666 } 2667 } 2668 2669 void wallpaperCommandComplete(IBinder window, Bundle result) { 2670 synchronized (mWindowMap) { 2671 if (mWaitingOnWallpaper != null && 2672 mWaitingOnWallpaper.mClient.asBinder() == window) { 2673 mWaitingOnWallpaper = null; 2674 mWindowMap.notifyAll(); 2675 } 2676 } 2677 } 2678 2679 public Bundle sendWindowWallpaperCommandLocked(WindowState window, 2680 String action, int x, int y, int z, Bundle extras, boolean sync) { 2681 if (window == mWallpaperTarget || window == mLowerWallpaperTarget 2682 || window == mUpperWallpaperTarget) { 2683 boolean doWait = sync; 2684 int curTokenIndex = mWallpaperTokens.size(); 2685 while (curTokenIndex > 0) { 2686 curTokenIndex--; 2687 WindowToken token = mWallpaperTokens.get(curTokenIndex); 2688 int curWallpaperIndex = token.windows.size(); 2689 while (curWallpaperIndex > 0) { 2690 curWallpaperIndex--; 2691 WindowState wallpaper = token.windows.get(curWallpaperIndex); 2692 try { 2693 wallpaper.mClient.dispatchWallpaperCommand(action, 2694 x, y, z, extras, sync); 2695 // We only want to be synchronous with one wallpaper. 2696 sync = false; 2697 } catch (RemoteException e) { 2698 } 2699 } 2700 } 2701 2702 if (doWait) { 2703 // XXX Need to wait for result. 2704 } 2705 } 2706 2707 return null; 2708 } 2709 2710 public void setUniverseTransformLocked(WindowState window, float alpha, 2711 float offx, float offy, float dsdx, float dtdx, float dsdy, float dtdy) { 2712 Transformation transform = window.mWinAnimator.mUniverseTransform; 2713 transform.setAlpha(alpha); 2714 Matrix matrix = transform.getMatrix(); 2715 matrix.getValues(mTmpFloats); 2716 mTmpFloats[Matrix.MTRANS_X] = offx; 2717 mTmpFloats[Matrix.MTRANS_Y] = offy; 2718 mTmpFloats[Matrix.MSCALE_X] = dsdx; 2719 mTmpFloats[Matrix.MSKEW_Y] = dtdx; 2720 mTmpFloats[Matrix.MSKEW_X] = dsdy; 2721 mTmpFloats[Matrix.MSCALE_Y] = dtdy; 2722 matrix.setValues(mTmpFloats); 2723 final DisplayInfo displayInfo = window.mDisplayContent.getDisplayInfo(); 2724 final RectF dispRect = new RectF(0, 0, 2725 displayInfo.logicalWidth, displayInfo.logicalHeight); 2726 matrix.mapRect(dispRect); 2727 window.mGivenTouchableRegion.set(0, 0, 2728 displayInfo.logicalWidth, displayInfo.logicalHeight); 2729 window.mGivenTouchableRegion.op((int)dispRect.left, (int)dispRect.top, 2730 (int)dispRect.right, (int)dispRect.bottom, Region.Op.DIFFERENCE); 2731 window.mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION; 2732 window.mDisplayContent.layoutNeeded = true; 2733 performLayoutAndPlaceSurfacesLocked(); 2734 } 2735 2736 public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) { 2737 synchronized (mWindowMap) { 2738 if (mDisplayMagnifier != null) { 2739 WindowState window = mWindowMap.get(token); 2740 //TODO (multidisplay): Magnification is supported only for the default display. 2741 if (window != null && window.getDisplayId() == Display.DEFAULT_DISPLAY) { 2742 mDisplayMagnifier.onRectangleOnScreenRequestedLocked(rectangle, immediate); 2743 } 2744 } 2745 } 2746 } 2747 2748 public IWindowId getWindowId(IBinder token) { 2749 synchronized (mWindowMap) { 2750 WindowState window = mWindowMap.get(token); 2751 return window != null ? window.mWindowId : null; 2752 } 2753 } 2754 2755 public int relayoutWindow(Session session, IWindow client, int seq, 2756 WindowManager.LayoutParams attrs, int requestedWidth, 2757 int requestedHeight, int viewVisibility, int flags, 2758 Rect outFrame, Rect outOverscanInsets, Rect outContentInsets, 2759 Rect outVisibleInsets, Configuration outConfig, Surface outSurface) { 2760 boolean toBeDisplayed = false; 2761 boolean inTouchMode; 2762 boolean configChanged; 2763 boolean surfaceChanged = false; 2764 boolean animating; 2765 2766 // if they don't have this permission, mask out the status bar bits 2767 int systemUiVisibility = 0; 2768 if (attrs != null) { 2769 systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility); 2770 if ((systemUiVisibility & StatusBarManager.DISABLE_MASK) != 0) { 2771 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) 2772 != PackageManager.PERMISSION_GRANTED) { 2773 systemUiVisibility &= ~StatusBarManager.DISABLE_MASK; 2774 } 2775 } 2776 } 2777 long origId = Binder.clearCallingIdentity(); 2778 2779 synchronized(mWindowMap) { 2780 WindowState win = windowForClientLocked(session, client, false); 2781 if (win == null) { 2782 return 0; 2783 } 2784 WindowStateAnimator winAnimator = win.mWinAnimator; 2785 if (win.mRequestedWidth != requestedWidth 2786 || win.mRequestedHeight != requestedHeight) { 2787 win.mLayoutNeeded = true; 2788 win.mRequestedWidth = requestedWidth; 2789 win.mRequestedHeight = requestedHeight; 2790 } 2791 if (attrs != null && seq == win.mSeq) { 2792 win.mSystemUiVisibility = systemUiVisibility; 2793 } 2794 2795 if (attrs != null) { 2796 mPolicy.adjustWindowParamsLw(attrs); 2797 } 2798 2799 winAnimator.mSurfaceDestroyDeferred = 2800 (flags&WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY) != 0; 2801 2802 int attrChanges = 0; 2803 int flagChanges = 0; 2804 if (attrs != null) { 2805 if (win.mAttrs.type != attrs.type) { 2806 throw new IllegalArgumentException( 2807 "Window type can not be changed after the window is added."); 2808 } 2809 flagChanges = win.mAttrs.flags ^= attrs.flags; 2810 attrChanges = win.mAttrs.copyFrom(attrs); 2811 if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED 2812 | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) { 2813 win.mLayoutNeeded = true; 2814 } 2815 } 2816 2817 if (DEBUG_LAYOUT) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility 2818 + " req=" + requestedWidth + "x" + requestedHeight + " " + win.mAttrs); 2819 2820 win.mEnforceSizeCompat = 2821 (win.mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0; 2822 2823 if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) { 2824 winAnimator.mAlpha = attrs.alpha; 2825 } 2826 2827 final boolean scaledWindow = 2828 ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0); 2829 2830 if (scaledWindow) { 2831 // requested{Width|Height} Surface's physical size 2832 // attrs.{width|height} Size on screen 2833 win.mHScale = (attrs.width != requestedWidth) ? 2834 (attrs.width / (float)requestedWidth) : 1.0f; 2835 win.mVScale = (attrs.height != requestedHeight) ? 2836 (attrs.height / (float)requestedHeight) : 1.0f; 2837 } else { 2838 win.mHScale = win.mVScale = 1; 2839 } 2840 2841 boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0; 2842 2843 final boolean isDefaultDisplay = win.isDefaultDisplay(); 2844 boolean focusMayChange = isDefaultDisplay && (win.mViewVisibility != viewVisibility 2845 || ((flagChanges & FLAG_NOT_FOCUSABLE) != 0) 2846 || (!win.mRelayoutCalled)); 2847 2848 boolean wallpaperMayMove = win.mViewVisibility != viewVisibility 2849 && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0; 2850 wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0; 2851 2852 win.mRelayoutCalled = true; 2853 final int oldVisibility = win.mViewVisibility; 2854 win.mViewVisibility = viewVisibility; 2855 if (DEBUG_SCREEN_ON) { 2856 RuntimeException stack = new RuntimeException(); 2857 stack.fillInStackTrace(); 2858 Slog.i(TAG, "Relayout " + win + ": oldVis=" + oldVisibility 2859 + " newVis=" + viewVisibility, stack); 2860 } 2861 if (viewVisibility == View.VISIBLE && 2862 (win.mAppToken == null || !win.mAppToken.clientHidden)) { 2863 toBeDisplayed = !win.isVisibleLw(); 2864 if (win.mExiting) { 2865 winAnimator.cancelExitAnimationForNextAnimationLocked(); 2866 win.mExiting = false; 2867 } 2868 if (win.mDestroying) { 2869 win.mDestroying = false; 2870 mDestroySurface.remove(win); 2871 } 2872 if (oldVisibility == View.GONE) { 2873 winAnimator.mEnterAnimationPending = true; 2874 } 2875 if (toBeDisplayed) { 2876 if (win.isDrawnLw() && okToDisplay()) { 2877 winAnimator.applyEnterAnimationLocked(); 2878 } 2879 if ((win.mAttrs.flags 2880 & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) { 2881 if (DEBUG_VISIBILITY) Slog.v(TAG, 2882 "Relayout window turning screen on: " + win); 2883 win.mTurnOnScreen = true; 2884 } 2885 if (win.isConfigChanged()) { 2886 if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + win 2887 + " visible with new config: " + mCurConfiguration); 2888 outConfig.setTo(mCurConfiguration); 2889 } 2890 } 2891 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) { 2892 // To change the format, we need to re-build the surface. 2893 winAnimator.destroySurfaceLocked(); 2894 toBeDisplayed = true; 2895 surfaceChanged = true; 2896 } 2897 try { 2898 if (!win.mHasSurface) { 2899 surfaceChanged = true; 2900 } 2901 SurfaceControl surfaceControl = winAnimator.createSurfaceLocked(); 2902 if (surfaceControl != null) { 2903 outSurface.copyFrom(surfaceControl); 2904 if (SHOW_TRANSACTIONS) Slog.i(TAG, 2905 " OUT SURFACE " + outSurface + ": copied"); 2906 } else { 2907 // For some reason there isn't a surface. Clear the 2908 // caller's object so they see the same state. 2909 outSurface.release(); 2910 } 2911 } catch (Exception e) { 2912 mInputMonitor.updateInputWindowsLw(true /*force*/); 2913 2914 Slog.w(TAG, "Exception thrown when creating surface for client " 2915 + client + " (" + win.mAttrs.getTitle() + ")", 2916 e); 2917 Binder.restoreCallingIdentity(origId); 2918 return 0; 2919 } 2920 if (toBeDisplayed) { 2921 focusMayChange = isDefaultDisplay; 2922 } 2923 if (win.mAttrs.type == TYPE_INPUT_METHOD 2924 && mInputMethodWindow == null) { 2925 mInputMethodWindow = win; 2926 imMayMove = true; 2927 } 2928 if (win.mAttrs.type == TYPE_BASE_APPLICATION 2929 && win.mAppToken != null 2930 && win.mAppToken.startingWindow != null) { 2931 // Special handling of starting window over the base 2932 // window of the app: propagate lock screen flags to it, 2933 // to provide the correct semantics while starting. 2934 final int mask = 2935 WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED 2936 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD 2937 | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; 2938 WindowManager.LayoutParams sa = win.mAppToken.startingWindow.mAttrs; 2939 sa.flags = (sa.flags&~mask) | (win.mAttrs.flags&mask); 2940 } 2941 } else { 2942 winAnimator.mEnterAnimationPending = false; 2943 if (winAnimator.mSurfaceControl != null) { 2944 if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win 2945 + ": mExiting=" + win.mExiting); 2946 // If we are not currently running the exit animation, we 2947 // need to see about starting one. 2948 if (!win.mExiting) { 2949 surfaceChanged = true; 2950 // Try starting an animation; if there isn't one, we 2951 // can destroy the surface right away. 2952 int transit = WindowManagerPolicy.TRANSIT_EXIT; 2953 if (win.mAttrs.type == TYPE_APPLICATION_STARTING) { 2954 transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; 2955 } 2956 if (win.isWinVisibleLw() && 2957 winAnimator.applyAnimationLocked(transit, false)) { 2958 focusMayChange = isDefaultDisplay; 2959 win.mExiting = true; 2960 } else if (win.mWinAnimator.isAnimating()) { 2961 // Currently in a hide animation... turn this into 2962 // an exit. 2963 win.mExiting = true; 2964 } else if (win == mWallpaperTarget) { 2965 // If the wallpaper is currently behind this 2966 // window, we need to change both of them inside 2967 // of a transaction to avoid artifacts. 2968 win.mExiting = true; 2969 win.mWinAnimator.mAnimating = true; 2970 } else { 2971 if (mInputMethodWindow == win) { 2972 mInputMethodWindow = null; 2973 } 2974 winAnimator.destroySurfaceLocked(); 2975 } 2976 //TODO (multidisplay): Magnification is supported only for the default 2977 if (mDisplayMagnifier != null 2978 && win.getDisplayId() == Display.DEFAULT_DISPLAY) { 2979 mDisplayMagnifier.onWindowTransitionLocked(win, transit); 2980 } 2981 } 2982 } 2983 2984 outSurface.release(); 2985 if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win); 2986 } 2987 2988 if (focusMayChange) { 2989 //System.out.println("Focus may change: " + win.mAttrs.getTitle()); 2990 if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 2991 false /*updateInputWindows*/)) { 2992 imMayMove = false; 2993 } 2994 //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus); 2995 } 2996 2997 // updateFocusedWindowLocked() already assigned layers so we only need to 2998 // reassign them at this point if the IM window state gets shuffled 2999 if (imMayMove && (moveInputMethodWindowsIfNeededLocked(false) || toBeDisplayed)) { 3000 // Little hack here -- we -should- be able to rely on the 3001 // function to return true if the IME has moved and needs 3002 // its layer recomputed. However, if the IME was hidden 3003 // and isn't actually moved in the list, its layer may be 3004 // out of data so we make sure to recompute it. 3005 assignLayersLocked(win.getWindowList()); 3006 } 3007 3008 if (wallpaperMayMove) { 3009 getDefaultDisplayContentLocked().pendingLayoutChanges |= 3010 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 3011 } 3012 3013 win.mDisplayContent.layoutNeeded = true; 3014 win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0; 3015 configChanged = updateOrientationFromAppTokensLocked(false); 3016 performLayoutAndPlaceSurfacesLocked(); 3017 if (toBeDisplayed && win.mIsWallpaper) { 3018 DisplayInfo displayInfo = getDefaultDisplayInfoLocked(); 3019 updateWallpaperOffsetLocked(win, 3020 displayInfo.logicalWidth, displayInfo.logicalHeight, false); 3021 } 3022 if (win.mAppToken != null) { 3023 win.mAppToken.updateReportedVisibilityLocked(); 3024 } 3025 outFrame.set(win.mCompatFrame); 3026 outOverscanInsets.set(win.mOverscanInsets); 3027 outContentInsets.set(win.mContentInsets); 3028 outVisibleInsets.set(win.mVisibleInsets); 3029 if (localLOGV) Slog.v( 3030 TAG, "Relayout given client " + client.asBinder() 3031 + ", requestedWidth=" + requestedWidth 3032 + ", requestedHeight=" + requestedHeight 3033 + ", viewVisibility=" + viewVisibility 3034 + "\nRelayout returning frame=" + outFrame 3035 + ", surface=" + outSurface); 3036 3037 if (localLOGV || DEBUG_FOCUS) Slog.v( 3038 TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange); 3039 3040 inTouchMode = mInTouchMode; 3041 animating = mAnimator.mAnimating && win.mWinAnimator.isAnimating(); 3042 if (animating && !mRelayoutWhileAnimating.contains(win)) { 3043 mRelayoutWhileAnimating.add(win); 3044 } 3045 3046 mInputMonitor.updateInputWindowsLw(true /*force*/); 3047 3048 if (DEBUG_LAYOUT) { 3049 Slog.v(TAG, "Relayout complete " + win + ": outFrame=" + outFrame.toShortString()); 3050 } 3051 } 3052 3053 if (configChanged) { 3054 sendNewConfiguration(); 3055 } 3056 3057 Binder.restoreCallingIdentity(origId); 3058 3059 return (inTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0) 3060 | (toBeDisplayed ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0) 3061 | (surfaceChanged ? WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED : 0) 3062 | (animating ? WindowManagerGlobal.RELAYOUT_RES_ANIMATING : 0); 3063 } 3064 3065 public void performDeferredDestroyWindow(Session session, IWindow client) { 3066 long origId = Binder.clearCallingIdentity(); 3067 3068 try { 3069 synchronized (mWindowMap) { 3070 WindowState win = windowForClientLocked(session, client, false); 3071 if (win == null) { 3072 return; 3073 } 3074 win.mWinAnimator.destroyDeferredSurfaceLocked(); 3075 } 3076 } finally { 3077 Binder.restoreCallingIdentity(origId); 3078 } 3079 } 3080 3081 public boolean outOfMemoryWindow(Session session, IWindow client) { 3082 long origId = Binder.clearCallingIdentity(); 3083 3084 try { 3085 synchronized (mWindowMap) { 3086 WindowState win = windowForClientLocked(session, client, false); 3087 if (win == null) { 3088 return false; 3089 } 3090 return reclaimSomeSurfaceMemoryLocked(win.mWinAnimator, "from-client", false); 3091 } 3092 } finally { 3093 Binder.restoreCallingIdentity(origId); 3094 } 3095 } 3096 3097 public void finishDrawingWindow(Session session, IWindow client) { 3098 final long origId = Binder.clearCallingIdentity(); 3099 try { 3100 synchronized (mWindowMap) { 3101 WindowState win = windowForClientLocked(session, client, false); 3102 if (win != null && win.mWinAnimator.finishDrawingLocked()) { 3103 if ((win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) { 3104 getDefaultDisplayContentLocked().pendingLayoutChanges |= 3105 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 3106 } 3107 win.mDisplayContent.layoutNeeded = true; 3108 requestTraversalLocked(); 3109 } 3110 } 3111 } finally { 3112 Binder.restoreCallingIdentity(origId); 3113 } 3114 } 3115 3116 @Override 3117 public void getWindowFrame(IBinder token, Rect outBounds) { 3118 if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO, 3119 "getWindowInfo()")) { 3120 throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission."); 3121 } 3122 synchronized (mWindowMap) { 3123 WindowState windowState = mWindowMap.get(token); 3124 if (windowState != null) { 3125 outBounds.set(windowState.mFrame); 3126 } else { 3127 outBounds.setEmpty(); 3128 } 3129 } 3130 } 3131 3132 @Override 3133 public void setMagnificationSpec(MagnificationSpec spec) { 3134 if (!checkCallingPermission(android.Manifest.permission.MAGNIFY_DISPLAY, 3135 "setMagnificationSpec()")) { 3136 throw new SecurityException("Requires MAGNIFY_DISPLAY permission."); 3137 } 3138 synchronized (mWindowMap) { 3139 if (mDisplayMagnifier != null) { 3140 mDisplayMagnifier.setMagnificationSpecLocked(spec); 3141 } else { 3142 throw new IllegalStateException("Magnification callbacks not set!"); 3143 } 3144 } 3145 if (Binder.getCallingPid() != android.os.Process.myPid()) { 3146 spec.recycle(); 3147 } 3148 } 3149 3150 @Override 3151 public MagnificationSpec getCompatibleMagnificationSpecForWindow(IBinder windowToken) { 3152 if (!checkCallingPermission(android.Manifest.permission.MAGNIFY_DISPLAY, 3153 "getCompatibleMagnificationSpecForWindow()")) { 3154 throw new SecurityException("Requires MAGNIFY_DISPLAY permission."); 3155 } 3156 synchronized (mWindowMap) { 3157 WindowState windowState = mWindowMap.get(windowToken); 3158 if (windowState == null) { 3159 return null; 3160 } 3161 MagnificationSpec spec = null; 3162 if (mDisplayMagnifier != null) { 3163 spec = mDisplayMagnifier.getMagnificationSpecForWindowLocked(windowState); 3164 } 3165 if ((spec == null || spec.isNop()) && windowState.mGlobalScale == 1.0f) { 3166 return null; 3167 } 3168 spec = (spec == null) ? MagnificationSpec.obtain() : MagnificationSpec.obtain(spec); 3169 spec.scale *= windowState.mGlobalScale; 3170 return spec; 3171 } 3172 } 3173 3174 @Override 3175 public void setMagnificationCallbacks(IMagnificationCallbacks callbacks) { 3176 if (!checkCallingPermission(android.Manifest.permission.MAGNIFY_DISPLAY, 3177 "setMagnificationCallbacks()")) { 3178 throw new SecurityException("Requires MAGNIFY_DISPLAY permission."); 3179 } 3180 synchronized (mWindowMap) { 3181 if (mDisplayMagnifier == null) { 3182 mDisplayMagnifier = new DisplayMagnifier(this, callbacks); 3183 } else { 3184 if (callbacks == null) { 3185 if (mDisplayMagnifier != null) { 3186 mDisplayMagnifier.destroyLocked(); 3187 mDisplayMagnifier = null; 3188 } 3189 } else { 3190 throw new IllegalStateException("Magnification callbacks already set!"); 3191 } 3192 } 3193 } 3194 } 3195 3196 private boolean applyAnimationLocked(AppWindowToken atoken, 3197 WindowManager.LayoutParams lp, int transit, boolean enter) { 3198 // Only apply an animation if the display isn't frozen. If it is 3199 // frozen, there is no reason to animate and it can cause strange 3200 // artifacts when we unfreeze the display if some different animation 3201 // is running. 3202 if (okToDisplay()) { 3203 DisplayInfo displayInfo = getDefaultDisplayInfoLocked(); 3204 final int width = displayInfo.appWidth; 3205 final int height = displayInfo.appHeight; 3206 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "applyAnimation: atoken=" 3207 + atoken); 3208 Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height); 3209 if (a != null) { 3210 if (DEBUG_ANIM) { 3211 RuntimeException e = null; 3212 if (!HIDE_STACK_CRAWLS) { 3213 e = new RuntimeException(); 3214 e.fillInStackTrace(); 3215 } 3216 Slog.v(TAG, "Loaded animation " + a + " for " + atoken, e); 3217 } 3218 atoken.mAppAnimator.setAnimation(a, width, height); 3219 } 3220 } else { 3221 atoken.mAppAnimator.clearAnimation(); 3222 } 3223 3224 return atoken.mAppAnimator.animation != null; 3225 } 3226 3227 // ------------------------------------------------------------- 3228 // Application Window Tokens 3229 // ------------------------------------------------------------- 3230 3231 public void validateAppTokens(int stackId, List<TaskGroup> tasks) { 3232 synchronized (mWindowMap) { 3233 int t = tasks.size() - 1; 3234 if (t < 0) { 3235 Slog.w(TAG, "validateAppTokens: empty task list"); 3236 return; 3237 } 3238 3239 TaskGroup task = tasks.get(0); 3240 int taskId = task.taskId; 3241 Task targetTask = mTaskIdToTask.get(taskId); 3242 DisplayContent displayContent = targetTask.getDisplayContent(); 3243 if (displayContent == null) { 3244 Slog.w(TAG, "validateAppTokens: no Display for taskId=" + taskId); 3245 return; 3246 } 3247 3248 final ArrayList<Task> localTasks = mStackIdToStack.get(stackId).getTasks(); 3249 int taskNdx; 3250 for (taskNdx = localTasks.size() - 1; taskNdx >= 0 && t >= 0; --taskNdx, --t) { 3251 AppTokenList localTokens = localTasks.get(taskNdx).mAppTokens; 3252 task = tasks.get(t); 3253 List<IApplicationToken> tokens = task.tokens; 3254 3255 DisplayContent lastDisplayContent = displayContent; 3256 displayContent = mTaskIdToTask.get(taskId).getDisplayContent(); 3257 if (displayContent != lastDisplayContent) { 3258 Slog.w(TAG, "validateAppTokens: displayContent changed in TaskGroup list!"); 3259 return; 3260 } 3261 3262 int tokenNdx; 3263 int v; 3264 for (tokenNdx = localTokens.size() - 1, v = task.tokens.size() - 1; 3265 tokenNdx >= 0 && v >= 0; ) { 3266 final AppWindowToken atoken = localTokens.get(tokenNdx); 3267 if (atoken.removed) { 3268 --tokenNdx; 3269 continue; 3270 } 3271 if (tokens.get(v) != atoken.token) { 3272 break; 3273 } 3274 --tokenNdx; 3275 v--; 3276 } 3277 3278 if (tokenNdx >= 0 || v >= 0) { 3279 break; 3280 } 3281 } 3282 3283 if (taskNdx >= 0 || t >= 0) { 3284 Slog.w(TAG, "validateAppTokens: Mismatch! ActivityManager=" + tasks); 3285 Slog.w(TAG, "validateAppTokens: Mismatch! WindowManager=" + localTasks); 3286 Slog.w(TAG, "validateAppTokens: Mismatch! Callers=" + Debug.getCallers(4)); 3287 } 3288 } 3289 } 3290 3291 public void validateStackOrder(Integer[] remoteStackIds) { 3292 // TODO: 3293 } 3294 3295 boolean checkCallingPermission(String permission, String func) { 3296 // Quick check: if the calling permission is me, it's all okay. 3297 if (Binder.getCallingPid() == Process.myPid()) { 3298 return true; 3299 } 3300 3301 if (mContext.checkCallingPermission(permission) 3302 == PackageManager.PERMISSION_GRANTED) { 3303 return true; 3304 } 3305 String msg = "Permission Denial: " + func + " from pid=" 3306 + Binder.getCallingPid() 3307 + ", uid=" + Binder.getCallingUid() 3308 + " requires " + permission; 3309 Slog.w(TAG, msg); 3310 return false; 3311 } 3312 3313 boolean okToDisplay() { 3314 return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully(); 3315 } 3316 3317 AppWindowToken findAppWindowToken(IBinder token) { 3318 WindowToken wtoken = mTokenMap.get(token); 3319 if (wtoken == null) { 3320 return null; 3321 } 3322 return wtoken.appWindowToken; 3323 } 3324 3325 @Override 3326 public void addWindowToken(IBinder token, int type) { 3327 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3328 "addWindowToken()")) { 3329 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3330 } 3331 3332 synchronized(mWindowMap) { 3333 WindowToken wtoken = mTokenMap.get(token); 3334 if (wtoken != null) { 3335 Slog.w(TAG, "Attempted to add existing input method token: " + token); 3336 return; 3337 } 3338 wtoken = new WindowToken(this, token, type, true); 3339 mTokenMap.put(token, wtoken); 3340 if (type == TYPE_WALLPAPER) { 3341 mWallpaperTokens.add(wtoken); 3342 } 3343 } 3344 } 3345 3346 @Override 3347 public void removeWindowToken(IBinder token) { 3348 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3349 "removeWindowToken()")) { 3350 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3351 } 3352 3353 final long origId = Binder.clearCallingIdentity(); 3354 synchronized(mWindowMap) { 3355 DisplayContent displayContent = null; 3356 WindowToken wtoken = mTokenMap.remove(token); 3357 if (wtoken != null) { 3358 boolean delayed = false; 3359 if (!wtoken.hidden) { 3360 final int N = wtoken.windows.size(); 3361 boolean changed = false; 3362 3363 for (int i=0; i<N; i++) { 3364 WindowState win = wtoken.windows.get(i); 3365 displayContent = win.mDisplayContent; 3366 3367 if (win.mWinAnimator.isAnimating()) { 3368 delayed = true; 3369 } 3370 3371 if (win.isVisibleNow()) { 3372 win.mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT, 3373 false); 3374 //TODO (multidisplay): Magnification is supported only for the default 3375 if (mDisplayMagnifier != null && win.isDefaultDisplay()) { 3376 mDisplayMagnifier.onWindowTransitionLocked(win, 3377 WindowManagerPolicy.TRANSIT_EXIT); 3378 } 3379 changed = true; 3380 displayContent.layoutNeeded = true; 3381 } 3382 } 3383 3384 wtoken.hidden = true; 3385 3386 if (changed) { 3387 performLayoutAndPlaceSurfacesLocked(); 3388 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, 3389 false /*updateInputWindows*/); 3390 } 3391 3392 if (delayed) { 3393 displayContent.mExitingTokens.add(wtoken); 3394 } else if (wtoken.windowType == TYPE_WALLPAPER) { 3395 mWallpaperTokens.remove(wtoken); 3396 } 3397 } 3398 3399 mInputMonitor.updateInputWindowsLw(true /*force*/); 3400 } else { 3401 Slog.w(TAG, "Attempted to remove non-existing token: " + token); 3402 } 3403 } 3404 Binder.restoreCallingIdentity(origId); 3405 } 3406 3407 private Task createTask(int taskId, int stackId, int userId, AppWindowToken atoken) { 3408 final TaskStack stack = mStackIdToStack.get(stackId); 3409 if (stack == null) { 3410 throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId); 3411 } 3412 EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId); 3413 Task task = new Task(atoken, stack, userId); 3414 mTaskIdToTask.put(taskId, task); 3415 stack.addTask(task, true); 3416 return task; 3417 } 3418 3419 @Override 3420 public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId, 3421 int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId, 3422 int configChanges) { 3423 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3424 "addAppToken()")) { 3425 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3426 } 3427 3428 // Get the dispatching timeout here while we are not holding any locks so that it 3429 // can be cached by the AppWindowToken. The timeout value is used later by the 3430 // input dispatcher in code that does hold locks. If we did not cache the value 3431 // here we would run the chance of introducing a deadlock between the window manager 3432 // (which holds locks while updating the input dispatcher state) and the activity manager 3433 // (which holds locks while querying the application token). 3434 long inputDispatchingTimeoutNanos; 3435 try { 3436 inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L; 3437 } catch (RemoteException ex) { 3438 Slog.w(TAG, "Could not get dispatching timeout.", ex); 3439 inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS; 3440 } 3441 3442 synchronized(mWindowMap) { 3443 AppWindowToken atoken = findAppWindowToken(token.asBinder()); 3444 if (atoken != null) { 3445 Slog.w(TAG, "Attempted to add existing app token: " + token); 3446 return; 3447 } 3448 atoken = new AppWindowToken(this, token); 3449 atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos; 3450 atoken.groupId = taskId; 3451 atoken.appFullscreen = fullscreen; 3452 atoken.showWhenLocked = showWhenLocked; 3453 atoken.requestedOrientation = requestedOrientation; 3454 atoken.layoutConfigChanges = (configChanges & 3455 (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0; 3456 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken 3457 + " to stack=" + stackId + " task=" + taskId + " at " + addPos); 3458 3459 Task task = mTaskIdToTask.get(taskId); 3460 if (task == null) { 3461 task = createTask(taskId, stackId, userId, atoken); 3462 } else { 3463 task.addAppToken(addPos, atoken); 3464 } 3465 3466 mTokenMap.put(token.asBinder(), atoken); 3467 3468 // Application tokens start out hidden. 3469 atoken.hidden = true; 3470 atoken.hiddenRequested = true; 3471 3472 //dump(); 3473 } 3474 } 3475 3476 @Override 3477 public void setAppGroupId(IBinder token, int groupId) { 3478 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3479 "setAppGroupId()")) { 3480 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3481 } 3482 3483 synchronized(mWindowMap) { 3484 final AppWindowToken atoken = findAppWindowToken(token); 3485 if (atoken == null) { 3486 Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token); 3487 return; 3488 } 3489 Task oldTask = mTaskIdToTask.get(atoken.groupId); 3490 oldTask.removeAppToken(atoken); 3491 3492 atoken.groupId = groupId; 3493 Task newTask = mTaskIdToTask.get(groupId); 3494 if (newTask == null) { 3495 newTask = createTask(groupId, oldTask.mStack.mStackId, oldTask.mUserId, atoken); 3496 } 3497 newTask.mAppTokens.add(atoken); 3498 } 3499 } 3500 3501 public int getOrientationFromWindowsLocked() { 3502 if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) { 3503 // If the display is frozen, some activities may be in the middle 3504 // of restarting, and thus have removed their old window. If the 3505 // window has the flag to hide the lock screen, then the lock screen 3506 // can re-appear and inflict its own orientation on us. Keep the 3507 // orientation stable until this all settles down. 3508 return mLastWindowForcedOrientation; 3509 } 3510 3511 // TODO(multidisplay): Change to the correct display. 3512 final WindowList windows = getDefaultWindowListLocked(); 3513 int pos = windows.size() - 1; 3514 while (pos >= 0) { 3515 WindowState win = windows.get(pos); 3516 pos--; 3517 if (win.mAppToken != null) { 3518 // We hit an application window. so the orientation will be determined by the 3519 // app window. No point in continuing further. 3520 return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 3521 } 3522 if (!win.isVisibleLw() || !win.mPolicyVisibilityAfterAnim) { 3523 continue; 3524 } 3525 int req = win.mAttrs.screenOrientation; 3526 if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) || 3527 (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){ 3528 continue; 3529 } 3530 3531 if (DEBUG_ORIENTATION) Slog.v(TAG, win + " forcing orientation to " + req); 3532 return (mLastWindowForcedOrientation=req); 3533 } 3534 return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); 3535 } 3536 3537 public int getOrientationFromAppTokensLocked() { 3538 int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 3539 boolean findingBehind = false; 3540 boolean lastFullscreen = false; 3541 // TODO: Multi window. 3542 DisplayContent displayContent = getDefaultDisplayContentLocked(); 3543 final ArrayList<Task> tasks = displayContent.getTasks(); 3544 for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { 3545 AppTokenList tokens = tasks.get(taskNdx).mAppTokens; 3546 final int firstToken = tokens.size() - 1; 3547 for (int tokenNdx = firstToken; tokenNdx >= 0; --tokenNdx) { 3548 final AppWindowToken atoken = tokens.get(tokenNdx); 3549 3550 if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + atoken); 3551 3552 // if we're about to tear down this window and not seek for 3553 // the behind activity, don't use it for orientation 3554 if (!findingBehind 3555 && (!atoken.hidden && atoken.hiddenRequested)) { 3556 if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken 3557 + " -- going to hide"); 3558 continue; 3559 } 3560 3561 if (tokenNdx == firstToken) { 3562 // If we have hit a new Task, and the bottom 3563 // of the previous group didn't explicitly say to use 3564 // the orientation behind it, and the last app was 3565 // full screen, then we'll stick with the 3566 // user's orientation. 3567 if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND 3568 && lastFullscreen) { 3569 if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken 3570 + " -- end of group, return " + lastOrientation); 3571 return lastOrientation; 3572 } 3573 } 3574 3575 // We ignore any hidden applications on the top. 3576 if (atoken.hiddenRequested || atoken.willBeHidden) { 3577 if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken 3578 + " -- hidden on top"); 3579 continue; 3580 } 3581 3582 if (tokenNdx == 0) { 3583 // Last token in this task. 3584 lastOrientation = atoken.requestedOrientation; 3585 } 3586 3587 int or = atoken.requestedOrientation; 3588 // If this application is fullscreen, and didn't explicitly say 3589 // to use the orientation behind it, then just take whatever 3590 // orientation it has and ignores whatever is under it. 3591 lastFullscreen = atoken.appFullscreen; 3592 if (lastFullscreen 3593 && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { 3594 if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken 3595 + " -- full screen, return " + or); 3596 return or; 3597 } 3598 // If this application has requested an explicit orientation, 3599 // then use it. 3600 if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED 3601 && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) { 3602 if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken 3603 + " -- explicitly set, return " + or); 3604 return or; 3605 } 3606 findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND); 3607 } 3608 } 3609 if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation"); 3610 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 3611 } 3612 3613 @Override 3614 public Configuration updateOrientationFromAppTokens( 3615 Configuration currentConfig, IBinder freezeThisOneIfNeeded) { 3616 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3617 "updateOrientationFromAppTokens()")) { 3618 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3619 } 3620 3621 Configuration config = null; 3622 long ident = Binder.clearCallingIdentity(); 3623 3624 synchronized(mWindowMap) { 3625 config = updateOrientationFromAppTokensLocked(currentConfig, 3626 freezeThisOneIfNeeded); 3627 } 3628 3629 Binder.restoreCallingIdentity(ident); 3630 return config; 3631 } 3632 3633 private Configuration updateOrientationFromAppTokensLocked( 3634 Configuration currentConfig, IBinder freezeThisOneIfNeeded) { 3635 Configuration config = null; 3636 3637 if (updateOrientationFromAppTokensLocked(false)) { 3638 if (freezeThisOneIfNeeded != null) { 3639 AppWindowToken atoken = findAppWindowToken(freezeThisOneIfNeeded); 3640 if (atoken != null) { 3641 startAppFreezingScreenLocked(atoken, ActivityInfo.CONFIG_ORIENTATION); 3642 } 3643 } 3644 config = computeNewConfigurationLocked(); 3645 3646 } else if (currentConfig != null) { 3647 // No obvious action we need to take, but if our current 3648 // state mismatches the activity manager's, update it, 3649 // disregarding font scale, which should remain set to 3650 // the value of the previous configuration. 3651 mTempConfiguration.setToDefaults(); 3652 mTempConfiguration.fontScale = currentConfig.fontScale; 3653 if (computeScreenConfigurationLocked(mTempConfiguration)) { 3654 if (currentConfig.diff(mTempConfiguration) != 0) { 3655 mWaitingForConfig = true; 3656 final DisplayContent displayContent = getDefaultDisplayContentLocked(); 3657 displayContent.layoutNeeded = true; 3658 int anim[] = new int[2]; 3659 if (displayContent.isDimming()) { 3660 anim[0] = anim[1] = 0; 3661 } else { 3662 mPolicy.selectRotationAnimationLw(anim); 3663 } 3664 startFreezingDisplayLocked(false, anim[0], anim[1]); 3665 config = new Configuration(mTempConfiguration); 3666 } 3667 } 3668 } 3669 3670 return config; 3671 } 3672 3673 /* 3674 * Determine the new desired orientation of the display, returning 3675 * a non-null new Configuration if it has changed from the current 3676 * orientation. IF TRUE IS RETURNED SOMEONE MUST CALL 3677 * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE 3678 * SCREEN. This will typically be done for you if you call 3679 * sendNewConfiguration(). 3680 * 3681 * The orientation is computed from non-application windows first. If none of 3682 * the non-application windows specify orientation, the orientation is computed from 3683 * application tokens. 3684 * @see android.view.IWindowManager#updateOrientationFromAppTokens( 3685 * android.os.IBinder) 3686 */ 3687 boolean updateOrientationFromAppTokensLocked(boolean inTransaction) { 3688 long ident = Binder.clearCallingIdentity(); 3689 try { 3690 int req = getOrientationFromWindowsLocked(); 3691 if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) { 3692 req = getOrientationFromAppTokensLocked(); 3693 } 3694 3695 if (req != mForcedAppOrientation) { 3696 mForcedAppOrientation = req; 3697 //send a message to Policy indicating orientation change to take 3698 //action like disabling/enabling sensors etc., 3699 mPolicy.setCurrentOrientationLw(req); 3700 if (updateRotationUncheckedLocked(inTransaction)) { 3701 // changed 3702 return true; 3703 } 3704 } 3705 3706 return false; 3707 } finally { 3708 Binder.restoreCallingIdentity(ident); 3709 } 3710 } 3711 3712 @Override 3713 public void setNewConfiguration(Configuration config) { 3714 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3715 "setNewConfiguration()")) { 3716 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3717 } 3718 3719 synchronized(mWindowMap) { 3720 mCurConfiguration = new Configuration(config); 3721 if (mWaitingForConfig) { 3722 mWaitingForConfig = false; 3723 mLastFinishedFreezeSource = "new-config"; 3724 } 3725 performLayoutAndPlaceSurfacesLocked(); 3726 } 3727 } 3728 3729 @Override 3730 public void setAppOrientation(IApplicationToken token, int requestedOrientation) { 3731 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3732 "setAppOrientation()")) { 3733 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3734 } 3735 3736 synchronized(mWindowMap) { 3737 AppWindowToken atoken = findAppWindowToken(token.asBinder()); 3738 if (atoken == null) { 3739 Slog.w(TAG, "Attempted to set orientation of non-existing app token: " + token); 3740 return; 3741 } 3742 3743 atoken.requestedOrientation = requestedOrientation; 3744 } 3745 } 3746 3747 @Override 3748 public int getAppOrientation(IApplicationToken token) { 3749 synchronized(mWindowMap) { 3750 AppWindowToken wtoken = findAppWindowToken(token.asBinder()); 3751 if (wtoken == null) { 3752 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 3753 } 3754 3755 return wtoken.requestedOrientation; 3756 } 3757 } 3758 3759 /** Call while in a Surface transaction. */ 3760 void setFocusedStackLayer() { 3761 mFocusedStackLayer = 0; 3762 if (mFocusedApp != null) { 3763 final WindowList windows = mFocusedApp.allAppWindows; 3764 for (int i = windows.size() - 1; i >= 0; --i) { 3765 final WindowState win = windows.get(i); 3766 final int animLayer = win.mWinAnimator.mAnimLayer; 3767 if (win.mAttachedWindow == null && win.isVisibleLw() && 3768 animLayer > mFocusedStackLayer) { 3769 mFocusedStackLayer = animLayer + LAYER_OFFSET_FOCUSED_STACK; 3770 } 3771 } 3772 } 3773 if (DEBUG_LAYERS) Slog.v(TAG, "Setting FocusedStackFrame to layer=" + 3774 mFocusedStackLayer); 3775 mFocusedStackFrame.setLayer(mFocusedStackLayer); 3776 } 3777 3778 void setFocusedStackFrame() { 3779 final TaskStack stack; 3780 if (mFocusedApp != null) { 3781 Task task = mTaskIdToTask.get(mFocusedApp.groupId); 3782 stack = task.mStack; 3783 task.getDisplayContent().setTouchExcludeRegion(stack); 3784 } else { 3785 stack = null; 3786 } 3787 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setFocusedStackFrame"); 3788 SurfaceControl.openTransaction(); 3789 try { 3790 if (stack == null) { 3791 mFocusedStackFrame.setVisibility(false); 3792 } else { 3793 final StackBox box = stack.mStackBox; 3794 final Rect bounds = box.mBounds; 3795 final boolean multipleStacks = box.mParent != null; 3796 mFocusedStackFrame.setBounds(bounds); 3797 mFocusedStackFrame.setVisibility(multipleStacks); 3798 } 3799 } finally { 3800 SurfaceControl.closeTransaction(); 3801 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setFocusedStackFrame"); 3802 } 3803 } 3804 3805 @Override 3806 public void setFocusedApp(IBinder token, boolean moveFocusNow) { 3807 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3808 "setFocusedApp()")) { 3809 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3810 } 3811 3812 synchronized(mWindowMap) { 3813 boolean changed = false; 3814 if (token == null) { 3815 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp); 3816 changed = mFocusedApp != null; 3817 mFocusedApp = null; 3818 if (changed) { 3819 mInputMonitor.setFocusedAppLw(null); 3820 } 3821 } else { 3822 AppWindowToken newFocus = findAppWindowToken(token); 3823 if (newFocus == null) { 3824 Slog.w(TAG, "Attempted to set focus to non-existing app token: " + token); 3825 return; 3826 } 3827 changed = mFocusedApp != newFocus; 3828 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Set focused app to: " + newFocus 3829 + " old focus=" + mFocusedApp + " moveFocusNow=" + moveFocusNow); 3830 mFocusedApp = newFocus; 3831 if (changed) { 3832 mInputMonitor.setFocusedAppLw(newFocus); 3833 } 3834 } 3835 3836 if (moveFocusNow && changed) { 3837 final long origId = Binder.clearCallingIdentity(); 3838 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); 3839 Binder.restoreCallingIdentity(origId); 3840 } 3841 } 3842 } 3843 3844 @Override 3845 public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) { 3846 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3847 "prepareAppTransition()")) { 3848 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3849 } 3850 3851 synchronized(mWindowMap) { 3852 if (DEBUG_APP_TRANSITIONS) Slog.v( 3853 TAG, "Prepare app transition: transit=" + transit 3854 + " " + mAppTransition 3855 + " alwaysKeepCurrent=" + alwaysKeepCurrent 3856 + " Callers=" + Debug.getCallers(3)); 3857 if (okToDisplay()) { 3858 if (!mAppTransition.isTransitionSet() || mAppTransition.isTransitionNone()) { 3859 mAppTransition.setAppTransition(transit); 3860 } else if (!alwaysKeepCurrent) { 3861 if (transit == AppTransition.TRANSIT_TASK_OPEN 3862 && mAppTransition.isTransitionEqual( 3863 AppTransition.TRANSIT_TASK_CLOSE)) { 3864 // Opening a new task always supersedes a close for the anim. 3865 mAppTransition.setAppTransition(transit); 3866 } else if (transit == AppTransition.TRANSIT_ACTIVITY_OPEN 3867 && mAppTransition.isTransitionEqual( 3868 AppTransition.TRANSIT_ACTIVITY_CLOSE)) { 3869 // Opening a new activity always supersedes a close for the anim. 3870 mAppTransition.setAppTransition(transit); 3871 } 3872 } 3873 mAppTransition.prepare(); 3874 mStartingIconInTransition = false; 3875 mSkipAppTransitionAnimation = false; 3876 mH.removeMessages(H.APP_TRANSITION_TIMEOUT); 3877 mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, 5000); 3878 } 3879 } 3880 } 3881 3882 @Override 3883 public int getPendingAppTransition() { 3884 return mAppTransition.getAppTransition(); 3885 } 3886 3887 @Override 3888 public void overridePendingAppTransition(String packageName, 3889 int enterAnim, int exitAnim, IRemoteCallback startedCallback) { 3890 synchronized(mWindowMap) { 3891 mAppTransition.overridePendingAppTransition(packageName, enterAnim, exitAnim, 3892 startedCallback); 3893 } 3894 } 3895 3896 @Override 3897 public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth, 3898 int startHeight) { 3899 synchronized(mWindowMap) { 3900 mAppTransition.overridePendingAppTransitionScaleUp(startX, startY, startWidth, 3901 startHeight); 3902 } 3903 } 3904 3905 @Override 3906 public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, 3907 int startY, IRemoteCallback startedCallback, boolean scaleUp) { 3908 synchronized(mWindowMap) { 3909 mAppTransition.overridePendingAppTransitionThumb(srcThumb, startX, startY, 3910 startedCallback, scaleUp); 3911 } 3912 } 3913 3914 @Override 3915 public void executeAppTransition() { 3916 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3917 "executeAppTransition()")) { 3918 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3919 } 3920 3921 synchronized(mWindowMap) { 3922 if (DEBUG_APP_TRANSITIONS) { 3923 RuntimeException e = new RuntimeException("here"); 3924 e.fillInStackTrace(); 3925 Slog.w(TAG, "Execute app transition: " + mAppTransition, e); 3926 } 3927 if (mAppTransition.isTransitionSet()) { 3928 mAppTransition.setReady(); 3929 final long origId = Binder.clearCallingIdentity(); 3930 performLayoutAndPlaceSurfacesLocked(); 3931 Binder.restoreCallingIdentity(origId); 3932 } 3933 } 3934 } 3935 3936 @Override 3937 public void setAppStartingWindow(IBinder token, String pkg, 3938 int theme, CompatibilityInfo compatInfo, 3939 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, 3940 int windowFlags, IBinder transferFrom, boolean createIfNeeded) { 3941 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 3942 "setAppStartingWindow()")) { 3943 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 3944 } 3945 3946 synchronized(mWindowMap) { 3947 if (DEBUG_STARTING_WINDOW) Slog.v( 3948 TAG, "setAppStartingWindow: token=" + token + " pkg=" + pkg 3949 + " transferFrom=" + transferFrom); 3950 3951 AppWindowToken wtoken = findAppWindowToken(token); 3952 if (wtoken == null) { 3953 Slog.w(TAG, "Attempted to set icon of non-existing app token: " + token); 3954 return; 3955 } 3956 3957 // If the display is frozen, we won't do anything until the 3958 // actual window is displayed so there is no reason to put in 3959 // the starting window. 3960 if (!okToDisplay()) { 3961 return; 3962 } 3963 3964 if (wtoken.startingData != null) { 3965 return; 3966 } 3967 3968 if (transferFrom != null) { 3969 AppWindowToken ttoken = findAppWindowToken(transferFrom); 3970 if (ttoken != null) { 3971 WindowState startingWindow = ttoken.startingWindow; 3972 if (startingWindow != null) { 3973 if (mStartingIconInTransition) { 3974 // In this case, the starting icon has already 3975 // been displayed, so start letting windows get 3976 // shown immediately without any more transitions. 3977 mSkipAppTransitionAnimation = true; 3978 } 3979 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, 3980 "Moving existing starting " + startingWindow + " from " + ttoken 3981 + " to " + wtoken); 3982 final long origId = Binder.clearCallingIdentity(); 3983 3984 // Transfer the starting window over to the new 3985 // token. 3986 wtoken.startingData = ttoken.startingData; 3987 wtoken.startingView = ttoken.startingView; 3988 wtoken.startingDisplayed = ttoken.startingDisplayed; 3989 ttoken.startingDisplayed = false; 3990 wtoken.startingWindow = startingWindow; 3991 wtoken.reportedVisible = ttoken.reportedVisible; 3992 ttoken.startingData = null; 3993 ttoken.startingView = null; 3994 ttoken.startingWindow = null; 3995 ttoken.startingMoved = true; 3996 startingWindow.mToken = wtoken; 3997 startingWindow.mRootToken = wtoken; 3998 startingWindow.mAppToken = wtoken; 3999 startingWindow.mWinAnimator.mAppAnimator = wtoken.mAppAnimator; 4000 4001 if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) { 4002 Slog.v(TAG, "Removing starting window: " + startingWindow); 4003 } 4004 removeStartingWindowTimeout(ttoken); 4005 startingWindow.getWindowList().remove(startingWindow); 4006 mWindowsChanged = true; 4007 if (DEBUG_ADD_REMOVE) Slog.v(TAG, 4008 "Removing starting " + startingWindow + " from " + ttoken); 4009 ttoken.windows.remove(startingWindow); 4010 ttoken.allAppWindows.remove(startingWindow); 4011 addWindowToListInOrderLocked(startingWindow, true); 4012 4013 // Propagate other interesting state between the 4014 // tokens. If the old token is displayed, we should 4015 // immediately force the new one to be displayed. If 4016 // it is animating, we need to move that animation to 4017 // the new one. 4018 if (ttoken.allDrawn) { 4019 wtoken.allDrawn = true; 4020 wtoken.deferClearAllDrawn = ttoken.deferClearAllDrawn; 4021 } 4022 if (ttoken.firstWindowDrawn) { 4023 wtoken.firstWindowDrawn = true; 4024 } 4025 if (!ttoken.hidden) { 4026 wtoken.hidden = false; 4027 wtoken.hiddenRequested = false; 4028 wtoken.willBeHidden = false; 4029 } 4030 if (wtoken.clientHidden != ttoken.clientHidden) { 4031 wtoken.clientHidden = ttoken.clientHidden; 4032 wtoken.sendAppVisibilityToClients(); 4033 } 4034 final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator; 4035 final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator; 4036 if (tAppAnimator.animation != null) { 4037 wAppAnimator.animation = tAppAnimator.animation; 4038 wAppAnimator.animating = tAppAnimator.animating; 4039 wAppAnimator.animLayerAdjustment = tAppAnimator.animLayerAdjustment; 4040 tAppAnimator.animation = null; 4041 tAppAnimator.animLayerAdjustment = 0; 4042 wAppAnimator.updateLayers(); 4043 tAppAnimator.updateLayers(); 4044 } 4045 4046 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 4047 true /*updateInputWindows*/); 4048 getDefaultDisplayContentLocked().layoutNeeded = true; 4049 performLayoutAndPlaceSurfacesLocked(); 4050 Binder.restoreCallingIdentity(origId); 4051 return; 4052 } else if (ttoken.startingData != null) { 4053 // The previous app was getting ready to show a 4054 // starting window, but hasn't yet done so. Steal it! 4055 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, 4056 "Moving pending starting from " + ttoken 4057 + " to " + wtoken); 4058 wtoken.startingData = ttoken.startingData; 4059 ttoken.startingData = null; 4060 ttoken.startingMoved = true; 4061 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken); 4062 // Note: we really want to do sendMessageAtFrontOfQueue() because we 4063 // want to process the message ASAP, before any other queued 4064 // messages. 4065 mH.sendMessageAtFrontOfQueue(m); 4066 return; 4067 } 4068 final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator; 4069 final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator; 4070 if (tAppAnimator.thumbnail != null) { 4071 // The old token is animating with a thumbnail, transfer 4072 // that to the new token. 4073 if (wAppAnimator.thumbnail != null) { 4074 wAppAnimator.thumbnail.destroy(); 4075 } 4076 wAppAnimator.thumbnail = tAppAnimator.thumbnail; 4077 wAppAnimator.thumbnailX = tAppAnimator.thumbnailX; 4078 wAppAnimator.thumbnailY = tAppAnimator.thumbnailY; 4079 wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer; 4080 wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation; 4081 tAppAnimator.thumbnail = null; 4082 } 4083 } 4084 } 4085 4086 // There is no existing starting window, and the caller doesn't 4087 // want us to create one, so that's it! 4088 if (!createIfNeeded) { 4089 return; 4090 } 4091 4092 // If this is a translucent window, then don't 4093 // show a starting window -- the current effect (a full-screen 4094 // opaque starting window that fades away to the real contents 4095 // when it is ready) does not work for this. 4096 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Checking theme of starting window: 0x" 4097 + Integer.toHexString(theme)); 4098 if (theme != 0) { 4099 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, 4100 com.android.internal.R.styleable.Window, mCurrentUserId); 4101 if (ent == null) { 4102 // Whoops! App doesn't exist. Um. Okay. We'll just 4103 // pretend like we didn't see that. 4104 return; 4105 } 4106 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Translucent=" 4107 + ent.array.getBoolean( 4108 com.android.internal.R.styleable.Window_windowIsTranslucent, false) 4109 + " Floating=" 4110 + ent.array.getBoolean( 4111 com.android.internal.R.styleable.Window_windowIsFloating, false) 4112 + " ShowWallpaper=" 4113 + ent.array.getBoolean( 4114 com.android.internal.R.styleable.Window_windowShowWallpaper, false)); 4115 if (ent.array.getBoolean( 4116 com.android.internal.R.styleable.Window_windowIsTranslucent, false)) { 4117 return; 4118 } 4119 if (ent.array.getBoolean( 4120 com.android.internal.R.styleable.Window_windowIsFloating, false)) { 4121 return; 4122 } 4123 if (ent.array.getBoolean( 4124 com.android.internal.R.styleable.Window_windowShowWallpaper, false)) { 4125 if (mWallpaperTarget == null) { 4126 // If this theme is requesting a wallpaper, and the wallpaper 4127 // is not curently visible, then this effectively serves as 4128 // an opaque window and our starting window transition animation 4129 // can still work. We just need to make sure the starting window 4130 // is also showing the wallpaper. 4131 windowFlags |= FLAG_SHOW_WALLPAPER; 4132 } else { 4133 return; 4134 } 4135 } 4136 } 4137 4138 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Creating StartingData"); 4139 mStartingIconInTransition = true; 4140 wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel, 4141 labelRes, icon, logo, windowFlags); 4142 Message m = mH.obtainMessage(H.ADD_STARTING, wtoken); 4143 // Note: we really want to do sendMessageAtFrontOfQueue() because we 4144 // want to process the message ASAP, before any other queued 4145 // messages. 4146 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING"); 4147 mH.sendMessageAtFrontOfQueue(m); 4148 } 4149 } 4150 4151 @Override 4152 public void setAppWillBeHidden(IBinder token) { 4153 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4154 "setAppWillBeHidden()")) { 4155 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4156 } 4157 4158 AppWindowToken wtoken; 4159 4160 synchronized(mWindowMap) { 4161 wtoken = findAppWindowToken(token); 4162 if (wtoken == null) { 4163 Slog.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token); 4164 return; 4165 } 4166 wtoken.willBeHidden = true; 4167 } 4168 } 4169 4170 public void setAppFullscreen(IBinder token, boolean toOpaque) { 4171 AppWindowToken atoken = findAppWindowToken(token); 4172 if (atoken != null) { 4173 atoken.appFullscreen = toOpaque; 4174 requestTraversal(); 4175 } 4176 } 4177 4178 boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp, 4179 boolean visible, int transit, boolean performLayout) { 4180 boolean delayed = false; 4181 4182 if (wtoken.clientHidden == visible) { 4183 wtoken.clientHidden = !visible; 4184 wtoken.sendAppVisibilityToClients(); 4185 } 4186 4187 wtoken.willBeHidden = false; 4188 if (wtoken.hidden == visible) { 4189 boolean changed = false; 4190 if (DEBUG_APP_TRANSITIONS) Slog.v( 4191 TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden 4192 + " performLayout=" + performLayout); 4193 4194 boolean runningAppAnimation = false; 4195 4196 if (transit != AppTransition.TRANSIT_UNSET) { 4197 if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) { 4198 wtoken.mAppAnimator.animation = null; 4199 } 4200 if (applyAnimationLocked(wtoken, lp, transit, visible)) { 4201 delayed = runningAppAnimation = true; 4202 } 4203 WindowState window = wtoken.findMainWindow(); 4204 //TODO (multidisplay): Magnification is supported only for the default display. 4205 if (window != null && mDisplayMagnifier != null 4206 && window.getDisplayId() == Display.DEFAULT_DISPLAY) { 4207 mDisplayMagnifier.onAppWindowTransitionLocked(window, transit); 4208 } 4209 changed = true; 4210 } 4211 4212 final int N = wtoken.allAppWindows.size(); 4213 for (int i=0; i<N; i++) { 4214 WindowState win = wtoken.allAppWindows.get(i); 4215 if (win == wtoken.startingWindow) { 4216 continue; 4217 } 4218 4219 //Slog.i(TAG, "Window " + win + ": vis=" + win.isVisible()); 4220 //win.dump(" "); 4221 if (visible) { 4222 if (!win.isVisibleNow()) { 4223 if (!runningAppAnimation) { 4224 win.mWinAnimator.applyAnimationLocked( 4225 WindowManagerPolicy.TRANSIT_ENTER, true); 4226 //TODO (multidisplay): Magnification is supported only for the default 4227 if (mDisplayMagnifier != null 4228 && win.getDisplayId() == Display.DEFAULT_DISPLAY) { 4229 mDisplayMagnifier.onWindowTransitionLocked(win, 4230 WindowManagerPolicy.TRANSIT_ENTER); 4231 } 4232 } 4233 changed = true; 4234 win.mDisplayContent.layoutNeeded = true; 4235 } 4236 } else if (win.isVisibleNow()) { 4237 if (!runningAppAnimation) { 4238 win.mWinAnimator.applyAnimationLocked( 4239 WindowManagerPolicy.TRANSIT_EXIT, false); 4240 //TODO (multidisplay): Magnification is supported only for the default 4241 if (mDisplayMagnifier != null 4242 && win.getDisplayId() == Display.DEFAULT_DISPLAY) { 4243 mDisplayMagnifier.onWindowTransitionLocked(win, 4244 WindowManagerPolicy.TRANSIT_EXIT); 4245 } 4246 } 4247 changed = true; 4248 win.mDisplayContent.layoutNeeded = true; 4249 } 4250 } 4251 4252 wtoken.hidden = wtoken.hiddenRequested = !visible; 4253 if (!visible) { 4254 unsetAppFreezingScreenLocked(wtoken, true, true); 4255 } else { 4256 // If we are being set visible, and the starting window is 4257 // not yet displayed, then make sure it doesn't get displayed. 4258 WindowState swin = wtoken.startingWindow; 4259 if (swin != null && !swin.isDrawnLw()) { 4260 swin.mPolicyVisibility = false; 4261 swin.mPolicyVisibilityAfterAnim = false; 4262 } 4263 } 4264 4265 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "setTokenVisibilityLocked: " + wtoken 4266 + ": hidden=" + wtoken.hidden + " hiddenRequested=" 4267 + wtoken.hiddenRequested); 4268 4269 if (changed) { 4270 mInputMonitor.setUpdateInputWindowsNeededLw(); 4271 if (performLayout) { 4272 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 4273 false /*updateInputWindows*/); 4274 performLayoutAndPlaceSurfacesLocked(); 4275 } 4276 mInputMonitor.updateInputWindowsLw(false /*force*/); 4277 } 4278 } 4279 4280 if (wtoken.mAppAnimator.animation != null) { 4281 delayed = true; 4282 } 4283 4284 for (int i = wtoken.allAppWindows.size() - 1; i >= 0 && !delayed; i--) { 4285 if (wtoken.allAppWindows.get(i).mWinAnimator.isWindowAnimating()) { 4286 delayed = true; 4287 } 4288 } 4289 4290 return delayed; 4291 } 4292 4293 @Override 4294 public void setAppVisibility(IBinder token, boolean visible) { 4295 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4296 "setAppVisibility()")) { 4297 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4298 } 4299 4300 AppWindowToken wtoken; 4301 4302 synchronized(mWindowMap) { 4303 wtoken = findAppWindowToken(token); 4304 if (wtoken == null) { 4305 Slog.w(TAG, "Attempted to set visibility of non-existing app token: " + token); 4306 return; 4307 } 4308 4309 if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) { 4310 RuntimeException e = null; 4311 if (!HIDE_STACK_CRAWLS) { 4312 e = new RuntimeException(); 4313 e.fillInStackTrace(); 4314 } 4315 Slog.v(TAG, "setAppVisibility(" + token + ", visible=" + visible 4316 + "): " + mAppTransition 4317 + " hidden=" + wtoken.hidden 4318 + " hiddenRequested=" + wtoken.hiddenRequested, e); 4319 } 4320 4321 // If we are preparing an app transition, then delay changing 4322 // the visibility of this token until we execute that transition. 4323 if (okToDisplay() && mAppTransition.isTransitionSet()) { 4324 wtoken.hiddenRequested = !visible; 4325 4326 if (!wtoken.startingDisplayed) { 4327 if (DEBUG_APP_TRANSITIONS) Slog.v( 4328 TAG, "Setting dummy animation on: " + wtoken); 4329 wtoken.mAppAnimator.setDummyAnimation(); 4330 } 4331 mOpeningApps.remove(wtoken); 4332 mClosingApps.remove(wtoken); 4333 wtoken.waitingToShow = wtoken.waitingToHide = false; 4334 wtoken.inPendingTransaction = true; 4335 if (visible) { 4336 mOpeningApps.add(wtoken); 4337 wtoken.startingMoved = false; 4338 4339 // If the token is currently hidden (should be the 4340 // common case), then we need to set up to wait for 4341 // its windows to be ready. 4342 if (wtoken.hidden) { 4343 wtoken.allDrawn = false; 4344 wtoken.deferClearAllDrawn = false; 4345 wtoken.waitingToShow = true; 4346 4347 if (wtoken.clientHidden) { 4348 // In the case where we are making an app visible 4349 // but holding off for a transition, we still need 4350 // to tell the client to make its windows visible so 4351 // they get drawn. Otherwise, we will wait on 4352 // performing the transition until all windows have 4353 // been drawn, they never will be, and we are sad. 4354 wtoken.clientHidden = false; 4355 wtoken.sendAppVisibilityToClients(); 4356 } 4357 } 4358 } else { 4359 mClosingApps.add(wtoken); 4360 4361 // If the token is currently visible (should be the 4362 // common case), then set up to wait for it to be hidden. 4363 if (!wtoken.hidden) { 4364 wtoken.waitingToHide = true; 4365 } 4366 } 4367 return; 4368 } 4369 4370 final long origId = Binder.clearCallingIdentity(); 4371 setTokenVisibilityLocked(wtoken, null, visible, AppTransition.TRANSIT_UNSET, 4372 true); 4373 wtoken.updateReportedVisibilityLocked(); 4374 Binder.restoreCallingIdentity(origId); 4375 } 4376 } 4377 4378 void unsetAppFreezingScreenLocked(AppWindowToken wtoken, 4379 boolean unfreezeSurfaceNow, boolean force) { 4380 if (wtoken.mAppAnimator.freezingScreen) { 4381 if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + wtoken 4382 + " force=" + force); 4383 final int N = wtoken.allAppWindows.size(); 4384 boolean unfrozeWindows = false; 4385 for (int i=0; i<N; i++) { 4386 WindowState w = wtoken.allAppWindows.get(i); 4387 if (w.mAppFreezing) { 4388 w.mAppFreezing = false; 4389 if (w.mHasSurface && !w.mOrientationChanging) { 4390 if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w); 4391 w.mOrientationChanging = true; 4392 mInnerFields.mOrientationChangeComplete = false; 4393 } 4394 w.mLastFreezeDuration = 0; 4395 unfrozeWindows = true; 4396 w.mDisplayContent.layoutNeeded = true; 4397 } 4398 } 4399 if (force || unfrozeWindows) { 4400 if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken); 4401 wtoken.mAppAnimator.freezingScreen = false; 4402 wtoken.mAppAnimator.lastFreezeDuration = (int)(SystemClock.elapsedRealtime() 4403 - mDisplayFreezeTime); 4404 mAppsFreezingScreen--; 4405 mLastFinishedFreezeSource = wtoken; 4406 } 4407 if (unfreezeSurfaceNow) { 4408 if (unfrozeWindows) { 4409 performLayoutAndPlaceSurfacesLocked(); 4410 } 4411 stopFreezingDisplayLocked(); 4412 } 4413 } 4414 } 4415 4416 public void startAppFreezingScreenLocked(AppWindowToken wtoken, 4417 int configChanges) { 4418 if (DEBUG_ORIENTATION) { 4419 RuntimeException e = null; 4420 if (!HIDE_STACK_CRAWLS) { 4421 e = new RuntimeException(); 4422 e.fillInStackTrace(); 4423 } 4424 Slog.i(TAG, "Set freezing of " + wtoken.appToken 4425 + ": hidden=" + wtoken.hidden + " freezing=" 4426 + wtoken.mAppAnimator.freezingScreen, e); 4427 } 4428 if (!wtoken.hiddenRequested) { 4429 if (!wtoken.mAppAnimator.freezingScreen) { 4430 wtoken.mAppAnimator.freezingScreen = true; 4431 wtoken.mAppAnimator.lastFreezeDuration = 0; 4432 mAppsFreezingScreen++; 4433 if (mAppsFreezingScreen == 1) { 4434 startFreezingDisplayLocked(false, 0, 0); 4435 mH.removeMessages(H.APP_FREEZE_TIMEOUT); 4436 mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 5000); 4437 } 4438 } 4439 final int N = wtoken.allAppWindows.size(); 4440 for (int i=0; i<N; i++) { 4441 WindowState w = wtoken.allAppWindows.get(i); 4442 w.mAppFreezing = true; 4443 } 4444 } 4445 } 4446 4447 @Override 4448 public void startAppFreezingScreen(IBinder token, int configChanges) { 4449 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4450 "setAppFreezingScreen()")) { 4451 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4452 } 4453 4454 synchronized(mWindowMap) { 4455 if (configChanges == 0 && okToDisplay()) { 4456 if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping set freeze of " + token); 4457 return; 4458 } 4459 4460 AppWindowToken wtoken = findAppWindowToken(token); 4461 if (wtoken == null || wtoken.appToken == null) { 4462 Slog.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken); 4463 return; 4464 } 4465 final long origId = Binder.clearCallingIdentity(); 4466 startAppFreezingScreenLocked(wtoken, configChanges); 4467 Binder.restoreCallingIdentity(origId); 4468 } 4469 } 4470 4471 @Override 4472 public void stopAppFreezingScreen(IBinder token, boolean force) { 4473 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4474 "setAppFreezingScreen()")) { 4475 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4476 } 4477 4478 synchronized(mWindowMap) { 4479 AppWindowToken wtoken = findAppWindowToken(token); 4480 if (wtoken == null || wtoken.appToken == null) { 4481 return; 4482 } 4483 final long origId = Binder.clearCallingIdentity(); 4484 if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + token 4485 + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen); 4486 unsetAppFreezingScreenLocked(wtoken, true, force); 4487 Binder.restoreCallingIdentity(origId); 4488 } 4489 } 4490 4491 @Override 4492 public void removeAppToken(IBinder token) { 4493 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 4494 "removeAppToken()")) { 4495 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 4496 } 4497 4498 AppWindowToken wtoken = null; 4499 AppWindowToken startingToken = null; 4500 boolean delayed = false; 4501 4502 final long origId = Binder.clearCallingIdentity(); 4503 synchronized(mWindowMap) { 4504 WindowToken basewtoken = mTokenMap.remove(token); 4505 if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) { 4506 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken); 4507 delayed = setTokenVisibilityLocked(wtoken, null, false, 4508 AppTransition.TRANSIT_UNSET, true); 4509 wtoken.inPendingTransaction = false; 4510 mOpeningApps.remove(wtoken); 4511 wtoken.waitingToShow = false; 4512 if (mClosingApps.contains(wtoken)) { 4513 delayed = true; 4514 } else if (mAppTransition.isTransitionSet()) { 4515 mClosingApps.add(wtoken); 4516 wtoken.waitingToHide = true; 4517 delayed = true; 4518 } 4519 if (DEBUG_APP_TRANSITIONS) Slog.v( 4520 TAG, "Removing app " + wtoken + " delayed=" + delayed 4521 + " animation=" + wtoken.mAppAnimator.animation 4522 + " animating=" + wtoken.mAppAnimator.animating); 4523 final Task task = mTaskIdToTask.get(wtoken.groupId); 4524 DisplayContent displayContent = task.getDisplayContent(); 4525 if (delayed) { 4526 // set the token aside because it has an active animation to be finished 4527 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, 4528 "removeAppToken make exiting: " + wtoken); 4529 displayContent.mExitingAppTokens.add(wtoken); 4530 } else { 4531 // Make sure there is no animation running on this token, 4532 // so any windows associated with it will be removed as 4533 // soon as their animations are complete 4534 wtoken.mAppAnimator.clearAnimation(); 4535 wtoken.mAppAnimator.animating = false; 4536 } 4537 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, 4538 "removeAppToken: " + wtoken); 4539 4540 if (task.removeAppToken(wtoken)) { 4541 mTaskIdToTask.delete(wtoken.groupId); 4542 } 4543 wtoken.removed = true; 4544 if (wtoken.startingData != null) { 4545 startingToken = wtoken; 4546 } 4547 unsetAppFreezingScreenLocked(wtoken, true, true); 4548 if (mFocusedApp == wtoken) { 4549 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Removing focused app token:" + wtoken); 4550 mFocusedApp = null; 4551 updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); 4552 mInputMonitor.setFocusedAppLw(null); 4553 } 4554 } else { 4555 Slog.w(TAG, "Attempted to remove non-existing app token: " + token); 4556 } 4557 4558 if (!delayed && wtoken != null) { 4559 wtoken.updateReportedVisibilityLocked(); 4560 } 4561 } 4562 Binder.restoreCallingIdentity(origId); 4563 4564 // Will only remove if startingToken non null. 4565 scheduleRemoveStartingWindow(startingToken); 4566 } 4567 4568 void removeStartingWindowTimeout(AppWindowToken wtoken) { 4569 if (wtoken != null) { 4570 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, Debug.getCallers(1) + 4571 ": Remove starting window timeout " + wtoken + (wtoken != null ? 4572 " startingWindow=" + wtoken.startingWindow : "")); 4573 mH.removeMessages(H.REMOVE_STARTING_TIMEOUT, wtoken); 4574 } 4575 } 4576 4577 void scheduleRemoveStartingWindow(AppWindowToken wtoken) { 4578 if (wtoken != null && wtoken.startingWindow != null) { 4579 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, Debug.getCallers(1) + 4580 ": Schedule remove starting " + wtoken + (wtoken != null ? 4581 " startingWindow=" + wtoken.startingWindow : "")); 4582 removeStartingWindowTimeout(wtoken); 4583 Message m = mH.obtainMessage(H.REMOVE_STARTING, wtoken); 4584 mH.sendMessage(m); 4585 } 4586 } 4587 private boolean tmpRemoveAppWindowsLocked(WindowToken token) { 4588 final int NW = token.windows.size(); 4589 if (NW > 0) { 4590 mWindowsChanged = true; 4591 } 4592 for (int i=0; i<NW; i++) { 4593 WindowState win = token.windows.get(i); 4594 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win); 4595 win.getWindowList().remove(win); 4596 int j = win.mChildWindows.size(); 4597 while (j > 0) { 4598 j--; 4599 WindowState cwin = win.mChildWindows.get(j); 4600 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, 4601 "Tmp removing child window " + cwin); 4602 cwin.getWindowList().remove(cwin); 4603 } 4604 } 4605 return NW > 0; 4606 } 4607 4608 void dumpAppTokensLocked() { 4609 final int numDisplays = mDisplayContents.size(); 4610 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 4611 final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); 4612 Slog.v(TAG, " Display " + displayContent.getDisplayId()); 4613 final ArrayList<Task> tasks = displayContent.getTasks(); 4614 int i = displayContent.numTokens(); 4615 for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { 4616 AppTokenList tokens = tasks.get(taskNdx).mAppTokens; 4617 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { 4618 final AppWindowToken wtoken = tokens.get(tokenNdx); 4619 Slog.v(TAG, " #" + --i + ": " + wtoken.token); 4620 } 4621 } 4622 } 4623 } 4624 4625 void dumpWindowsLocked() { 4626 int i = 0; 4627 final int numDisplays = mDisplayContents.size(); 4628 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 4629 final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); 4630 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { 4631 Slog.v(TAG, " #" + i++ + ": " + windows.get(winNdx)); 4632 } 4633 } 4634 } 4635 4636 private int findAppWindowInsertionPointLocked(AppWindowToken target) { 4637 final int taskId = target.groupId; 4638 Task targetTask = mTaskIdToTask.get(taskId); 4639 if (targetTask == null) { 4640 Slog.w(TAG, "findAppWindowInsertionPointLocked: no Task for " + target + " taskId=" 4641 + taskId); 4642 return 0; 4643 } 4644 DisplayContent displayContent = targetTask.getDisplayContent(); 4645 if (displayContent == null) { 4646 Slog.w(TAG, "findAppWindowInsertionPointLocked: no DisplayContent for " + target); 4647 return 0; 4648 } 4649 final WindowList windows = displayContent.getWindowList(); 4650 final int NW = windows.size(); 4651 4652 boolean found = false; 4653 final ArrayList<Task> tasks = displayContent.getTasks(); 4654 for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { 4655 final Task task = tasks.get(taskNdx); 4656 if (!found && task.taskId != taskId) { 4657 continue; 4658 } 4659 AppTokenList tokens = task.mAppTokens; 4660 for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) { 4661 final AppWindowToken wtoken = tokens.get(tokenNdx); 4662 if (!found && wtoken == target) { 4663 found = true; 4664 } 4665 if (found) { 4666 // Find the first app token below the new position that has 4667 // a window displayed. 4668 if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows in " + wtoken.token); 4669 if (wtoken.sendingToBottom) { 4670 if (DEBUG_REORDER) Slog.v(TAG, "Skipping token -- currently sending to bottom"); 4671 continue; 4672 } 4673 for (int i = wtoken.windows.size() - 1; i >= 0; --i) { 4674 WindowState win = wtoken.windows.get(i); 4675 for (int j = win.mChildWindows.size() - 1; j >= 0; --j) { 4676 WindowState cwin = win.mChildWindows.get(j); 4677 if (cwin.mSubLayer >= 0) { 4678 for (int pos = NW - 1; pos >= 0; pos--) { 4679 if (windows.get(pos) == cwin) { 4680 if (DEBUG_REORDER) Slog.v(TAG, 4681 "Found child win @" + (pos + 1)); 4682 return pos + 1; 4683 } 4684 } 4685 } 4686 } 4687 for (int pos = NW - 1; pos >= 0; pos--) { 4688 if (windows.get(pos) == win) { 4689 if (DEBUG_REORDER) Slog.v(TAG, "Found win @" + (pos + 1)); 4690 return pos + 1; 4691 } 4692 } 4693 } 4694 } 4695 } 4696 } 4697 // Never put an app window underneath wallpaper. 4698 for (int pos = NW - 1; pos >= 0; pos--) { 4699 if (windows.get(pos).mIsWallpaper) { 4700 if (DEBUG_REORDER) Slog.v(TAG, "Found wallpaper @" + pos); 4701 return pos + 1; 4702 } 4703 } 4704 return 0; 4705 } 4706 4707 private final int reAddWindowLocked(int index, WindowState win) { 4708 final WindowList windows = win.getWindowList(); 4709 final int NCW = win.mChildWindows.size(); 4710 boolean added = false; 4711 for (int j=0; j<NCW; j++) { 4712 WindowState cwin = win.mChildWindows.get(j); 4713 if (!added && cwin.mSubLayer >= 0) { 4714 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding child window at " 4715 + index + ": " + cwin); 4716 win.mRebuilding = false; 4717 windows.add(index, win); 4718 index++; 4719 added = true; 4720 } 4721 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at " 4722 + index + ": " + cwin); 4723 cwin.mRebuilding = false; 4724 windows.add(index, cwin); 4725 index++; 4726 } 4727 if (!added) { 4728 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at " 4729 + index + ": " + win); 4730 win.mRebuilding = false; 4731 windows.add(index, win); 4732 index++; 4733 } 4734 mWindowsChanged = true; 4735 return index; 4736 } 4737 4738 private final int reAddAppWindowsLocked(final DisplayContent displayContent, int index, 4739 WindowToken token) { 4740 final int NW = token.windows.size(); 4741 for (int i=0; i<NW; i++) { 4742 final WindowState win = token.windows.get(i); 4743 if (win.mDisplayContent == displayContent) { 4744 index = reAddWindowLocked(index, win); 4745 } 4746 } 4747 return index; 4748 } 4749 4750 void moveStackWindowsLocked(DisplayContent displayContent) { 4751 // First remove all of the windows from the list. 4752 final ArrayList<Task> tasks = displayContent.getTasks(); 4753 final int numTasks = tasks.size(); 4754 for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) { 4755 AppTokenList tokens = tasks.get(taskNdx).mAppTokens; 4756 final int numTokens = tokens.size(); 4757 for (int tokenNdx = numTokens - 1; tokenNdx >= 0; --tokenNdx) { 4758 tmpRemoveAppWindowsLocked(tokens.get(tokenNdx)); 4759 } 4760 } 4761 4762 // And now add them back at the correct place. 4763 // Where to start adding? 4764 for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) { 4765 AppTokenList tokens = tasks.get(taskNdx).mAppTokens; 4766 int pos = findAppWindowInsertionPointLocked(tokens.get(0)); 4767 final int numTokens = tokens.size(); 4768 for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) { 4769 final AppWindowToken wtoken = tokens.get(tokenNdx); 4770 if (wtoken != null) { 4771 final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken); 4772 if (newPos != pos) { 4773 displayContent.layoutNeeded = true; 4774 } 4775 pos = newPos; 4776 } 4777 } 4778 } 4779 4780 if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 4781 false /*updateInputWindows*/)) { 4782 assignLayersLocked(displayContent.getWindowList()); 4783 } 4784 4785 mInputMonitor.setUpdateInputWindowsNeededLw(); 4786 performLayoutAndPlaceSurfacesLocked(); 4787 mInputMonitor.updateInputWindowsLw(false /*force*/); 4788 4789 //dump(); 4790 } 4791 4792 public void moveTaskToTop(int taskId) { 4793 final long origId = Binder.clearCallingIdentity(); 4794 try { 4795 synchronized(mWindowMap) { 4796 Task task = mTaskIdToTask.get(taskId); 4797 if (task == null) { 4798 // Normal behavior, addAppToken will be called next and task will be created. 4799 return; 4800 } 4801 final TaskStack stack = task.mStack; 4802 final DisplayContent displayContent = task.getDisplayContent(); 4803 final boolean isHomeStackTask = stack.isHomeStack(); 4804 if (isHomeStackTask != displayContent.homeOnTop()) { 4805 // First move the stack itself. 4806 displayContent.moveHomeStackBox(isHomeStackTask); 4807 } 4808 stack.moveTaskToTop(task); 4809 } 4810 } finally { 4811 Binder.restoreCallingIdentity(origId); 4812 } 4813 } 4814 4815 public void moveTaskToBottom(int taskId) { 4816 final long origId = Binder.clearCallingIdentity(); 4817 try { 4818 synchronized(mWindowMap) { 4819 Task task = mTaskIdToTask.get(taskId); 4820 if (task == null) { 4821 Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId 4822 + " not found in mTaskIdToTask"); 4823 return; 4824 } 4825 final TaskStack stack = task.mStack; 4826 stack.moveTaskToBottom(task); 4827 moveStackWindowsLocked(stack.getDisplayContent()); 4828 } 4829 } finally { 4830 Binder.restoreCallingIdentity(origId); 4831 } 4832 } 4833 4834 /** 4835 * Create a new TaskStack and place it next to an existing stack. 4836 * @param stackId The unique identifier of the new stack. 4837 * @param relativeStackBoxId The existing stack that this stack goes before or after. 4838 * @param position One of: 4839 * {@link StackBox#TASK_STACK_GOES_BEFORE} 4840 * {@link StackBox#TASK_STACK_GOES_AFTER} 4841 * {@link StackBox#TASK_STACK_GOES_ABOVE} 4842 * {@link StackBox#TASK_STACK_GOES_BELOW} 4843 * {@link StackBox#TASK_STACK_GOES_UNDER} 4844 * {@link StackBox#TASK_STACK_GOES_OVER} 4845 * @param weight Relative weight for determining how big to make the new TaskStack. 4846 */ 4847 public void createStack(int stackId, int relativeStackBoxId, int position, float weight) { 4848 synchronized (mWindowMap) { 4849 if (position <= StackBox.TASK_STACK_GOES_BELOW && 4850 (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX)) { 4851 throw new IllegalArgumentException( 4852 "createStack: weight must be between " + STACK_WEIGHT_MIN + " and " + 4853 STACK_WEIGHT_MAX + ", weight=" + weight); 4854 } 4855 final int numDisplays = mDisplayContents.size(); 4856 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 4857 final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); 4858 TaskStack stack = displayContent.createStack(stackId, relativeStackBoxId, position, 4859 weight); 4860 if (stack != null) { 4861 mStackIdToStack.put(stackId, stack); 4862 performLayoutAndPlaceSurfacesLocked(); 4863 return; 4864 } 4865 } 4866 Slog.e(TAG, "createStack: Unable to find relativeStackBoxId=" + relativeStackBoxId); 4867 } 4868 } 4869 4870 public int removeStack(int stackId) { 4871 synchronized (mWindowMap) { 4872 final TaskStack stack = mStackIdToStack.get(stackId); 4873 if (stack != null) { 4874 mStackIdToStack.delete(stackId); 4875 int nextStackId = stack.remove(); 4876 stack.getDisplayContent().layoutNeeded = true; 4877 requestTraversalLocked(); 4878 return nextStackId; 4879 } 4880 if (DEBUG_STACK) Slog.i(TAG, "removeStack: could not find stackId=" + stackId); 4881 } 4882 return HOME_STACK_ID; 4883 } 4884 4885 public void removeTask(int taskId) { 4886 synchronized (mWindowMap) { 4887 Task task = mTaskIdToTask.get(taskId); 4888 if (task == null) { 4889 if (DEBUG_STACK) Slog.i(TAG, "removeTask: could not find taskId=" + taskId); 4890 return; 4891 } 4892 final TaskStack stack = task.mStack; 4893 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask"); 4894 stack.removeTask(task); 4895 stack.getDisplayContent().layoutNeeded = true; 4896 } 4897 } 4898 4899 public void addTask(int taskId, int stackId, boolean toTop) { 4900 synchronized (mWindowMap) { 4901 Task task = mTaskIdToTask.get(taskId); 4902 if (task == null) { 4903 return; 4904 } 4905 TaskStack stack = mStackIdToStack.get(stackId); 4906 stack.addTask(task, toTop); 4907 final DisplayContent displayContent = stack.getDisplayContent(); 4908 displayContent.layoutNeeded = true; 4909 performLayoutAndPlaceSurfacesLocked(); 4910 } 4911 } 4912 4913 public void resizeStackBox(int stackBoxId, float weight) { 4914 if (weight < STACK_WEIGHT_MIN || weight > STACK_WEIGHT_MAX) { 4915 throw new IllegalArgumentException( 4916 "resizeStack: weight must be between " + STACK_WEIGHT_MIN + " and " + 4917 STACK_WEIGHT_MAX + ", weight=" + weight); 4918 } 4919 synchronized (mWindowMap) { 4920 final int numDisplays = mDisplayContents.size(); 4921 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 4922 if (mDisplayContents.valueAt(displayNdx).resizeStack(stackBoxId, weight)) { 4923 performLayoutAndPlaceSurfacesLocked(); 4924 return; 4925 } 4926 } 4927 } 4928 throw new IllegalArgumentException("resizeStack: stackBoxId " + stackBoxId 4929 + " not found."); 4930 } 4931 4932 public ArrayList<StackBoxInfo> getStackBoxInfos() { 4933 synchronized(mWindowMap) { 4934 return getDefaultDisplayContentLocked().getStackBoxInfos(); 4935 } 4936 } 4937 4938 public Rect getStackBounds(int stackId) { 4939 final int numDisplays = mDisplayContents.size(); 4940 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 4941 Rect bounds = mDisplayContents.valueAt(displayNdx).getStackBounds(stackId); 4942 if (bounds != null) { 4943 return bounds; 4944 } 4945 } 4946 return null; 4947 } 4948 4949 // ------------------------------------------------------------- 4950 // Misc IWindowSession methods 4951 // ------------------------------------------------------------- 4952 4953 @Override 4954 public void startFreezingScreen(int exitAnim, int enterAnim) { 4955 if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN, 4956 "startFreezingScreen()")) { 4957 throw new SecurityException("Requires FREEZE_SCREEN permission"); 4958 } 4959 4960 synchronized(mWindowMap) { 4961 if (!mClientFreezingScreen) { 4962 mClientFreezingScreen = true; 4963 final long origId = Binder.clearCallingIdentity(); 4964 try { 4965 startFreezingDisplayLocked(false, exitAnim, enterAnim); 4966 mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT); 4967 mH.sendEmptyMessageDelayed(H.CLIENT_FREEZE_TIMEOUT, 5000); 4968 } finally { 4969 Binder.restoreCallingIdentity(origId); 4970 } 4971 } 4972 } 4973 } 4974 4975 @Override 4976 public void stopFreezingScreen() { 4977 if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN, 4978 "stopFreezingScreen()")) { 4979 throw new SecurityException("Requires FREEZE_SCREEN permission"); 4980 } 4981 4982 synchronized(mWindowMap) { 4983 if (mClientFreezingScreen) { 4984 mClientFreezingScreen = false; 4985 mLastFinishedFreezeSource = "client"; 4986 final long origId = Binder.clearCallingIdentity(); 4987 try { 4988 stopFreezingDisplayLocked(); 4989 } finally { 4990 Binder.restoreCallingIdentity(origId); 4991 } 4992 } 4993 } 4994 } 4995 4996 @Override 4997 public void disableKeyguard(IBinder token, String tag) { 4998 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) 4999 != PackageManager.PERMISSION_GRANTED) { 5000 throw new SecurityException("Requires DISABLE_KEYGUARD permission"); 5001 } 5002 5003 mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage( 5004 KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag))); 5005 } 5006 5007 @Override 5008 public void reenableKeyguard(IBinder token) { 5009 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) 5010 != PackageManager.PERMISSION_GRANTED) { 5011 throw new SecurityException("Requires DISABLE_KEYGUARD permission"); 5012 } 5013 5014 mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage( 5015 KeyguardDisableHandler.KEYGUARD_REENABLE, token)); 5016 } 5017 5018 /** 5019 * @see android.app.KeyguardManager#exitKeyguardSecurely 5020 */ 5021 @Override 5022 public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) { 5023 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) 5024 != PackageManager.PERMISSION_GRANTED) { 5025 throw new SecurityException("Requires DISABLE_KEYGUARD permission"); 5026 } 5027 mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() { 5028 @Override 5029 public void onKeyguardExitResult(boolean success) { 5030 try { 5031 callback.onKeyguardExitResult(success); 5032 } catch (RemoteException e) { 5033 // Client has died, we don't care. 5034 } 5035 } 5036 }); 5037 } 5038 5039 @Override 5040 public boolean inKeyguardRestrictedInputMode() { 5041 return mPolicy.inKeyguardRestrictedKeyInputMode(); 5042 } 5043 5044 @Override 5045 public boolean isKeyguardLocked() { 5046 return mPolicy.isKeyguardLocked(); 5047 } 5048 5049 @Override 5050 public boolean isKeyguardSecure() { 5051 return mPolicy.isKeyguardSecure(); 5052 } 5053 5054 @Override 5055 public void dismissKeyguard() { 5056 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD) 5057 != PackageManager.PERMISSION_GRANTED) { 5058 throw new SecurityException("Requires DISABLE_KEYGUARD permission"); 5059 } 5060 synchronized(mWindowMap) { 5061 mPolicy.dismissKeyguardLw(); 5062 } 5063 } 5064 5065 @Override 5066 public void closeSystemDialogs(String reason) { 5067 synchronized(mWindowMap) { 5068 final int numDisplays = mDisplayContents.size(); 5069 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 5070 final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); 5071 final int numWindows = windows.size(); 5072 for (int winNdx = 0; winNdx < numWindows; ++winNdx) { 5073 final WindowState w = windows.get(winNdx); 5074 if (w.mHasSurface) { 5075 try { 5076 w.mClient.closeSystemDialogs(reason); 5077 } catch (RemoteException e) { 5078 } 5079 } 5080 } 5081 } 5082 } 5083 } 5084 5085 static float fixScale(float scale) { 5086 if (scale < 0) scale = 0; 5087 else if (scale > 20) scale = 20; 5088 return Math.abs(scale); 5089 } 5090 5091 @Override 5092 public void setAnimationScale(int which, float scale) { 5093 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE, 5094 "setAnimationScale()")) { 5095 throw new SecurityException("Requires SET_ANIMATION_SCALE permission"); 5096 } 5097 5098 scale = fixScale(scale); 5099 switch (which) { 5100 case 0: mWindowAnimationScale = scale; break; 5101 case 1: mTransitionAnimationScale = scale; break; 5102 case 2: mAnimatorDurationScale = scale; break; 5103 } 5104 5105 // Persist setting 5106 mH.sendEmptyMessage(H.PERSIST_ANIMATION_SCALE); 5107 } 5108 5109 @Override 5110 public void setAnimationScales(float[] scales) { 5111 if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE, 5112 "setAnimationScale()")) { 5113 throw new SecurityException("Requires SET_ANIMATION_SCALE permission"); 5114 } 5115 5116 if (scales != null) { 5117 if (scales.length >= 1) { 5118 mWindowAnimationScale = fixScale(scales[0]); 5119 } 5120 if (scales.length >= 2) { 5121 mTransitionAnimationScale = fixScale(scales[1]); 5122 } 5123 if (scales.length >= 3) { 5124 setAnimatorDurationScale(fixScale(scales[2])); 5125 } 5126 } 5127 5128 // Persist setting 5129 mH.sendEmptyMessage(H.PERSIST_ANIMATION_SCALE); 5130 } 5131 5132 private void setAnimatorDurationScale(float scale) { 5133 mAnimatorDurationScale = scale; 5134 ValueAnimator.setDurationScale(scale); 5135 } 5136 5137 @Override 5138 public float getAnimationScale(int which) { 5139 switch (which) { 5140 case 0: return mWindowAnimationScale; 5141 case 1: return mTransitionAnimationScale; 5142 case 2: return mAnimatorDurationScale; 5143 } 5144 return 0; 5145 } 5146 5147 @Override 5148 public float[] getAnimationScales() { 5149 return new float[] { mWindowAnimationScale, mTransitionAnimationScale, 5150 mAnimatorDurationScale }; 5151 } 5152 5153 @Override 5154 public void registerPointerEventListener(PointerEventListener listener) { 5155 mPointerEventDispatcher.registerInputEventListener(listener); 5156 } 5157 5158 @Override 5159 public void unregisterPointerEventListener(PointerEventListener listener) { 5160 mPointerEventDispatcher.unregisterInputEventListener(listener); 5161 } 5162 5163 // Called by window manager policy. Not exposed externally. 5164 @Override 5165 public int getLidState() { 5166 int sw = mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, 5167 InputManagerService.SW_LID); 5168 if (sw > 0) { 5169 // Switch state: AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL. 5170 return LID_CLOSED; 5171 } else if (sw == 0) { 5172 // Switch state: AKEY_STATE_UP. 5173 return LID_OPEN; 5174 } else { 5175 // Switch state: AKEY_STATE_UNKNOWN. 5176 return LID_ABSENT; 5177 } 5178 } 5179 5180 // Called by window manager policy. Not exposed externally. 5181 @Override 5182 public void switchKeyboardLayout(int deviceId, int direction) { 5183 mInputManager.switchKeyboardLayout(deviceId, direction); 5184 } 5185 5186 // Called by window manager policy. Not exposed externally. 5187 @Override 5188 public void shutdown(boolean confirm) { 5189 ShutdownThread.shutdown(mContext, confirm); 5190 } 5191 5192 // Called by window manager policy. Not exposed externally. 5193 @Override 5194 public void rebootSafeMode(boolean confirm) { 5195 ShutdownThread.rebootSafeMode(mContext, confirm); 5196 } 5197 5198 @Override 5199 public void setInputFilter(IInputFilter filter) { 5200 if (!checkCallingPermission(android.Manifest.permission.FILTER_EVENTS, "setInputFilter()")) { 5201 throw new SecurityException("Requires FILTER_EVENTS permission"); 5202 } 5203 mInputManager.setInputFilter(filter); 5204 } 5205 5206 @Override 5207 public void setTouchExplorationEnabled(boolean enabled) { 5208 mPolicy.setTouchExplorationEnabled(enabled); 5209 } 5210 5211 public void setCurrentUser(final int newUserId) { 5212 synchronized (mWindowMap) { 5213 int oldUserId = mCurrentUserId; 5214 mCurrentUserId = newUserId; 5215 mAppTransition.setCurrentUser(newUserId); 5216 mPolicy.setCurrentUserLw(newUserId); 5217 5218 // Hide windows that should not be seen by the new user. 5219 final int numDisplays = mDisplayContents.size(); 5220 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 5221 final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); 5222 displayContent.switchUserStacks(oldUserId, newUserId); 5223 rebuildAppWindowListLocked(displayContent); 5224 } 5225 performLayoutAndPlaceSurfacesLocked(); 5226 } 5227 } 5228 5229 public void enableScreenAfterBoot() { 5230 synchronized(mWindowMap) { 5231 if (DEBUG_BOOT) { 5232 RuntimeException here = new RuntimeException("here"); 5233 here.fillInStackTrace(); 5234 Slog.i(TAG, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled 5235 + " mForceDisplayEnabled=" + mForceDisplayEnabled 5236 + " mShowingBootMessages=" + mShowingBootMessages 5237 + " mSystemBooted=" + mSystemBooted, here); 5238 } 5239 if (mSystemBooted) { 5240 return; 5241 } 5242 mSystemBooted = true; 5243 hideBootMessagesLocked(); 5244 // If the screen still doesn't come up after 30 seconds, give 5245 // up and turn it on. 5246 mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30*1000); 5247 } 5248 5249 mPolicy.systemBooted(); 5250 5251 performEnableScreen(); 5252 } 5253 5254 void enableScreenIfNeededLocked() { 5255 if (DEBUG_BOOT) { 5256 RuntimeException here = new RuntimeException("here"); 5257 here.fillInStackTrace(); 5258 Slog.i(TAG, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled 5259 + " mForceDisplayEnabled=" + mForceDisplayEnabled 5260 + " mShowingBootMessages=" + mShowingBootMessages 5261 + " mSystemBooted=" + mSystemBooted, here); 5262 } 5263 if (mDisplayEnabled) { 5264 return; 5265 } 5266 if (!mSystemBooted && !mShowingBootMessages) { 5267 return; 5268 } 5269 mH.sendEmptyMessage(H.ENABLE_SCREEN); 5270 } 5271 5272 public void performBootTimeout() { 5273 synchronized(mWindowMap) { 5274 if (mDisplayEnabled || mHeadless) { 5275 return; 5276 } 5277 Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled"); 5278 mForceDisplayEnabled = true; 5279 } 5280 performEnableScreen(); 5281 } 5282 5283 public void performEnableScreen() { 5284 synchronized(mWindowMap) { 5285 if (DEBUG_BOOT) { 5286 RuntimeException here = new RuntimeException("here"); 5287 here.fillInStackTrace(); 5288 Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled 5289 + " mForceDisplayEnabled=" + mForceDisplayEnabled 5290 + " mShowingBootMessages=" + mShowingBootMessages 5291 + " mSystemBooted=" + mSystemBooted 5292 + " mOnlyCore=" + mOnlyCore, here); 5293 } 5294 if (mDisplayEnabled) { 5295 return; 5296 } 5297 if (!mSystemBooted && !mShowingBootMessages) { 5298 return; 5299 } 5300 5301 if (!mForceDisplayEnabled) { 5302 // Don't enable the screen until all existing windows 5303 // have been drawn. 5304 boolean haveBootMsg = false; 5305 boolean haveApp = false; 5306 // if the wallpaper service is disabled on the device, we're never going to have 5307 // wallpaper, don't bother waiting for it 5308 boolean haveWallpaper = false; 5309 boolean wallpaperEnabled = mContext.getResources().getBoolean( 5310 com.android.internal.R.bool.config_enableWallpaperService) 5311 && !mOnlyCore; 5312 boolean haveKeyguard = true; 5313 // TODO(multidisplay): Expand to all displays? 5314 final WindowList windows = getDefaultWindowListLocked(); 5315 final int N = windows.size(); 5316 for (int i=0; i<N; i++) { 5317 WindowState w = windows.get(i); 5318 if (w.mAttrs.type == TYPE_KEYGUARD) { 5319 // Only if there is a keyguard attached to the window manager 5320 // will we consider ourselves as having a keyguard. If it 5321 // isn't attached, we don't know if it wants to be shown or 5322 // hidden. If it is attached, we will say we have a keyguard 5323 // if the window doesn't want to be visible, because in that 5324 // case it explicitly doesn't want to be shown so we should 5325 // not delay turning the screen on for it. 5326 boolean vis = w.mViewVisibility == View.VISIBLE 5327 && w.mPolicyVisibility; 5328 haveKeyguard = !vis; 5329 } 5330 if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { 5331 return; 5332 } 5333 if (w.isDrawnLw()) { 5334 if (w.mAttrs.type == TYPE_BOOT_PROGRESS) { 5335 haveBootMsg = true; 5336 } else if (w.mAttrs.type == TYPE_APPLICATION) { 5337 haveApp = true; 5338 } else if (w.mAttrs.type == TYPE_WALLPAPER) { 5339 haveWallpaper = true; 5340 } else if (w.mAttrs.type == TYPE_KEYGUARD) { 5341 haveKeyguard = true; 5342 } 5343 } 5344 } 5345 5346 if (DEBUG_SCREEN_ON || DEBUG_BOOT) { 5347 Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages 5348 + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp 5349 + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled 5350 + " haveKeyguard=" + haveKeyguard); 5351 } 5352 5353 // If we are turning on the screen to show the boot message, 5354 // don't do it until the boot message is actually displayed. 5355 if (!mSystemBooted && !haveBootMsg) { 5356 return; 5357 } 5358 5359 // If we are turning on the screen after the boot is completed 5360 // normally, don't do so until we have the application and 5361 // wallpaper. 5362 if (mSystemBooted && ((!haveApp && !haveKeyguard) || 5363 (wallpaperEnabled && !haveWallpaper))) { 5364 return; 5365 } 5366 } 5367 5368 mDisplayEnabled = true; 5369 if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!"); 5370 if (false) { 5371 StringWriter sw = new StringWriter(); 5372 PrintWriter pw = new FastPrintWriter(sw, false, 1024); 5373 this.dump(null, pw, null); 5374 pw.flush(); 5375 Slog.i(TAG, sw.toString()); 5376 } 5377 try { 5378 IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger"); 5379 if (surfaceFlinger != null) { 5380 //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!"); 5381 Parcel data = Parcel.obtain(); 5382 data.writeInterfaceToken("android.ui.ISurfaceComposer"); 5383 surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED 5384 data, null, 0); 5385 data.recycle(); 5386 } 5387 } catch (RemoteException ex) { 5388 Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!"); 5389 } 5390 5391 // Enable input dispatch. 5392 mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled); 5393 } 5394 5395 mPolicy.enableScreenAfterBoot(); 5396 5397 // Make sure the last requested orientation has been applied. 5398 updateRotationUnchecked(false, false); 5399 } 5400 5401 public void showBootMessage(final CharSequence msg, final boolean always) { 5402 boolean first = false; 5403 synchronized(mWindowMap) { 5404 if (DEBUG_BOOT) { 5405 RuntimeException here = new RuntimeException("here"); 5406 here.fillInStackTrace(); 5407 Slog.i(TAG, "showBootMessage: msg=" + msg + " always=" + always 5408 + " mAllowBootMessages=" + mAllowBootMessages 5409 + " mShowingBootMessages=" + mShowingBootMessages 5410 + " mSystemBooted=" + mSystemBooted, here); 5411 } 5412 if (!mAllowBootMessages) { 5413 return; 5414 } 5415 if (!mShowingBootMessages) { 5416 if (!always) { 5417 return; 5418 } 5419 first = true; 5420 } 5421 if (mSystemBooted) { 5422 return; 5423 } 5424 mShowingBootMessages = true; 5425 mPolicy.showBootMessage(msg, always); 5426 } 5427 if (first) { 5428 performEnableScreen(); 5429 } 5430 } 5431 5432 public void hideBootMessagesLocked() { 5433 if (DEBUG_BOOT) { 5434 RuntimeException here = new RuntimeException("here"); 5435 here.fillInStackTrace(); 5436 Slog.i(TAG, "hideBootMessagesLocked: mDisplayEnabled=" + mDisplayEnabled 5437 + " mForceDisplayEnabled=" + mForceDisplayEnabled 5438 + " mShowingBootMessages=" + mShowingBootMessages 5439 + " mSystemBooted=" + mSystemBooted, here); 5440 } 5441 if (mShowingBootMessages) { 5442 mShowingBootMessages = false; 5443 mPolicy.hideBootMessages(); 5444 } 5445 } 5446 5447 @Override 5448 public void setInTouchMode(boolean mode) { 5449 synchronized(mWindowMap) { 5450 mInTouchMode = mode; 5451 } 5452 } 5453 5454 // TODO: more accounting of which pid(s) turned it on, keep count, 5455 // only allow disables from pids which have count on, etc. 5456 @Override 5457 public void showStrictModeViolation(boolean on) { 5458 if (mHeadless) return; 5459 int pid = Binder.getCallingPid(); 5460 mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid)); 5461 } 5462 5463 private void showStrictModeViolation(int arg, int pid) { 5464 final boolean on = arg != 0; 5465 synchronized(mWindowMap) { 5466 // Ignoring requests to enable the red border from clients 5467 // which aren't on screen. (e.g. Broadcast Receivers in 5468 // the background..) 5469 if (on) { 5470 boolean isVisible = false; 5471 final int numDisplays = mDisplayContents.size(); 5472 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 5473 final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); 5474 final int numWindows = windows.size(); 5475 for (int winNdx = 0; winNdx < numWindows; ++winNdx) { 5476 final WindowState ws = windows.get(winNdx); 5477 if (ws.mSession.mPid == pid && ws.isVisibleLw()) { 5478 isVisible = true; 5479 break; 5480 } 5481 } 5482 } 5483 if (!isVisible) { 5484 return; 5485 } 5486 } 5487 5488 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, 5489 ">>> OPEN TRANSACTION showStrictModeViolation"); 5490 SurfaceControl.openTransaction(); 5491 try { 5492 // TODO(multi-display): support multiple displays 5493 if (mStrictModeFlash == null) { 5494 mStrictModeFlash = new StrictModeFlash( 5495 getDefaultDisplayContentLocked().getDisplay(), mFxSession); 5496 } 5497 mStrictModeFlash.setVisibility(on); 5498 } finally { 5499 SurfaceControl.closeTransaction(); 5500 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, 5501 "<<< CLOSE TRANSACTION showStrictModeViolation"); 5502 } 5503 } 5504 } 5505 5506 @Override 5507 public void setStrictModeVisualIndicatorPreference(String value) { 5508 SystemProperties.set(StrictMode.VISUAL_PROPERTY, value); 5509 } 5510 5511 /** 5512 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. 5513 * In portrait mode, it grabs the upper region of the screen based on the vertical dimension 5514 * of the target image. 5515 * 5516 * @param displayId the Display to take a screenshot of. 5517 * @param width the width of the target bitmap 5518 * @param height the height of the target bitmap 5519 * @param force565 if true the returned bitmap will be RGB_565, otherwise it 5520 * will be the same config as the surface 5521 */ 5522 @Override 5523 public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, 5524 int height, boolean force565) { 5525 if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER, 5526 "screenshotApplications()")) { 5527 throw new SecurityException("Requires READ_FRAME_BUFFER permission"); 5528 } 5529 5530 Bitmap rawss = null; 5531 5532 int maxLayer = 0; 5533 final Rect frame = new Rect(); 5534 5535 float scale = 0; 5536 int dw, dh; 5537 int rot = Surface.ROTATION_0; 5538 5539 boolean screenshotReady; 5540 int minLayer; 5541 if (appToken == null) { 5542 screenshotReady = true; 5543 minLayer = 0; 5544 } else { 5545 screenshotReady = false; 5546 minLayer = Integer.MAX_VALUE; 5547 } 5548 5549 int retryCount = 0; 5550 WindowState appWin = null; 5551 5552 do { 5553 if (retryCount++ > 0) { 5554 try { 5555 Thread.sleep(100); 5556 } catch (InterruptedException e) { 5557 } 5558 } 5559 synchronized(mWindowMap) { 5560 final DisplayContent displayContent = getDisplayContentLocked(displayId); 5561 if (displayContent == null) { 5562 return null; 5563 } 5564 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 5565 dw = displayInfo.logicalWidth; 5566 dh = displayInfo.logicalHeight; 5567 5568 int aboveAppLayer = mPolicy.windowTypeToLayerLw(TYPE_APPLICATION) 5569 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; 5570 aboveAppLayer += TYPE_LAYER_MULTIPLIER; 5571 5572 boolean isImeTarget = mInputMethodTarget != null 5573 && mInputMethodTarget.mAppToken != null 5574 && mInputMethodTarget.mAppToken.appToken != null 5575 && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken; 5576 5577 // Figure out the part of the screen that is actually the app. 5578 boolean including = false; 5579 appWin = null; 5580 final WindowList windows = displayContent.getWindowList(); 5581 final Rect stackBounds = new Rect(); 5582 for (int i = windows.size() - 1; i >= 0; i--) { 5583 WindowState ws = windows.get(i); 5584 if (!ws.mHasSurface) { 5585 continue; 5586 } 5587 if (ws.mLayer >= aboveAppLayer) { 5588 continue; 5589 } 5590 // When we will skip windows: when we are not including 5591 // ones behind a window we didn't skip, and we are actually 5592 // taking a screenshot of a specific app. 5593 if (!including && appToken != null) { 5594 // Also, we can possibly skip this window if it is not 5595 // an IME target or the application for the screenshot 5596 // is not the current IME target. 5597 if (!ws.mIsImWindow || !isImeTarget) { 5598 // And finally, this window is of no interest if it 5599 // is not associated with the screenshot app. 5600 if (ws.mAppToken == null || ws.mAppToken.token != appToken) { 5601 continue; 5602 } 5603 appWin = ws; 5604 stackBounds.set(ws.getStackBounds()); 5605 } 5606 } 5607 5608 // We keep on including windows until we go past a full-screen 5609 // window. 5610 boolean fullscreen = ws.isFullscreen(dw, dh); 5611 including = !ws.mIsImWindow && !fullscreen; 5612 5613 final WindowStateAnimator winAnim = ws.mWinAnimator; 5614 if (maxLayer < winAnim.mSurfaceLayer) { 5615 maxLayer = winAnim.mSurfaceLayer; 5616 } 5617 if (minLayer > winAnim.mSurfaceLayer) { 5618 minLayer = winAnim.mSurfaceLayer; 5619 } 5620 5621 // Don't include wallpaper in bounds calculation 5622 if (!ws.mIsWallpaper) { 5623 final Rect wf = ws.mFrame; 5624 final Rect cr = ws.mContentInsets; 5625 int left = wf.left + cr.left; 5626 int top = wf.top + cr.top; 5627 int right = wf.right - cr.right; 5628 int bottom = wf.bottom - cr.bottom; 5629 frame.union(left, top, right, bottom); 5630 frame.intersect(stackBounds); 5631 } 5632 5633 if (ws.mAppToken != null && ws.mAppToken.token == appToken && 5634 ws.isDisplayedLw()) { 5635 screenshotReady = true; 5636 } 5637 5638 if (fullscreen) { 5639 // No point in continuing down through windows. 5640 break; 5641 } 5642 } 5643 5644 if (appToken != null && appWin == null) { 5645 // Can't find a window to snapshot. 5646 if (DEBUG_SCREENSHOT) Slog.i(TAG, 5647 "Screenshot: Couldn't find a surface matching " + appToken); 5648 return null; 5649 } 5650 if (!screenshotReady) { 5651 // Delay and hope that window gets drawn. 5652 if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot: No image ready for " + appToken 5653 + ", " + appWin + " drawState=" + appWin.mWinAnimator.mDrawState); 5654 continue; 5655 } 5656 5657 // Constrain frame to the screen size. 5658 frame.intersect(0, 0, dw, dh); 5659 5660 if (frame.isEmpty() || maxLayer == 0) { 5661 if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot of " + appToken 5662 + ": returning null frame=" + frame.toShortString() + " maxLayer=" 5663 + maxLayer); 5664 return null; 5665 } 5666 5667 // The screenshot API does not apply the current screen rotation. 5668 rot = getDefaultDisplayContentLocked().getDisplay().getRotation(); 5669 int fw = frame.width(); 5670 int fh = frame.height(); 5671 5672 // Constrain thumbnail to smaller of screen width or height. Assumes aspect 5673 // of thumbnail is the same as the screen (in landscape) or square. 5674 scale = Math.max(width / (float) fw, height / (float) fh); 5675 /* 5676 float targetWidthScale = width / (float) fw; 5677 float targetHeightScale = height / (float) fh; 5678 if (fw <= fh) { 5679 scale = targetWidthScale; 5680 // If aspect of thumbnail is the same as the screen (in landscape), 5681 // select the slightly larger value so we fill the entire bitmap 5682 if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) { 5683 scale = targetHeightScale; 5684 } 5685 } else { 5686 scale = targetHeightScale; 5687 // If aspect of thumbnail is the same as the screen (in landscape), 5688 // select the slightly larger value so we fill the entire bitmap 5689 if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) { 5690 scale = targetWidthScale; 5691 } 5692 } 5693 */ 5694 5695 // The screen shot will contain the entire screen. 5696 dw = (int)(dw*scale); 5697 dh = (int)(dh*scale); 5698 if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { 5699 int tmp = dw; 5700 dw = dh; 5701 dh = tmp; 5702 rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90; 5703 } 5704 if (DEBUG_SCREENSHOT) { 5705 Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to " 5706 + maxLayer + " appToken=" + appToken); 5707 for (int i = 0; i < windows.size(); i++) { 5708 WindowState win = windows.get(i); 5709 Slog.i(TAG, win + ": " + win.mLayer 5710 + " animLayer=" + win.mWinAnimator.mAnimLayer 5711 + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer); 5712 } 5713 } 5714 rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer); 5715 } 5716 } while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES); 5717 if (retryCount > MAX_SCREENSHOT_RETRIES) Slog.i(TAG, "Screenshot max retries " + 5718 retryCount + " of " + appToken + " appWin=" + (appWin == null ? 5719 "null" : (appWin + " drawState=" + appWin.mWinAnimator.mDrawState))); 5720 5721 if (rawss == null) { 5722 Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh 5723 + ") to layer " + maxLayer); 5724 return null; 5725 } 5726 5727 Bitmap bm = Bitmap.createBitmap(width, height, force565 ? Config.RGB_565 : rawss.getConfig()); 5728 frame.scale(scale); 5729 Matrix matrix = new Matrix(); 5730 ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix); 5731 // TODO: Test for RTL vs. LTR and use frame.right-width instead of -frame.left 5732 matrix.postTranslate(-FloatMath.ceil(frame.left), -FloatMath.ceil(frame.top)); 5733 Canvas canvas = new Canvas(bm); 5734 canvas.drawColor(0xFF000000); 5735 canvas.drawBitmap(rawss, matrix, null); 5736 canvas.setBitmap(null); 5737 5738 if (DEBUG_SCREENSHOT) { 5739 // TEST IF IT's ALL BLACK 5740 int[] buffer = new int[bm.getWidth() * bm.getHeight()]; 5741 bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight()); 5742 boolean allBlack = true; 5743 final int firstColor = buffer[0]; 5744 for (int i = 0; i < buffer.length; i++) { 5745 if (buffer[i] != firstColor) { 5746 allBlack = false; 5747 break; 5748 } 5749 } 5750 if (allBlack) { 5751 Slog.i(TAG, "Screenshot " + appWin + " was monochrome(" + 5752 Integer.toHexString(firstColor) + ")! mSurfaceLayer=" + 5753 (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null") + 5754 " minLayer=" + minLayer + " maxLayer=" + maxLayer); 5755 } 5756 } 5757 5758 rawss.recycle(); 5759 return bm; 5760 } 5761 5762 /** 5763 * Freeze rotation changes. (Enable "rotation lock".) 5764 * Persists across reboots. 5765 * @param rotation The desired rotation to freeze to, or -1 to use the 5766 * current rotation. 5767 */ 5768 @Override 5769 public void freezeRotation(int rotation) { 5770 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, 5771 "freezeRotation()")) { 5772 throw new SecurityException("Requires SET_ORIENTATION permission"); 5773 } 5774 if (rotation < -1 || rotation > Surface.ROTATION_270) { 5775 throw new IllegalArgumentException("Rotation argument must be -1 or a valid " 5776 + "rotation constant."); 5777 } 5778 5779 if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation); 5780 5781 long origId = Binder.clearCallingIdentity(); 5782 try { 5783 mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED, 5784 rotation == -1 ? mRotation : rotation); 5785 } finally { 5786 Binder.restoreCallingIdentity(origId); 5787 } 5788 5789 updateRotationUnchecked(false, false); 5790 } 5791 5792 /** 5793 * Thaw rotation changes. (Disable "rotation lock".) 5794 * Persists across reboots. 5795 */ 5796 @Override 5797 public void thawRotation() { 5798 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, 5799 "thawRotation()")) { 5800 throw new SecurityException("Requires SET_ORIENTATION permission"); 5801 } 5802 5803 if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation); 5804 5805 long origId = Binder.clearCallingIdentity(); 5806 try { 5807 mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 5808 777); // rot not used 5809 } finally { 5810 Binder.restoreCallingIdentity(origId); 5811 } 5812 5813 updateRotationUnchecked(false, false); 5814 } 5815 5816 /** 5817 * Recalculate the current rotation. 5818 * 5819 * Called by the window manager policy whenever the state of the system changes 5820 * such that the current rotation might need to be updated, such as when the 5821 * device is docked or rotated into a new posture. 5822 */ 5823 @Override 5824 public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) { 5825 updateRotationUnchecked(alwaysSendConfiguration, forceRelayout); 5826 } 5827 5828 /** 5829 * Temporarily pauses rotation changes until resumed. 5830 * 5831 * This can be used to prevent rotation changes from occurring while the user is 5832 * performing certain operations, such as drag and drop. 5833 * 5834 * This call nests and must be matched by an equal number of calls to 5835 * {@link #resumeRotationLocked}. 5836 */ 5837 void pauseRotationLocked() { 5838 mDeferredRotationPauseCount += 1; 5839 } 5840 5841 /** 5842 * Resumes normal rotation changes after being paused. 5843 */ 5844 void resumeRotationLocked() { 5845 if (mDeferredRotationPauseCount > 0) { 5846 mDeferredRotationPauseCount -= 1; 5847 if (mDeferredRotationPauseCount == 0) { 5848 boolean changed = updateRotationUncheckedLocked(false); 5849 if (changed) { 5850 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 5851 } 5852 } 5853 } 5854 } 5855 5856 public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) { 5857 if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked(" 5858 + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")"); 5859 5860 long origId = Binder.clearCallingIdentity(); 5861 boolean changed; 5862 synchronized(mWindowMap) { 5863 changed = updateRotationUncheckedLocked(false); 5864 if (!changed || forceRelayout) { 5865 getDefaultDisplayContentLocked().layoutNeeded = true; 5866 performLayoutAndPlaceSurfacesLocked(); 5867 } 5868 } 5869 5870 if (changed || alwaysSendConfiguration) { 5871 sendNewConfiguration(); 5872 } 5873 5874 Binder.restoreCallingIdentity(origId); 5875 } 5876 5877 // TODO(multidisplay): Rotate any display? 5878 /** 5879 * Updates the current rotation. 5880 * 5881 * Returns true if the rotation has been changed. In this case YOU 5882 * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN. 5883 */ 5884 public boolean updateRotationUncheckedLocked(boolean inTransaction) { 5885 if (mDeferredRotationPauseCount > 0) { 5886 // Rotation updates have been paused temporarily. Defer the update until 5887 // updates have been resumed. 5888 if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused."); 5889 return false; 5890 } 5891 5892 ScreenRotationAnimation screenRotationAnimation = 5893 mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY); 5894 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) { 5895 // Rotation updates cannot be performed while the previous rotation change 5896 // animation is still in progress. Skip this update. We will try updating 5897 // again after the animation is finished and the display is unfrozen. 5898 if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress."); 5899 return false; 5900 } 5901 5902 if (!mDisplayEnabled) { 5903 // No point choosing a rotation if the display is not enabled. 5904 if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled."); 5905 return false; 5906 } 5907 5908 // TODO: Implement forced rotation changes. 5909 // Set mAltOrientation to indicate that the application is receiving 5910 // an orientation that has different metrics than it expected. 5911 // eg. Portrait instead of Landscape. 5912 5913 int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation); 5914 boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw( 5915 mForcedAppOrientation, rotation); 5916 5917 if (DEBUG_ORIENTATION) { 5918 Slog.v(TAG, "Application requested orientation " 5919 + mForcedAppOrientation + ", got rotation " + rotation 5920 + " which has " + (altOrientation ? "incompatible" : "compatible") 5921 + " metrics"); 5922 } 5923 5924 if (mRotation == rotation && mAltOrientation == altOrientation) { 5925 // No change. 5926 return false; 5927 } 5928 5929 if (DEBUG_ORIENTATION) { 5930 Slog.v(TAG, 5931 "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "") 5932 + " from " + mRotation + (mAltOrientation ? " (alt)" : "") 5933 + ", forceApp=" + mForcedAppOrientation); 5934 } 5935 5936 mRotation = rotation; 5937 mAltOrientation = altOrientation; 5938 mPolicy.setRotationLw(mRotation); 5939 5940 mWindowsFreezingScreen = true; 5941 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); 5942 mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION); 5943 mWaitingForConfig = true; 5944 final DisplayContent displayContent = getDefaultDisplayContentLocked(); 5945 displayContent.layoutNeeded = true; 5946 final int[] anim = new int[2]; 5947 if (displayContent.isDimming()) { 5948 anim[0] = anim[1] = 0; 5949 } else { 5950 mPolicy.selectRotationAnimationLw(anim); 5951 } 5952 startFreezingDisplayLocked(inTransaction, anim[0], anim[1]); 5953 // startFreezingDisplayLocked can reset the ScreenRotationAnimation. 5954 screenRotationAnimation = 5955 mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY); 5956 5957 // We need to update our screen size information to match the new 5958 // rotation. Note that this is redundant with the later call to 5959 // sendNewConfiguration() that must be called after this function 5960 // returns... however we need to do the screen size part of that 5961 // before then so we have the correct size to use when initializing 5962 // the rotation animation for the new rotation. 5963 computeScreenConfigurationLocked(null); 5964 5965 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 5966 if (!inTransaction) { 5967 if (SHOW_TRANSACTIONS) { 5968 Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked"); 5969 } 5970 SurfaceControl.openTransaction(); 5971 } 5972 try { 5973 // NOTE: We disable the rotation in the emulator because 5974 // it doesn't support hardware OpenGL emulation yet. 5975 if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null 5976 && screenRotationAnimation.hasScreenshot()) { 5977 if (screenRotationAnimation.setRotationInTransaction( 5978 rotation, mFxSession, 5979 MAX_ANIMATION_DURATION, mTransitionAnimationScale, 5980 displayInfo.logicalWidth, displayInfo.logicalHeight)) { 5981 scheduleAnimationLocked(); 5982 } 5983 } 5984 5985 mDisplayManagerService.performTraversalInTransactionFromWindowManager(); 5986 } finally { 5987 if (!inTransaction) { 5988 SurfaceControl.closeTransaction(); 5989 if (SHOW_LIGHT_TRANSACTIONS) { 5990 Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked"); 5991 } 5992 } 5993 } 5994 5995 final WindowList windows = displayContent.getWindowList(); 5996 for (int i = windows.size() - 1; i >= 0; i--) { 5997 WindowState w = windows.get(i); 5998 if (w.mHasSurface) { 5999 if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w); 6000 w.mOrientationChanging = true; 6001 mInnerFields.mOrientationChangeComplete = false; 6002 } 6003 w.mLastFreezeDuration = 0; 6004 } 6005 6006 for (int i=mRotationWatchers.size()-1; i>=0; i--) { 6007 try { 6008 mRotationWatchers.get(i).watcher.onRotationChanged(rotation); 6009 } catch (RemoteException e) { 6010 } 6011 } 6012 6013 //TODO (multidisplay): Magnification is supported only for the default display. 6014 if (mDisplayMagnifier != null 6015 && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) { 6016 mDisplayMagnifier.onRotationChangedLocked(getDefaultDisplayContentLocked(), rotation); 6017 } 6018 6019 return true; 6020 } 6021 6022 @Override 6023 public int getRotation() { 6024 return mRotation; 6025 } 6026 6027 @Override 6028 public boolean isRotationFrozen() { 6029 return mPolicy.getUserRotationMode() == WindowManagerPolicy.USER_ROTATION_LOCKED; 6030 } 6031 6032 @Override 6033 public int watchRotation(IRotationWatcher watcher) { 6034 final IBinder watcherBinder = watcher.asBinder(); 6035 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() { 6036 @Override 6037 public void binderDied() { 6038 synchronized (mWindowMap) { 6039 for (int i=0; i<mRotationWatchers.size(); i++) { 6040 if (watcherBinder == mRotationWatchers.get(i).watcher.asBinder()) { 6041 RotationWatcher removed = mRotationWatchers.remove(i); 6042 if (removed != null) { 6043 removed.watcher.asBinder().unlinkToDeath(this, 0); 6044 } 6045 i--; 6046 } 6047 } 6048 } 6049 } 6050 }; 6051 6052 synchronized (mWindowMap) { 6053 try { 6054 watcher.asBinder().linkToDeath(dr, 0); 6055 mRotationWatchers.add(new RotationWatcher(watcher, dr)); 6056 } catch (RemoteException e) { 6057 // Client died, no cleanup needed. 6058 } 6059 6060 return mRotation; 6061 } 6062 } 6063 6064 @Override 6065 public void removeRotationWatcher(IRotationWatcher watcher) { 6066 final IBinder watcherBinder = watcher.asBinder(); 6067 synchronized (mWindowMap) { 6068 for (int i=0; i<mRotationWatchers.size(); i++) { 6069 RotationWatcher rotationWatcher = mRotationWatchers.get(i); 6070 if (watcherBinder == rotationWatcher.watcher.asBinder()) { 6071 RotationWatcher removed = mRotationWatchers.remove(i); 6072 if (removed != null) { 6073 removed.watcher.asBinder().unlinkToDeath(removed.dr, 0); 6074 i--; 6075 } 6076 } 6077 } 6078 } 6079 } 6080 6081 /** 6082 * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact 6083 * theme attribute) on devices that feature a physical options menu key attempt to position 6084 * their menu panel window along the edge of the screen nearest the physical menu key. 6085 * This lowers the travel distance between invoking the menu panel and selecting 6086 * a menu option. 6087 * 6088 * This method helps control where that menu is placed. Its current implementation makes 6089 * assumptions about the menu key and its relationship to the screen based on whether 6090 * the device's natural orientation is portrait (width < height) or landscape. 6091 * 6092 * The menu key is assumed to be located along the bottom edge of natural-portrait 6093 * devices and along the right edge of natural-landscape devices. If these assumptions 6094 * do not hold for the target device, this method should be changed to reflect that. 6095 * 6096 * @return A {@link Gravity} value for placing the options menu window 6097 */ 6098 @Override 6099 public int getPreferredOptionsPanelGravity() { 6100 synchronized (mWindowMap) { 6101 final int rotation = getRotation(); 6102 6103 // TODO(multidisplay): Assume that such devices physical keys are on the main screen. 6104 final DisplayContent displayContent = getDefaultDisplayContentLocked(); 6105 if (displayContent.mInitialDisplayWidth < displayContent.mInitialDisplayHeight) { 6106 // On devices with a natural orientation of portrait 6107 switch (rotation) { 6108 default: 6109 case Surface.ROTATION_0: 6110 return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 6111 case Surface.ROTATION_90: 6112 return Gravity.RIGHT | Gravity.BOTTOM; 6113 case Surface.ROTATION_180: 6114 return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 6115 case Surface.ROTATION_270: 6116 return Gravity.START | Gravity.BOTTOM; 6117 } 6118 } 6119 6120 // On devices with a natural orientation of landscape 6121 switch (rotation) { 6122 default: 6123 case Surface.ROTATION_0: 6124 return Gravity.RIGHT | Gravity.BOTTOM; 6125 case Surface.ROTATION_90: 6126 return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 6127 case Surface.ROTATION_180: 6128 return Gravity.START | Gravity.BOTTOM; 6129 case Surface.ROTATION_270: 6130 return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM; 6131 } 6132 } 6133 } 6134 6135 /** 6136 * Starts the view server on the specified port. 6137 * 6138 * @param port The port to listener to. 6139 * 6140 * @return True if the server was successfully started, false otherwise. 6141 * 6142 * @see com.android.server.wm.ViewServer 6143 * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT 6144 */ 6145 @Override 6146 public boolean startViewServer(int port) { 6147 if (isSystemSecure()) { 6148 return false; 6149 } 6150 6151 if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) { 6152 return false; 6153 } 6154 6155 if (port < 1024) { 6156 return false; 6157 } 6158 6159 if (mViewServer != null) { 6160 if (!mViewServer.isRunning()) { 6161 try { 6162 return mViewServer.start(); 6163 } catch (IOException e) { 6164 Slog.w(TAG, "View server did not start"); 6165 } 6166 } 6167 return false; 6168 } 6169 6170 try { 6171 mViewServer = new ViewServer(this, port); 6172 return mViewServer.start(); 6173 } catch (IOException e) { 6174 Slog.w(TAG, "View server did not start"); 6175 } 6176 return false; 6177 } 6178 6179 private boolean isSystemSecure() { 6180 return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) && 6181 "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); 6182 } 6183 6184 /** 6185 * Stops the view server if it exists. 6186 * 6187 * @return True if the server stopped, false if it wasn't started or 6188 * couldn't be stopped. 6189 * 6190 * @see com.android.server.wm.ViewServer 6191 */ 6192 @Override 6193 public boolean stopViewServer() { 6194 if (isSystemSecure()) { 6195 return false; 6196 } 6197 6198 if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) { 6199 return false; 6200 } 6201 6202 if (mViewServer != null) { 6203 return mViewServer.stop(); 6204 } 6205 return false; 6206 } 6207 6208 /** 6209 * Indicates whether the view server is running. 6210 * 6211 * @return True if the server is running, false otherwise. 6212 * 6213 * @see com.android.server.wm.ViewServer 6214 */ 6215 @Override 6216 public boolean isViewServerRunning() { 6217 if (isSystemSecure()) { 6218 return false; 6219 } 6220 6221 if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) { 6222 return false; 6223 } 6224 6225 return mViewServer != null && mViewServer.isRunning(); 6226 } 6227 6228 /** 6229 * Lists all availble windows in the system. The listing is written in the 6230 * specified Socket's output stream with the following syntax: 6231 * windowHashCodeInHexadecimal windowName 6232 * Each line of the ouput represents a different window. 6233 * 6234 * @param client The remote client to send the listing to. 6235 * @return False if an error occured, true otherwise. 6236 */ 6237 boolean viewServerListWindows(Socket client) { 6238 if (isSystemSecure()) { 6239 return false; 6240 } 6241 6242 boolean result = true; 6243 6244 WindowList windows = new WindowList(); 6245 synchronized (mWindowMap) { 6246 //noinspection unchecked 6247 final int numDisplays = mDisplayContents.size(); 6248 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 6249 final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx); 6250 windows.addAll(displayContent.getWindowList()); 6251 } 6252 } 6253 6254 BufferedWriter out = null; 6255 6256 // Any uncaught exception will crash the system process 6257 try { 6258 OutputStream clientStream = client.getOutputStream(); 6259 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024); 6260 6261 final int count = windows.size(); 6262 for (int i = 0; i < count; i++) { 6263 final WindowState w = windows.get(i); 6264 out.write(Integer.toHexString(System.identityHashCode(w))); 6265 out.write(' '); 6266 out.append(w.mAttrs.getTitle()); 6267 out.write('\n'); 6268 } 6269 6270 out.write("DONE.\n"); 6271 out.flush(); 6272 } catch (Exception e) { 6273 result = false; 6274 } finally { 6275 if (out != null) { 6276 try { 6277 out.close(); 6278 } catch (IOException e) { 6279 result = false; 6280 } 6281 } 6282 } 6283 6284 return result; 6285 } 6286 6287 // TODO(multidisplay): Extend to multiple displays. 6288 /** 6289 * Returns the focused window in the following format: 6290 * windowHashCodeInHexadecimal windowName 6291 * 6292 * @param client The remote client to send the listing to. 6293 * @return False if an error occurred, true otherwise. 6294 */ 6295 boolean viewServerGetFocusedWindow(Socket client) { 6296 if (isSystemSecure()) { 6297 return false; 6298 } 6299 6300 boolean result = true; 6301 6302 WindowState focusedWindow = getFocusedWindow(); 6303 6304 BufferedWriter out = null; 6305 6306 // Any uncaught exception will crash the system process 6307 try { 6308 OutputStream clientStream = client.getOutputStream(); 6309 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024); 6310 6311 if(focusedWindow != null) { 6312 out.write(Integer.toHexString(System.identityHashCode(focusedWindow))); 6313 out.write(' '); 6314 out.append(focusedWindow.mAttrs.getTitle()); 6315 } 6316 out.write('\n'); 6317 out.flush(); 6318 } catch (Exception e) { 6319 result = false; 6320 } finally { 6321 if (out != null) { 6322 try { 6323 out.close(); 6324 } catch (IOException e) { 6325 result = false; 6326 } 6327 } 6328 } 6329 6330 return result; 6331 } 6332 6333 /** 6334 * Sends a command to a target window. The result of the command, if any, will be 6335 * written in the output stream of the specified socket. 6336 * 6337 * The parameters must follow this syntax: 6338 * windowHashcode extra 6339 * 6340 * Where XX is the length in characeters of the windowTitle. 6341 * 6342 * The first parameter is the target window. The window with the specified hashcode 6343 * will be the target. If no target can be found, nothing happens. The extra parameters 6344 * will be delivered to the target window and as parameters to the command itself. 6345 * 6346 * @param client The remote client to sent the result, if any, to. 6347 * @param command The command to execute. 6348 * @param parameters The command parameters. 6349 * 6350 * @return True if the command was successfully delivered, false otherwise. This does 6351 * not indicate whether the command itself was successful. 6352 */ 6353 boolean viewServerWindowCommand(Socket client, String command, String parameters) { 6354 if (isSystemSecure()) { 6355 return false; 6356 } 6357 6358 boolean success = true; 6359 Parcel data = null; 6360 Parcel reply = null; 6361 6362 BufferedWriter out = null; 6363 6364 // Any uncaught exception will crash the system process 6365 try { 6366 // Find the hashcode of the window 6367 int index = parameters.indexOf(' '); 6368 if (index == -1) { 6369 index = parameters.length(); 6370 } 6371 final String code = parameters.substring(0, index); 6372 int hashCode = (int) Long.parseLong(code, 16); 6373 6374 // Extract the command's parameter after the window description 6375 if (index < parameters.length()) { 6376 parameters = parameters.substring(index + 1); 6377 } else { 6378 parameters = ""; 6379 } 6380 6381 final WindowState window = findWindow(hashCode); 6382 if (window == null) { 6383 return false; 6384 } 6385 6386 data = Parcel.obtain(); 6387 data.writeInterfaceToken("android.view.IWindow"); 6388 data.writeString(command); 6389 data.writeString(parameters); 6390 data.writeInt(1); 6391 ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0); 6392 6393 reply = Parcel.obtain(); 6394 6395 final IBinder binder = window.mClient.asBinder(); 6396 // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER 6397 binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0); 6398 6399 reply.readException(); 6400 6401 if (!client.isOutputShutdown()) { 6402 out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); 6403 out.write("DONE\n"); 6404 out.flush(); 6405 } 6406 6407 } catch (Exception e) { 6408 Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e); 6409 success = false; 6410 } finally { 6411 if (data != null) { 6412 data.recycle(); 6413 } 6414 if (reply != null) { 6415 reply.recycle(); 6416 } 6417 if (out != null) { 6418 try { 6419 out.close(); 6420 } catch (IOException e) { 6421 6422 } 6423 } 6424 } 6425 6426 return success; 6427 } 6428 6429 public void addWindowChangeListener(WindowChangeListener listener) { 6430 synchronized(mWindowMap) { 6431 mWindowChangeListeners.add(listener); 6432 } 6433 } 6434 6435 public void removeWindowChangeListener(WindowChangeListener listener) { 6436 synchronized(mWindowMap) { 6437 mWindowChangeListeners.remove(listener); 6438 } 6439 } 6440 6441 private void notifyWindowsChanged() { 6442 WindowChangeListener[] windowChangeListeners; 6443 synchronized(mWindowMap) { 6444 if(mWindowChangeListeners.isEmpty()) { 6445 return; 6446 } 6447 windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()]; 6448 windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners); 6449 } 6450 int N = windowChangeListeners.length; 6451 for(int i = 0; i < N; i++) { 6452 windowChangeListeners[i].windowsChanged(); 6453 } 6454 } 6455 6456 private void notifyFocusChanged() { 6457 WindowChangeListener[] windowChangeListeners; 6458 synchronized(mWindowMap) { 6459 if(mWindowChangeListeners.isEmpty()) { 6460 return; 6461 } 6462 windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()]; 6463 windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners); 6464 } 6465 int N = windowChangeListeners.length; 6466 for(int i = 0; i < N; i++) { 6467 windowChangeListeners[i].focusChanged(); 6468 } 6469 } 6470 6471 private WindowState findWindow(int hashCode) { 6472 if (hashCode == -1) { 6473 // TODO(multidisplay): Extend to multiple displays. 6474 return getFocusedWindow(); 6475 } 6476 6477 synchronized (mWindowMap) { 6478 final int numDisplays = mDisplayContents.size(); 6479 for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { 6480 final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList(); 6481 final int numWindows = windows.size(); 6482 for (int winNdx = 0; winNdx < numWindows; ++winNdx) { 6483 final WindowState w = windows.get(winNdx); 6484 if (System.identityHashCode(w) == hashCode) { 6485 return w; 6486 } 6487 } 6488 } 6489 } 6490 6491 return null; 6492 } 6493 6494 /* 6495 * Instruct the Activity Manager to fetch the current configuration and broadcast 6496 * that to config-changed listeners if appropriate. 6497 */ 6498 void sendNewConfiguration() { 6499 try { 6500 mActivityManager.updateConfiguration(null); 6501 } catch (RemoteException e) { 6502 } 6503 } 6504 6505 public Configuration computeNewConfiguration() { 6506 synchronized (mWindowMap) { 6507 Configuration config = computeNewConfigurationLocked(); 6508 if (config == null && mWaitingForConfig) { 6509 // Nothing changed but we are waiting for something... stop that! 6510 mWaitingForConfig = false; 6511 mLastFinishedFreezeSource = "new-config"; 6512 performLayoutAndPlaceSurfacesLocked(); 6513 } 6514 return config; 6515 } 6516 } 6517 6518 Configuration computeNewConfigurationLocked() { 6519 Configuration config = new Configuration(); 6520 config.fontScale = 0; 6521 if (!computeScreenConfigurationLocked(config)) { 6522 return null; 6523 } 6524 return config; 6525 } 6526 6527 private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) { 6528 // TODO: Multidisplay: for now only use with default display. 6529 final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation); 6530 if (width < displayInfo.smallestNominalAppWidth) { 6531 displayInfo.smallestNominalAppWidth = width; 6532 } 6533 if (width > displayInfo.largestNominalAppWidth) { 6534 displayInfo.largestNominalAppWidth = width; 6535 } 6536 final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation); 6537 if (height < displayInfo.smallestNominalAppHeight) { 6538 displayInfo.smallestNominalAppHeight = height; 6539 } 6540 if (height > displayInfo.largestNominalAppHeight) { 6541 displayInfo.largestNominalAppHeight = height; 6542 } 6543 } 6544 6545 private int reduceConfigLayout(int curLayout, int rotation, float density, 6546 int dw, int dh) { 6547 // TODO: Multidisplay: for now only use with default display. 6548 // Get the app screen size at this rotation. 6549 int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation); 6550 int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation); 6551 6552 // Compute the screen layout size class for this rotation. 6553 int longSize = w; 6554 int shortSize = h; 6555 if (longSize < shortSize) { 6556 int tmp = longSize; 6557 longSize = shortSize; 6558 shortSize = tmp; 6559 } 6560 longSize = (int)(longSize/density); 6561 shortSize = (int)(shortSize/density); 6562 return Configuration.reduceScreenLayout(curLayout, longSize, shortSize); 6563 } 6564 6565 private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated, 6566 int dw, int dh, float density, Configuration outConfig) { 6567 // TODO: Multidisplay: for now only use with default display. 6568 6569 // We need to determine the smallest width that will occur under normal 6570 // operation. To this, start with the base screen size and compute the 6571 // width under the different possible rotations. We need to un-rotate 6572 // the current screen dimensions before doing this. 6573 int unrotDw, unrotDh; 6574 if (rotated) { 6575 unrotDw = dh; 6576 unrotDh = dw; 6577 } else { 6578 unrotDw = dw; 6579 unrotDh = dh; 6580 } 6581 displayInfo.smallestNominalAppWidth = 1<<30; 6582 displayInfo.smallestNominalAppHeight = 1<<30; 6583 displayInfo.largestNominalAppWidth = 0; 6584 displayInfo.largestNominalAppHeight = 0; 6585 adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh); 6586 adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw); 6587 adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh); 6588 adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw); 6589 int sl = Configuration.resetScreenLayout(outConfig.screenLayout); 6590 sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh); 6591 sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw); 6592 sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh); 6593 sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw); 6594 outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density); 6595 outConfig.screenLayout = sl; 6596 } 6597 6598 private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm, 6599 int dw, int dh) { 6600 // TODO: Multidisplay: for now only use with default display. 6601 dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation); 6602 dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation); 6603 float scale = CompatibilityInfo.computeCompatibleScaling(dm, null); 6604 int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f); 6605 if (curSize == 0 || size < curSize) { 6606 curSize = size; 6607 } 6608 return curSize; 6609 } 6610 6611 private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) { 6612 // TODO: Multidisplay: for now only use with default display. 6613 mTmpDisplayMetrics.setTo(dm); 6614 final DisplayMetrics tmpDm = mTmpDisplayMetrics; 6615 final int unrotDw, unrotDh; 6616 if (rotated) { 6617 unrotDw = dh; 6618 unrotDh = dw; 6619 } else { 6620 unrotDw = dw; 6621 unrotDh = dh; 6622 } 6623 int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh); 6624 sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw); 6625 sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh); 6626 sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw); 6627 return sw; 6628 } 6629 6630 boolean computeScreenConfigurationLocked(Configuration config) { 6631 if (!mDisplayReady) { 6632 return false; 6633 } 6634 6635 // TODO(multidisplay): For now, apply Configuration to main screen only. 6636 final DisplayContent displayContent = getDefaultDisplayContentLocked(); 6637 6638 // Use the effective "visual" dimensions based on current rotation 6639 final boolean rotated = (mRotation == Surface.ROTATION_90 6640 || mRotation == Surface.ROTATION_270); 6641 final int realdw = rotated ? 6642 displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth; 6643 final int realdh = rotated ? 6644 displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight; 6645 int dw = realdw; 6646 int dh = realdh; 6647 6648 if (mAltOrientation) { 6649 if (realdw > realdh) { 6650 // Turn landscape into portrait. 6651 int maxw = (int)(realdh/1.3f); 6652 if (maxw < realdw) { 6653 dw = maxw; 6654 } 6655 } else { 6656 // Turn portrait into landscape. 6657 int maxh = (int)(realdw/1.3f); 6658 if (maxh < realdh) { 6659 dh = maxh; 6660 } 6661 } 6662 } 6663 6664 if (config != null) { 6665 config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT : 6666 Configuration.ORIENTATION_LANDSCAPE; 6667 } 6668 6669 // Update application display metrics. 6670 final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation); 6671 final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation); 6672 final DisplayInfo displayInfo = displayContent.getDisplayInfo(); 6673 synchronized(displayContent.mDisplaySizeLock) { 6674 displayInfo.rotation = mRotation; 6675 displayInfo.logicalWidth = dw; 6676 displayInfo.logicalHeight = dh; 6677 displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity; 6678 displayInfo.appWidth = appWidth; 6679 displayInfo.appHeight = appHeight; 6680 displayInfo.getLogicalMetrics(mRealDisplayMetrics, 6681 CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null); 6682 displayInfo.getAppMetrics(mDisplayMetrics); 6683 mDisplayManagerService.setDisplayInfoOverrideFromWindowManager( 6684 displayContent.getDisplayId(), displayInfo); 6685 } 6686 if (false) { 6687 Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight); 6688 } 6689 6690 final DisplayMetrics dm = mDisplayMetrics; 6691 mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm, 6692 mCompatDisplayMetrics); 6693 6694 if (config != null) { 6695 config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation) 6696 / dm.density); 6697 config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation) 6698 / dm.density); 6699 computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config); 6700 6701 config