WindowManagerService.java revision 161e67ff3ba26408eea09221734ad2e29a1eed11
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 void setInputFilter(InputFilter filter) { 4634 mInputManager.setInputFilter(filter); 4635 } 4636 4637 public InputDevice getInputDevice(int deviceId) { 4638 return mInputManager.getInputDevice(deviceId); 4639 } 4640 4641 public int[] getInputDeviceIds() { 4642 return mInputManager.getInputDeviceIds(); 4643 } 4644 4645 public void enableScreenAfterBoot() { 4646 synchronized(mWindowMap) { 4647 if (mSystemBooted) { 4648 return; 4649 } 4650 mSystemBooted = true; 4651 } 4652 4653 performEnableScreen(); 4654 } 4655 4656 public void enableScreenIfNeededLocked() { 4657 if (mDisplayEnabled) { 4658 return; 4659 } 4660 if (!mSystemBooted) { 4661 return; 4662 } 4663 mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN)); 4664 } 4665 4666 public void performEnableScreen() { 4667 synchronized(mWindowMap) { 4668 if (mDisplayEnabled) { 4669 return; 4670 } 4671 if (!mSystemBooted) { 4672 return; 4673 } 4674 4675 // Don't enable the screen until all existing windows 4676 // have been drawn. 4677 final int N = mWindows.size(); 4678 for (int i=0; i<N; i++) { 4679 WindowState w = mWindows.get(i); 4680 if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { 4681 return; 4682 } 4683 } 4684 4685 mDisplayEnabled = true; 4686 if (false) { 4687 Slog.i(TAG, "ENABLING SCREEN!"); 4688 StringWriter sw = new StringWriter(); 4689 PrintWriter pw = new PrintWriter(sw); 4690 this.dump(null, pw, null); 4691 Slog.i(TAG, sw.toString()); 4692 } 4693 try { 4694 IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger"); 4695 if (surfaceFlinger != null) { 4696 //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!"); 4697 Parcel data = Parcel.obtain(); 4698 data.writeInterfaceToken("android.ui.ISurfaceComposer"); 4699 surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, 4700 data, null, 0); 4701 data.recycle(); 4702 } 4703 } catch (RemoteException ex) { 4704 Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!"); 4705 } 4706 } 4707 4708 mPolicy.enableScreenAfterBoot(); 4709 4710 // Make sure the last requested orientation has been applied. 4711 setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 4712 mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); 4713 } 4714 4715 public void setInTouchMode(boolean mode) { 4716 synchronized(mWindowMap) { 4717 mInTouchMode = mode; 4718 } 4719 } 4720 4721 // TODO: more accounting of which pid(s) turned it on, keep count, 4722 // only allow disables from pids which have count on, etc. 4723 public void showStrictModeViolation(boolean on) { 4724 int pid = Binder.getCallingPid(); 4725 synchronized(mWindowMap) { 4726 // Ignoring requests to enable the red border from clients 4727 // which aren't on screen. (e.g. Broadcast Receivers in 4728 // the background..) 4729 if (on) { 4730 boolean isVisible = false; 4731 for (WindowState ws : mWindows) { 4732 if (ws.mSession.mPid == pid && ws.isVisibleLw()) { 4733 isVisible = true; 4734 break; 4735 } 4736 } 4737 if (!isVisible) { 4738 return; 4739 } 4740 } 4741 4742 if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION showStrictModeViolation"); 4743 Surface.openTransaction(); 4744 try { 4745 if (mStrictModeFlash == null) { 4746 mStrictModeFlash = new StrictModeFlash(mDisplay, mFxSession); 4747 } 4748 mStrictModeFlash.setVisibility(on); 4749 } finally { 4750 Surface.closeTransaction(); 4751 if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION showStrictModeViolation"); 4752 } 4753 } 4754 } 4755 4756 public void setStrictModeVisualIndicatorPreference(String value) { 4757 SystemProperties.set(StrictMode.VISUAL_PROPERTY, value); 4758 } 4759 4760 /** 4761 * Takes a snapshot of the screen. In landscape mode this grabs the whole screen. 4762 * In portrait mode, it grabs the upper region of the screen based on the vertical dimension 4763 * of the target image. 4764 * 4765 * @param width the width of the target bitmap 4766 * @param height the height of the target bitmap 4767 */ 4768 public Bitmap screenshotApplications(IBinder appToken, int width, int height) { 4769 if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER, 4770 "screenshotApplications()")) { 4771 throw new SecurityException("Requires READ_FRAME_BUFFER permission"); 4772 } 4773 4774 Bitmap rawss; 4775 4776 int maxLayer = 0; 4777 final Rect frame = new Rect(); 4778 4779 float scale; 4780 int dw, dh; 4781 int rot; 4782 4783 synchronized(mWindowMap) { 4784 long ident = Binder.clearCallingIdentity(); 4785 4786 dw = mPolicy.getNonDecorDisplayWidth(mRotation, mCurDisplayWidth); 4787 dh = mPolicy.getNonDecorDisplayHeight(mRotation, mCurDisplayHeight); 4788 4789 int aboveAppLayer = mPolicy.windowTypeToLayerLw( 4790 WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER 4791 + TYPE_LAYER_OFFSET; 4792 aboveAppLayer += TYPE_LAYER_MULTIPLIER; 4793 4794 boolean isImeTarget = mInputMethodTarget != null 4795 && mInputMethodTarget.mAppToken != null 4796 && mInputMethodTarget.mAppToken.appToken != null 4797 && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken; 4798 4799 // Figure out the part of the screen that is actually the app. 4800 boolean including = false; 4801 for (int i=mWindows.size()-1; i>=0; i--) { 4802 WindowState ws = mWindows.get(i); 4803 if (ws.mSurface == null) { 4804 continue; 4805 } 4806 if (ws.mLayer >= aboveAppLayer) { 4807 continue; 4808 } 4809 // When we will skip windows: when we are not including 4810 // ones behind a window we didn't skip, and we are actually 4811 // taking a screenshot of a specific app. 4812 if (!including && appToken != null) { 4813 // Also, we can possibly skip this window if it is not 4814 // an IME target or the application for the screenshot 4815 // is not the current IME target. 4816 if (!ws.mIsImWindow || !isImeTarget) { 4817 // And finally, this window is of no interest if it 4818 // is not associated with the screenshot app. 4819 if (ws.mAppToken == null || ws.mAppToken.token != appToken) { 4820 continue; 4821 } 4822 } 4823 } 4824 4825 // We keep on including windows until we go past a full-screen 4826 // window. 4827 including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh); 4828 4829 if (maxLayer < ws.mAnimLayer) { 4830 maxLayer = ws.mAnimLayer; 4831 } 4832 4833 // Don't include wallpaper in bounds calculation 4834 if (!ws.mIsWallpaper) { 4835 final Rect wf = ws.mFrame; 4836 final Rect cr = ws.mContentInsets; 4837 int left = wf.left + cr.left; 4838 int top = wf.top + cr.top; 4839 int right = wf.right - cr.right; 4840 int bottom = wf.bottom - cr.bottom; 4841 frame.union(left, top, right, bottom); 4842 } 4843 } 4844 Binder.restoreCallingIdentity(ident); 4845 4846 // Constrain frame to the screen size. 4847 frame.intersect(0, 0, dw, dh); 4848 4849 if (frame.isEmpty() || maxLayer == 0) { 4850 return null; 4851 } 4852 4853 // The screenshot API does not apply the current screen rotation. 4854 rot = mDisplay.getRotation(); 4855 int fw = frame.width(); 4856 int fh = frame.height(); 4857 4858 // First try reducing to fit in x dimension. 4859 scale = width/(float)fw; 4860 4861 // The screen shot will contain the entire screen. 4862 dw = (int)(dw*scale); 4863 dh = (int)(dh*scale); 4864 if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { 4865 int tmp = dw; 4866 dw = dh; 4867 dh = tmp; 4868 rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90; 4869 } 4870 rawss = Surface.screenshot(dw, dh, 0, maxLayer); 4871 } 4872 4873 if (rawss == null) { 4874 Log.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh 4875 + ") to layer " + maxLayer); 4876 return null; 4877 } 4878 4879 Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig()); 4880 Matrix matrix = new Matrix(); 4881 ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix); 4882 matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale)); 4883 Canvas canvas = new Canvas(bm); 4884 canvas.drawBitmap(rawss, matrix, null); 4885 4886 rawss.recycle(); 4887 return bm; 4888 } 4889 4890 public void freezeRotation() { 4891 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, 4892 "freezeRotation()")) { 4893 throw new SecurityException("Requires SET_ORIENTATION permission"); 4894 } 4895 4896 if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation); 4897 4898 mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED, mRotation); 4899 setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0); 4900 } 4901 4902 public void thawRotation() { 4903 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, 4904 "thawRotation()")) { 4905 throw new SecurityException("Requires SET_ORIENTATION permission"); 4906 } 4907 4908 if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation); 4909 4910 mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used 4911 setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0); 4912 } 4913 4914 public void setRotation(int rotation, 4915 boolean alwaysSendConfiguration, int animFlags) { 4916 if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION, 4917 "setRotation()")) { 4918 throw new SecurityException("Requires SET_ORIENTATION permission"); 4919 } 4920 4921 setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags); 4922 } 4923 4924 public void setRotationUnchecked(int rotation, 4925 boolean alwaysSendConfiguration, int animFlags) { 4926 if(DEBUG_ORIENTATION) Slog.v(TAG, 4927 "setRotationUnchecked(rotation=" + rotation + 4928 " alwaysSendConfiguration=" + alwaysSendConfiguration + 4929 " animFlags=" + animFlags); 4930 4931 long origId = Binder.clearCallingIdentity(); 4932 boolean changed; 4933 synchronized(mWindowMap) { 4934 changed = setRotationUncheckedLocked(rotation, animFlags, false); 4935 } 4936 4937 if (changed || alwaysSendConfiguration) { 4938 sendNewConfiguration(); 4939 } 4940 4941 Binder.restoreCallingIdentity(origId); 4942 } 4943 4944 /** 4945 * Apply a new rotation to the screen, respecting the requests of 4946 * applications. Use WindowManagerPolicy.USE_LAST_ROTATION to simply 4947 * re-evaluate the desired rotation. 4948 * 4949 * Returns null if the rotation has been changed. In this case YOU 4950 * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN. 4951 */ 4952 public boolean setRotationUncheckedLocked(int rotation, int animFlags, boolean inTransaction) { 4953 if (mDragState != null || mScreenRotationAnimation != null) { 4954 // Potential rotation during a drag. Don't do the rotation now, but make 4955 // a note to perform the rotation later. 4956 if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation."); 4957 if (rotation != WindowManagerPolicy.USE_LAST_ROTATION) { 4958 mDeferredRotation = rotation; 4959 mDeferredRotationAnimFlags = animFlags; 4960 } 4961 return false; 4962 } 4963 4964 boolean changed; 4965 if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) { 4966 if (mDeferredRotation != WindowManagerPolicy.USE_LAST_ROTATION) { 4967 rotation = mDeferredRotation; 4968 mRequestedRotation = rotation; 4969 mLastRotationFlags = mDeferredRotationAnimFlags; 4970 } 4971 rotation = mRequestedRotation; 4972 } else { 4973 mRequestedRotation = rotation; 4974 mLastRotationFlags = animFlags; 4975 } 4976 mDeferredRotation = WindowManagerPolicy.USE_LAST_ROTATION; 4977 if (DEBUG_ORIENTATION) Slog.v(TAG, "Overwriting rotation value from " + rotation); 4978 rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, 4979 mRotation, mDisplayEnabled); 4980 if (DEBUG_ORIENTATION) Slog.v(TAG, "new rotation is set to " + rotation); 4981 4982 int desiredRotation = rotation; 4983 int lockedRotation = mPolicy.getLockedRotationLw(); 4984 if (lockedRotation >= 0 && rotation != lockedRotation) { 4985 // We are locked in a rotation but something is requesting 4986 // a different rotation... we will either keep the locked 4987 // rotation if it results in the same orientation, or have to 4988 // switch into an emulated orientation mode. 4989 4990 // First, we know that our rotation is actually going to be 4991 // the locked rotation. 4992 rotation = lockedRotation; 4993 4994 // Now the difference between the desired and lockedRotation 4995 // may mean that the orientation is different... if that is 4996 // not the case, we can just make the desired rotation be the 4997 // same as the new locked rotation. 4998 switch (lockedRotation) { 4999 case Surface.ROTATION_0: 5000 if (rotation == Surface.ROTATION_180) { 5001 desiredRotation = lockedRotation; 5002 } 5003 break; 5004 case Surface.ROTATION_90: 5005 if (rotation == Surface.ROTATION_270) { 5006 desiredRotation = lockedRotation; 5007 } 5008 break; 5009 case Surface.ROTATION_180: 5010 if (rotation == Surface.ROTATION_0) { 5011 desiredRotation = lockedRotation; 5012 } 5013 break; 5014 case Surface.ROTATION_270: 5015 if (rotation == Surface.ROTATION_90) { 5016 desiredRotation = lockedRotation; 5017 } 5018 break; 5019 } 5020 } 5021 5022 changed = mDisplayEnabled && mRotation != rotation; 5023 if (mAltOrientation != (rotation != desiredRotation)) { 5024 changed = true; 5025 mAltOrientation = rotation != desiredRotation; 5026 } 5027 5028 if (changed) { 5029 if (DEBUG_ORIENTATION) Slog.v(TAG, 5030 "Rotation changed to " + rotation 5031 + " from " + mRotation 5032 + " (forceApp=" + mForcedAppOrientation 5033 + ", req=" + mRequestedRotation + ")"); 5034 mRotation = rotation; 5035 mWindowsFreezingScreen = true; 5036 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); 5037 mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), 5038 2000); 5039 mWaitingForConfig = true; 5040 mLayoutNeeded = true; 5041 startFreezingDisplayLocked(inTransaction); 5042 Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags); 5043 mInputManager.setDisplayOrientation(0, rotation); 5044 if (mDisplayEnabled) { 5045 // NOTE: We disable the rotation in the emulator because 5046 // it doesn't support hardware OpenGL emulation yet. 5047 if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null 5048 && mScreenRotationAnimation.hasScreenshot()) { 5049 Surface.freezeDisplay(0); 5050 if (!inTransaction) { 5051 if (SHOW_TRANSACTIONS) Slog.i(TAG, 5052 ">>> OPEN TRANSACTION setRotationUnchecked"); 5053 Surface.openTransaction(); 5054 } 5055 try { 5056 if (mScreenRotationAnimation != null) { 5057 mScreenRotationAnimation.setRotation(rotation); 5058 } 5059 } finally { 5060 if (!inTransaction) { 5061 Surface.closeTransaction(); 5062 if (SHOW_TRANSACTIONS) Slog.i(TAG, 5063 "<<< CLOSE TRANSACTION setRotationUnchecked"); 5064 } 5065 } 5066 Surface.setOrientation(0, rotation, animFlags); 5067 Surface.unfreezeDisplay(0); 5068 } else { 5069 Surface.setOrientation(0, rotation, animFlags); 5070 } 5071 rebuildBlackFrame(inTransaction); 5072 } 5073 5074 for (int i=mWindows.size()-1; i>=0; i--) { 5075 WindowState w = mWindows.get(i); 5076 if (w.mSurface != null) { 5077 w.mOrientationChanging = true; 5078 } 5079 } 5080 for (int i=mRotationWatchers.size()-1; i>=0; i--) { 5081 try { 5082 mRotationWatchers.get(i).onRotationChanged(rotation); 5083 } catch (RemoteException e) { 5084 } 5085 } 5086 } //end if changed 5087 5088 return changed; 5089 } 5090 5091 public int getRotation() { 5092 return mRotation; 5093 } 5094 5095 public int watchRotation(IRotationWatcher watcher) { 5096 final IBinder watcherBinder = watcher.asBinder(); 5097 IBinder.DeathRecipient dr = new IBinder.DeathRecipient() { 5098 public void binderDied() { 5099 synchronized (mWindowMap) { 5100 for (int i=0; i<mRotationWatchers.size(); i++) { 5101 if (watcherBinder == mRotationWatchers.get(i).asBinder()) { 5102 IRotationWatcher removed = mRotationWatchers.remove(i); 5103 if (removed != null) { 5104 removed.asBinder().unlinkToDeath(this, 0); 5105 } 5106 i--; 5107 } 5108 } 5109 } 5110 } 5111 }; 5112 5113 synchronized (mWindowMap) { 5114 try { 5115 watcher.asBinder().linkToDeath(dr, 0); 5116 mRotationWatchers.add(watcher); 5117 } catch (RemoteException e) { 5118 // Client died, no cleanup needed. 5119 } 5120 5121 return mRotation; 5122 } 5123 } 5124 5125 /** 5126 * Starts the view server on the specified port. 5127 * 5128 * @param port The port to listener to. 5129 * 5130 * @return True if the server was successfully started, false otherwise. 5131 * 5132 * @see com.android.server.wm.ViewServer 5133 * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT 5134 */ 5135 public boolean startViewServer(int port) { 5136 if (isSystemSecure()) { 5137 return false; 5138 } 5139 5140 if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) { 5141 return false; 5142 } 5143 5144 if (port < 1024) { 5145 return false; 5146 } 5147 5148 if (mViewServer != null) { 5149 if (!mViewServer.isRunning()) { 5150 try { 5151 return mViewServer.start(); 5152 } catch (IOException e) { 5153 Slog.w(TAG, "View server did not start"); 5154 } 5155 } 5156 return false; 5157 } 5158 5159 try { 5160 mViewServer = new ViewServer(this, port); 5161 return mViewServer.start(); 5162 } catch (IOException e) { 5163 Slog.w(TAG, "View server did not start"); 5164 } 5165 return false; 5166 } 5167 5168 private boolean isSystemSecure() { 5169 return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) && 5170 "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0")); 5171 } 5172 5173 /** 5174 * Stops the view server if it exists. 5175 * 5176 * @return True if the server stopped, false if it wasn't started or 5177 * couldn't be stopped. 5178 * 5179 * @see com.android.server.wm.ViewServer 5180 */ 5181 public boolean stopViewServer() { 5182 if (isSystemSecure()) { 5183 return false; 5184 } 5185 5186 if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) { 5187 return false; 5188 } 5189 5190 if (mViewServer != null) { 5191 return mViewServer.stop(); 5192 } 5193 return false; 5194 } 5195 5196 /** 5197 * Indicates whether the view server is running. 5198 * 5199 * @return True if the server is running, false otherwise. 5200 * 5201 * @see com.android.server.wm.ViewServer 5202 */ 5203 public boolean isViewServerRunning() { 5204 if (isSystemSecure()) { 5205 return false; 5206 } 5207 5208 if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) { 5209 return false; 5210 } 5211 5212 return mViewServer != null && mViewServer.isRunning(); 5213 } 5214 5215 /** 5216 * Lists all availble windows in the system. The listing is written in the 5217 * specified Socket's output stream with the following syntax: 5218 * windowHashCodeInHexadecimal windowName 5219 * Each line of the ouput represents a different window. 5220 * 5221 * @param client The remote client to send the listing to. 5222 * @return False if an error occured, true otherwise. 5223 */ 5224 boolean viewServerListWindows(Socket client) { 5225 if (isSystemSecure()) { 5226 return false; 5227 } 5228 5229 boolean result = true; 5230 5231 WindowState[] windows; 5232 synchronized (mWindowMap) { 5233 //noinspection unchecked 5234 windows = mWindows.toArray(new WindowState[mWindows.size()]); 5235 } 5236 5237 BufferedWriter out = null; 5238 5239 // Any uncaught exception will crash the system process 5240 try { 5241 OutputStream clientStream = client.getOutputStream(); 5242 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024); 5243 5244 final int count = windows.length; 5245 for (int i = 0; i < count; i++) { 5246 final WindowState w = windows[i]; 5247 out.write(Integer.toHexString(System.identityHashCode(w))); 5248 out.write(' '); 5249 out.append(w.mAttrs.getTitle()); 5250 out.write('\n'); 5251 } 5252 5253 out.write("DONE.\n"); 5254 out.flush(); 5255 } catch (Exception e) { 5256 result = false; 5257 } finally { 5258 if (out != null) { 5259 try { 5260 out.close(); 5261 } catch (IOException e) { 5262 result = false; 5263 } 5264 } 5265 } 5266 5267 return result; 5268 } 5269 5270 /** 5271 * Returns the focused window in the following format: 5272 * windowHashCodeInHexadecimal windowName 5273 * 5274 * @param client The remote client to send the listing to. 5275 * @return False if an error occurred, true otherwise. 5276 */ 5277 boolean viewServerGetFocusedWindow(Socket client) { 5278 if (isSystemSecure()) { 5279 return false; 5280 } 5281 5282 boolean result = true; 5283 5284 WindowState focusedWindow = getFocusedWindow(); 5285 5286 BufferedWriter out = null; 5287 5288 // Any uncaught exception will crash the system process 5289 try { 5290 OutputStream clientStream = client.getOutputStream(); 5291 out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024); 5292 5293 if(focusedWindow != null) { 5294 out.write(Integer.toHexString(System.identityHashCode(focusedWindow))); 5295 out.write(' '); 5296 out.append(focusedWindow.mAttrs.getTitle()); 5297 } 5298 out.write('\n'); 5299 out.flush(); 5300 } catch (Exception e) { 5301 result = false; 5302 } finally { 5303 if (out != null) { 5304 try { 5305 out.close(); 5306 } catch (IOException e) { 5307 result = false; 5308 } 5309 } 5310 } 5311 5312 return result; 5313 } 5314 5315 /** 5316 * Sends a command to a target window. The result of the command, if any, will be 5317 * written in the output stream of the specified socket. 5318 * 5319 * The parameters must follow this syntax: 5320 * windowHashcode extra 5321 * 5322 * Where XX is the length in characeters of the windowTitle. 5323 * 5324 * The first parameter is the target window. The window with the specified hashcode 5325 * will be the target. If no target can be found, nothing happens. The extra parameters 5326 * will be delivered to the target window and as parameters to the command itself. 5327 * 5328 * @param client The remote client to sent the result, if any, to. 5329 * @param command The command to execute. 5330 * @param parameters The command parameters. 5331 * 5332 * @return True if the command was successfully delivered, false otherwise. This does 5333 * not indicate whether the command itself was successful. 5334 */ 5335 boolean viewServerWindowCommand(Socket client, String command, String parameters) { 5336 if (isSystemSecure()) { 5337 return false; 5338 } 5339 5340 boolean success = true; 5341 Parcel data = null; 5342 Parcel reply = null; 5343 5344 BufferedWriter out = null; 5345 5346 // Any uncaught exception will crash the system process 5347 try { 5348 // Find the hashcode of the window 5349 int index = parameters.indexOf(' '); 5350 if (index == -1) { 5351 index = parameters.length(); 5352 } 5353 final String code = parameters.substring(0, index); 5354 int hashCode = (int) Long.parseLong(code, 16); 5355 5356 // Extract the command's parameter after the window description 5357 if (index < parameters.length()) { 5358 parameters = parameters.substring(index + 1); 5359 } else { 5360 parameters = ""; 5361 } 5362 5363 final WindowState window = findWindow(hashCode); 5364 if (window == null) { 5365 return false; 5366 } 5367 5368 data = Parcel.obtain(); 5369 data.writeInterfaceToken("android.view.IWindow"); 5370 data.writeString(command); 5371 data.writeString(parameters); 5372 data.writeInt(1); 5373 ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0); 5374 5375 reply = Parcel.obtain(); 5376 5377 final IBinder binder = window.mClient.asBinder(); 5378 // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER 5379 binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0); 5380 5381 reply.readException(); 5382 5383 if (!client.isOutputShutdown()) { 5384 out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); 5385 out.write("DONE\n"); 5386 out.flush(); 5387 } 5388 5389 } catch (Exception e) { 5390 Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e); 5391 success = false; 5392 } finally { 5393 if (data != null) { 5394 data.recycle(); 5395 } 5396 if (reply != null) { 5397 reply.recycle(); 5398 } 5399 if (out != null) { 5400 try { 5401 out.close(); 5402 } catch (IOException e) { 5403 5404 } 5405 } 5406 } 5407 5408 return success; 5409 } 5410 5411 public void addWindowChangeListener(WindowChangeListener listener) { 5412 synchronized(mWindowMap) { 5413 mWindowChangeListeners.add(listener); 5414 } 5415 } 5416 5417 public void removeWindowChangeListener(WindowChangeListener listener) { 5418 synchronized(mWindowMap) { 5419 mWindowChangeListeners.remove(listener); 5420 } 5421 } 5422 5423 private void notifyWindowsChanged() { 5424 WindowChangeListener[] windowChangeListeners; 5425 synchronized(mWindowMap) { 5426 if(mWindowChangeListeners.isEmpty()) { 5427 return; 5428 } 5429 windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()]; 5430 windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners); 5431 } 5432 int N = windowChangeListeners.length; 5433 for(int i = 0; i < N; i++) { 5434 windowChangeListeners[i].windowsChanged(); 5435 } 5436 } 5437 5438 private void notifyFocusChanged() { 5439 WindowChangeListener[] windowChangeListeners; 5440 synchronized(mWindowMap) { 5441 if(mWindowChangeListeners.isEmpty()) { 5442 return; 5443 } 5444 windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()]; 5445 windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners); 5446 } 5447 int N = windowChangeListeners.length; 5448 for(int i = 0; i < N; i++) { 5449 windowChangeListeners[i].focusChanged(); 5450 } 5451 } 5452 5453 private WindowState findWindow(int hashCode) { 5454 if (hashCode == -1) { 5455 return getFocusedWindow(); 5456 } 5457 5458 synchronized (mWindowMap) { 5459 final ArrayList<WindowState> windows = mWindows; 5460 final int count = windows.size(); 5461 5462 for (int i = 0; i < count; i++) { 5463 WindowState w = windows.get(i); 5464 if (System.identityHashCode(w) == hashCode) { 5465 return w; 5466 } 5467 } 5468 } 5469 5470 return null; 5471 } 5472 5473 /* 5474 * Instruct the Activity Manager to fetch the current configuration and broadcast 5475 * that to config-changed listeners if appropriate. 5476 */ 5477 void sendNewConfiguration() { 5478 try { 5479 mActivityManager.updateConfiguration(null); 5480 } catch (RemoteException e) { 5481 } 5482 } 5483 5484 public Configuration computeNewConfiguration() { 5485 synchronized (mWindowMap) { 5486 Configuration config = computeNewConfigurationLocked(); 5487 if (config == null && mWaitingForConfig) { 5488 // Nothing changed but we are waiting for something... stop that! 5489 mWaitingForConfig = false; 5490 performLayoutAndPlaceSurfacesLocked(); 5491 } 5492 return config; 5493 } 5494 } 5495 5496 Configuration computeNewConfigurationLocked() { 5497 Configuration config = new Configuration(); 5498 if (!computeNewConfigurationLocked(config)) { 5499 return null; 5500 } 5501 return config; 5502 } 5503 5504 private int reduceConfigWidthSize(int curSize, int rotation, float density, int dw) { 5505 int size = (int)(mPolicy.getConfigDisplayWidth(rotation, dw) / density); 5506 if (size < curSize) { 5507 curSize = size; 5508 } 5509 return curSize; 5510 } 5511 5512 boolean computeNewConfigurationLocked(Configuration config) { 5513 if (mDisplay == null) { 5514 return false; 5515 } 5516 5517 mInputManager.getInputConfiguration(config); 5518 5519 // Use the effective "visual" dimensions based on current rotation 5520 final boolean rotated = (mRotation == Surface.ROTATION_90 5521 || mRotation == Surface.ROTATION_270); 5522 final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth; 5523 final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight; 5524 5525 if (mAltOrientation) { 5526 mCurDisplayWidth = realdw; 5527 mCurDisplayHeight = realdh; 5528 if (realdw > realdh) { 5529 // Turn landscape into portrait. 5530 int maxw = (int)(realdh/1.3f); 5531 if (maxw < realdw) { 5532 mCurDisplayWidth = maxw; 5533 } 5534 } else { 5535 // Turn portrait into landscape. 5536 int maxh = (int)(realdw/1.3f); 5537 if (maxh < realdh) { 5538 mCurDisplayHeight = maxh; 5539 } 5540 } 5541 } else { 5542 mCurDisplayWidth = realdw; 5543 mCurDisplayHeight = realdh; 5544 } 5545 5546 final int dw = mCurDisplayWidth; 5547 final int dh = mCurDisplayHeight; 5548 5549 int orientation = Configuration.ORIENTATION_SQUARE; 5550 if (dw < dh) { 5551 orientation = Configuration.ORIENTATION_PORTRAIT; 5552 } else if (dw > dh) { 5553 orientation = Configuration.ORIENTATION_LANDSCAPE; 5554 } 5555 config.orientation = orientation; 5556 5557 DisplayMetrics dm = new DisplayMetrics(); 5558 mDisplay.getRealMetrics(dm); 5559 5560 // Override display width and height with what we are computing, 5561 // to be sure they remain consistent. 5562 dm.widthPixels = dm.realWidthPixels = mPolicy.getNonDecorDisplayWidth( 5563 mRotation, dw); 5564 dm.heightPixels = dm.realHeightPixels = mPolicy.getNonDecorDisplayHeight( 5565 mRotation, dh); 5566 5567 mCompatibleScreenScale = CompatibilityInfo.updateCompatibleScreenFrame( 5568 dm, mCompatibleScreenFrame, null); 5569 5570 config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(mRotation, dw) / dm.density); 5571 config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(mRotation, dh) / dm.density); 5572 5573 // We need to determine the smallest width that will occur under normal 5574 // operation. To this, start with the base screen size and compute the 5575 // width under the different possible rotations. We need to un-rotate 5576 // the current screen dimensions before doing this. 5577 int unrotDw, unrotDh; 5578 if (rotated) { 5579 unrotDw = dh; 5580 unrotDh = dw; 5581 } else { 5582 unrotDw = dw; 5583 unrotDh = dh; 5584 } 5585 config.smallestScreenWidthDp = reduceConfigWidthSize(unrotDw, 5586 Surface.ROTATION_0, dm.density, unrotDw); 5587 config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp, 5588 Surface.ROTATION_90, dm.density, unrotDh); 5589 config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp, 5590 Surface.ROTATION_180, dm.density, unrotDw); 5591 config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp, 5592 Surface.ROTATION_270, dm.density, unrotDh); 5593 5594 // Compute the screen layout size class. 5595 int screenLayout; 5596 int longSize = dw; 5597 int shortSize = dh; 5598 if (longSize < shortSize) { 5599 int tmp = longSize; 5600 longSize = shortSize; 5601 shortSize = tmp; 5602 } 5603 longSize = (int)(longSize/dm.density); 5604 shortSize = (int)(shortSize/dm.density); 5605 5606 // These semi-magic numbers define our compatibility modes for 5607 // applications with different screens. These are guarantees to 5608 // app developers about the space they can expect for a particular 5609 // configuration. DO NOT CHANGE! 5610 if (longSize < 470) { 5611 // This is shorter than an HVGA normal density screen (which 5612 // is 480 pixels on its long side). 5613 screenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL 5614 | Configuration.SCREENLAYOUT_LONG_NO; 5615 } else { 5616 // What size is this screen screen? 5617 if (longSize >= 960 && shortSize >= 720) { 5618 // 1.5xVGA or larger screens at medium density are the point 5619 // at which we consider it to be an extra large screen. 5620 screenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE; 5621 } else if (longSize >= 640 && shortSize >= 480) { 5622 // VGA or larger screens at medium density are the point 5623 // at which we consider it to be a large screen. 5624 screenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE; 5625 } else { 5626 screenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL; 5627 } 5628 5629 // If this screen is wider than normal HVGA, or taller 5630 // than FWVGA, then for old apps we want to run in size 5631 // compatibility mode. 5632 if (shortSize > 321 || longSize > 570) { 5633 screenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED; 5634 } 5635 5636 // Is this a long screen? 5637 if (((longSize*3)/5) >= (shortSize-1)) { 5638 // Anything wider than WVGA (5:3) is considering to be long. 5639 screenLayout |= Configuration.SCREENLAYOUT_LONG_YES; 5640 } else { 5641 screenLayout |= Configuration.SCREENLAYOUT_LONG_NO; 5642 } 5643 } 5644 config.screenLayout = screenLayout; 5645 5646 // Determine whether a hard keyboard is available and enabled. 5647 boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS; 5648 if (hardKeyboardAvailable != mHardKeyboardAvailable) { 5649 mHardKeyboardAvailable = hardKeyboardAvailable; 5650 mHardKeyboardEnabled = hardKeyboardAvailable; 5651 5652 mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); 5653 mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); 5654 } 5655 if (!mHardKeyboardEnabled) { 5656 config.keyboard = Configuration.KEYBOARD_NOKEYS; 5657 } 5658 5659 // Update value of keyboardHidden, hardKeyboardHidden and navigationHidden 5660 // based on whether a hard or soft keyboard is present, whether navigation keys 5661 // are present and the lid switch state. 5662 config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO; 5663 config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO; 5664 config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO; 5665 mPolicy.adjustConfigurationLw(config); 5666 return true; 5667 } 5668 5669 public boolean isHardKeyboardAvailable() { 5670 synchronized (mWindowMap) { 5671 return mHardKeyboardAvailable; 5672 } 5673 } 5674 5675 public boolean isHardKeyboardEnabled() { 5676 synchronized (mWindowMap) { 5677 return mHardKeyboardEnabled; 5678 } 5679 } 5680 5681 public void setHardKeyboardEnabled(boolean enabled) { 5682 synchronized (mWindowMap) { 5683 if (mHardKeyboardEnabled != enabled) { 5684 mHardKeyboardEnabled = enabled; 5685 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 5686 } 5687 } 5688 } 5689 5690 public void setOnHardKeyboardStatusChangeListener( 5691 OnHardKeyboardStatusChangeListener listener) { 5692 synchronized (mWindowMap) { 5693 mHardKeyboardStatusChangeListener = listener; 5694 } 5695 } 5696 5697 void notifyHardKeyboardStatusChange() { 5698 final boolean available, enabled; 5699 final OnHardKeyboardStatusChangeListener listener; 5700 synchronized (mWindowMap) { 5701 listener = mHardKeyboardStatusChangeListener; 5702 available = mHardKeyboardAvailable; 5703 enabled = mHardKeyboardEnabled; 5704 } 5705 if (listener != null) { 5706 listener.onHardKeyboardStatusChange(available, enabled); 5707 } 5708 } 5709 5710 // ------------------------------------------------------------- 5711 // Drag and drop 5712 // ------------------------------------------------------------- 5713 5714 IBinder prepareDragSurface(IWindow window, SurfaceSession session, 5715 int flags, int width, int height, Surface outSurface) { 5716 if (DEBUG_DRAG) { 5717 Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height 5718 + " flags=" + Integer.toHexString(flags) + " win=" + window 5719 + " asbinder=" + window.asBinder()); 5720 } 5721 5722 final int callerPid = Binder.getCallingPid(); 5723 final long origId = Binder.clearCallingIdentity(); 5724 IBinder token = null; 5725 5726 try { 5727 synchronized (mWindowMap) { 5728 try { 5729 if (mDragState == null) { 5730 Surface surface = new Surface(session, callerPid, "drag surface", 0, 5731 width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN); 5732 if (SHOW_TRANSACTIONS) Slog.i(TAG, " DRAG " 5733 + surface + ": CREATE"); 5734 outSurface.copyFrom(surface); 5735 final IBinder winBinder = window.asBinder(); 5736 token = new Binder(); 5737 mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder); 5738 mDragState.mSurface = surface; 5739 token = mDragState.mToken = new Binder(); 5740 5741 // 5 second timeout for this window to actually begin the drag 5742 mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder); 5743 Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder); 5744 mH.sendMessageDelayed(msg, 5000); 5745 } else { 5746 Slog.w(TAG, "Drag already in progress"); 5747 } 5748 } catch (Surface.OutOfResourcesException e) { 5749 Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e); 5750 if (mDragState != null) { 5751 mDragState.reset(); 5752 mDragState = null; 5753 } 5754 } 5755 } 5756 } finally { 5757 Binder.restoreCallingIdentity(origId); 5758 } 5759 5760 return token; 5761 } 5762 5763 // ------------------------------------------------------------- 5764 // Input Events and Focus Management 5765 // ------------------------------------------------------------- 5766 5767 final InputMonitor mInputMonitor = new InputMonitor(this); 5768 5769 public void pauseKeyDispatching(IBinder _token) { 5770 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 5771 "pauseKeyDispatching()")) { 5772 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 5773 } 5774 5775 synchronized (mWindowMap) { 5776 WindowToken token = mTokenMap.get(_token); 5777 if (token != null) { 5778 mInputMonitor.pauseDispatchingLw(token); 5779 } 5780 } 5781 } 5782 5783 public void resumeKeyDispatching(IBinder _token) { 5784 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 5785 "resumeKeyDispatching()")) { 5786 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 5787 } 5788 5789 synchronized (mWindowMap) { 5790 WindowToken token = mTokenMap.get(_token); 5791 if (token != null) { 5792 mInputMonitor.resumeDispatchingLw(token); 5793 } 5794 } 5795 } 5796 5797 public void setEventDispatching(boolean enabled) { 5798 if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, 5799 "resumeKeyDispatching()")) { 5800 throw new SecurityException("Requires MANAGE_APP_TOKENS permission"); 5801 } 5802 5803 synchronized (mWindowMap) { 5804 mInputMonitor.setEventDispatchingLw(enabled); 5805 } 5806 } 5807 5808 /** 5809 * Injects a keystroke event into the UI. 5810 * Even when sync is false, this method may block while waiting for current 5811 * input events to be dispatched. 5812 * 5813 * @param ev A motion event describing the keystroke action. (Be sure to use 5814 * {@link SystemClock#uptimeMillis()} as the timebase.) 5815 * @param sync If true, wait for the event to be completed before returning to the caller. 5816 * @return Returns true if event was dispatched, false if it was dropped for any reason 5817 */ 5818 public boolean injectKeyEvent(KeyEvent ev, boolean sync) { 5819 long downTime = ev.getDownTime(); 5820 long eventTime = ev.getEventTime(); 5821 5822 int action = ev.getAction(); 5823 int code = ev.getKeyCode(); 5824 int repeatCount = ev.getRepeatCount(); 5825 int metaState = ev.getMetaState(); 5826 int deviceId = ev.getDeviceId(); 5827 int scancode = ev.getScanCode(); 5828 int source = ev.getSource(); 5829 int flags = ev.getFlags(); 5830 5831 if (source == InputDevice.SOURCE_UNKNOWN) { 5832 source = InputDevice.SOURCE_KEYBOARD; 5833 } 5834 5835 if (eventTime == 0) eventTime = SystemClock.uptimeMillis(); 5836 if (downTime == 0) downTime = eventTime; 5837 5838 KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState, 5839 deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source); 5840 5841 final int pid = Binder.getCallingPid(); 5842 final int uid = Binder.getCallingUid(); 5843 final long ident = Binder.clearCallingIdentity(); 5844 5845 final int result = mInputManager.injectInputEvent(newEvent, pid, uid, 5846 sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH 5847 : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, 5848 INJECTION_TIMEOUT_MILLIS); 5849 5850 Binder.restoreCallingIdentity(ident); 5851 return reportInjectionResult(result); 5852 } 5853 5854 /** 5855 * Inject a pointer (touch) event into the UI. 5856 * Even when sync is false, this method may block while waiting for current 5857 * input events to be dispatched. 5858 * 5859 * @param ev A motion event describing the pointer (touch) action. (As noted in 5860 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use 5861 * {@link SystemClock#uptimeMillis()} as the timebase.) 5862 * @param sync If true, wait for the event to be completed before returning to the caller. 5863 * @return Returns true if event was dispatched, false if it was dropped for any reason 5864 */ 5865 public boolean injectPointerEvent(MotionEvent ev, boolean sync) { 5866 final int pid = Binder.getCallingPid(); 5867 final int uid = Binder.getCallingUid(); 5868 final long ident = Binder.clearCallingIdentity(); 5869 5870 MotionEvent newEvent = MotionEvent.obtain(ev); 5871 if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) { 5872 newEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN); 5873 } 5874 5875 final int result = mInputManager.injectInputEvent(newEvent, pid, uid, 5876 sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH 5877 : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, 5878 INJECTION_TIMEOUT_MILLIS); 5879 5880 Binder.restoreCallingIdentity(ident); 5881 return reportInjectionResult(result); 5882 } 5883 5884 /** 5885 * Inject a trackball (navigation device) event into the UI. 5886 * Even when sync is false, this method may block while waiting for current 5887 * input events to be dispatched. 5888 * 5889 * @param ev A motion event describing the trackball action. (As noted in 5890 * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use 5891 * {@link SystemClock#uptimeMillis()} as the timebase.) 5892 * @param sync If true, wait for the event to be completed before returning to the caller. 5893 * @return Returns true if event was dispatched, false if it was dropped for any reason 5894 */ 5895 public boolean injectTrackballEvent(MotionEvent ev, boolean sync) { 5896 final int pid = Binder.getCallingPid(); 5897 final int uid = Binder.getCallingUid(); 5898 final long ident = Binder.clearCallingIdentity(); 5899 5900 MotionEvent newEvent = MotionEvent.obtain(ev); 5901 if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) { 5902 newEvent.setSource(InputDevice.SOURCE_TRACKBALL); 5903 } 5904 5905 final int result = mInputManager.injectInputEvent(newEvent, pid, uid, 5906 sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH 5907 : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT, 5908 INJECTION_TIMEOUT_MILLIS); 5909 5910 Binder.restoreCallingIdentity(ident); 5911 return reportInjectionResult(result); 5912 } 5913 5914 /** 5915 * Inject an input event into the UI without waiting for dispatch to commence. 5916 * This variant is useful for fire-and-forget input event injection. It does not 5917 * block any longer than it takes to enqueue the input event. 5918 * 5919 * @param ev An input event. (Be sure to set the input source correctly.) 5920 * @return Returns true if event was dispatched, false if it was dropped for any reason 5921 */ 5922 public boolean injectInputEventNoWait(InputEvent ev) { 5923 final int pid = Binder.getCallingPid(); 5924 final int uid = Binder.getCallingUid(); 5925 final long ident = Binder.clearCallingIdentity(); 5926 5927 final int result = mInputManager.injectInputEvent(ev, pid, uid, 5928 InputManager.INPUT_EVENT_INJECTION_SYNC_NONE, 5929 INJECTION_TIMEOUT_MILLIS); 5930 5931 Binder.restoreCallingIdentity(ident); 5932 return reportInjectionResult(result); 5933 } 5934 5935 private boolean reportInjectionResult(int result) { 5936 switch (result) { 5937 case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED: 5938 Slog.w(TAG, "Input event injection permission denied."); 5939 throw new SecurityException( 5940 "Injecting to another application requires INJECT_EVENTS permission"); 5941 case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED: 5942 //Slog.v(TAG, "Input event injection succeeded."); 5943 return true; 5944 case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT: 5945 Slog.w(TAG, "Input event injection timed out."); 5946 return false; 5947 case InputManager.INPUT_EVENT_INJECTION_FAILED: 5948 default: 5949 Slog.w(TAG, "Input event injection failed."); 5950 return false; 5951 } 5952 } 5953 5954 private WindowState getFocusedWindow() { 5955 synchronized (mWindowMap) { 5956 return getFocusedWindowLocked(); 5957 } 5958 } 5959 5960 private WindowState getFocusedWindowLocked() { 5961 return mCurrentFocus; 5962 } 5963 5964 public boolean detectSafeMode() { 5965 if (!mInputMonitor.waitForInputDevicesReady( 5966 INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) { 5967 Slog.w(TAG, "Devices still not ready after waiting " 5968 + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS 5969 + " milliseconds before attempting to detect safe mode."); 5970 } 5971 5972 mSafeMode = mPolicy.detectSafeMode(); 5973 return mSafeMode; 5974 } 5975 5976 public void systemReady() { 5977 synchronized(mWindowMap) { 5978 if (mDisplay != null) { 5979 throw new IllegalStateException("Display already initialized"); 5980 } 5981 WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); 5982 mDisplay = wm.getDefaultDisplay(); 5983 mInitialDisplayWidth = mDisplay.getRealWidth(); 5984 mInitialDisplayHeight = mDisplay.getRealHeight(); 5985 int rot = mDisplay.getRotation(); 5986 if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) { 5987 // If the screen is currently rotated, we need to swap the 5988 // initial width and height to get the true natural values. 5989 int tmp = mInitialDisplayWidth; 5990 mInitialDisplayWidth = mInitialDisplayHeight; 5991 mInitialDisplayHeight = tmp; 5992 } 5993 mBaseDisplayWidth = mCurDisplayWidth = mInitialDisplayWidth; 5994 mBaseDisplayHeight = mCurDisplayHeight = mInitialDisplayHeight; 5995 mInputManager.setDisplaySize(0, mDisplay.getRawWidth(), mDisplay.getRawHeight()); 5996 mPolicy.setInitialDisplaySize(mInitialDisplayWidth, mInitialDisplayHeight); 5997 } 5998 5999 try { 6000 mActivityManager.updateConfiguration(null); 6001 } catch (RemoteException e) { 6002 } 6003 6004 mPolicy.systemReady(); 6005 } 6006 6007 // This is an animation that does nothing: it just immediately finishes 6008 // itself every time it is called. It is used as a stub animation in cases 6009 // where we want to synchronize multiple things that may be animating. 6010 static final class DummyAnimation extends Animation { 6011 public boolean getTransformation(long currentTime, Transformation outTransformation) { 6012 return false; 6013 } 6014 } 6015 static final Animation sDummyAnimation = new DummyAnimation(); 6016 6017 // ------------------------------------------------------------- 6018 // Async Handler 6019 // ------------------------------------------------------------- 6020 6021 final class H extends Handler { 6022 public static final int REPORT_FOCUS_CHANGE = 2; 6023 public static final int REPORT_LOSING_FOCUS = 3; 6024 public static final int ANIMATE = 4; 6025 public static final int ADD_STARTING = 5; 6026 public static final int REMOVE_STARTING = 6; 6027 public static final int FINISHED_STARTING = 7; 6028 public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8; 6029 public static final int WINDOW_FREEZE_TIMEOUT = 11; 6030 public static final int HOLD_SCREEN_CHANGED = 12; 6031 public static final int APP_TRANSITION_TIMEOUT = 13; 6032 public static final int PERSIST_ANIMATION_SCALE = 14; 6033 public static final int FORCE_GC = 15; 6034 public static final int ENABLE_SCREEN = 16; 6035 public static final int APP_FREEZE_TIMEOUT = 17; 6036 public static final int SEND_NEW_CONFIGURATION = 18; 6037 public static final int REPORT_WINDOWS_CHANGE = 19; 6038 public static final int DRAG_START_TIMEOUT = 20; 6039 public static final int DRAG_END_TIMEOUT = 21; 6040 public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22; 6041 6042 private Session mLastReportedHold; 6043 6044 public H() { 6045 } 6046 6047 @Override 6048 public void handleMessage(Message msg) { 6049 switch (msg.what) { 6050 case REPORT_FOCUS_CHANGE: { 6051 WindowState lastFocus; 6052 WindowState newFocus; 6053 6054 synchronized(mWindowMap) { 6055 lastFocus = mLastFocus; 6056 newFocus = mCurrentFocus; 6057 if (lastFocus == newFocus) { 6058 // Focus is not changing, so nothing to do. 6059 return; 6060 } 6061 mLastFocus = newFocus; 6062 //Slog.i(TAG, "Focus moving from " + lastFocus 6063 // + " to " + newFocus); 6064 if (newFocus != null && lastFocus != null 6065 && !newFocus.isDisplayedLw()) { 6066 //Slog.i(TAG, "Delaying loss of focus..."); 6067 mLosingFocus.add(lastFocus); 6068 lastFocus = null; 6069 } 6070 } 6071 6072 if (lastFocus != newFocus) { 6073 //System.out.println("Changing focus from " + lastFocus 6074 // + " to " + newFocus); 6075 if (newFocus != null) { 6076 try { 6077 //Slog.i(TAG, "Gaining focus: " + newFocus); 6078 newFocus.mClient.windowFocusChanged(true, mInTouchMode); 6079 } catch (RemoteException e) { 6080 // Ignore if process has died. 6081 } 6082 notifyFocusChanged(); 6083 } 6084 6085 if (lastFocus != null) { 6086 try { 6087 //Slog.i(TAG, "Losing focus: " + lastFocus); 6088 lastFocus.mClient.windowFocusChanged(false, mInTouchMode); 6089 } catch (RemoteException e) { 6090 // Ignore if process has died. 6091 } 6092 } 6093 6094 mPolicy.focusChanged(lastFocus, newFocus); 6095 } 6096 } break; 6097 6098 case REPORT_LOSING_FOCUS: { 6099 ArrayList<WindowState> losers; 6100 6101 synchronized(mWindowMap) { 6102 losers = mLosingFocus; 6103 mLosingFocus = new ArrayList<WindowState>(); 6104 } 6105 6106 final int N = losers.size(); 6107 for (int i=0; i<N; i++) { 6108 try { 6109 //Slog.i(TAG, "Losing delayed focus: " + losers.get(i)); 6110 losers.get(i).mClient.windowFocusChanged(false, mInTouchMode); 6111 } catch (RemoteException e) { 6112 // Ignore if process has died. 6113 } 6114 } 6115 } break; 6116 6117 case ANIMATE: { 6118 synchronized(mWindowMap) { 6119 mAnimationPending = false; 6120 performLayoutAndPlaceSurfacesLocked(); 6121 } 6122 } break; 6123 6124 case ADD_STARTING: { 6125 final AppWindowToken wtoken = (AppWindowToken)msg.obj; 6126 final StartingData sd = wtoken.startingData; 6127 6128 if (sd == null) { 6129 // Animation has been canceled... do nothing. 6130 return; 6131 } 6132 6133 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting " 6134 + wtoken + ": pkg=" + sd.pkg); 6135 6136 View view = null; 6137 try { 6138 view = mPolicy.addStartingWindow( 6139 wtoken.token, sd.pkg, 6140 sd.theme, sd.nonLocalizedLabel, sd.labelRes, 6141 sd.icon, sd.windowFlags); 6142 } catch (Exception e) { 6143 Slog.w(TAG, "Exception when adding starting window", e); 6144 } 6145 6146 if (view != null) { 6147 boolean abort = false; 6148 6149 synchronized(mWindowMap) { 6150 if (wtoken.removed || wtoken.startingData == null) { 6151 // If the window was successfully added, then 6152 // we need to remove it. 6153 if (wtoken.startingWindow != null) { 6154 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, 6155 "Aborted starting " + wtoken 6156 + ": removed=" + wtoken.removed 6157 + " startingData=" + wtoken.startingData); 6158 wtoken.startingWindow = null; 6159 wtoken.startingData = null; 6160 abort = true; 6161 } 6162 } else { 6163 wtoken.startingView = view; 6164 } 6165 if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG, 6166 "Added starting " + wtoken 6167 + ": startingWindow=" 6168 + wtoken.startingWindow + " startingView=" 6169 + wtoken.startingView); 6170 } 6171 6172 if (abort) { 6173 try { 6174 mPolicy.removeStartingWindow(wtoken.token, view); 6175 } catch (Exception e) { 6176 Slog.w(TAG, "Exception when removing starting window", e); 6177 } 6178 } 6179 } 6180 } break; 6181 6182 case REMOVE_STARTING: { 6183 final AppWindowToken wtoken = (AppWindowToken)msg.obj; 6184 IBinder token = null; 6185 View view = null; 6186 synchronized (mWindowMap) { 6187 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting " 6188 + wtoken + ": startingWindow=" 6189 + wtoken.startingWindow + " startingView=" 6190 + wtoken.startingView); 6191 if (wtoken.startingWindow != null) { 6192 view = wtoken.startingView; 6193 token = wtoken.token; 6194 wtoken.startingData = null; 6195 wtoken.startingView = null; 6196 wtoken.startingWindow = null; 6197 } 6198 } 6199 if (view != null) { 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 FINISHED_STARTING: { 6209 IBinder token = null; 6210 View view = null; 6211 while (true) { 6212 synchronized (mWindowMap) { 6213 final int N = mFinishedStarting.size(); 6214 if (N <= 0) { 6215 break; 6216 } 6217 AppWindowToken wtoken = mFinishedStarting.remove(N-1); 6218 6219 if (DEBUG_STARTING_WINDOW) Slog.v(TAG, 6220 "Finished starting " + wtoken 6221 + ": startingWindow=" + wtoken.startingWindow 6222 + " startingView=" + wtoken.startingView); 6223 6224 if (wtoken.startingWindow == null) { 6225 continue; 6226 } 6227 6228 view = wtoken.startingView; 6229 token = wtoken.token; 6230 wtoken.startingData = null; 6231 wtoken.startingView = null; 6232 wtoken.startingWindow = null; 6233 } 6234 6235 try { 6236 mPolicy.removeStartingWindow(token, view); 6237 } catch (Exception e) { 6238 Slog.w(TAG, "Exception when removing starting window", e); 6239 } 6240 } 6241 } break; 6242 6243 case REPORT_APPLICATION_TOKEN_WINDOWS: { 6244 final AppWindowToken wtoken = (AppWindowToken)msg.obj; 6245 6246 boolean nowVisible = msg.arg1 != 0; 6247 boolean nowGone = msg.arg2 != 0; 6248 6249 try { 6250 if (DEBUG_VISIBILITY) Slog.v( 6251 TAG, "Reporting visible in " + wtoken 6252 + " visible=" + nowVisible 6253 + " gone=" + nowGone); 6254 if (nowVisible) { 6255 wtoken.appToken.windowsVisible(); 6256 } else { 6257 wtoken.appToken.windowsGone(); 6258 } 6259 } catch (RemoteException ex) { 6260 } 6261 } break; 6262 6263 case WINDOW_FREEZE_TIMEOUT: { 6264 synchronized (mWindowMap) { 6265 Slog.w(TAG, "Window freeze timeout expired."); 6266 int i = mWindows.size(); 6267 while (i > 0) { 6268 i--; 6269 WindowState w = mWindows.get(i); 6270 if (w.mOrientationChanging) { 6271 w.mOrientationChanging = false; 6272 Slog.w(TAG, "Force clearing orientation change: " + w); 6273 } 6274 } 6275 performLayoutAndPlaceSurfacesLocked(); 6276 } 6277 break; 6278 } 6279 6280 case HOLD_SCREEN_CHANGED: { 6281 Session oldHold; 6282 Session newHold; 6283 synchronized (mWindowMap) { 6284 oldHold = mLastReportedHold; 6285 newHold = (Session)msg.obj; 6286 mLastReportedHold = newHold; 6287 } 6288 6289 if (oldHold != newHold) { 6290 try { 6291 if (oldHold != null) { 6292 mBatteryStats.noteStopWakelock(oldHold.mUid, -1, 6293 "window", 6294 BatteryStats.WAKE_TYPE_WINDOW); 6295 } 6296 if (newHold != null) { 6297 mBatteryStats.noteStartWakelock(newHold.mUid, -1, 6298 "window", 6299 BatteryStats.WAKE_TYPE_WINDOW); 6300 } 6301 } catch (RemoteException e) { 6302 } 6303 } 6304 break; 6305 } 6306 6307 case APP_TRANSITION_TIMEOUT: { 6308 synchronized (mWindowMap) { 6309 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 6310 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 6311 "*** APP TRANSITION TIMEOUT"); 6312 mAppTransitionReady = true; 6313 mAppTransitionTimeout = true; 6314 performLayoutAndPlaceSurfacesLocked(); 6315 } 6316 } 6317 break; 6318 } 6319 6320 case PERSIST_ANIMATION_SCALE: { 6321 Settings.System.putFloat(mContext.getContentResolver(), 6322 Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale); 6323 Settings.System.putFloat(mContext.getContentResolver(), 6324 Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale); 6325 break; 6326 } 6327 6328 case FORCE_GC: { 6329 synchronized(mWindowMap) { 6330 if (mAnimationPending) { 6331 // If we are animating, don't do the gc now but 6332 // delay a bit so we don't interrupt the animation. 6333 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC), 6334 2000); 6335 return; 6336 } 6337 // If we are currently rotating the display, it will 6338 // schedule a new message when done. 6339 if (mDisplayFrozen) { 6340 return; 6341 } 6342 mFreezeGcPending = 0; 6343 } 6344 Runtime.getRuntime().gc(); 6345 break; 6346 } 6347 6348 case ENABLE_SCREEN: { 6349 performEnableScreen(); 6350 break; 6351 } 6352 6353 case APP_FREEZE_TIMEOUT: { 6354 synchronized (mWindowMap) { 6355 Slog.w(TAG, "App freeze timeout expired."); 6356 int i = mAppTokens.size(); 6357 while (i > 0) { 6358 i--; 6359 AppWindowToken tok = mAppTokens.get(i); 6360 if (tok.freezingScreen) { 6361 Slog.w(TAG, "Force clearing freeze: " + tok); 6362 unsetAppFreezingScreenLocked(tok, true, true); 6363 } 6364 } 6365 } 6366 break; 6367 } 6368 6369 case SEND_NEW_CONFIGURATION: { 6370 removeMessages(SEND_NEW_CONFIGURATION); 6371 sendNewConfiguration(); 6372 break; 6373 } 6374 6375 case REPORT_WINDOWS_CHANGE: { 6376 if (mWindowsChanged) { 6377 synchronized (mWindowMap) { 6378 mWindowsChanged = false; 6379 } 6380 notifyWindowsChanged(); 6381 } 6382 break; 6383 } 6384 6385 case DRAG_START_TIMEOUT: { 6386 IBinder win = (IBinder)msg.obj; 6387 if (DEBUG_DRAG) { 6388 Slog.w(TAG, "Timeout starting drag by win " + win); 6389 } 6390 synchronized (mWindowMap) { 6391 // !!! TODO: ANR the app that has failed to start the drag in time 6392 if (mDragState != null) { 6393 mDragState.unregister(); 6394 mInputMonitor.updateInputWindowsLw(true /*force*/); 6395 mDragState.reset(); 6396 mDragState = null; 6397 } 6398 } 6399 break; 6400 } 6401 6402 case DRAG_END_TIMEOUT: { 6403 IBinder win = (IBinder)msg.obj; 6404 if (DEBUG_DRAG) { 6405 Slog.w(TAG, "Timeout ending drag to win " + win); 6406 } 6407 synchronized (mWindowMap) { 6408 // !!! TODO: ANR the drag-receiving app 6409 mDragState.mDragResult = false; 6410 mDragState.endDragLw(); 6411 } 6412 break; 6413 } 6414 6415 case REPORT_HARD_KEYBOARD_STATUS_CHANGE: { 6416 notifyHardKeyboardStatusChange(); 6417 break; 6418 } 6419 } 6420 } 6421 } 6422 6423 // ------------------------------------------------------------- 6424 // IWindowManager API 6425 // ------------------------------------------------------------- 6426 6427 public IWindowSession openSession(IInputMethodClient client, 6428 IInputContext inputContext) { 6429 if (client == null) throw new IllegalArgumentException("null client"); 6430 if (inputContext == null) throw new IllegalArgumentException("null inputContext"); 6431 Session session = new Session(this, client, inputContext); 6432 return session; 6433 } 6434 6435 public boolean inputMethodClientHasFocus(IInputMethodClient client) { 6436 synchronized (mWindowMap) { 6437 // The focus for the client is the window immediately below 6438 // where we would place the input method window. 6439 int idx = findDesiredInputMethodWindowIndexLocked(false); 6440 WindowState imFocus; 6441 if (idx > 0) { 6442 imFocus = mWindows.get(idx-1); 6443 //Log.i(TAG, "Desired input method target: " + imFocus); 6444 //Log.i(TAG, "Current focus: " + this.mCurrentFocus); 6445 //Log.i(TAG, "Last focus: " + this.mLastFocus); 6446 if (imFocus != null) { 6447 // This may be a starting window, in which case we still want 6448 // to count it as okay. 6449 if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING 6450 && imFocus.mAppToken != null) { 6451 // The client has definitely started, so it really should 6452 // have a window in this app token. Let's look for it. 6453 for (int i=0; i<imFocus.mAppToken.windows.size(); i++) { 6454 WindowState w = imFocus.mAppToken.windows.get(i); 6455 if (w != imFocus) { 6456 //Log.i(TAG, "Switching to real app window: " + w); 6457 imFocus = w; 6458 break; 6459 } 6460 } 6461 } 6462 //Log.i(TAG, "IM target client: " + imFocus.mSession.mClient); 6463 //if (imFocus.mSession.mClient != null) { 6464 // Log.i(TAG, "IM target client binder: " + imFocus.mSession.mClient.asBinder()); 6465 // Log.i(TAG, "Requesting client binder: " + client.asBinder()); 6466 //} 6467 if (imFocus.mSession.mClient != null && 6468 imFocus.mSession.mClient.asBinder() == client.asBinder()) { 6469 return true; 6470 } 6471 6472 // Okay, how about this... what is the current focus? 6473 // It seems in some cases we may not have moved the IM 6474 // target window, such as when it was in a pop-up window, 6475 // so let's also look at the current focus. (An example: 6476 // go to Gmail, start searching so the keyboard goes up, 6477 // press home. Sometimes the IME won't go down.) 6478 // Would be nice to fix this more correctly, but it's 6479 // way at the end of a release, and this should be good enough. 6480 if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null && 6481 mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) { 6482 return true; 6483 } 6484 } 6485 } 6486 } 6487 return false; 6488 } 6489 6490 public void getDisplaySize(Point size) { 6491 synchronized(mWindowMap) { 6492 size.x = mCurDisplayWidth; 6493 size.y = mCurDisplayHeight; 6494 } 6495 } 6496 6497 public int getMaximumSizeDimension() { 6498 synchronized(mWindowMap) { 6499 // Do this based on the raw screen size, until we are smarter. 6500 return mBaseDisplayWidth > mBaseDisplayHeight 6501 ? mBaseDisplayWidth : mBaseDisplayHeight; 6502 } 6503 } 6504 6505 public void setForcedDisplaySize(int longDimen, int shortDimen) { 6506 synchronized(mWindowMap) { 6507 int width, height; 6508 if (mInitialDisplayWidth < mInitialDisplayHeight) { 6509 width = shortDimen < mInitialDisplayWidth 6510 ? shortDimen : mInitialDisplayWidth; 6511 height = longDimen < mInitialDisplayHeight 6512 ? longDimen : mInitialDisplayHeight; 6513 } else { 6514 width = longDimen < mInitialDisplayWidth 6515 ? longDimen : mInitialDisplayWidth; 6516 height = shortDimen < mInitialDisplayHeight 6517 ? shortDimen : mInitialDisplayHeight; 6518 } 6519 setForcedDisplaySizeLocked(width, height); 6520 } 6521 } 6522 6523 private void rebuildBlackFrame(boolean inTransaction) { 6524 if (!inTransaction) { 6525 if (SHOW_TRANSACTIONS) Slog.i(TAG, 6526 ">>> OPEN TRANSACTION rebuildBlackFrame"); 6527 Surface.openTransaction(); 6528 } 6529 try { 6530 if (mBlackFrame != null) { 6531 mBlackFrame.kill(); 6532 mBlackFrame = null; 6533 } 6534 if (mBaseDisplayWidth < mInitialDisplayWidth 6535 || mBaseDisplayHeight < mInitialDisplayHeight) { 6536 int initW, initH, baseW, baseH; 6537 final boolean rotated = (mRotation == Surface.ROTATION_90 6538 || mRotation == Surface.ROTATION_270); 6539 if (rotated) { 6540 initW = mInitialDisplayHeight; 6541 initH = mInitialDisplayWidth; 6542 baseW = mBaseDisplayHeight; 6543 baseH = mBaseDisplayWidth; 6544 } else { 6545 initW = mInitialDisplayWidth; 6546 initH = mInitialDisplayHeight; 6547 baseW = mBaseDisplayWidth; 6548 baseH = mBaseDisplayHeight; 6549 } 6550 Rect outer = new Rect(0, 0, initW, initH); 6551 Rect inner = new Rect(0, 0, baseW, baseH); 6552 try { 6553 mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER); 6554 } catch (Surface.OutOfResourcesException e) { 6555 } 6556 } 6557 } finally { 6558 if (!inTransaction) { 6559 Surface.closeTransaction(); 6560 if (SHOW_TRANSACTIONS) Slog.i(TAG, 6561 "<<< CLOSE TRANSACTION rebuildBlackFrame"); 6562 } 6563 } 6564 } 6565 6566 private void setForcedDisplaySizeLocked(int width, int height) { 6567 mBaseDisplayWidth = width; 6568 mBaseDisplayHeight = height; 6569 mPolicy.setInitialDisplaySize(mBaseDisplayWidth, mBaseDisplayHeight); 6570 6571 mLayoutNeeded = true; 6572 6573 boolean configChanged = updateOrientationFromAppTokensLocked(false); 6574 mTempConfiguration.setToDefaults(); 6575 mTempConfiguration.fontScale = mCurConfiguration.fontScale; 6576 if (computeNewConfigurationLocked(mTempConfiguration)) { 6577 if (mCurConfiguration.diff(mTempConfiguration) != 0) { 6578 configChanged = true; 6579 } 6580 } 6581 6582 if (configChanged) { 6583 mWaitingForConfig = true; 6584 startFreezingDisplayLocked(false); 6585 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 6586 } 6587 6588 rebuildBlackFrame(false); 6589 6590 performLayoutAndPlaceSurfacesLocked(); 6591 } 6592 6593 public void clearForcedDisplaySize() { 6594 synchronized(mWindowMap) { 6595 setForcedDisplaySizeLocked(mInitialDisplayWidth, mInitialDisplayHeight); 6596 } 6597 } 6598 6599 // ------------------------------------------------------------- 6600 // Internals 6601 // ------------------------------------------------------------- 6602 6603 final WindowState windowForClientLocked(Session session, IWindow client, 6604 boolean throwOnError) { 6605 return windowForClientLocked(session, client.asBinder(), throwOnError); 6606 } 6607 6608 final WindowState windowForClientLocked(Session session, IBinder client, 6609 boolean throwOnError) { 6610 WindowState win = mWindowMap.get(client); 6611 if (localLOGV) Slog.v( 6612 TAG, "Looking up client " + client + ": " + win); 6613 if (win == null) { 6614 RuntimeException ex = new IllegalArgumentException( 6615 "Requested window " + client + " does not exist"); 6616 if (throwOnError) { 6617 throw ex; 6618 } 6619 Slog.w(TAG, "Failed looking up window", ex); 6620 return null; 6621 } 6622 if (session != null && win.mSession != session) { 6623 RuntimeException ex = new IllegalArgumentException( 6624 "Requested window " + client + " is in session " + 6625 win.mSession + ", not " + session); 6626 if (throwOnError) { 6627 throw ex; 6628 } 6629 Slog.w(TAG, "Failed looking up window", ex); 6630 return null; 6631 } 6632 6633 return win; 6634 } 6635 6636 final void rebuildAppWindowListLocked() { 6637 int NW = mWindows.size(); 6638 int i; 6639 int lastWallpaper = -1; 6640 int numRemoved = 0; 6641 6642 if (mRebuildTmp.length < NW) { 6643 mRebuildTmp = new WindowState[NW+10]; 6644 } 6645 6646 // First remove all existing app windows. 6647 i=0; 6648 while (i < NW) { 6649 WindowState w = mWindows.get(i); 6650 if (w.mAppToken != null) { 6651 WindowState win = mWindows.remove(i); 6652 win.mRebuilding = true; 6653 mRebuildTmp[numRemoved] = win; 6654 mWindowsChanged = true; 6655 if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, 6656 "Rebuild removing window: " + win); 6657 NW--; 6658 numRemoved++; 6659 continue; 6660 } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER 6661 && lastWallpaper == i-1) { 6662 lastWallpaper = i; 6663 } 6664 i++; 6665 } 6666 6667 // The wallpaper window(s) typically live at the bottom of the stack, 6668 // so skip them before adding app tokens. 6669 lastWallpaper++; 6670 i = lastWallpaper; 6671 6672 // First add all of the exiting app tokens... these are no longer 6673 // in the main app list, but still have windows shown. We put them 6674 // in the back because now that the animation is over we no longer 6675 // will care about them. 6676 int NT = mExitingAppTokens.size(); 6677 for (int j=0; j<NT; j++) { 6678 i = reAddAppWindowsLocked(i, mExitingAppTokens.get(j)); 6679 } 6680 6681 // And add in the still active app tokens in Z order. 6682 NT = mAppTokens.size(); 6683 for (int j=0; j<NT; j++) { 6684 i = reAddAppWindowsLocked(i, mAppTokens.get(j)); 6685 } 6686 6687 i -= lastWallpaper; 6688 if (i != numRemoved) { 6689 Slog.w(TAG, "Rebuild removed " + numRemoved 6690 + " windows but added " + i); 6691 for (i=0; i<numRemoved; i++) { 6692 WindowState ws = mRebuildTmp[i]; 6693 if (ws.mRebuilding) { 6694 StringWriter sw = new StringWriter(); 6695 PrintWriter pw = new PrintWriter(sw); 6696 ws.dump(pw, ""); 6697 pw.flush(); 6698 Slog.w(TAG, "This window was lost: " + ws); 6699 Slog.w(TAG, sw.toString()); 6700 } 6701 } 6702 Slog.w(TAG, "Current app token list:"); 6703 dumpAppTokensLocked(); 6704 Slog.w(TAG, "Final window list:"); 6705 dumpWindowsLocked(); 6706 } 6707 } 6708 6709 private final void assignLayersLocked() { 6710 int N = mWindows.size(); 6711 int curBaseLayer = 0; 6712 int curLayer = 0; 6713 int i; 6714 6715 if (DEBUG_LAYERS) { 6716 RuntimeException here = new RuntimeException("here"); 6717 here.fillInStackTrace(); 6718 Log.v(TAG, "Assigning layers", here); 6719 } 6720 6721 for (i=0; i<N; i++) { 6722 WindowState w = mWindows.get(i); 6723 if (w.mBaseLayer == curBaseLayer || w.mIsImWindow 6724 || (i > 0 && w.mIsWallpaper)) { 6725 curLayer += WINDOW_LAYER_MULTIPLIER; 6726 w.mLayer = curLayer; 6727 } else { 6728 curBaseLayer = curLayer = w.mBaseLayer; 6729 w.mLayer = curLayer; 6730 } 6731 if (w.mTargetAppToken != null) { 6732 w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment; 6733 } else if (w.mAppToken != null) { 6734 w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment; 6735 } else { 6736 w.mAnimLayer = w.mLayer; 6737 } 6738 if (w.mIsImWindow) { 6739 w.mAnimLayer += mInputMethodAnimLayerAdjustment; 6740 } else if (w.mIsWallpaper) { 6741 w.mAnimLayer += mWallpaperAnimLayerAdjustment; 6742 } 6743 if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": " 6744 + w.mAnimLayer); 6745 //System.out.println( 6746 // "Assigned layer " + curLayer + " to " + w.mClient.asBinder()); 6747 } 6748 } 6749 6750 private boolean mInLayout = false; 6751 private final void performLayoutAndPlaceSurfacesLocked() { 6752 if (mInLayout) { 6753 if (DEBUG) { 6754 throw new RuntimeException("Recursive call!"); 6755 } 6756 Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout"); 6757 return; 6758 } 6759 6760 if (mWaitingForConfig) { 6761 // Our configuration has changed (most likely rotation), but we 6762 // don't yet have the complete configuration to report to 6763 // applications. Don't do any window layout until we have it. 6764 return; 6765 } 6766 6767 if (mDisplay == null) { 6768 // Not yet initialized, nothing to do. 6769 return; 6770 } 6771 6772 mInLayout = true; 6773 boolean recoveringMemory = false; 6774 6775 try { 6776 if (mForceRemoves != null) { 6777 recoveringMemory = true; 6778 // Wait a little bit for things to settle down, and off we go. 6779 for (int i=0; i<mForceRemoves.size(); i++) { 6780 WindowState ws = mForceRemoves.get(i); 6781 Slog.i(TAG, "Force removing: " + ws); 6782 removeWindowInnerLocked(ws.mSession, ws); 6783 } 6784 mForceRemoves = null; 6785 Slog.w(TAG, "Due to memory failure, waiting a bit for next layout"); 6786 Object tmp = new Object(); 6787 synchronized (tmp) { 6788 try { 6789 tmp.wait(250); 6790 } catch (InterruptedException e) { 6791 } 6792 } 6793 } 6794 } catch (RuntimeException e) { 6795 Slog.e(TAG, "Unhandled exception while force removing for memory", e); 6796 } 6797 6798 try { 6799 performLayoutAndPlaceSurfacesLockedInner(recoveringMemory); 6800 6801 int N = mPendingRemove.size(); 6802 if (N > 0) { 6803 if (mPendingRemoveTmp.length < N) { 6804 mPendingRemoveTmp = new WindowState[N+10]; 6805 } 6806 mPendingRemove.toArray(mPendingRemoveTmp); 6807 mPendingRemove.clear(); 6808 for (int i=0; i<N; i++) { 6809 WindowState w = mPendingRemoveTmp[i]; 6810 removeWindowInnerLocked(w.mSession, w); 6811 } 6812 6813 mInLayout = false; 6814 assignLayersLocked(); 6815 mLayoutNeeded = true; 6816 performLayoutAndPlaceSurfacesLocked(); 6817 6818 } else { 6819 mInLayout = false; 6820 if (mLayoutNeeded) { 6821 requestAnimationLocked(0); 6822 } 6823 } 6824 if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) { 6825 mH.removeMessages(H.REPORT_WINDOWS_CHANGE); 6826 mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE)); 6827 } 6828 } catch (RuntimeException e) { 6829 mInLayout = false; 6830 Slog.e(TAG, "Unhandled exception while layout out windows", e); 6831 } 6832 } 6833 6834 private final int performLayoutLockedInner(boolean initial, boolean updateInputWindows) { 6835 if (!mLayoutNeeded) { 6836 return 0; 6837 } 6838 6839 mLayoutNeeded = false; 6840 6841 final int dw = mCurDisplayWidth; 6842 final int dh = mCurDisplayHeight; 6843 6844 final int N = mWindows.size(); 6845 int i; 6846 6847 if (DEBUG_LAYOUT) Slog.v(TAG, "performLayout: needed=" 6848 + mLayoutNeeded + " dw=" + dw + " dh=" + dh); 6849 6850 mPolicy.beginLayoutLw(dw, dh); 6851 6852 int seq = mLayoutSeq+1; 6853 if (seq < 0) seq = 0; 6854 mLayoutSeq = seq; 6855 6856 // First perform layout of any root windows (not attached 6857 // to another window). 6858 int topAttached = -1; 6859 for (i = N-1; i >= 0; i--) { 6860 WindowState win = mWindows.get(i); 6861 6862 // Don't do layout of a window if it is not visible, or 6863 // soon won't be visible, to avoid wasting time and funky 6864 // changes while a window is animating away. 6865 final AppWindowToken atoken = win.mAppToken; 6866 final boolean gone = win.mViewVisibility == View.GONE 6867 || !win.mRelayoutCalled 6868 || (atoken == null && win.mRootToken.hidden) 6869 || (atoken != null && atoken.hiddenRequested) 6870 || win.mAttachedHidden 6871 || win.mExiting || win.mDestroying; 6872 6873 if (DEBUG_LAYOUT && !win.mLayoutAttached) { 6874 Slog.v(TAG, "First pass " + win 6875 + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame 6876 + " mLayoutAttached=" + win.mLayoutAttached); 6877 if (gone) Slog.v(TAG, " (mViewVisibility=" 6878 + win.mViewVisibility + " mRelayoutCalled=" 6879 + win.mRelayoutCalled + " hidden=" 6880 + win.mRootToken.hidden + " hiddenRequested=" 6881 + (atoken != null && atoken.hiddenRequested) 6882 + " mAttachedHidden=" + win.mAttachedHidden); 6883 } 6884 6885 // If this view is GONE, then skip it -- keep the current 6886 // frame, and let the caller know so they can ignore it 6887 // if they want. (We do the normal layout for INVISIBLE 6888 // windows, since that means "perform layout as normal, 6889 // just don't display"). 6890 if (!gone || !win.mHaveFrame) { 6891 if (!win.mLayoutAttached) { 6892 if (initial) { 6893 //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); 6894 win.mContentChanged = false; 6895 } 6896 win.prelayout(); 6897 mPolicy.layoutWindowLw(win, win.mAttrs, null); 6898 win.mLayoutSeq = seq; 6899 if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame=" 6900 + win.mFrame + " mContainingFrame=" 6901 + win.mContainingFrame + " mDisplayFrame=" 6902 + win.mDisplayFrame); 6903 } else { 6904 if (topAttached < 0) topAttached = i; 6905 } 6906 } 6907 } 6908 6909 // Now perform layout of attached windows, which usually 6910 // depend on the position of the window they are attached to. 6911 // XXX does not deal with windows that are attached to windows 6912 // that are themselves attached. 6913 for (i = topAttached; i >= 0; i--) { 6914 WindowState win = mWindows.get(i); 6915 6916 if (win.mLayoutAttached) { 6917 if (DEBUG_LAYOUT) Slog.v(TAG, "Second pass " + win 6918 + " mHaveFrame=" + win.mHaveFrame 6919 + " mViewVisibility=" + win.mViewVisibility 6920 + " mRelayoutCalled=" + win.mRelayoutCalled); 6921 // If this view is GONE, then skip it -- keep the current 6922 // frame, and let the caller know so they can ignore it 6923 // if they want. (We do the normal layout for INVISIBLE 6924 // windows, since that means "perform layout as normal, 6925 // just don't display"). 6926 if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled) 6927 || !win.mHaveFrame) { 6928 if (initial) { 6929 //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial"); 6930 win.mContentChanged = false; 6931 } 6932 win.prelayout(); 6933 mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow); 6934 win.mLayoutSeq = seq; 6935 if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame=" 6936 + win.mFrame + " mContainingFrame=" 6937 + win.mContainingFrame + " mDisplayFrame=" 6938 + win.mDisplayFrame); 6939 } 6940 } 6941 } 6942 6943 // Window frames may have changed. Tell the input dispatcher about it. 6944 mInputMonitor.setUpdateInputWindowsNeededLw(); 6945 if (updateInputWindows) { 6946 mInputMonitor.updateInputWindowsLw(false /*force*/); 6947 } 6948 6949 return mPolicy.finishLayoutLw(); 6950 } 6951 6952 // "Something has changed! Let's make it correct now." 6953 private final void performLayoutAndPlaceSurfacesLockedInner( 6954 boolean recoveringMemory) { 6955 if (mDisplay == null) { 6956 Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay"); 6957 return; 6958 } 6959 6960 final long currentTime = SystemClock.uptimeMillis(); 6961 final int dw = mCurDisplayWidth; 6962 final int dh = mCurDisplayHeight; 6963 6964 final int innerDw = mPolicy.getNonDecorDisplayWidth(mRotation, dw); 6965 final int innerDh = mPolicy.getNonDecorDisplayHeight(mRotation, dh); 6966 6967 int i; 6968 6969 if (mFocusMayChange) { 6970 mFocusMayChange = false; 6971 updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 6972 false /*updateInputWindows*/); 6973 } 6974 6975 // Initialize state of exiting tokens. 6976 for (i=mExitingTokens.size()-1; i>=0; i--) { 6977 mExitingTokens.get(i).hasVisible = false; 6978 } 6979 6980 // Initialize state of exiting applications. 6981 for (i=mExitingAppTokens.size()-1; i>=0; i--) { 6982 mExitingAppTokens.get(i).hasVisible = false; 6983 } 6984 6985 boolean orientationChangeComplete = true; 6986 Session holdScreen = null; 6987 float screenBrightness = -1; 6988 float buttonBrightness = -1; 6989 boolean focusDisplayed = false; 6990 boolean animating = false; 6991 boolean createWatermark = false; 6992 boolean updateRotation = false; 6993 boolean screenRotationFinished = false; 6994 6995 if (mFxSession == null) { 6996 mFxSession = new SurfaceSession(); 6997 createWatermark = true; 6998 } 6999 7000 if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces"); 7001 7002 Surface.openTransaction(); 7003 7004 if (createWatermark) { 7005 createWatermark(); 7006 } 7007 if (mWatermark != null) { 7008 mWatermark.positionSurface(dw, dh); 7009 } 7010 if (mStrictModeFlash != null) { 7011 mStrictModeFlash.positionSurface(dw, dh); 7012 } 7013 7014 try { 7015 boolean wallpaperForceHidingChanged = false; 7016 int repeats = 0; 7017 int changes = 0; 7018 7019 do { 7020 repeats++; 7021 if (repeats > 6) { 7022 Slog.w(TAG, "Animation repeat aborted after too many iterations"); 7023 mLayoutNeeded = false; 7024 break; 7025 } 7026 7027 if ((changes&(WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER 7028 | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG 7029 | WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) { 7030 if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) { 7031 if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) { 7032 assignLayersLocked(); 7033 mLayoutNeeded = true; 7034 } 7035 } 7036 if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) { 7037 if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout"); 7038 if (updateOrientationFromAppTokensLocked(true)) { 7039 mLayoutNeeded = true; 7040 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 7041 } 7042 } 7043 if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) { 7044 mLayoutNeeded = true; 7045 } 7046 } 7047 7048 // FIRST LOOP: Perform a layout, if needed. 7049 if (repeats < 4) { 7050 changes = performLayoutLockedInner(repeats == 0, false /*updateInputWindows*/); 7051 if (changes != 0) { 7052 continue; 7053 } 7054 } else { 7055 Slog.w(TAG, "Layout repeat skipped after too many iterations"); 7056 changes = 0; 7057 } 7058 7059 final int transactionSequence = ++mTransactionSequence; 7060 7061 // Update animations of all applications, including those 7062 // associated with exiting/removed apps 7063 boolean tokensAnimating = false; 7064 final int NAT = mAppTokens.size(); 7065 for (i=0; i<NAT; i++) { 7066 if (mAppTokens.get(i).stepAnimationLocked(currentTime, 7067 innerDw, innerDh)) { 7068 tokensAnimating = true; 7069 } 7070 } 7071 final int NEAT = mExitingAppTokens.size(); 7072 for (i=0; i<NEAT; i++) { 7073 if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, 7074 innerDw, innerDh)) { 7075 tokensAnimating = true; 7076 } 7077 } 7078 7079 // SECOND LOOP: Execute animations and update visibility of windows. 7080 7081 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq=" 7082 + transactionSequence + " tokensAnimating=" 7083 + tokensAnimating); 7084 7085 animating = tokensAnimating; 7086 7087 if (mScreenRotationAnimation != null) { 7088 if (mScreenRotationAnimation.isAnimating()) { 7089 if (mScreenRotationAnimation.stepAnimation(currentTime)) { 7090 animating = true; 7091 } else { 7092 screenRotationFinished = true; 7093 updateRotation = true; 7094 } 7095 } 7096 } 7097 7098 boolean tokenMayBeDrawn = false; 7099 boolean wallpaperMayChange = false; 7100 boolean forceHiding = false; 7101 WindowState windowDetachedWallpaper = null; 7102 WindowState windowAnimationBackground = null; 7103 int windowAnimationBackgroundColor = 0; 7104 7105 mPolicy.beginAnimationLw(dw, dh); 7106 7107 final int N = mWindows.size(); 7108 7109 for (i=N-1; i>=0; i--) { 7110 WindowState w = mWindows.get(i); 7111 7112 final WindowManager.LayoutParams attrs = w.mAttrs; 7113 7114 if (w.mSurface != null) { 7115 // Take care of the window being ready to display. 7116 if (w.commitFinishDrawingLocked(currentTime)) { 7117 if ((w.mAttrs.flags 7118 & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { 7119 if (DEBUG_WALLPAPER) Slog.v(TAG, 7120 "First draw done in potential wallpaper target " + w); 7121 wallpaperMayChange = true; 7122 } 7123 } 7124 7125 final boolean wasAnimating = w.mAnimating; 7126 7127 int animDw = innerDw; 7128 int animDh = innerDh; 7129 7130 // If the window has moved due to its containing 7131 // content frame changing, then we'd like to animate 7132 // it. The checks here are ordered by what is least 7133 // likely to be true first. 7134 if (w.shouldAnimateMove()) { 7135 // Frame has moved, containing content frame 7136 // has also moved, and we're not currently animating... 7137 // let's do something. 7138 Animation a = AnimationUtils.loadAnimation(mContext, 7139 com.android.internal.R.anim.window_move_from_decor); 7140 w.setAnimation(a); 7141 animDw = w.mLastFrame.left - w.mFrame.left; 7142 animDh = w.mLastFrame.top - w.mFrame.top; 7143 } 7144 7145 // Execute animation. 7146 final boolean nowAnimating = w.stepAnimationLocked(currentTime, 7147 animDw, animDh); 7148 7149 // If this window is animating, make a note that we have 7150 // an animating window and take care of a request to run 7151 // a detached wallpaper animation. 7152 if (nowAnimating) { 7153 if (w.mAnimation != null) { 7154 if (w.mAnimation.getDetachWallpaper()) { 7155 windowDetachedWallpaper = w; 7156 } 7157 if (w.mAnimation.getBackgroundColor() != 0) { 7158 windowAnimationBackground = w; 7159 windowAnimationBackgroundColor = 7160 w.mAnimation.getBackgroundColor(); 7161 } 7162 } 7163 animating = true; 7164 } 7165 7166 // If this window's app token is running a detached wallpaper 7167 // animation, make a note so we can ensure the wallpaper is 7168 // displayed behind it. 7169 if (w.mAppToken != null && w.mAppToken.animation != null) { 7170 if (w.mAppToken.animation.getDetachWallpaper()) { 7171 windowDetachedWallpaper = w; 7172 } 7173 if (w.mAppToken.animation.getBackgroundColor() != 0) { 7174 windowAnimationBackground = w; 7175 windowAnimationBackgroundColor = 7176 w.mAppToken.animation.getBackgroundColor(); 7177 } 7178 } 7179 7180 if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) { 7181 wallpaperMayChange = true; 7182 } 7183 7184 if (mPolicy.doesForceHide(w, attrs)) { 7185 if (!wasAnimating && nowAnimating) { 7186 if (DEBUG_VISIBILITY) Slog.v(TAG, 7187 "Animation started that could impact force hide: " 7188 + w); 7189 wallpaperForceHidingChanged = true; 7190 mFocusMayChange = true; 7191 } else if (w.isReadyForDisplay() && w.mAnimation == null) { 7192 forceHiding = true; 7193 } 7194 } else if (mPolicy.canBeForceHidden(w, attrs)) { 7195 boolean changed; 7196 if (forceHiding) { 7197 changed = w.hideLw(false, false); 7198 if (DEBUG_VISIBILITY && changed) Slog.v(TAG, 7199 "Now policy hidden: " + w); 7200 } else { 7201 changed = w.showLw(false, false); 7202 if (DEBUG_VISIBILITY && changed) Slog.v(TAG, 7203 "Now policy shown: " + w); 7204 if (changed) { 7205 if (wallpaperForceHidingChanged 7206 && w.isVisibleNow() /*w.isReadyForDisplay()*/) { 7207 // Assume we will need to animate. If 7208 // we don't (because the wallpaper will 7209 // stay with the lock screen), then we will 7210 // clean up later. 7211 Animation a = mPolicy.createForceHideEnterAnimation(); 7212 if (a != null) { 7213 w.setAnimation(a); 7214 } 7215 } 7216 if (mCurrentFocus == null || 7217 mCurrentFocus.mLayer < w.mLayer) { 7218 // We are showing on to of the current 7219 // focus, so re-evaluate focus to make 7220 // sure it is correct. 7221 mFocusMayChange = true; 7222 } 7223 } 7224 } 7225 if (changed && (attrs.flags 7226 & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { 7227 wallpaperMayChange = true; 7228 } 7229 } 7230 7231 mPolicy.animatingWindowLw(w, attrs); 7232 } 7233 7234 final AppWindowToken atoken = w.mAppToken; 7235 if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) { 7236 if (atoken.lastTransactionSequence != transactionSequence) { 7237 atoken.lastTransactionSequence = transactionSequence; 7238 atoken.numInterestingWindows = atoken.numDrawnWindows = 0; 7239 atoken.startingDisplayed = false; 7240 } 7241 if ((w.isOnScreen() || w.mAttrs.type 7242 == WindowManager.LayoutParams.TYPE_BASE_APPLICATION) 7243 && !w.mExiting && !w.mDestroying) { 7244 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) { 7245 Slog.v(TAG, "Eval win " + w + ": isDrawn=" 7246 + w.isDrawnLw() 7247 + ", isAnimating=" + w.isAnimating()); 7248 if (!w.isDrawnLw()) { 7249 Slog.v(TAG, "Not displayed: s=" + w.mSurface 7250 + " pv=" + w.mPolicyVisibility 7251 + " dp=" + w.mDrawPending 7252 + " cdp=" + w.mCommitDrawPending 7253 + " ah=" + w.mAttachedHidden 7254 + " th=" + atoken.hiddenRequested 7255 + " a=" + w.mAnimating); 7256 } 7257 } 7258 if (w != atoken.startingWindow) { 7259 if (!atoken.freezingScreen || !w.mAppFreezing) { 7260 atoken.numInterestingWindows++; 7261 if (w.isDrawnLw()) { 7262 atoken.numDrawnWindows++; 7263 if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, 7264 "tokenMayBeDrawn: " + atoken 7265 + " freezingScreen=" + atoken.freezingScreen 7266 + " mAppFreezing=" + w.mAppFreezing); 7267 tokenMayBeDrawn = true; 7268 } 7269 } 7270 } else if (w.isDrawnLw()) { 7271 atoken.startingDisplayed = true; 7272 } 7273 } 7274 } else if (w.mReadyToShow) { 7275 w.performShowLocked(); 7276 } 7277 } 7278 7279 changes |= mPolicy.finishAnimationLw(); 7280 7281 if (tokenMayBeDrawn) { 7282 // See if any windows have been drawn, so they (and others 7283 // associated with them) can now be shown. 7284 final int NT = mAppTokens.size(); 7285 for (i=0; i<NT; i++) { 7286 AppWindowToken wtoken = mAppTokens.get(i); 7287 if (wtoken.freezingScreen) { 7288 int numInteresting = wtoken.numInterestingWindows; 7289 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { 7290 if (DEBUG_VISIBILITY) Slog.v(TAG, 7291 "allDrawn: " + wtoken 7292 + " interesting=" + numInteresting 7293 + " drawn=" + wtoken.numDrawnWindows); 7294 wtoken.showAllWindowsLocked(); 7295 unsetAppFreezingScreenLocked(wtoken, false, true); 7296 orientationChangeComplete = true; 7297 } 7298 } else if (!wtoken.allDrawn) { 7299 int numInteresting = wtoken.numInterestingWindows; 7300 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { 7301 if (DEBUG_VISIBILITY) Slog.v(TAG, 7302 "allDrawn: " + wtoken 7303 + " interesting=" + numInteresting 7304 + " drawn=" + wtoken.numDrawnWindows); 7305 wtoken.allDrawn = true; 7306 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM; 7307 7308 // We can now show all of the drawn windows! 7309 if (!mOpeningApps.contains(wtoken)) { 7310 wtoken.showAllWindowsLocked(); 7311 } 7312 } 7313 } 7314 } 7315 } 7316 7317 // If we are ready to perform an app transition, check through 7318 // all of the app tokens to be shown and see if they are ready 7319 // to go. 7320 if (mAppTransitionReady) { 7321 int NN = mOpeningApps.size(); 7322 boolean goodToGo = true; 7323 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 7324 "Checking " + NN + " opening apps (frozen=" 7325 + mDisplayFrozen + " timeout=" 7326 + mAppTransitionTimeout + ")..."); 7327 if (!mDisplayFrozen && !mAppTransitionTimeout) { 7328 // If the display isn't frozen, wait to do anything until 7329 // all of the apps are ready. Otherwise just go because 7330 // we'll unfreeze the display when everyone is ready. 7331 for (i=0; i<NN && goodToGo; i++) { 7332 AppWindowToken wtoken = mOpeningApps.get(i); 7333 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 7334 "Check opening app" + wtoken + ": allDrawn=" 7335 + wtoken.allDrawn + " startingDisplayed=" 7336 + wtoken.startingDisplayed); 7337 if (!wtoken.allDrawn && !wtoken.startingDisplayed 7338 && !wtoken.startingMoved) { 7339 goodToGo = false; 7340 } 7341 } 7342 } 7343 if (goodToGo) { 7344 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO"); 7345 int transit = mNextAppTransition; 7346 if (mSkipAppTransitionAnimation) { 7347 transit = WindowManagerPolicy.TRANSIT_UNSET; 7348 } 7349 mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET; 7350 mAppTransitionReady = false; 7351 mAppTransitionRunning = true; 7352 mAppTransitionTimeout = false; 7353 mStartingIconInTransition = false; 7354 mSkipAppTransitionAnimation = false; 7355 7356 mH.removeMessages(H.APP_TRANSITION_TIMEOUT); 7357 7358 // If there are applications waiting to come to the 7359 // top of the stack, now is the time to move their windows. 7360 // (Note that we don't do apps going to the bottom 7361 // here -- we want to keep their windows in the old 7362 // Z-order until the animation completes.) 7363 if (mToTopApps.size() > 0) { 7364 NN = mAppTokens.size(); 7365 for (i=0; i<NN; i++) { 7366 AppWindowToken wtoken = mAppTokens.get(i); 7367 if (wtoken.sendingToTop) { 7368 wtoken.sendingToTop = false; 7369 moveAppWindowsLocked(wtoken, NN, false); 7370 } 7371 } 7372 mToTopApps.clear(); 7373 } 7374 7375 WindowState oldWallpaper = mWallpaperTarget; 7376 7377 adjustWallpaperWindowsLocked(); 7378 wallpaperMayChange = false; 7379 7380 // The top-most window will supply the layout params, 7381 // and we will determine it below. 7382 LayoutParams animLp = null; 7383 int bestAnimLayer = -1; 7384 boolean fullscreenAnim = false; 7385 7386 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 7387 "New wallpaper target=" + mWallpaperTarget 7388 + ", lower target=" + mLowerWallpaperTarget 7389 + ", upper target=" + mUpperWallpaperTarget); 7390 int foundWallpapers = 0; 7391 // Do a first pass through the tokens for two 7392 // things: 7393 // (1) Determine if both the closing and opening 7394 // app token sets are wallpaper targets, in which 7395 // case special animations are needed 7396 // (since the wallpaper needs to stay static 7397 // behind them). 7398 // (2) Find the layout params of the top-most 7399 // application window in the tokens, which is 7400 // what will control the animation theme. 7401 final int NC = mClosingApps.size(); 7402 NN = NC + mOpeningApps.size(); 7403 for (i=0; i<NN; i++) { 7404 AppWindowToken wtoken; 7405 int mode; 7406 if (i < NC) { 7407 wtoken = mClosingApps.get(i); 7408 mode = 1; 7409 } else { 7410 wtoken = mOpeningApps.get(i-NC); 7411 mode = 2; 7412 } 7413 if (mLowerWallpaperTarget != null) { 7414 if (mLowerWallpaperTarget.mAppToken == wtoken 7415 || mUpperWallpaperTarget.mAppToken == wtoken) { 7416 foundWallpapers |= mode; 7417 } 7418 } 7419 if (wtoken.appFullscreen) { 7420 WindowState ws = wtoken.findMainWindow(); 7421 if (ws != null) { 7422 animLp = ws.mAttrs; 7423 bestAnimLayer = ws.mLayer; 7424 fullscreenAnim = true; 7425 } 7426 } else if (!fullscreenAnim) { 7427 WindowState ws = wtoken.findMainWindow(); 7428 if (ws != null) { 7429 if (ws.mLayer > bestAnimLayer) { 7430 animLp = ws.mAttrs; 7431 bestAnimLayer = ws.mLayer; 7432 } 7433 } 7434 } 7435 } 7436 7437 if (foundWallpapers == 3) { 7438 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 7439 "Wallpaper animation!"); 7440 switch (transit) { 7441 case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: 7442 case WindowManagerPolicy.TRANSIT_TASK_OPEN: 7443 case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT: 7444 transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN; 7445 break; 7446 case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: 7447 case WindowManagerPolicy.TRANSIT_TASK_CLOSE: 7448 case WindowManagerPolicy.TRANSIT_TASK_TO_BACK: 7449 transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE; 7450 break; 7451 } 7452 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 7453 "New transit: " + transit); 7454 } else if (oldWallpaper != null) { 7455 // We are transitioning from an activity with 7456 // a wallpaper to one without. 7457 transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE; 7458 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 7459 "New transit away from wallpaper: " + transit); 7460 } else if (mWallpaperTarget != null) { 7461 // We are transitioning from an activity without 7462 // a wallpaper to now showing the wallpaper 7463 transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN; 7464 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 7465 "New transit into wallpaper: " + transit); 7466 } 7467 7468 // If all closing windows are obscured, then there is 7469 // no need to do an animation. This is the case, for 7470 // example, when this transition is being done behind 7471 // the lock screen. 7472 if (!mPolicy.allowAppAnimationsLw()) { 7473 animLp = null; 7474 } 7475 7476 NN = mOpeningApps.size(); 7477 for (i=0; i<NN; i++) { 7478 AppWindowToken wtoken = mOpeningApps.get(i); 7479 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 7480 "Now opening app" + wtoken); 7481 wtoken.reportedVisible = false; 7482 wtoken.inPendingTransaction = false; 7483 wtoken.animation = null; 7484 setTokenVisibilityLocked(wtoken, animLp, true, 7485 transit, false); 7486 wtoken.updateReportedVisibilityLocked(); 7487 wtoken.waitingToShow = false; 7488 wtoken.showAllWindowsLocked(); 7489 } 7490 NN = mClosingApps.size(); 7491 for (i=0; i<NN; i++) { 7492 AppWindowToken wtoken = mClosingApps.get(i); 7493 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, 7494 "Now closing app" + wtoken); 7495 wtoken.inPendingTransaction = false; 7496 wtoken.animation = null; 7497 setTokenVisibilityLocked(wtoken, animLp, false, 7498 transit, false); 7499 wtoken.updateReportedVisibilityLocked(); 7500 wtoken.waitingToHide = false; 7501 // Force the allDrawn flag, because we want to start 7502 // this guy's animations regardless of whether it's 7503 // gotten drawn. 7504 wtoken.allDrawn = true; 7505 } 7506 7507 mNextAppTransitionPackage = null; 7508 7509 mOpeningApps.clear(); 7510 mClosingApps.clear(); 7511 7512 // This has changed the visibility of windows, so perform 7513 // a new layout to get them all up-to-date. 7514 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT 7515 | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; 7516 mLayoutNeeded = true; 7517 if (!moveInputMethodWindowsIfNeededLocked(true)) { 7518 assignLayersLocked(); 7519 } 7520 updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, 7521 false /*updateInputWindows*/); 7522 mFocusMayChange = false; 7523 } 7524 } 7525 7526 int adjResult = 0; 7527 7528 if (!animating && mAppTransitionRunning) { 7529 // We have finished the animation of an app transition. To do 7530 // this, we have delayed a lot of operations like showing and 7531 // hiding apps, moving apps in Z-order, etc. The app token list 7532 // reflects the correct Z-order, but the window list may now 7533 // be out of sync with it. So here we will just rebuild the 7534 // entire app window list. Fun! 7535 mAppTransitionRunning = false; 7536 // Clear information about apps that were moving. 7537 mToBottomApps.clear(); 7538 7539 rebuildAppWindowListLocked(); 7540 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; 7541 adjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED; 7542 moveInputMethodWindowsIfNeededLocked(false); 7543 wallpaperMayChange = true; 7544 // Since the window list has been rebuilt, focus might 7545 // have to be recomputed since the actual order of windows 7546 // might have changed again. 7547 mFocusMayChange = true; 7548 } 7549 7550 if (wallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) { 7551 // At this point, there was a window with a wallpaper that 7552 // was force hiding other windows behind it, but now it 7553 // is going away. This may be simple -- just animate 7554 // away the wallpaper and its window -- or it may be 7555 // hard -- the wallpaper now needs to be shown behind 7556 // something that was hidden. 7557 WindowState oldWallpaper = mWallpaperTarget; 7558 if (mLowerWallpaperTarget != null 7559 && mLowerWallpaperTarget.mAppToken != null) { 7560 if (DEBUG_WALLPAPER) Slog.v(TAG, 7561 "wallpaperForceHiding changed with lower=" 7562 + mLowerWallpaperTarget); 7563 if (DEBUG_WALLPAPER) Slog.v(TAG, 7564 "hidden=" + mLowerWallpaperTarget.mAppToken.hidden + 7565 " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested); 7566 if (mLowerWallpaperTarget.mAppToken.hidden) { 7567 // The lower target has become hidden before we 7568 // actually started the animation... let's completely 7569 // re-evaluate everything. 7570 mLowerWallpaperTarget = mUpperWallpaperTarget = null; 7571 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM; 7572 } 7573 } 7574 adjResult |= adjustWallpaperWindowsLocked(); 7575 wallpaperMayChange = false; 7576 wallpaperForceHidingChanged = false; 7577 if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper 7578 + " NEW: " + mWallpaperTarget 7579 + " LOWER: " + mLowerWallpaperTarget); 7580 if (mLowerWallpaperTarget == null) { 7581 // Whoops, we don't need a special wallpaper animation. 7582 // Clear them out. 7583 forceHiding = false; 7584 for (i=N-1; i>=0; i--) { 7585 WindowState w = mWindows.get(i); 7586 if (w.mSurface != null) { 7587 final WindowManager.LayoutParams attrs = w.mAttrs; 7588 if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) { 7589 if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows"); 7590 forceHiding = true; 7591 } else if (mPolicy.canBeForceHidden(w, attrs)) { 7592 if (!w.mAnimating) { 7593 // We set the animation above so it 7594 // is not yet running. 7595 w.clearAnimation(); 7596 } 7597 } 7598 } 7599 } 7600 } 7601 } 7602 7603 if (mWindowDetachedWallpaper != windowDetachedWallpaper) { 7604 if (DEBUG_WALLPAPER) Slog.v(TAG, 7605 "Detached wallpaper changed from " + mWindowDetachedWallpaper 7606 + windowDetachedWallpaper); 7607 mWindowDetachedWallpaper = windowDetachedWallpaper; 7608 wallpaperMayChange = true; 7609 } 7610 7611 if (windowAnimationBackgroundColor != 0) { 7612 if (mWindowAnimationBackgroundSurface == null) { 7613 mWindowAnimationBackgroundSurface = new DimSurface(mFxSession); 7614 } 7615 mWindowAnimationBackgroundSurface.show(dw, dh, 7616 windowAnimationBackground.mAnimLayer - LAYER_OFFSET_DIM, 7617 windowAnimationBackgroundColor); 7618 } else if (mWindowAnimationBackgroundSurface != null) { 7619 mWindowAnimationBackgroundSurface.hide(); 7620 } 7621 7622 if (wallpaperMayChange) { 7623 if (DEBUG_WALLPAPER) Slog.v(TAG, 7624 "Wallpaper may change! Adjusting"); 7625 adjResult |= adjustWallpaperWindowsLocked(); 7626 } 7627 7628 if ((adjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) { 7629 if (DEBUG_WALLPAPER) Slog.v(TAG, 7630 "Wallpaper layer changed: assigning layers + relayout"); 7631 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; 7632 assignLayersLocked(); 7633 } else if ((adjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) { 7634 if (DEBUG_WALLPAPER) Slog.v(TAG, 7635 "Wallpaper visibility changed: relayout"); 7636 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; 7637 } 7638 7639 if (mFocusMayChange) { 7640 mFocusMayChange = false; 7641 if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, 7642 false /*updateInputWindows*/)) { 7643 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM; 7644 adjResult = 0; 7645 } 7646 } 7647 7648 if (mLayoutNeeded) { 7649 changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; 7650 } 7651 7652 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x" 7653 + Integer.toHexString(changes)); 7654 } while (changes != 0); 7655 7656 // THIRD LOOP: Update the surfaces of all windows. 7657 7658 final boolean someoneLosingFocus = mLosingFocus.size() != 0; 7659 7660 boolean obscured = false; 7661 boolean blurring = false; 7662 boolean dimming = false; 7663 boolean covered = false; 7664 boolean syswin = false; 7665 7666 final int N = mWindows.size(); 7667 7668 for (i=N-1; i>=0; i--) { 7669 WindowState w = mWindows.get(i); 7670 7671 boolean displayed = false; 7672 final WindowManager.LayoutParams attrs = w.mAttrs; 7673 final int attrFlags = attrs.flags; 7674 7675 if (w.mSurface != null) { 7676 // XXX NOTE: The logic here could be improved. We have 7677 // the decision about whether to resize a window separated 7678 // from whether to hide the surface. This can cause us to 7679 // resize a surface even if we are going to hide it. You 7680 // can see this by (1) holding device in landscape mode on 7681 // home screen; (2) tapping browser icon (device will rotate 7682 // to landscape; (3) tap home. The wallpaper will be resized 7683 // in step 2 but then immediately hidden, causing us to 7684 // have to resize and then redraw it again in step 3. It 7685 // would be nice to figure out how to avoid this, but it is 7686 // difficult because we do need to resize surfaces in some 7687 // cases while they are hidden such as when first showing a 7688 // window. 7689 7690 w.computeShownFrameLocked(); 7691 if (localLOGV) Slog.v( 7692 TAG, "Placing surface #" + i + " " + w.mSurface 7693 + ": new=" + w.mShownFrame); 7694 7695 int width, height; 7696 if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) { 7697 // for a scaled surface, we just want to use 7698 // the requested size. 7699 width = w.mRequestedWidth; 7700 height = w.mRequestedHeight; 7701 } else { 7702 width = w.mCompatFrame.width(); 7703 height = w.mCompatFrame.height(); 7704 } 7705 7706 if (w.mSurface != null) { 7707 if (w.mSurfaceX != w.mShownFrame.left 7708 || w.mSurfaceY != w.mShownFrame.top) { 7709 try { 7710 if (SHOW_TRANSACTIONS) logSurface(w, 7711 "POS " + w.mShownFrame.left 7712 + ", " + w.mShownFrame.top, null); 7713 w.mSurfaceX = w.mShownFrame.left; 7714 w.mSurfaceY = w.mShownFrame.top; 7715 w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top); 7716 } catch (RuntimeException e) { 7717 Slog.w(TAG, "Error positioning surface of " + w 7718 + " pos=(" + w.mShownFrame.left 7719 + "," + w.mShownFrame.top + ")", e); 7720 if (!recoveringMemory) { 7721 reclaimSomeSurfaceMemoryLocked(w, "position", true); 7722 } 7723 } 7724 } 7725 7726 if (width < 1) { 7727 width = 1; 7728 } 7729 if (height < 1) { 7730 height = 1; 7731 } 7732 7733 if (w.mSurfaceW != width || w.mSurfaceH != height) { 7734 try { 7735 if (SHOW_TRANSACTIONS) logSurface(w, 7736 "SIZE " + w.mShownFrame.width() + "x" 7737 + w.mShownFrame.height(), null); 7738 w.mSurfaceResized = true; 7739 w.mSurfaceW = width; 7740 w.mSurfaceH = height; 7741 w.mSurface.setSize(width, height); 7742 } catch (RuntimeException e) { 7743 // If something goes wrong with the surface (such 7744 // as running out of memory), don't take down the 7745 // entire system. 7746 Slog.e(TAG, "Error resizing surface of " + w 7747 + " size=(" + width + "x" + height + ")", e); 7748 if (!recoveringMemory) { 7749 reclaimSomeSurfaceMemoryLocked(w, "size", true); 7750 } 7751 } 7752 } 7753 } 7754 7755 if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) { 7756 w.mContentInsetsChanged = 7757 !w.mLastContentInsets.equals(w.mContentInsets); 7758 w.mVisibleInsetsChanged = 7759 !w.mLastVisibleInsets.equals(w.mVisibleInsets); 7760 boolean configChanged = 7761 w.mConfiguration != mCurConfiguration 7762 && (w.mConfiguration == null 7763 || mCurConfiguration.diff(w.mConfiguration) != 0); 7764 if (DEBUG_CONFIGURATION && configChanged) { 7765 Slog.v(TAG, "Win " + w + " config changed: " 7766 + mCurConfiguration); 7767 } 7768 if (localLOGV) Slog.v(TAG, "Resizing " + w 7769 + ": configChanged=" + configChanged 7770 + " last=" + w.mLastCompatFrame + " frame=" + w.mCompatFrame); 7771 boolean frameChanged = !w.mLastCompatFrame.equals(w.mCompatFrame); 7772 if (frameChanged 7773 || w.mContentInsetsChanged 7774 || w.mVisibleInsetsChanged 7775 || w.mSurfaceResized 7776 || configChanged) { 7777 if (DEBUG_RESIZE || DEBUG_ORIENTATION) { 7778 Slog.v(TAG, "Resize reasons: " 7779 + "frameChanged=" + frameChanged 7780 + " contentInsetsChanged=" + w.mContentInsetsChanged 7781 + " visibleInsetsChanged=" + w.mVisibleInsetsChanged 7782 + " surfaceResized=" + w.mSurfaceResized 7783 + " configChanged=" + configChanged); 7784 } 7785 7786 w.mLastFrame.set(w.mFrame); 7787 w.mLastCompatFrame.set(w.mCompatFrame); 7788 w.mLastContentInsets.set(w.mContentInsets); 7789 w.mLastVisibleInsets.set(w.mVisibleInsets); 7790 // If the screen is currently frozen, then keep 7791 // it frozen until this window draws at its new 7792 // orientation. 7793 if (mDisplayFrozen) { 7794 if (DEBUG_ORIENTATION) Slog.v(TAG, 7795 "Resizing while display frozen: " + w); 7796 w.mOrientationChanging = true; 7797 if (!mWindowsFreezingScreen) { 7798 mWindowsFreezingScreen = true; 7799 // XXX should probably keep timeout from 7800 // when we first froze the display. 7801 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); 7802 mH.sendMessageDelayed(mH.obtainMessage( 7803 H.WINDOW_FREEZE_TIMEOUT), 2000); 7804 } 7805 } 7806 // If the orientation is changing, then we need to 7807 // hold off on unfreezing the display until this 7808 // window has been redrawn; to do that, we need 7809 // to go through the process of getting informed 7810 // by the application when it has finished drawing. 7811 if (w.mOrientationChanging) { 7812 if (DEBUG_ORIENTATION) Slog.v(TAG, 7813 "Orientation start waiting for draw in " 7814 + w + ", surface " + w.mSurface); 7815 w.mDrawPending = true; 7816 w.mCommitDrawPending = false; 7817 w.mReadyToShow = false; 7818 if (w.mAppToken != null) { 7819 w.mAppToken.allDrawn = false; 7820 } 7821 } 7822 if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, 7823 "Resizing window " + w + " to " + w.mCompatFrame); 7824 mResizingWindows.add(w); 7825 } else if (w.mOrientationChanging) { 7826 if (!w.mDrawPending && !w.mCommitDrawPending) { 7827 if (DEBUG_ORIENTATION) Slog.v(TAG, 7828 "Orientation not waiting for draw in " 7829 + w + ", surface " + w.mSurface); 7830 w.mOrientationChanging = false; 7831 } 7832 } 7833 } 7834 7835 if (w.mAttachedHidden || !w.isReadyForDisplay()) { 7836 if (!w.mLastHidden) { 7837 //dump(); 7838 w.mLastHidden = true; 7839 if (SHOW_TRANSACTIONS) logSurface(w, 7840 "HIDE (performLayout)", null); 7841 if (w.mSurface != null) { 7842 w.mSurfaceShown = false; 7843 try { 7844 w.mSurface.hide(); 7845 } catch (RuntimeException e) { 7846 Slog.w(TAG, "Exception hiding surface in " + w); 7847 } 7848 } 7849 } 7850 // If we are waiting for this window to handle an 7851 // orientation change, well, it is hidden, so 7852 // doesn't really matter. Note that this does 7853 // introduce a potential glitch if the window 7854 // becomes unhidden before it has drawn for the 7855 // new orientation. 7856 if (w.mOrientationChanging) { 7857 w.mOrientationChanging = false; 7858 if (DEBUG_ORIENTATION) Slog.v(TAG, 7859 "Orientation change skips hidden " + w); 7860 } 7861 } else if (w.mLastLayer != w.mAnimLayer 7862 || w.mLastAlpha != w.mShownAlpha 7863 || w.mLastDsDx != w.mDsDx 7864 || w.mLastDtDx != w.mDtDx 7865 || w.mLastDsDy != w.mDsDy 7866 || w.mLastDtDy != w.mDtDy 7867 || w.mLastHScale != w.mHScale 7868 || w.mLastVScale != w.mVScale 7869 || w.mLastHidden) { 7870 displayed = true; 7871 w.mLastAlpha = w.mShownAlpha; 7872 w.mLastLayer = w.mAnimLayer; 7873 w.mLastDsDx = w.mDsDx; 7874 w.mLastDtDx = w.mDtDx; 7875 w.mLastDsDy = w.mDsDy; 7876 w.mLastDtDy = w.mDtDy; 7877 w.mLastHScale = w.mHScale; 7878 w.mLastVScale = w.mVScale; 7879 if (SHOW_TRANSACTIONS) logSurface(w, 7880 "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer 7881 + " matrix=[" + (w.mDsDx*w.mHScale) 7882 + "," + (w.mDtDx*w.mVScale) 7883 + "][" + (w.mDsDy*w.mHScale) 7884 + "," + (w.mDtDy*w.mVScale) + "]", null); 7885 if (w.mSurface != null) { 7886 try { 7887 w.mSurfaceAlpha = w.mShownAlpha; 7888 w.mSurface.setAlpha(w.mShownAlpha); 7889 w.mSurfaceLayer = w.mAnimLayer; 7890 w.mSurface.setLayer(w.mAnimLayer); 7891 w.mSurface.setMatrix( 7892 w.mDsDx*w.mHScale, w.mDtDx*w.mVScale, 7893 w.mDsDy*w.mHScale, w.mDtDy*w.mVScale); 7894 } catch (RuntimeException e) { 7895 Slog.w(TAG, "Error updating surface in " + w, e); 7896 if (!recoveringMemory) { 7897 reclaimSomeSurfaceMemoryLocked(w, "update", true); 7898 } 7899 } 7900 } 7901 7902 if (w.mLastHidden && !w.mDrawPending 7903 && !w.mCommitDrawPending 7904 && !w.mReadyToShow) { 7905 if (SHOW_TRANSACTIONS) logSurface(w, 7906 "SHOW (performLayout)", null); 7907 if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w 7908 + " during relayout"); 7909 if (showSurfaceRobustlyLocked(w)) { 7910 w.mHasDrawn = true; 7911 w.mLastHidden = false; 7912 } else { 7913 w.mOrientationChanging = false; 7914 } 7915 } 7916 if (w.mSurface != null) { 7917 w.mToken.hasVisible = true; 7918 } 7919 } else { 7920 displayed = true; 7921 } 7922 7923 if (displayed) { 7924 if (!covered) { 7925 if (attrs.width == LayoutParams.MATCH_PARENT 7926 && attrs.height == LayoutParams.MATCH_PARENT) { 7927 covered = true; 7928 } 7929 } 7930 if (w.mOrientationChanging) { 7931 if (w.mDrawPending || w.mCommitDrawPending) { 7932 orientationChangeComplete = false; 7933 if (DEBUG_ORIENTATION) Slog.v(TAG, 7934 "Orientation continue waiting for draw in " + w); 7935 } else { 7936 w.mOrientationChanging = false; 7937 if (DEBUG_ORIENTATION) Slog.v(TAG, 7938 "Orientation change complete in " + w); 7939 } 7940 } 7941 w.mToken.hasVisible = true; 7942 } 7943 } else if (w.mOrientationChanging) { 7944 if (DEBUG_ORIENTATION) Slog.v(TAG, 7945 "Orientation change skips hidden " + w); 7946 w.mOrientationChanging = false; 7947 } 7948 7949 if (w.mContentChanged) { 7950 //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing"); 7951 w.mContentChanged = false; 7952 } 7953 7954 final boolean canBeSeen = w.isDisplayedLw(); 7955 7956 if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) { 7957 focusDisplayed = true; 7958 } 7959 7960 final boolean obscuredChanged = w.mObscured != obscured; 7961 7962 // Update effect. 7963 if (!(w.mObscured=obscured)) { 7964 if (w.mSurface != null) { 7965 if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) { 7966 holdScreen = w.mSession; 7967 } 7968 if (!syswin && w.mAttrs.screenBrightness >= 0 7969 && screenBrightness < 0) { 7970 screenBrightness = w.mAttrs.screenBrightness; 7971 } 7972 if (!syswin && w.mAttrs.buttonBrightness >= 0 7973 && buttonBrightness < 0) { 7974 buttonBrightness = w.mAttrs.buttonBrightness; 7975 } 7976 if (canBeSeen 7977 && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG 7978 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD 7979 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) { 7980 syswin = true; 7981 } 7982 } 7983 7984 boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn(); 7985 if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) { 7986 // This window completely covers everything behind it, 7987 // so we want to leave all of them as unblurred (for 7988 // performance reasons). 7989 obscured = true; 7990 } else if (canBeSeen && !obscured && 7991 (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) { 7992 if (localLOGV) Slog.v(TAG, "Win " + w 7993 + ": blurring=" + blurring 7994 + " obscured=" + obscured 7995 + " displayed=" + displayed); 7996 if ((attrFlags&FLAG_DIM_BEHIND) != 0) { 7997 if (!dimming) { 7998 //Slog.i(TAG, "DIM BEHIND: " + w); 7999 dimming = true; 8000 if (mDimAnimator == null) { 8001 mDimAnimator = new DimAnimator(mFxSession); 8002 } 8003 mDimAnimator.show(dw, dh); 8004 mDimAnimator.updateParameters(mContext.getResources(), 8005 w, currentTime); 8006 } 8007 } 8008 if ((attrFlags&FLAG_BLUR_BEHIND) != 0) { 8009 if (!blurring) { 8010 //Slog.i(TAG, "BLUR BEHIND: " + w); 8011 blurring = true; 8012 if (mBlurSurface == null) { 8013 try { 8014 mBlurSurface = new Surface(mFxSession, 0, 8015 "BlurSurface", 8016 -1, 16, 16, 8017 PixelFormat.OPAQUE, 8018 Surface.FX_SURFACE_BLUR); 8019 } catch (Exception e) { 8020 Slog.e(TAG, "Exception creating Blur surface", e); 8021 } 8022 if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " 8023 + mBlurSurface + ": CREATE"); 8024 } 8025 if (mBlurSurface != null) { 8026 if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " 8027 + mBlurSurface + ": pos=(0,0) (" + 8028 dw + "x" + dh + "), layer=" + (w.mAnimLayer-1)); 8029 mBlurSurface.setPosition(0, 0); 8030 mBlurSurface.setSize(dw, dh); 8031 mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR); 8032 if (!mBlurShown) { 8033 try { 8034 if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " 8035 + mBlurSurface + ": SHOW"); 8036 mBlurSurface.show(); 8037 } catch (RuntimeException e) { 8038 Slog.w(TAG, "Failure showing blur surface", e); 8039 } 8040 mBlurShown = true; 8041 } 8042 } 8043 } 8044 } 8045 } 8046 } 8047 8048 if (obscuredChanged && mWallpaperTarget == w) { 8049 // This is the wallpaper target and its obscured state 8050 // changed... make sure the current wallaper's visibility 8051 // has been updated accordingly. 8052 updateWallpaperVisibilityLocked(); 8053 } 8054 } 8055 8056 if (mDimAnimator != null && mDimAnimator.mDimShown) { 8057 animating |= mDimAnimator.updateSurface(dimming, currentTime, 8058 mDisplayFrozen || !mPolicy.isScreenOn()); 8059 } 8060 8061 if (!blurring && mBlurShown) { 8062 if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " + mBlurSurface 8063 + ": HIDE"); 8064 try { 8065 mBlurSurface.hide(); 8066 } catch (IllegalArgumentException e) { 8067 Slog.w(TAG, "Illegal argument exception hiding blur surface"); 8068 } 8069 mBlurShown = false; 8070 } 8071 8072 if (mBlackFrame != null) { 8073 if (mScreenRotationAnimation != null) { 8074 mBlackFrame.setMatrix( 8075 mScreenRotationAnimation.getEnterTransformation().getMatrix()); 8076 } else { 8077 mBlackFrame.clearMatrix(); 8078 } 8079 } 8080 } catch (RuntimeException e) { 8081 Slog.e(TAG, "Unhandled exception in Window Manager", e); 8082 } 8083 8084 Surface.closeTransaction(); 8085 8086 if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces"); 8087 8088 if (mWatermark != null) { 8089 mWatermark.drawIfNeeded(); 8090 } 8091 8092 if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG, 8093 "With display frozen, orientationChangeComplete=" 8094 + orientationChangeComplete); 8095 if (orientationChangeComplete) { 8096 if (mWindowsFreezingScreen) { 8097 mWindowsFreezingScreen = false; 8098 mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT); 8099 } 8100 stopFreezingDisplayLocked(); 8101 } 8102 8103 i = mResizingWindows.size(); 8104 if (i > 0) { 8105 do { 8106 i--; 8107 WindowState win = mResizingWindows.get(i); 8108 try { 8109 if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, 8110 "Reporting new frame to " + win + ": " + win.mCompatFrame); 8111 int diff = 0; 8112 boolean configChanged = 8113 win.mConfiguration != mCurConfiguration 8114 && (win.mConfiguration == null 8115 || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0); 8116 if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) 8117 && configChanged) { 8118 Slog.i(TAG, "Sending new config to window " + win + ": " 8119 + win.mCompatFrame.width() + "x" + win.mCompatFrame.height() 8120 + " / " + mCurConfiguration + " / 0x" 8121 + Integer.toHexString(diff)); 8122 } 8123 win.mConfiguration = mCurConfiguration; 8124 win.mClient.resized(win.mCompatFrame.width(), 8125 win.mCompatFrame.height(), win.mLastContentInsets, 8126 win.mLastVisibleInsets, win.mDrawPending, 8127 configChanged ? win.mConfiguration : null); 8128 win.mContentInsetsChanged = false; 8129 win.mVisibleInsetsChanged = false; 8130 win.mSurfaceResized = false; 8131 } catch (RemoteException e) { 8132 win.mOrientationChanging = false; 8133 } 8134 } while (i > 0); 8135 mResizingWindows.clear(); 8136 } 8137 8138 // Destroy the surface of any windows that are no longer visible. 8139 boolean wallpaperDestroyed = false; 8140 i = mDestroySurface.size(); 8141 if (i > 0) { 8142 do { 8143 i--; 8144 WindowState win = mDestroySurface.get(i); 8145 win.mDestroying = false; 8146 if (mInputMethodWindow == win) { 8147 mInputMethodWindow = null; 8148 } 8149 if (win == mWallpaperTarget) { 8150 wallpaperDestroyed = true; 8151 } 8152 win.destroySurfaceLocked(); 8153 } while (i > 0); 8154 mDestroySurface.clear(); 8155 } 8156 8157 // Time to remove any exiting tokens? 8158 for (i=mExitingTokens.size()-1; i>=0; i--) { 8159 WindowToken token = mExitingTokens.get(i); 8160 if (!token.hasVisible) { 8161 mExitingTokens.remove(i); 8162 if (token.windowType == TYPE_WALLPAPER) { 8163 mWallpaperTokens.remove(token); 8164 } 8165 } 8166 } 8167 8168 // Time to remove any exiting applications? 8169 for (i=mExitingAppTokens.size()-1; i>=0; i--) { 8170 AppWindowToken token = mExitingAppTokens.get(i); 8171 if (!token.hasVisible && !mClosingApps.contains(token)) { 8172 // Make sure there is no animation running on this token, 8173 // so any windows associated with it will be removed as 8174 // soon as their animations are complete 8175 token.animation = null; 8176 token.animating = false; 8177 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, 8178 "performLayout: App token exiting now removed" + token); 8179 mAppTokens.remove(token); 8180 mExitingAppTokens.remove(i); 8181 } 8182 } 8183 8184 boolean needRelayout = false; 8185 8186 if (!animating && mAppTransitionRunning) { 8187 // We have finished the animation of an app transition. To do 8188 // this, we have delayed a lot of operations like showing and 8189 // hiding apps, moving apps in Z-order, etc. The app token list 8190 // reflects the correct Z-order, but the window list may now 8191 // be out of sync with it. So here we will just rebuild the 8192 // entire app window list. Fun! 8193 mAppTransitionRunning = false; 8194 needRelayout = true; 8195 rebuildAppWindowListLocked(); 8196 assignLayersLocked(); 8197 // Clear information about apps that were moving. 8198 mToBottomApps.clear(); 8199 } 8200 8201 if (focusDisplayed) { 8202 mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS); 8203 } 8204 if (wallpaperDestroyed) { 8205 needRelayout = adjustWallpaperWindowsLocked() != 0; 8206 } 8207 if (needRelayout) { 8208 requestAnimationLocked(0); 8209 } else if (animating) { 8210 requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis()); 8211 } 8212 8213 // Finally update all input windows now that the window changes have stabilized. 8214 mInputMonitor.updateInputWindowsLw(true /*force*/); 8215 8216 setHoldScreenLocked(holdScreen != null); 8217 if (!mDisplayFrozen) { 8218 if (screenBrightness < 0 || screenBrightness > 1.0f) { 8219 mPowerManager.setScreenBrightnessOverride(-1); 8220 } else { 8221 mPowerManager.setScreenBrightnessOverride((int) 8222 (screenBrightness * Power.BRIGHTNESS_ON)); 8223 } 8224 if (buttonBrightness < 0 || buttonBrightness > 1.0f) { 8225 mPowerManager.setButtonBrightnessOverride(-1); 8226 } else { 8227 mPowerManager.setButtonBrightnessOverride((int) 8228 (buttonBrightness * Power.BRIGHTNESS_ON)); 8229 } 8230 } 8231 if (holdScreen != mHoldingScreenOn) { 8232 mHoldingScreenOn = holdScreen; 8233 Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen); 8234 mH.sendMessage(m); 8235 } 8236 8237 if (mTurnOnScreen) { 8238 if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!"); 8239 mPowerManager.userActivity(SystemClock.uptimeMillis(), false, 8240 LocalPowerManager.BUTTON_EVENT, true); 8241 mTurnOnScreen = false; 8242 } 8243 8244 if (screenRotationFinished && mScreenRotationAnimation != null) { 8245 mScreenRotationAnimation.kill(); 8246 mScreenRotationAnimation = null; 8247 } 8248 8249 if (updateRotation) { 8250 if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); 8251 boolean changed = setRotationUncheckedLocked( 8252 WindowManagerPolicy.USE_LAST_ROTATION, 0, false); 8253 if (changed) { 8254 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 8255 } 8256 } 8257 8258 // Check to see if we are now in a state where the screen should 8259 // be enabled, because the window obscured flags have changed. 8260 enableScreenIfNeededLocked(); 8261 } 8262 8263 /** 8264 * Must be called with the main window manager lock held. 8265 */ 8266 void setHoldScreenLocked(boolean holding) { 8267 boolean state = mHoldingScreenWakeLock.isHeld(); 8268 if (holding != state) { 8269 if (holding) { 8270 mHoldingScreenWakeLock.acquire(); 8271 } else { 8272 mPolicy.screenOnStoppedLw(); 8273 mHoldingScreenWakeLock.release(); 8274 } 8275 } 8276 } 8277 8278 void requestAnimationLocked(long delay) { 8279 if (!mAnimationPending) { 8280 mAnimationPending = true; 8281 mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay); 8282 } 8283 } 8284 8285 /** 8286 * Have the surface flinger show a surface, robustly dealing with 8287 * error conditions. In particular, if there is not enough memory 8288 * to show the surface, then we will try to get rid of other surfaces 8289 * in order to succeed. 8290 * 8291 * @return Returns true if the surface was successfully shown. 8292 */ 8293 boolean showSurfaceRobustlyLocked(WindowState win) { 8294 try { 8295 if (win.mSurface != null) { 8296 win.mSurfaceShown = true; 8297 win.mSurface.show(); 8298 if (win.mTurnOnScreen) { 8299 if (DEBUG_VISIBILITY) Slog.v(TAG, 8300 "Show surface turning screen on: " + win); 8301 win.mTurnOnScreen = false; 8302 mTurnOnScreen = true; 8303 } 8304 } 8305 return true; 8306 } catch (RuntimeException e) { 8307 Slog.w(TAG, "Failure showing surface " + win.mSurface + " in " + win, e); 8308 } 8309 8310 reclaimSomeSurfaceMemoryLocked(win, "show", true); 8311 8312 return false; 8313 } 8314 8315 boolean reclaimSomeSurfaceMemoryLocked(WindowState win, String operation, boolean secure) { 8316 final Surface surface = win.mSurface; 8317 boolean leakedSurface = false; 8318 boolean killedApps = false; 8319 8320 EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, win.toString(), 8321 win.mSession.mPid, operation); 8322 8323 if (mForceRemoves == null) { 8324 mForceRemoves = new ArrayList<WindowState>(); 8325 } 8326 8327 long callingIdentity = Binder.clearCallingIdentity(); 8328 try { 8329 // There was some problem... first, do a sanity check of the 8330 // window list to make sure we haven't left any dangling surfaces 8331 // around. 8332 int N = mWindows.size(); 8333 Slog.i(TAG, "Out of memory for surface! Looking for leaks..."); 8334 for (int i=0; i<N; i++) { 8335 WindowState ws = mWindows.get(i); 8336 if (ws.mSurface != null) { 8337 if (!mSessions.contains(ws.mSession)) { 8338 Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): " 8339 + ws + " surface=" + ws.mSurface 8340 + " token=" + win.mToken 8341 + " pid=" + ws.mSession.mPid 8342 + " uid=" + ws.mSession.mUid); 8343 if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null); 8344 ws.mSurface.destroy(); 8345 ws.mSurfaceShown = false; 8346 ws.mSurface = null; 8347 mForceRemoves.add(ws); 8348 i--; 8349 N--; 8350 leakedSurface = true; 8351 } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) { 8352 Slog.w(TAG, "LEAKED SURFACE (app token hidden): " 8353 + ws + " surface=" + ws.mSurface 8354 + " token=" + win.mAppToken); 8355 if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null); 8356 ws.mSurface.destroy(); 8357 ws.mSurfaceShown = false; 8358 ws.mSurface = null; 8359 leakedSurface = true; 8360 } 8361 } 8362 } 8363 8364 if (!leakedSurface) { 8365 Slog.w(TAG, "No leaked surfaces; killing applicatons!"); 8366 SparseIntArray pidCandidates = new SparseIntArray(); 8367 for (int i=0; i<N; i++) { 8368 WindowState ws = mWindows.get(i); 8369 if (ws.mSurface != null) { 8370 pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid); 8371 } 8372 } 8373 if (pidCandidates.size() > 0) { 8374 int[] pids = new int[pidCandidates.size()]; 8375 for (int i=0; i<pids.length; i++) { 8376 pids[i] = pidCandidates.keyAt(i); 8377 } 8378 try { 8379 if (mActivityManager.killPids(pids, "Free memory", secure)) { 8380 killedApps = true; 8381 } 8382 } catch (RemoteException e) { 8383 } 8384 } 8385 } 8386 8387 if (leakedSurface || killedApps) { 8388 // We managed to reclaim some memory, so get rid of the trouble 8389 // surface and ask the app to request another one. 8390 Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry."); 8391 if (surface != null) { 8392 if (SHOW_TRANSACTIONS) logSurface(win, "RECOVER DESTROY", null); 8393 surface.destroy(); 8394 win.mSurfaceShown = false; 8395 win.mSurface = null; 8396 } 8397 8398 try { 8399 win.mClient.dispatchGetNewSurface(); 8400 } catch (RemoteException e) { 8401 } 8402 } 8403 } finally { 8404 Binder.restoreCallingIdentity(callingIdentity); 8405 } 8406 8407 return leakedSurface || killedApps; 8408 } 8409 8410 private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) { 8411 WindowState newFocus = computeFocusedWindowLocked(); 8412 if (mCurrentFocus != newFocus) { 8413 // This check makes sure that we don't already have the focus 8414 // change message pending. 8415 mH.removeMessages(H.REPORT_FOCUS_CHANGE); 8416 mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE); 8417 if (localLOGV) Slog.v( 8418 TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus); 8419 final WindowState oldFocus = mCurrentFocus; 8420 mCurrentFocus = newFocus; 8421 mLosingFocus.remove(newFocus); 8422 8423 final WindowState imWindow = mInputMethodWindow; 8424 if (newFocus != imWindow && oldFocus != imWindow) { 8425 if (moveInputMethodWindowsIfNeededLocked( 8426 mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS && 8427 mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) { 8428 mLayoutNeeded = true; 8429 } 8430 if (mode == UPDATE_FOCUS_PLACING_SURFACES) { 8431 performLayoutLockedInner(true /*initial*/, updateInputWindows); 8432 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) { 8433 // Client will do the layout, but we need to assign layers 8434 // for handleNewWindowLocked() below. 8435 assignLayersLocked(); 8436 } 8437 } 8438 8439 if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) { 8440 // If we defer assigning layers, then the caller is responsible for 8441 // doing this part. 8442 finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows); 8443 } 8444 return true; 8445 } 8446 return false; 8447 } 8448 8449 private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) { 8450 mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows); 8451 } 8452 8453 private WindowState computeFocusedWindowLocked() { 8454 WindowState result = null; 8455 WindowState win; 8456 8457 int i = mWindows.size() - 1; 8458 int nextAppIndex = mAppTokens.size()-1; 8459 WindowToken nextApp = nextAppIndex >= 0 8460 ? mAppTokens.get(nextAppIndex) : null; 8461 8462 while (i >= 0) { 8463 win = mWindows.get(i); 8464 8465 if (localLOGV || DEBUG_FOCUS) Slog.v( 8466 TAG, "Looking for focus: " + i 8467 + " = " + win 8468 + ", flags=" + win.mAttrs.flags 8469 + ", canReceive=" + win.canReceiveKeys()); 8470 8471 AppWindowToken thisApp = win.mAppToken; 8472 8473 // If this window's application has been removed, just skip it. 8474 if (thisApp != null && thisApp.removed) { 8475 i--; 8476 continue; 8477 } 8478 8479 // If there is a focused app, don't allow focus to go to any 8480 // windows below it. If this is an application window, step 8481 // through the app tokens until we find its app. 8482 if (thisApp != null && nextApp != null && thisApp != nextApp 8483 && win.mAttrs.type != TYPE_APPLICATION_STARTING) { 8484 int origAppIndex = nextAppIndex; 8485 while (nextAppIndex > 0) { 8486 if (nextApp == mFocusedApp) { 8487 // Whoops, we are below the focused app... no focus 8488 // for you! 8489 if (localLOGV || DEBUG_FOCUS) Slog.v( 8490 TAG, "Reached focused app: " + mFocusedApp); 8491 return null; 8492 } 8493 nextAppIndex--; 8494 nextApp = mAppTokens.get(nextAppIndex); 8495 if (nextApp == thisApp) { 8496 break; 8497 } 8498 } 8499 if (thisApp != nextApp) { 8500 // Uh oh, the app token doesn't exist! This shouldn't 8501 // happen, but if it does we can get totally hosed... 8502 // so restart at the original app. 8503 nextAppIndex = origAppIndex; 8504 nextApp = mAppTokens.get(nextAppIndex); 8505 } 8506 } 8507 8508 // Dispatch to this window if it is wants key events. 8509 if (win.canReceiveKeys()) { 8510 if (DEBUG_FOCUS) Slog.v( 8511 TAG, "Found focus @ " + i + " = " + win); 8512 result = win; 8513 break; 8514 } 8515 8516 i--; 8517 } 8518 8519 return result; 8520 } 8521 8522 private void startFreezingDisplayLocked(boolean inTransaction) { 8523 if (mDisplayFrozen) { 8524 return; 8525 } 8526 8527 mScreenFrozenLock.acquire(); 8528 8529 long now = SystemClock.uptimeMillis(); 8530 //Slog.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now); 8531 if (mFreezeGcPending != 0) { 8532 if (now > (mFreezeGcPending+1000)) { 8533 //Slog.i(TAG, "Gc! " + now + " > " + (mFreezeGcPending+1000)); 8534 mH.removeMessages(H.FORCE_GC); 8535 Runtime.getRuntime().gc(); 8536 mFreezeGcPending = now; 8537 } 8538 } else { 8539 mFreezeGcPending = now; 8540 } 8541 8542 mDisplayFrozen = true; 8543 8544 mInputMonitor.freezeInputDispatchingLw(); 8545 8546 if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { 8547 mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET; 8548 mNextAppTransitionPackage = null; 8549 mAppTransitionReady = true; 8550 } 8551 8552 if (PROFILE_ORIENTATION) { 8553 File file = new File("/data/system/frozen"); 8554 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024); 8555 } 8556 8557 if (CUSTOM_SCREEN_ROTATION) { 8558 if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) { 8559 mScreenRotationAnimation.kill(); 8560 mScreenRotationAnimation = null; 8561 } 8562 if (mScreenRotationAnimation == null) { 8563 mScreenRotationAnimation = new ScreenRotationAnimation(mContext, 8564 mDisplay, mFxSession, inTransaction); 8565 } 8566 if (!mScreenRotationAnimation.hasScreenshot()) { 8567 Surface.freezeDisplay(0); 8568 } 8569 } else { 8570 Surface.freezeDisplay(0); 8571 } 8572 } 8573 8574 private void stopFreezingDisplayLocked() { 8575 if (!mDisplayFrozen) { 8576 return; 8577 } 8578 8579 if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) { 8580 return; 8581 } 8582 8583 mDisplayFrozen = false; 8584 mH.removeMessages(H.APP_FREEZE_TIMEOUT); 8585 if (PROFILE_ORIENTATION) { 8586 Debug.stopMethodTracing(); 8587 } 8588 8589 boolean updateRotation = false; 8590 8591 if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null 8592 && mScreenRotationAnimation.hasScreenshot()) { 8593 if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION, 8594 mTransitionAnimationScale)) { 8595 requestAnimationLocked(0); 8596 } else { 8597 mScreenRotationAnimation = null; 8598 updateRotation = true; 8599 } 8600 } else { 8601 if (mScreenRotationAnimation != null) { 8602 mScreenRotationAnimation.kill(); 8603 mScreenRotationAnimation = null; 8604 } 8605 updateRotation = true; 8606 Surface.unfreezeDisplay(0); 8607 } 8608 8609 mInputMonitor.thawInputDispatchingLw(); 8610 8611 boolean configChanged; 8612 8613 // While the display is frozen we don't re-compute the orientation 8614 // to avoid inconsistent states. However, something interesting 8615 // could have actually changed during that time so re-evaluate it 8616 // now to catch that. 8617 configChanged = updateOrientationFromAppTokensLocked(false); 8618 8619 // A little kludge: a lot could have happened while the 8620 // display was frozen, so now that we are coming back we 8621 // do a gc so that any remote references the system 8622 // processes holds on others can be released if they are 8623 // no longer needed. 8624 mH.removeMessages(H.FORCE_GC); 8625 mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC), 8626 2000); 8627 8628 mScreenFrozenLock.release(); 8629 8630 if (updateRotation) { 8631 if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation"); 8632 configChanged |= setRotationUncheckedLocked( 8633 WindowManagerPolicy.USE_LAST_ROTATION, 0, false); 8634 } 8635 8636 if (configChanged) { 8637 mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); 8638 } 8639 } 8640 8641 static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps, 8642 DisplayMetrics dm) { 8643 if (index < tokens.length) { 8644 String str = tokens[index]; 8645 if (str != null && str.length() > 0) { 8646 try { 8647 int val = Integer.parseInt(str); 8648 return val; 8649 } catch (Exception e) { 8650 } 8651 } 8652 } 8653 if (defUnits == TypedValue.COMPLEX_UNIT_PX) { 8654 return defDps; 8655 } 8656 int val = (int)TypedValue.applyDimension(defUnits, defDps, dm); 8657 return val; 8658 } 8659 8660 void createWatermark() { 8661 if (mWatermark != null) { 8662 return; 8663 } 8664 8665 File file = new File("/system/etc/setup.conf"); 8666 FileInputStream in = null; 8667 try { 8668 in = new FileInputStream(file); 8669 DataInputStream ind = new DataInputStream(in); 8670 String line = ind.readLine(); 8671 if (line != null) { 8672 String[] toks = line.split("%"); 8673 if (toks != null && toks.length > 0) { 8674 mWatermark = new Watermark(mDisplay, mFxSession, toks); 8675 } 8676 } 8677 } catch (FileNotFoundException e) { 8678 } catch (IOException e) { 8679 } finally { 8680 if (in != null) { 8681 try { 8682 in.close(); 8683 } catch (IOException e) { 8684 } 8685 } 8686 } 8687 } 8688 8689 @Override 8690 public void statusBarVisibilityChanged(int visibility) { 8691 mInputManager.setSystemUiVisibility(visibility); 8692 synchronized (mWindowMap) { 8693 final int N = mWindows.size(); 8694 for (int i = 0; i < N; i++) { 8695 WindowState ws = mWindows.get(i); 8696 try { 8697 if (ws.getAttrs().hasSystemUiListeners) { 8698 ws.mClient.dispatchSystemUiVisibilityChanged(visibility); 8699 } 8700 } catch (RemoteException e) { 8701 // so sorry 8702 } 8703 } 8704 } 8705 } 8706 8707 @Override 8708 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 8709 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP") 8710 != PackageManager.PERMISSION_GRANTED) { 8711 pw.println("Permission Denial: can't dump WindowManager from from pid=" 8712 + Binder.getCallingPid() 8713 + ", uid=" + Binder.getCallingUid()); 8714 return; 8715 } 8716 8717 mInputManager.dump(pw); 8718 pw.println(" "); 8719 8720 synchronized(mWindowMap) { 8721 pw.println("Current Window Manager state:"); 8722 for (int i=mWindows.size()-1; i>=0; i--) { 8723 WindowState w = mWindows.get(i); 8724 pw.print(" Window #"); pw.print(i); pw.print(' '); 8725 pw.print(w); pw.println(":"); 8726 w.dump(pw, " "); 8727 } 8728 if (mInputMethodDialogs.size() > 0) { 8729 pw.println(" "); 8730 pw.println(" Input method dialogs:"); 8731 for (int i=mInputMethodDialogs.size()-1; i>=0; i--) { 8732 WindowState w = mInputMethodDialogs.get(i); 8733 pw.print(" IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w); 8734 } 8735 } 8736 if (mPendingRemove.size() > 0) { 8737 pw.println(" "); 8738 pw.println(" Remove pending for:"); 8739 for (int i=mPendingRemove.size()-1; i>=0; i--) { 8740 WindowState w = mPendingRemove.get(i); 8741 pw.print(" Remove #"); pw.print(i); pw.print(' '); 8742 pw.print(w); pw.println(":"); 8743 w.dump(pw, " "); 8744 } 8745 } 8746 if (mForceRemoves != null && mForceRemoves.size() > 0) { 8747 pw.println(" "); 8748 pw.println(" Windows force removing:"); 8749 for (int i=mForceRemoves.size()-1; i>=0; i--) { 8750 WindowState w = mForceRemoves.get(i); 8751 pw.print(" Removing #"); pw.print(i); pw.print(' '); 8752 pw.print(w); pw.println(":"); 8753 w.dump(pw, " "); 8754 } 8755 } 8756 if (mDestroySurface.size() > 0) { 8757 pw.println(" "); 8758 pw.println(" Windows waiting to destroy their surface:"); 8759 for (int i=mDestroySurface.size()-1; i>=0; i--) { 8760 WindowState w = mDestroySurface.get(i); 8761 pw.print(" Destroy #"); pw.print(i); pw.print(' '); 8762 pw.print(w); pw.println(":"); 8763 w.dump(pw, " "); 8764 } 8765 } 8766 if (mLosingFocus.size() > 0) { 8767 pw.println(" "); 8768 pw.println(" Windows losing focus:"); 8769 for (int i=mLosingFocus.size()-1; i>=0; i--) { 8770 WindowState w = mLosingFocus.get(i); 8771 pw.print(" Losing #"); pw.print(i); pw.print(' '); 8772 pw.print(w); pw.println(":"); 8773 w.dump(pw, " "); 8774 } 8775 } 8776 if (mResizingWindows.size() > 0) { 8777 pw.println(" "); 8778 pw.println(" Windows waiting to resize:"); 8779 for (int i=mResizingWindows.size()-1; i>=0; i--) { 8780 WindowState w = mResizingWindows.get(i); 8781 pw.print(" Resizing #"); pw.print(i); pw.print(' '); 8782 pw.print(w); pw.println(":"); 8783 w.dump(pw, " "); 8784 } 8785 } 8786 if (mSessions.size() > 0) { 8787 pw.println(" "); 8788 pw.println(" All active sessions:"); 8789 Iterator<Session> it = mSessions.iterator(); 8790 while (it.hasNext()) { 8791 Session s = it.next(); 8792 pw.print(" Session "); pw.print(s); pw.println(':'); 8793 s.dump(pw, " "); 8794 } 8795 } 8796 if (mTokenMap.size() > 0) { 8797 pw.println(" "); 8798 pw.println(" All tokens:"); 8799 Iterator<WindowToken> it = mTokenMap.values().iterator(); 8800 while (it.hasNext()) { 8801 WindowToken token = it.next(); 8802 pw.print(" Token "); pw.print(token.token); pw.println(':'); 8803 token.dump(pw, " "); 8804 } 8805 } 8806 if (mWallpaperTokens.size() > 0) { 8807 pw.println(" "); 8808 pw.println(" Wallpaper tokens:"); 8809 for (int i=mWallpaperTokens.size()-1; i>=0; i--) { 8810 WindowToken token = mWallpaperTokens.get(i); 8811 pw.print(" Wallpaper #"); pw.print(i); 8812 pw.print(' '); pw.print(token); pw.println(':'); 8813 token.dump(pw, " "); 8814 } 8815 } 8816 if (mAppTokens.size() > 0) { 8817 pw.println(" "); 8818 pw.println(" Application tokens in Z order:"); 8819 for (int i=mAppTokens.size()-1; i>=0; i--) { 8820 pw.print(" App #"); pw.print(i); pw.print(": "); 8821 pw.println(mAppTokens.get(i)); 8822 } 8823 } 8824 if (mFinishedStarting.size() > 0) { 8825 pw.println(" "); 8826 pw.println(" Finishing start of application tokens:"); 8827 for (int i=mFinishedStarting.size()-1; i>=0; i--) { 8828 WindowToken token = mFinishedStarting.get(i); 8829 pw.print(" Finished Starting #"); pw.print(i); 8830 pw.print(' '); pw.print(token); pw.println(':'); 8831 token.dump(pw, " "); 8832 } 8833 } 8834 if (mExitingTokens.size() > 0) { 8835 pw.println(" "); 8836 pw.println(" Exiting tokens:"); 8837 for (int i=mExitingTokens.size()-1; i>=0; i--) { 8838 WindowToken token = mExitingTokens.get(i); 8839 pw.print(" Exiting #"); pw.print(i); 8840 pw.print(' '); pw.print(token); pw.println(':'); 8841 token.dump(pw, " "); 8842 } 8843 } 8844 if (mExitingAppTokens.size() > 0) { 8845 pw.println(" "); 8846 pw.println(" Exiting application tokens:"); 8847 for (int i=mExitingAppTokens.size()-1; i>=0; i--) { 8848 WindowToken token = mExitingAppTokens.get(i); 8849 pw.print(" Exiting App #"); pw.print(i); 8850 pw.print(' '); pw.print(token); pw.println(':'); 8851 token.dump(pw, " "); 8852 } 8853 } 8854 pw.println(" "); 8855 pw.print(" mCurrentFocus="); pw.println(mCurrentFocus); 8856 pw.print(" mLastFocus="); pw.println(mLastFocus); 8857 pw.print(" mFocusedApp="); pw.println(mFocusedApp); 8858 pw.print(" mInputMethodTarget="); pw.println(mInputMethodTarget); 8859 pw.print(" mInputMethodWindow="); pw.println(mInputMethodWindow); 8860 pw.print(" mWallpaperTarget="); pw.println(mWallpaperTarget); 8861 if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) { 8862 pw.print(" mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget); 8863 pw.print(" mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget); 8864 } 8865 if (mWindowDetachedWallpaper != null) { 8866 pw.print(" mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper); 8867 } 8868 if (mWindowAnimationBackgroundSurface != null) { 8869 pw.println(" mWindowAnimationBackgroundSurface:"); 8870 mWindowAnimationBackgroundSurface.printTo(" ", pw); 8871 } 8872 pw.print(" mCurConfiguration="); pw.println(this.mCurConfiguration); 8873 pw.print(" mInTouchMode="); pw.print(mInTouchMode); 8874 pw.print(" mLayoutSeq="); pw.println(mLayoutSeq); 8875 pw.print(" mSystemBooted="); pw.print(mSystemBooted); 8876 pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled); 8877 pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded); 8878 pw.print(" mBlurShown="); pw.println(mBlurShown); 8879 if (mDimAnimator != null) { 8880 pw.println(" mDimAnimator:"); 8881 mDimAnimator.printTo(" ", pw); 8882 } else { 8883 pw.println( " no DimAnimator "); 8884 } 8885 pw.print(" mInputMethodAnimLayerAdjustment="); 8886 pw.print(mInputMethodAnimLayerAdjustment); 8887 pw.print(" mWallpaperAnimLayerAdjustment="); 8888 pw.println(mWallpaperAnimLayerAdjustment); 8889 pw.print(" mLastWallpaperX="); pw.print(mLastWallpaperX); 8890 pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY); 8891 pw.print(" mDisplayFrozen="); pw.print(mDisplayFrozen); 8892 pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen); 8893 pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen); 8894 pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig); 8895 pw.print(" mRotation="); pw.print(mRotation); 8896 pw.print(" mForcedAppOrientation="); pw.print(mForcedAppOrientation); 8897 pw.print(" mRequestedRotation="); pw.print(mRequestedRotation); 8898 pw.print(" mAltOrientation="); pw.println(mAltOrientation); 8899 pw.print(" mDeferredRotation="); pw.print(mDeferredRotation); 8900 pw.print(", mDeferredRotationAnimFlags="); pw.println(mDeferredRotationAnimFlags); 8901 pw.print(" mAnimationPending="); pw.print(mAnimationPending); 8902 pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale); 8903 pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale); 8904 pw.print(" mNextAppTransition=0x"); 8905 pw.print(Integer.toHexString(mNextAppTransition)); 8906 pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady); 8907 pw.print(" mAppTransitionRunning="); pw.print(mAppTransitionRunning); 8908 pw.print(" mAppTransitionTimeout="); pw.println( mAppTransitionTimeout); 8909 if (mNextAppTransitionPackage != null) { 8910 pw.print(" mNextAppTransitionPackage="); 8911 pw.print(mNextAppTransitionPackage); 8912 pw.print(" mNextAppTransitionEnter=0x"); 8913 pw.print(Integer.toHexString(mNextAppTransitionEnter)); 8914 pw.print(" mNextAppTransitionExit=0x"); 8915 pw.print(Integer.toHexString(mNextAppTransitionExit)); 8916 } 8917 pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition); 8918 pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation); 8919 if (mOpeningApps.size() > 0) { 8920 pw.print(" mOpeningApps="); pw.println(mOpeningApps); 8921 } 8922 if (mClosingApps.size() > 0) { 8923 pw.print(" mClosingApps="); pw.println(mClosingApps); 8924 } 8925 if (mToTopApps.size() > 0) { 8926 pw.print(" mToTopApps="); pw.println(mToTopApps); 8927 } 8928 if (mToBottomApps.size() > 0) { 8929 pw.print(" mToBottomApps="); pw.println(mToBottomApps); 8930 } 8931 if (mDisplay != null) { 8932 pw.print(" Display: init="); pw.print(mInitialDisplayWidth); pw.print("x"); 8933 pw.print(mInitialDisplayHeight); pw.print(" base="); 8934 pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight); 8935 pw.print(" cur="); 8936 pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight); 8937 pw.print(" real="); pw.print(mDisplay.getRealWidth()); 8938 pw.print("x"); pw.print(mDisplay.getRealHeight()); 8939 pw.print(" raw="); pw.print(mDisplay.getRawWidth()); 8940 pw.print("x"); pw.println(mDisplay.getRawHeight()); 8941 } else { 8942 pw.println(" NO DISPLAY"); 8943 } 8944 pw.println(" Policy:"); 8945 mPolicy.dump(" ", fd, pw, args); 8946 } 8947 } 8948 8949 // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection). 8950 public void monitor() { 8951 synchronized (mWindowMap) { } 8952 synchronized (mKeyguardTokenWatcher) { } 8953 } 8954 8955 public interface OnHardKeyboardStatusChangeListener { 8956 public void onHardKeyboardStatusChange(boolean available, boolean enabled); 8957 } 8958} 8959