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