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