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