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