WindowManagerService.java revision 738cfc91053fc888397ec2d139e0798f8c95b3ca
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        mResizingWindows.remove(win);
2424        mWindowsChanged = true;
2425        if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win);
2426
2427        if (mInputMethodWindow == win) {
2428            mInputMethodWindow = null;
2429        } else if (win.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
2430            mInputMethodDialogs.remove(win);
2431        }
2432
2433        final WindowToken token = win.mToken;
2434        final AppWindowToken atoken = win.mAppToken;
2435        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing " + win + " from " + token);
2436        token.windows.remove(win);
2437        if (atoken != null) {
2438            atoken.allAppWindows.remove(win);
2439        }
2440        if (localLOGV) Slog.v(
2441                TAG, "**** Removing window " + win + ": count="
2442                + token.windows.size());
2443        if (token.windows.size() == 0) {
2444            if (!token.explicit) {
2445                mTokenMap.remove(token.token);
2446            } else if (atoken != null) {
2447                atoken.firstWindowDrawn = false;
2448            }
2449        }
2450
2451        if (atoken != null) {
2452            if (atoken.startingWindow == win) {
2453                if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Nulling startingWindow " + win);
2454                atoken.startingWindow = null;
2455            } else if (atoken.allAppWindows.size() == 0 && atoken.startingData != null) {
2456                // If this is the last window and we had requested a starting
2457                // transition window, well there is no point now.
2458                if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Nulling last startingWindow");
2459                atoken.startingData = null;
2460            } else if (atoken.allAppWindows.size() == 1 && atoken.startingView != null) {
2461                // If this is the last window except for a starting transition
2462                // window, we need to get rid of the starting transition.
2463                if (DEBUG_STARTING_WINDOW) {
2464                    Slog.v(TAG, "Schedule remove starting " + token
2465                            + ": no more real windows");
2466                }
2467                Message m = mH.obtainMessage(H.REMOVE_STARTING, atoken);
2468                mH.sendMessage(m);
2469            }
2470        }
2471
2472        if (win.mAttrs.type == TYPE_WALLPAPER) {
2473            mLastWallpaperTimeoutTime = 0;
2474            adjustWallpaperWindowsLocked();
2475        } else if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
2476            adjustWallpaperWindowsLocked();
2477        }
2478
2479        if (!mInLayout) {
2480            assignLayersLocked(windows);
2481            win.mDisplayContent.layoutNeeded = true;
2482            performLayoutAndPlaceSurfacesLocked();
2483            if (win.mAppToken != null) {
2484                win.mAppToken.updateReportedVisibilityLocked();
2485            }
2486        }
2487
2488        mInputMonitor.updateInputWindowsLw(true /*force*/);
2489    }
2490
2491    static void logSurface(WindowState w, String msg, RuntimeException where) {
2492        String str = "  SURFACE " + msg + ": " + w;
2493        if (where != null) {
2494            Slog.i(TAG, str, where);
2495        } else {
2496            Slog.i(TAG, str);
2497        }
2498    }
2499
2500    static void logSurface(Surface s, String title, String msg, RuntimeException where) {
2501        String str = "  SURFACE " + s + ": " + msg + " / " + title;
2502        if (where != null) {
2503            Slog.i(TAG, str, where);
2504        } else {
2505            Slog.i(TAG, str);
2506        }
2507    }
2508
2509    // TODO(cmautner): Move to WindowStateAnimator.
2510    void setTransparentRegionHint(final WindowStateAnimator winAnimator, final Region region) {
2511        mH.sendMessage(mH.obtainMessage(H.SET_TRANSPARENT_REGION,
2512                new Pair<WindowStateAnimator, Region>(winAnimator, region)));
2513    }
2514
2515    void setTransparentRegionWindow(Session session, IWindow client, Region region) {
2516        long origId = Binder.clearCallingIdentity();
2517        try {
2518            synchronized (mWindowMap) {
2519                WindowState w = windowForClientLocked(session, client, false);
2520                if ((w != null) && w.mHasSurface) {
2521                    setTransparentRegionHint(w.mWinAnimator, region);
2522                }
2523            }
2524        } finally {
2525            Binder.restoreCallingIdentity(origId);
2526        }
2527    }
2528
2529    void setInsetsWindow(Session session, IWindow client,
2530            int touchableInsets, Rect contentInsets,
2531            Rect visibleInsets, Region touchableRegion) {
2532        long origId = Binder.clearCallingIdentity();
2533        try {
2534            synchronized (mWindowMap) {
2535                WindowState w = windowForClientLocked(session, client, false);
2536                if (w != null) {
2537                    w.mGivenInsetsPending = false;
2538                    w.mGivenContentInsets.set(contentInsets);
2539                    w.mGivenVisibleInsets.set(visibleInsets);
2540                    w.mGivenTouchableRegion.set(touchableRegion);
2541                    w.mTouchableInsets = touchableInsets;
2542                    if (w.mGlobalScale != 1) {
2543                        w.mGivenContentInsets.scale(w.mGlobalScale);
2544                        w.mGivenVisibleInsets.scale(w.mGlobalScale);
2545                        w.mGivenTouchableRegion.scale(w.mGlobalScale);
2546                    }
2547                    w.mDisplayContent.layoutNeeded = true;
2548                    performLayoutAndPlaceSurfacesLocked();
2549                }
2550            }
2551        } finally {
2552            Binder.restoreCallingIdentity(origId);
2553        }
2554    }
2555
2556    public void getWindowDisplayFrame(Session session, IWindow client,
2557            Rect outDisplayFrame) {
2558        synchronized(mWindowMap) {
2559            WindowState win = windowForClientLocked(session, client, false);
2560            if (win == null) {
2561                outDisplayFrame.setEmpty();
2562                return;
2563            }
2564            outDisplayFrame.set(win.mDisplayFrame);
2565        }
2566    }
2567
2568    public void setWindowWallpaperPositionLocked(WindowState window, float x, float y,
2569            float xStep, float yStep) {
2570        if (window.mWallpaperX != x || window.mWallpaperY != y)  {
2571            window.mWallpaperX = x;
2572            window.mWallpaperY = y;
2573            window.mWallpaperXStep = xStep;
2574            window.mWallpaperYStep = yStep;
2575            updateWallpaperOffsetLocked(window, true);
2576        }
2577    }
2578
2579    void wallpaperCommandComplete(IBinder window, Bundle result) {
2580        synchronized (mWindowMap) {
2581            if (mWaitingOnWallpaper != null &&
2582                    mWaitingOnWallpaper.mClient.asBinder() == window) {
2583                mWaitingOnWallpaper = null;
2584                mWindowMap.notifyAll();
2585            }
2586        }
2587    }
2588
2589    public Bundle sendWindowWallpaperCommandLocked(WindowState window,
2590            String action, int x, int y, int z, Bundle extras, boolean sync) {
2591        if (window == mWallpaperTarget || window == mLowerWallpaperTarget
2592                || window == mUpperWallpaperTarget) {
2593            boolean doWait = sync;
2594            int curTokenIndex = mWallpaperTokens.size();
2595            while (curTokenIndex > 0) {
2596                curTokenIndex--;
2597                WindowToken token = mWallpaperTokens.get(curTokenIndex);
2598                int curWallpaperIndex = token.windows.size();
2599                while (curWallpaperIndex > 0) {
2600                    curWallpaperIndex--;
2601                    WindowState wallpaper = token.windows.get(curWallpaperIndex);
2602                    try {
2603                        wallpaper.mClient.dispatchWallpaperCommand(action,
2604                                x, y, z, extras, sync);
2605                        // We only want to be synchronous with one wallpaper.
2606                        sync = false;
2607                    } catch (RemoteException e) {
2608                    }
2609                }
2610            }
2611
2612            if (doWait) {
2613                // XXX Need to wait for result.
2614            }
2615        }
2616
2617        return null;
2618    }
2619
2620    public void setUniverseTransformLocked(WindowState window, float alpha,
2621            float offx, float offy, float dsdx, float dtdx, float dsdy, float dtdy) {
2622        Transformation transform = window.mWinAnimator.mUniverseTransform;
2623        transform.setAlpha(alpha);
2624        Matrix matrix = transform.getMatrix();
2625        matrix.getValues(mTmpFloats);
2626        mTmpFloats[Matrix.MTRANS_X] = offx;
2627        mTmpFloats[Matrix.MTRANS_Y] = offy;
2628        mTmpFloats[Matrix.MSCALE_X] = dsdx;
2629        mTmpFloats[Matrix.MSKEW_Y] = dtdx;
2630        mTmpFloats[Matrix.MSKEW_X] = dsdy;
2631        mTmpFloats[Matrix.MSCALE_Y] = dtdy;
2632        matrix.setValues(mTmpFloats);
2633        final DisplayInfo displayInfo = window.mDisplayContent.getDisplayInfo();
2634        final RectF dispRect = new RectF(0, 0,
2635                displayInfo.logicalWidth, displayInfo.logicalHeight);
2636        matrix.mapRect(dispRect);
2637        window.mGivenTouchableRegion.set(0, 0,
2638                displayInfo.logicalWidth, displayInfo.logicalHeight);
2639        window.mGivenTouchableRegion.op((int)dispRect.left, (int)dispRect.top,
2640                (int)dispRect.right, (int)dispRect.bottom, Region.Op.DIFFERENCE);
2641        window.mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION;
2642        window.mDisplayContent.layoutNeeded = true;
2643        performLayoutAndPlaceSurfacesLocked();
2644    }
2645
2646    public void onRectangleOnScreenRequested(IBinder token, Rect rectangle, boolean immediate) {
2647        synchronized (mWindowMap) {
2648            WindowState window = mWindowMap.get(token);
2649            if (window != null) {
2650                scheduleNotifyRectangleOnScreenRequestedIfNeededLocked(window, rectangle,
2651                        immediate);
2652            }
2653        }
2654    }
2655
2656    private void scheduleNotifyRectangleOnScreenRequestedIfNeededLocked(WindowState window,
2657            Rect rectangle, boolean immediate) {
2658        DisplayContent displayContent = window.mDisplayContent;
2659        if (displayContent.mDisplayContentChangeListeners != null
2660                && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) {
2661            mH.obtainMessage(H.NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED, displayContent.getDisplayId(),
2662                    immediate? 1 : 0, new Rect(rectangle)).sendToTarget();
2663        }
2664    }
2665
2666    private void handleNotifyRectangleOnScreenRequested(int displayId, Rect rectangle,
2667            boolean immediate) {
2668        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
2669        synchronized (mWindowMap) {
2670            DisplayContent displayContent = getDisplayContentLocked(displayId);
2671            if (displayContent == null) {
2672                return;
2673            }
2674            callbacks = displayContent.mDisplayContentChangeListeners;
2675            if (callbacks == null) {
2676                return;
2677            }
2678        }
2679        final int callbackCount = callbacks.beginBroadcast();
2680        try {
2681            for (int i = 0; i < callbackCount; i++) {
2682                try {
2683                    callbacks.getBroadcastItem(i).onRectangleOnScreenRequested(displayId,
2684                            rectangle, immediate);
2685                } catch (RemoteException re) {
2686                    /* ignore */
2687                }
2688            }
2689        } finally {
2690            callbacks.finishBroadcast();
2691        }
2692    }
2693
2694    public int relayoutWindow(Session session, IWindow client, int seq,
2695            WindowManager.LayoutParams attrs, int requestedWidth,
2696            int requestedHeight, int viewVisibility, int flags,
2697            Rect outFrame, Rect outContentInsets,
2698            Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
2699        boolean toBeDisplayed = false;
2700        boolean inTouchMode;
2701        boolean configChanged;
2702        boolean surfaceChanged = false;
2703        boolean animating;
2704
2705        // if they don't have this permission, mask out the status bar bits
2706        int systemUiVisibility = 0;
2707        if (attrs != null) {
2708            systemUiVisibility = (attrs.systemUiVisibility|attrs.subtreeSystemUiVisibility);
2709            if ((systemUiVisibility & StatusBarManager.DISABLE_MASK) != 0) {
2710                if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
2711                        != PackageManager.PERMISSION_GRANTED) {
2712                    systemUiVisibility &= ~StatusBarManager.DISABLE_MASK;
2713                }
2714            }
2715        }
2716        long origId = Binder.clearCallingIdentity();
2717
2718        synchronized(mWindowMap) {
2719            // TODO(cmautner): synchronize on mAnimator or win.mWinAnimator.
2720            WindowState win = windowForClientLocked(session, client, false);
2721            if (win == null) {
2722                return 0;
2723            }
2724            WindowStateAnimator winAnimator = win.mWinAnimator;
2725            if (win.mRequestedWidth != requestedWidth
2726                    || win.mRequestedHeight != requestedHeight) {
2727                win.mLayoutNeeded = true;
2728                win.mRequestedWidth = requestedWidth;
2729                win.mRequestedHeight = requestedHeight;
2730            }
2731            if (attrs != null && seq == win.mSeq) {
2732                win.mSystemUiVisibility = systemUiVisibility;
2733            }
2734
2735            if (attrs != null) {
2736                mPolicy.adjustWindowParamsLw(attrs);
2737            }
2738
2739            winAnimator.mSurfaceDestroyDeferred =
2740                    (flags&WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY) != 0;
2741
2742            int attrChanges = 0;
2743            int flagChanges = 0;
2744            if (attrs != null) {
2745                if (win.mAttrs.type != attrs.type) {
2746                    throw new IllegalArgumentException(
2747                            "Window type can not be changed after the window is added.");
2748                }
2749                flagChanges = win.mAttrs.flags ^= attrs.flags;
2750                attrChanges = win.mAttrs.copyFrom(attrs);
2751                if ((attrChanges & (WindowManager.LayoutParams.LAYOUT_CHANGED
2752                        | WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED)) != 0) {
2753                    win.mLayoutNeeded = true;
2754                }
2755            }
2756
2757            if (DEBUG_LAYOUT
2758                    // TODO: Remove once b/7094175 is fixed
2759                    || ((String)win.mAttrs.getTitle()).contains("Keyguard")
2760                ) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
2761                    + " " + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
2762
2763            win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
2764
2765            if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
2766                winAnimator.mAlpha = attrs.alpha;
2767            }
2768
2769            final boolean scaledWindow =
2770                ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0);
2771
2772            if (scaledWindow) {
2773                // requested{Width|Height} Surface's physical size
2774                // attrs.{width|height} Size on screen
2775                win.mHScale = (attrs.width  != requestedWidth)  ?
2776                        (attrs.width  / (float)requestedWidth) : 1.0f;
2777                win.mVScale = (attrs.height != requestedHeight) ?
2778                        (attrs.height / (float)requestedHeight) : 1.0f;
2779            } else {
2780                win.mHScale = win.mVScale = 1;
2781            }
2782
2783            boolean imMayMove = (flagChanges & (FLAG_ALT_FOCUSABLE_IM | FLAG_NOT_FOCUSABLE)) != 0;
2784
2785            final boolean isDefaultDisplay = win.isDefaultDisplay();
2786            boolean focusMayChange = isDefaultDisplay && (win.mViewVisibility != viewVisibility
2787                    || ((flagChanges & FLAG_NOT_FOCUSABLE) != 0)
2788                    || (!win.mRelayoutCalled));
2789
2790            boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
2791                    && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
2792            wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0;
2793
2794            win.mRelayoutCalled = true;
2795            final int oldVisibility = win.mViewVisibility;
2796            win.mViewVisibility = viewVisibility;
2797            if (DEBUG_SCREEN_ON) {
2798                RuntimeException stack = new RuntimeException();
2799                stack.fillInStackTrace();
2800                Slog.i(TAG, "Relayout " + win + ": oldVis=" + oldVisibility
2801                        + " newVis=" + viewVisibility, stack);
2802            }
2803            if (viewVisibility == View.VISIBLE &&
2804                    (win.mAppToken == null || !win.mAppToken.clientHidden)) {
2805                toBeDisplayed = !win.isVisibleLw();
2806                if (win.mExiting) {
2807                    winAnimator.cancelExitAnimationForNextAnimationLocked();
2808                    win.mExiting = false;
2809                }
2810                if (win.mDestroying) {
2811                    win.mDestroying = false;
2812                    mDestroySurface.remove(win);
2813                }
2814                if (oldVisibility == View.GONE) {
2815                    winAnimator.mEnterAnimationPending = true;
2816                }
2817                if (toBeDisplayed) {
2818                    if (win.isDrawnLw() && okToDisplay()) {
2819                        winAnimator.applyEnterAnimationLocked();
2820                    }
2821                    if ((win.mAttrs.flags
2822                            & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
2823                        if (DEBUG_VISIBILITY) Slog.v(TAG,
2824                                "Relayout window turning screen on: " + win);
2825                        win.mTurnOnScreen = true;
2826                    }
2827                    if (win.isConfigChanged()) {
2828                        if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + win
2829                                + " visible with new config: " + win.mConfiguration);
2830                        outConfig.setTo(mCurConfiguration);
2831                    }
2832                }
2833                if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
2834                    // To change the format, we need to re-build the surface.
2835                    winAnimator.destroySurfaceLocked();
2836                    toBeDisplayed = true;
2837                    surfaceChanged = true;
2838                }
2839                try {
2840                    if (!win.mHasSurface) {
2841                        surfaceChanged = true;
2842                    }
2843                    Surface surface = winAnimator.createSurfaceLocked();
2844                    if (surface != null) {
2845                        outSurface.copyFrom(surface);
2846                        if (SHOW_TRANSACTIONS) Slog.i(TAG,
2847                                "  OUT SURFACE " + outSurface + ": copied");
2848                    } else {
2849                        // For some reason there isn't a surface.  Clear the
2850                        // caller's object so they see the same state.
2851                        outSurface.release();
2852                    }
2853                } catch (Exception e) {
2854                    mInputMonitor.updateInputWindowsLw(true /*force*/);
2855
2856                    Slog.w(TAG, "Exception thrown when creating surface for client "
2857                             + client + " (" + win.mAttrs.getTitle() + ")",
2858                             e);
2859                    Binder.restoreCallingIdentity(origId);
2860                    return 0;
2861                }
2862                if (toBeDisplayed) {
2863                    focusMayChange = isDefaultDisplay;
2864                }
2865                if (win.mAttrs.type == TYPE_INPUT_METHOD
2866                        && mInputMethodWindow == null) {
2867                    mInputMethodWindow = win;
2868                    imMayMove = true;
2869                }
2870                if (win.mAttrs.type == TYPE_BASE_APPLICATION
2871                        && win.mAppToken != null
2872                        && win.mAppToken.startingWindow != null) {
2873                    // Special handling of starting window over the base
2874                    // window of the app: propagate lock screen flags to it,
2875                    // to provide the correct semantics while starting.
2876                    final int mask =
2877                        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
2878                        | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
2879                        | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
2880                    WindowManager.LayoutParams sa = win.mAppToken.startingWindow.mAttrs;
2881                    sa.flags = (sa.flags&~mask) | (win.mAttrs.flags&mask);
2882                }
2883            } else {
2884                winAnimator.mEnterAnimationPending = false;
2885                if (winAnimator.mSurface != null) {
2886                    if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
2887                            + ": mExiting=" + win.mExiting);
2888                    // If we are not currently running the exit animation, we
2889                    // need to see about starting one.
2890                    if (!win.mExiting) {
2891                        surfaceChanged = true;
2892                        // Try starting an animation; if there isn't one, we
2893                        // can destroy the surface right away.
2894                        int transit = WindowManagerPolicy.TRANSIT_EXIT;
2895                        if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
2896                            transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
2897                        }
2898                        if (win.isWinVisibleLw() &&
2899                                winAnimator.applyAnimationLocked(transit, false)) {
2900                            focusMayChange = isDefaultDisplay;
2901                            win.mExiting = true;
2902                        } else if (win.mWinAnimator.isAnimating()) {
2903                            // Currently in a hide animation... turn this into
2904                            // an exit.
2905                            win.mExiting = true;
2906                        } else if (win == mWallpaperTarget) {
2907                            // If the wallpaper is currently behind this
2908                            // window, we need to change both of them inside
2909                            // of a transaction to avoid artifacts.
2910                            win.mExiting = true;
2911                            win.mWinAnimator.mAnimating = true;
2912                        } else {
2913                            if (mInputMethodWindow == win) {
2914                                mInputMethodWindow = null;
2915                            }
2916                            winAnimator.destroySurfaceLocked();
2917                        }
2918                        scheduleNotifyWindowTranstionIfNeededLocked(win, transit);
2919                    }
2920                }
2921
2922                outSurface.release();
2923                if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
2924            }
2925
2926            if (focusMayChange) {
2927                //System.out.println("Focus may change: " + win.mAttrs.getTitle());
2928                if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
2929                        false /*updateInputWindows*/)) {
2930                    imMayMove = false;
2931                }
2932                //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
2933            }
2934
2935            // updateFocusedWindowLocked() already assigned layers so we only need to
2936            // reassign them at this point if the IM window state gets shuffled
2937            boolean assignLayers = false;
2938
2939            if (imMayMove) {
2940                if (moveInputMethodWindowsIfNeededLocked(false) || toBeDisplayed) {
2941                    // Little hack here -- we -should- be able to rely on the
2942                    // function to return true if the IME has moved and needs
2943                    // its layer recomputed.  However, if the IME was hidden
2944                    // and isn't actually moved in the list, its layer may be
2945                    // out of data so we make sure to recompute it.
2946                    assignLayers = true;
2947                }
2948            }
2949            if (wallpaperMayMove) {
2950                if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
2951                    assignLayers = true;
2952                }
2953            }
2954
2955            win.mDisplayContent.layoutNeeded = true;
2956            win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
2957            if (assignLayers) {
2958                assignLayersLocked(win.getWindowList());
2959            }
2960            configChanged = updateOrientationFromAppTokensLocked(false);
2961            performLayoutAndPlaceSurfacesLocked();
2962            if (toBeDisplayed && win.mIsWallpaper) {
2963                DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
2964                updateWallpaperOffsetLocked(win,
2965                        displayInfo.appWidth, displayInfo.appHeight, false);
2966            }
2967            if (win.mAppToken != null) {
2968                win.mAppToken.updateReportedVisibilityLocked();
2969            }
2970            outFrame.set(win.mCompatFrame);
2971            outContentInsets.set(win.mContentInsets);
2972            outVisibleInsets.set(win.mVisibleInsets);
2973            if (localLOGV) Slog.v(
2974                TAG, "Relayout given client " + client.asBinder()
2975                + ", requestedWidth=" + requestedWidth
2976                + ", requestedHeight=" + requestedHeight
2977                + ", viewVisibility=" + viewVisibility
2978                + "\nRelayout returning frame=" + outFrame
2979                + ", surface=" + outSurface);
2980
2981            if (localLOGV || DEBUG_FOCUS) Slog.v(
2982                TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
2983
2984            inTouchMode = mInTouchMode;
2985            animating = mAnimator.mAnimating;
2986            if (animating && !mRelayoutWhileAnimating.contains(win)) {
2987                mRelayoutWhileAnimating.add(win);
2988            }
2989
2990            mInputMonitor.updateInputWindowsLw(true /*force*/);
2991        }
2992
2993        if (configChanged) {
2994            sendNewConfiguration();
2995        }
2996
2997        Binder.restoreCallingIdentity(origId);
2998
2999        return (inTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0)
3000                | (toBeDisplayed ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0)
3001                | (surfaceChanged ? WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED : 0)
3002                | (animating ? WindowManagerGlobal.RELAYOUT_RES_ANIMATING : 0);
3003    }
3004
3005    public void performDeferredDestroyWindow(Session session, IWindow client) {
3006        long origId = Binder.clearCallingIdentity();
3007
3008        try {
3009            synchronized(mWindowMap) {
3010                WindowState win = windowForClientLocked(session, client, false);
3011                if (win == null) {
3012                    return;
3013                }
3014                win.mWinAnimator.destroyDeferredSurfaceLocked();
3015            }
3016        } finally {
3017            Binder.restoreCallingIdentity(origId);
3018        }
3019    }
3020
3021    public boolean outOfMemoryWindow(Session session, IWindow client) {
3022        long origId = Binder.clearCallingIdentity();
3023
3024        try {
3025            synchronized(mWindowMap) {
3026                WindowState win = windowForClientLocked(session, client, false);
3027                if (win == null) {
3028                    return false;
3029                }
3030                return reclaimSomeSurfaceMemoryLocked(win.mWinAnimator, "from-client", false);
3031            }
3032        } finally {
3033            Binder.restoreCallingIdentity(origId);
3034        }
3035    }
3036
3037    public void finishDrawingWindow(Session session, IWindow client) {
3038        final long origId = Binder.clearCallingIdentity();
3039        synchronized(mWindowMap) {
3040            WindowState win = windowForClientLocked(session, client, false);
3041            if (win != null && win.mWinAnimator.finishDrawingLocked()) {
3042                if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
3043                    adjustWallpaperWindowsLocked();
3044                }
3045                win.mDisplayContent.layoutNeeded = true;
3046                performLayoutAndPlaceSurfacesLocked();
3047            }
3048        }
3049        Binder.restoreCallingIdentity(origId);
3050    }
3051
3052    @Override
3053    public float getWindowCompatibilityScale(IBinder windowToken) {
3054        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
3055                "getWindowCompatibilityScale()")) {
3056            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
3057        }
3058        synchronized (mWindowMap) {
3059            WindowState windowState = mWindowMap.get(windowToken);
3060            return (windowState != null) ? windowState.mGlobalScale : 1.0f;
3061        }
3062    }
3063
3064    @Override
3065    public WindowInfo getWindowInfo(IBinder token) {
3066        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
3067                "getWindowInfo()")) {
3068            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
3069        }
3070        synchronized (mWindowMap) {
3071            WindowState window = mWindowMap.get(token);
3072            if (window != null) {
3073                return getWindowInfoForWindowStateLocked(window);
3074            }
3075            return null;
3076        }
3077    }
3078
3079    @Override
3080    public void getVisibleWindowsForDisplay(int displayId, List<WindowInfo> outInfos) {
3081        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
3082                "getWindowInfos()")) {
3083            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
3084        }
3085        synchronized (mWindowMap) {
3086            DisplayContent displayContent = getDisplayContentLocked(displayId);
3087            if (displayContent == null) {
3088                return;
3089            }
3090            WindowList windows = displayContent.getWindowList();
3091            final int windowCount = windows.size();
3092            for (int i = 0; i < windowCount; i++) {
3093                WindowState window = windows.get(i);
3094                if (window.isVisibleLw() || window.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
3095                    WindowInfo info = getWindowInfoForWindowStateLocked(window);
3096                    outInfos.add(info);
3097                }
3098            }
3099        }
3100    }
3101
3102    @Override
3103    public void magnifyDisplay(int displayId, float scale, float offsetX, float offsetY) {
3104        if (!checkCallingPermission(
3105                android.Manifest.permission.MAGNIFY_DISPLAY, "magnifyDisplay()")) {
3106            throw new SecurityException("Requires MAGNIFY_DISPLAY permission");
3107        }
3108        synchronized (mWindowMap) {
3109            MagnificationSpec spec = getDisplayMagnificationSpecLocked(displayId);
3110            if (spec != null) {
3111                final boolean scaleChanged = spec.mScale != scale;
3112                final boolean offsetChanged = spec.mOffsetX != offsetX || spec.mOffsetY != offsetY;
3113                if (!scaleChanged && !offsetChanged) {
3114                    return;
3115                }
3116                spec.initialize(scale, offsetX, offsetY);
3117                // If the offset has changed we need to re-add the input windows
3118                // since the offsets have to be propagated to the input system.
3119                if (offsetChanged) {
3120                    // TODO(multidisplay): Input only occurs on the default display.
3121                    if (displayId == Display.DEFAULT_DISPLAY) {
3122                        mInputMonitor.updateInputWindowsLw(true);
3123                    }
3124                }
3125                scheduleAnimationLocked();
3126            }
3127        }
3128    }
3129
3130    MagnificationSpec getDisplayMagnificationSpecLocked(int displayId) {
3131        DisplayContent displayContent = getDisplayContentLocked(displayId);
3132        if (displayContent != null) {
3133            if (displayContent.mMagnificationSpec == null) {
3134                displayContent.mMagnificationSpec = new MagnificationSpec();
3135            }
3136            return displayContent.mMagnificationSpec;
3137        }
3138        return null;
3139    }
3140
3141    private WindowInfo getWindowInfoForWindowStateLocked(WindowState window) {
3142        WindowInfo info = WindowInfo.obtain();
3143        info.token = window.mToken.token;
3144        info.frame.set(window.mFrame);
3145        info.type = window.mAttrs.type;
3146        info.displayId = window.getDisplayId();
3147        info.compatibilityScale = window.mGlobalScale;
3148        info.visible = window.isVisibleLw() || info.type == TYPE_UNIVERSE_BACKGROUND;
3149        info.layer = window.mLayer;
3150        window.getTouchableRegion(mTempRegion);
3151        mTempRegion.getBounds(info.touchableRegion);
3152        return info;
3153    }
3154
3155    private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
3156        if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
3157                + (lp != null ? lp.packageName : null)
3158                + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
3159        if (lp != null && lp.windowAnimations != 0) {
3160            // If this is a system resource, don't try to load it from the
3161            // application resources.  It is nice to avoid loading application
3162            // resources if we can.
3163            String packageName = lp.packageName != null ? lp.packageName : "android";
3164            int resId = lp.windowAnimations;
3165            if ((resId&0xFF000000) == 0x01000000) {
3166                packageName = "android";
3167            }
3168            if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
3169                    + packageName);
3170            return AttributeCache.instance().get(packageName, resId,
3171                    com.android.internal.R.styleable.WindowAnimation);
3172        }
3173        return null;
3174    }
3175
3176    private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
3177        if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
3178                + packageName + " resId=0x" + Integer.toHexString(resId));
3179        if (packageName != null) {
3180            if ((resId&0xFF000000) == 0x01000000) {
3181                packageName = "android";
3182            }
3183            if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
3184                    + packageName);
3185            return AttributeCache.instance().get(packageName, resId,
3186                    com.android.internal.R.styleable.WindowAnimation);
3187        }
3188        return null;
3189    }
3190
3191    Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
3192        int anim = 0;
3193        Context context = mContext;
3194        if (animAttr >= 0) {
3195            AttributeCache.Entry ent = getCachedAnimations(lp);
3196            if (ent != null) {
3197                context = ent.context;
3198                anim = ent.array.getResourceId(animAttr, 0);
3199            }
3200        }
3201        if (anim != 0) {
3202            return AnimationUtils.loadAnimation(context, anim);
3203        }
3204        return null;
3205    }
3206
3207    private Animation loadAnimation(String packageName, int resId) {
3208        int anim = 0;
3209        Context context = mContext;
3210        if (resId >= 0) {
3211            AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
3212            if (ent != null) {
3213                context = ent.context;
3214                anim = resId;
3215            }
3216        }
3217        if (anim != 0) {
3218            return AnimationUtils.loadAnimation(context, anim);
3219        }
3220        return null;
3221    }
3222
3223    private Animation createExitAnimationLocked(int transit, int duration) {
3224        if (transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN ||
3225                transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE) {
3226            // If we are on top of the wallpaper, we need an animation that
3227            // correctly handles the wallpaper staying static behind all of
3228            // the animated elements.  To do this, will just have the existing
3229            // element fade out.
3230            Animation a = new AlphaAnimation(1, 0);
3231            a.setDetachWallpaper(true);
3232            a.setDuration(duration);
3233            return a;
3234        }
3235        // For normal animations, the exiting element just holds in place.
3236        Animation a = new AlphaAnimation(1, 1);
3237        a.setDuration(duration);
3238        return a;
3239    }
3240
3241    /**
3242     * Compute the pivot point for an animation that is scaling from a small
3243     * rect on screen to a larger rect.  The pivot point varies depending on
3244     * the distance between the inner and outer edges on both sides.  This
3245     * function computes the pivot point for one dimension.
3246     * @param startPos  Offset from left/top edge of outer rectangle to
3247     * left/top edge of inner rectangle.
3248     * @param finalScale The scaling factor between the size of the outer
3249     * and inner rectangles.
3250     */
3251    private static float computePivot(int startPos, float finalScale) {
3252        final float denom = finalScale-1;
3253        if (Math.abs(denom) < .0001f) {
3254            return startPos;
3255        }
3256        return -startPos / denom;
3257    }
3258
3259    private Animation createScaleUpAnimationLocked(int transit, boolean enter) {
3260        Animation a;
3261        // Pick the desired duration.  If this is an inter-activity transition,
3262        // it  is the standard duration for that.  Otherwise we use the longer
3263        // task transition duration.
3264        int duration;
3265        switch (transit) {
3266            case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
3267            case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
3268                duration = mContext.getResources().getInteger(
3269                        com.android.internal.R.integer.config_shortAnimTime);
3270                break;
3271            default:
3272                duration = 300;
3273                break;
3274        }
3275        // TODO(multidisplay): For now assume all app animation is on main display.
3276        final DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
3277        if (enter) {
3278            // Entering app zooms out from the center of the initial rect.
3279            float scaleW = mNextAppTransitionStartWidth / (float) displayInfo.appWidth;
3280            float scaleH = mNextAppTransitionStartHeight / (float) displayInfo.appHeight;
3281            Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
3282                    computePivot(mNextAppTransitionStartX, scaleW),
3283                    computePivot(mNextAppTransitionStartY, scaleH));
3284            scale.setDuration(duration);
3285            AnimationSet set = new AnimationSet(true);
3286            Animation alpha = new AlphaAnimation(0, 1);
3287            scale.setDuration(duration);
3288            set.addAnimation(scale);
3289            alpha.setDuration(duration);
3290            set.addAnimation(alpha);
3291            set.setDetachWallpaper(true);
3292            a = set;
3293        } else {
3294            a = createExitAnimationLocked(transit, duration);
3295        }
3296        a.setFillAfter(true);
3297        final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
3298                com.android.internal.R.interpolator.decelerate_cubic);
3299        a.setInterpolator(interpolator);
3300        a.initialize(displayInfo.appWidth, displayInfo.appHeight,
3301                displayInfo.appWidth, displayInfo.appHeight);
3302        return a;
3303    }
3304
3305    private Animation createThumbnailAnimationLocked(int transit,
3306            boolean enter, boolean thumb, boolean scaleUp) {
3307        Animation a;
3308        final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
3309        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
3310        final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
3311        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
3312        // Pick the desired duration.  If this is an inter-activity transition,
3313        // it  is the standard duration for that.  Otherwise we use the longer
3314        // task transition duration.
3315        int duration;
3316        switch (transit) {
3317            case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
3318            case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
3319                duration = mContext.getResources().getInteger(
3320                        com.android.internal.R.integer.config_shortAnimTime);
3321                break;
3322            default:
3323                duration = 250;
3324                break;
3325        }
3326        // TOOD(multidisplay): For now assume all app animation is on the main screen.
3327        DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
3328        if (thumb) {
3329            // Animation for zooming thumbnail from its initial size to
3330            // filling the screen.
3331            if (scaleUp) {
3332                float scaleW = displayInfo.appWidth / thumbWidth;
3333                float scaleH = displayInfo.appHeight / thumbHeight;
3334
3335                Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
3336                        computePivot(mNextAppTransitionStartX, 1 / scaleW),
3337                        computePivot(mNextAppTransitionStartY, 1 / scaleH));
3338                AnimationSet set = new AnimationSet(true);
3339                Animation alpha = new AlphaAnimation(1, 0);
3340                scale.setDuration(duration);
3341                scale.setInterpolator(
3342                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
3343                set.addAnimation(scale);
3344                alpha.setDuration(duration);
3345                set.addAnimation(alpha);
3346                set.setFillBefore(true);
3347                a = set;
3348            } else {
3349                float scaleW = displayInfo.appWidth / thumbWidth;
3350                float scaleH = displayInfo.appHeight / thumbHeight;
3351
3352                Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
3353                        computePivot(mNextAppTransitionStartX, 1 / scaleW),
3354                        computePivot(mNextAppTransitionStartY, 1 / scaleH));
3355                AnimationSet set = new AnimationSet(true);
3356                Animation alpha = new AlphaAnimation(1, 1);
3357                scale.setDuration(duration);
3358                scale.setInterpolator(
3359                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
3360                set.addAnimation(scale);
3361                alpha.setDuration(duration);
3362                set.addAnimation(alpha);
3363                set.setFillBefore(true);
3364
3365                a = set;
3366            }
3367        } else if (enter) {
3368            // Entering app zooms out from the center of the thumbnail.
3369            if (scaleUp) {
3370                float scaleW = thumbWidth / displayInfo.appWidth;
3371                float scaleH = thumbHeight / displayInfo.appHeight;
3372                Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
3373                        computePivot(mNextAppTransitionStartX, scaleW),
3374                        computePivot(mNextAppTransitionStartY, scaleH));
3375                scale.setDuration(duration);
3376                scale.setInterpolator(
3377                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
3378                scale.setFillBefore(true);
3379                a = scale;
3380            } else {
3381                // noop animation
3382                a = new AlphaAnimation(1, 1);
3383                a.setDuration(duration);
3384            }
3385        } else {
3386            // Exiting app
3387            if (scaleUp) {
3388                if (transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN) {
3389                    // Fade out while bringing up selected activity. This keeps the
3390                    // current activity from showing through a launching wallpaper
3391                    // activity.
3392                    a = new AlphaAnimation(1, 0);
3393                } else {
3394                    // noop animation
3395                    a = new AlphaAnimation(1, 1);
3396                }
3397                a.setDuration(duration);
3398            } else {
3399                float scaleW = thumbWidth / displayInfo.appWidth;
3400                float scaleH = thumbHeight / displayInfo.appHeight;
3401                Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
3402                        computePivot(mNextAppTransitionStartX, scaleW),
3403                        computePivot(mNextAppTransitionStartY, scaleH));
3404                scale.setDuration(duration);
3405                scale.setInterpolator(
3406                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
3407                scale.setFillBefore(true);
3408                AnimationSet set = new AnimationSet(true);
3409                Animation alpha = new AlphaAnimation(1, 0);
3410                set.addAnimation(scale);
3411                alpha.setDuration(duration);
3412                alpha.setInterpolator(new DecelerateInterpolator(
3413                        THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
3414                set.addAnimation(alpha);
3415                set.setFillBefore(true);
3416                set.setZAdjustment(Animation.ZORDER_TOP);
3417                a = set;
3418            }
3419        }
3420        a.setFillAfter(true);
3421        final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
3422                com.android.internal.R.interpolator.decelerate_quad);
3423        a.setInterpolator(interpolator);
3424        a.initialize(displayInfo.appWidth, displayInfo.appHeight,
3425                displayInfo.appWidth, displayInfo.appHeight);
3426        return a;
3427    }
3428
3429    private boolean applyAnimationLocked(AppWindowToken atoken,
3430            WindowManager.LayoutParams lp, int transit, boolean enter) {
3431        // Only apply an animation if the display isn't frozen.  If it is
3432        // frozen, there is no reason to animate and it can cause strange
3433        // artifacts when we unfreeze the display if some different animation
3434        // is running.
3435        if (okToDisplay()) {
3436            Animation a;
3437            boolean initialized = false;
3438            if (mNextAppTransitionType == ActivityOptions.ANIM_CUSTOM) {
3439                a = loadAnimation(mNextAppTransitionPackage, enter ?
3440                        mNextAppTransitionEnter : mNextAppTransitionExit);
3441                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
3442                        "applyAnimation: atoken=" + atoken
3443                        + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
3444                        + " transit=" + transit + " isEntrance=" + enter
3445                        + " Callers=" + Debug.getCallers(3));
3446            } else if (mNextAppTransitionType == ActivityOptions.ANIM_SCALE_UP) {
3447                a = createScaleUpAnimationLocked(transit, enter);
3448                initialized = true;
3449                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
3450                        "applyAnimation: atoken=" + atoken
3451                        + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
3452                        + " transit=" + transit + " isEntrance=" + enter
3453                        + " Callers=" + Debug.getCallers(3));
3454            } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP ||
3455                    mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN) {
3456                boolean scaleUp = (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP);
3457                a = createThumbnailAnimationLocked(transit, enter, false, scaleUp);
3458                initialized = true;
3459                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
3460                    String animName = scaleUp ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
3461                    Slog.v(TAG, "applyAnimation: atoken=" + atoken
3462                            + " anim=" + a + " nextAppTransition=" + animName
3463                            + " transit=" + transit + " isEntrance=" + enter
3464                            + " Callers=" + Debug.getCallers(3));
3465                }
3466            } else {
3467                int animAttr = 0;
3468                switch (transit) {
3469                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
3470                        animAttr = enter
3471                                ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
3472                                : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
3473                        break;
3474                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
3475                        animAttr = enter
3476                                ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
3477                                : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
3478                        break;
3479                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
3480                        animAttr = enter
3481                                ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
3482                                : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
3483                        break;
3484                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
3485                        animAttr = enter
3486                                ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
3487                                : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
3488                        break;
3489                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
3490                        animAttr = enter
3491                                ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
3492                                : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
3493                        break;
3494                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
3495                        animAttr = enter
3496                                ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
3497                                : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
3498                        break;
3499                    case WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN:
3500                        animAttr = enter
3501                                ? com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
3502                                : com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
3503                        break;
3504                    case WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE:
3505                        animAttr = enter
3506                                ? com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
3507                                : com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
3508                        break;
3509                    case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN:
3510                        animAttr = enter
3511                                ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
3512                                : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
3513                        break;
3514                    case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE:
3515                        animAttr = enter
3516                                ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
3517                                : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
3518                        break;
3519                }
3520                a = animAttr != 0 ? loadAnimation(lp, animAttr) : null;
3521                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
3522                        "applyAnimation: atoken=" + atoken
3523                        + " anim=" + a
3524                        + " animAttr=0x" + Integer.toHexString(animAttr)
3525                        + " transit=" + transit + " isEntrance=" + enter
3526                        + " Callers=" + Debug.getCallers(3));
3527            }
3528            if (a != null) {
3529                if (DEBUG_ANIM) {
3530                    RuntimeException e = null;
3531                    if (!HIDE_STACK_CRAWLS) {
3532                        e = new RuntimeException();
3533                        e.fillInStackTrace();
3534                    }
3535                    Slog.v(TAG, "Loaded animation " + a + " for " + atoken, e);
3536                }
3537                atoken.mAppAnimator.setAnimation(a, initialized);
3538            }
3539        } else {
3540            atoken.mAppAnimator.clearAnimation();
3541        }
3542
3543        return atoken.mAppAnimator.animation != null;
3544    }
3545
3546    // -------------------------------------------------------------
3547    // Application Window Tokens
3548    // -------------------------------------------------------------
3549
3550    public void validateAppTokens(List<IBinder> tokens) {
3551        int v = tokens.size()-1;
3552        int m = mAppTokens.size()-1;
3553        while (v >= 0 && m >= 0) {
3554            AppWindowToken atoken = mAppTokens.get(m);
3555            if (atoken.removed) {
3556                m--;
3557                continue;
3558            }
3559            if (tokens.get(v) != atoken.token) {
3560                Slog.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
3561                      + " @ " + v + ", internal is " + atoken.token + " @ " + m);
3562            }
3563            v--;
3564            m--;
3565        }
3566        while (v >= 0) {
3567            Slog.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
3568            v--;
3569        }
3570        while (m >= 0) {
3571            AppWindowToken atoken = mAppTokens.get(m);
3572            if (!atoken.removed) {
3573                Slog.w(TAG, "Invalid internal atoken: " + atoken.token + " @ " + m);
3574            }
3575            m--;
3576        }
3577    }
3578
3579    boolean checkCallingPermission(String permission, String func) {
3580        // Quick check: if the calling permission is me, it's all okay.
3581        if (Binder.getCallingPid() == Process.myPid()) {
3582            return true;
3583        }
3584
3585        if (mContext.checkCallingPermission(permission)
3586                == PackageManager.PERMISSION_GRANTED) {
3587            return true;
3588        }
3589        String msg = "Permission Denial: " + func + " from pid="
3590                + Binder.getCallingPid()
3591                + ", uid=" + Binder.getCallingUid()
3592                + " requires " + permission;
3593        Slog.w(TAG, msg);
3594        return false;
3595    }
3596
3597    boolean okToDisplay() {
3598        return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully();
3599    }
3600
3601    AppWindowToken findAppWindowToken(IBinder token) {
3602        WindowToken wtoken = mTokenMap.get(token);
3603        if (wtoken == null) {
3604            return null;
3605        }
3606        return wtoken.appWindowToken;
3607    }
3608
3609    @Override
3610    public void addWindowToken(IBinder token, int type) {
3611        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3612                "addWindowToken()")) {
3613            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3614        }
3615
3616        synchronized(mWindowMap) {
3617            WindowToken wtoken = mTokenMap.get(token);
3618            if (wtoken != null) {
3619                Slog.w(TAG, "Attempted to add existing input method token: " + token);
3620                return;
3621            }
3622            wtoken = new WindowToken(this, token, type, true);
3623            mTokenMap.put(token, wtoken);
3624            if (type == TYPE_WALLPAPER) {
3625                mWallpaperTokens.add(wtoken);
3626                updateLayoutToAnimWallpaperTokens();
3627            }
3628        }
3629    }
3630
3631    @Override
3632    public void removeWindowToken(IBinder token) {
3633        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3634                "removeWindowToken()")) {
3635            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3636        }
3637
3638        final long origId = Binder.clearCallingIdentity();
3639        synchronized(mWindowMap) {
3640            WindowToken wtoken = mTokenMap.remove(token);
3641            if (wtoken != null) {
3642                boolean delayed = false;
3643                if (!wtoken.hidden) {
3644                    final int N = wtoken.windows.size();
3645                    boolean changed = false;
3646
3647                    for (int i=0; i<N; i++) {
3648                        WindowState win = wtoken.windows.get(i);
3649
3650                        if (win.mWinAnimator.isAnimating()) {
3651                            delayed = true;
3652                        }
3653
3654                        if (win.isVisibleNow()) {
3655                            win.mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT,
3656                                    false);
3657                            scheduleNotifyWindowTranstionIfNeededLocked(win,
3658                                    WindowManagerPolicy.TRANSIT_EXIT);
3659                            changed = true;
3660                            win.mDisplayContent.layoutNeeded = true;
3661                        }
3662                    }
3663
3664                    wtoken.hidden = true;
3665
3666                    if (changed) {
3667                        performLayoutAndPlaceSurfacesLocked();
3668                        updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
3669                                false /*updateInputWindows*/);
3670                    }
3671
3672                    if (delayed) {
3673                        mExitingTokens.add(wtoken);
3674                    } else if (wtoken.windowType == TYPE_WALLPAPER) {
3675                        mWallpaperTokens.remove(wtoken);
3676                        updateLayoutToAnimWallpaperTokens();
3677                    }
3678                }
3679
3680                mInputMonitor.updateInputWindowsLw(true /*force*/);
3681            } else {
3682                Slog.w(TAG, "Attempted to remove non-existing token: " + token);
3683            }
3684        }
3685        Binder.restoreCallingIdentity(origId);
3686    }
3687
3688    /**
3689     *  Find the location to insert a new AppWindowToken into the window-ordered app token list.
3690     *  Note that mAppTokens.size() == mAnimatingAppTokens.size() + 1.
3691     * @param addPos The location the token was inserted into in mAppTokens.
3692     * @param atoken The token to insert.
3693     */
3694    private void addAppTokenToAnimating(final int addPos, final AppWindowToken atoken) {
3695        if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
3696            // It was inserted into the beginning or end of mAppTokens. Honor that.
3697            mAnimatingAppTokens.add(addPos, atoken);
3698            return;
3699        }
3700        // Find the item immediately above the mAppTokens insertion point and put the token
3701        // immediately below that one in mAnimatingAppTokens.
3702        final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1);
3703        mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), atoken);
3704    }
3705
3706    @Override
3707    public void addAppToken(int addPos, IApplicationToken token,
3708            int groupId, int requestedOrientation, boolean fullscreen, boolean showWhenLocked) {
3709        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3710                "addAppToken()")) {
3711            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3712        }
3713
3714        // Get the dispatching timeout here while we are not holding any locks so that it
3715        // can be cached by the AppWindowToken.  The timeout value is used later by the
3716        // input dispatcher in code that does hold locks.  If we did not cache the value
3717        // here we would run the chance of introducing a deadlock between the window manager
3718        // (which holds locks while updating the input dispatcher state) and the activity manager
3719        // (which holds locks while querying the application token).
3720        long inputDispatchingTimeoutNanos;
3721        try {
3722            inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;
3723        } catch (RemoteException ex) {
3724            Slog.w(TAG, "Could not get dispatching timeout.", ex);
3725            inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
3726        }
3727
3728        synchronized(mWindowMap) {
3729            AppWindowToken atoken = findAppWindowToken(token.asBinder());
3730            if (atoken != null) {
3731                Slog.w(TAG, "Attempted to add existing app token: " + token);
3732                return;
3733            }
3734            atoken = new AppWindowToken(this, token);
3735            atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
3736            atoken.groupId = groupId;
3737            atoken.appFullscreen = fullscreen;
3738            atoken.showWhenLocked = showWhenLocked;
3739            atoken.requestedOrientation = requestedOrientation;
3740            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
3741                    + " at " + addPos);
3742            mAppTokens.add(addPos, atoken);
3743            addAppTokenToAnimating(addPos, atoken);
3744            mTokenMap.put(token.asBinder(), atoken);
3745
3746            // Application tokens start out hidden.
3747            atoken.hidden = true;
3748            atoken.hiddenRequested = true;
3749
3750            //dump();
3751        }
3752    }
3753
3754    @Override
3755    public void setAppGroupId(IBinder token, int groupId) {
3756        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3757                "setAppGroupId()")) {
3758            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3759        }
3760
3761        synchronized(mWindowMap) {
3762            AppWindowToken atoken = findAppWindowToken(token);
3763            if (atoken == null) {
3764                Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
3765                return;
3766            }
3767            atoken.groupId = groupId;
3768        }
3769    }
3770
3771    public int getOrientationFromWindowsLocked() {
3772        if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
3773            // If the display is frozen, some activities may be in the middle
3774            // of restarting, and thus have removed their old window.  If the
3775            // window has the flag to hide the lock screen, then the lock screen
3776            // can re-appear and inflict its own orientation on us.  Keep the
3777            // orientation stable until this all settles down.
3778            return mLastWindowForcedOrientation;
3779        }
3780
3781        // TODO(multidisplay): Change to the correct display.
3782        final WindowList windows = getDefaultWindowListLocked();
3783        int pos = windows.size() - 1;
3784        while (pos >= 0) {
3785            WindowState wtoken = windows.get(pos);
3786            pos--;
3787            if (wtoken.mAppToken != null) {
3788                // We hit an application window. so the orientation will be determined by the
3789                // app window. No point in continuing further.
3790                return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
3791            }
3792            if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) {
3793                continue;
3794            }
3795            int req = wtoken.mAttrs.screenOrientation;
3796            if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
3797                    (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
3798                continue;
3799            }
3800
3801            return (mLastWindowForcedOrientation=req);
3802        }
3803        return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
3804    }
3805
3806    public int getOrientationFromAppTokensLocked() {
3807        int curGroup = 0;
3808        int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3809        boolean findingBehind = false;
3810        boolean haveGroup = false;
3811        boolean lastFullscreen = false;
3812        for (int pos = mAppTokens.size() - 1; pos >= 0; pos--) {
3813            AppWindowToken atoken = mAppTokens.get(pos);
3814
3815            if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + atoken);
3816
3817            // if we're about to tear down this window and not seek for
3818            // the behind activity, don't use it for orientation
3819            if (!findingBehind
3820                    && (!atoken.hidden && atoken.hiddenRequested)) {
3821                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
3822                        + " -- going to hide");
3823                continue;
3824            }
3825
3826            if (haveGroup == true && curGroup != atoken.groupId) {
3827                // If we have hit a new application group, and the bottom
3828                // of the previous group didn't explicitly say to use
3829                // the orientation behind it, and the last app was
3830                // full screen, then we'll stick with the
3831                // user's orientation.
3832                if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
3833                        && lastFullscreen) {
3834                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
3835                            + " -- end of group, return " + lastOrientation);
3836                    return lastOrientation;
3837                }
3838            }
3839
3840            // We ignore any hidden applications on the top.
3841            if (atoken.hiddenRequested || atoken.willBeHidden) {
3842                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
3843                        + " -- hidden on top");
3844                continue;
3845            }
3846
3847            if (!haveGroup) {
3848                haveGroup = true;
3849                curGroup = atoken.groupId;
3850                lastOrientation = atoken.requestedOrientation;
3851            }
3852
3853            int or = atoken.requestedOrientation;
3854            // If this application is fullscreen, and didn't explicitly say
3855            // to use the orientation behind it, then just take whatever
3856            // orientation it has and ignores whatever is under it.
3857            lastFullscreen = atoken.appFullscreen;
3858            if (lastFullscreen
3859                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
3860                if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
3861                        + " -- full screen, return " + or);
3862                return or;
3863            }
3864            // If this application has requested an explicit orientation,
3865            // then use it.
3866            if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
3867                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
3868                if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
3869                        + " -- explicitly set, return " + or);
3870                return or;
3871            }
3872            findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
3873        }
3874        if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation");
3875        return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3876    }
3877
3878    @Override
3879    public Configuration updateOrientationFromAppTokens(
3880            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
3881        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3882                "updateOrientationFromAppTokens()")) {
3883            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3884        }
3885
3886        Configuration config = null;
3887        long ident = Binder.clearCallingIdentity();
3888
3889        synchronized(mWindowMap) {
3890            config = updateOrientationFromAppTokensLocked(currentConfig,
3891                    freezeThisOneIfNeeded);
3892        }
3893
3894        Binder.restoreCallingIdentity(ident);
3895        return config;
3896    }
3897
3898    private Configuration updateOrientationFromAppTokensLocked(
3899            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
3900        Configuration config = null;
3901
3902        if (updateOrientationFromAppTokensLocked(false)) {
3903            if (freezeThisOneIfNeeded != null) {
3904                AppWindowToken atoken = findAppWindowToken(
3905                        freezeThisOneIfNeeded);
3906                if (atoken != null) {
3907                    startAppFreezingScreenLocked(atoken,
3908                            ActivityInfo.CONFIG_ORIENTATION);
3909                }
3910            }
3911            config = computeNewConfigurationLocked();
3912
3913        } else if (currentConfig != null) {
3914            // No obvious action we need to take, but if our current
3915            // state mismatches the activity manager's, update it,
3916            // disregarding font scale, which should remain set to
3917            // the value of the previous configuration.
3918            mTempConfiguration.setToDefaults();
3919            mTempConfiguration.fontScale = currentConfig.fontScale;
3920            if (computeScreenConfigurationLocked(mTempConfiguration)) {
3921                if (currentConfig.diff(mTempConfiguration) != 0) {
3922                    mWaitingForConfig = true;
3923                    getDefaultDisplayContentLocked().layoutNeeded = true;
3924                    startFreezingDisplayLocked(false, 0, 0);
3925                    config = new Configuration(mTempConfiguration);
3926                }
3927            }
3928        }
3929
3930        return config;
3931    }
3932
3933    /*
3934     * Determine the new desired orientation of the display, returning
3935     * a non-null new Configuration if it has changed from the current
3936     * orientation.  IF TRUE IS RETURNED SOMEONE MUST CALL
3937     * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE
3938     * SCREEN.  This will typically be done for you if you call
3939     * sendNewConfiguration().
3940     *
3941     * The orientation is computed from non-application windows first. If none of
3942     * the non-application windows specify orientation, the orientation is computed from
3943     * application tokens.
3944     * @see android.view.IWindowManager#updateOrientationFromAppTokens(
3945     * android.os.IBinder)
3946     */
3947    boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
3948        long ident = Binder.clearCallingIdentity();
3949        try {
3950            int req = computeForcedAppOrientationLocked();
3951
3952            if (req != mForcedAppOrientation) {
3953                mForcedAppOrientation = req;
3954                //send a message to Policy indicating orientation change to take
3955                //action like disabling/enabling sensors etc.,
3956                mPolicy.setCurrentOrientationLw(req);
3957                if (updateRotationUncheckedLocked(inTransaction)) {
3958                    // changed
3959                    return true;
3960                }
3961            }
3962
3963            return false;
3964        } finally {
3965            Binder.restoreCallingIdentity(ident);
3966        }
3967    }
3968
3969    int computeForcedAppOrientationLocked() {
3970        int req = getOrientationFromWindowsLocked();
3971        if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
3972            req = getOrientationFromAppTokensLocked();
3973        }
3974        return req;
3975    }
3976
3977    @Override
3978    public void setNewConfiguration(Configuration config) {
3979        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3980                "setNewConfiguration()")) {
3981            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3982        }
3983
3984        synchronized(mWindowMap) {
3985            mCurConfiguration = new Configuration(config);
3986            mWaitingForConfig = false;
3987            performLayoutAndPlaceSurfacesLocked();
3988        }
3989    }
3990
3991    @Override
3992    public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
3993        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3994                "setAppOrientation()")) {
3995            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3996        }
3997
3998        synchronized(mWindowMap) {
3999            AppWindowToken atoken = findAppWindowToken(token.asBinder());
4000            if (atoken == null) {
4001                Slog.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
4002                return;
4003            }
4004
4005            atoken.requestedOrientation = requestedOrientation;
4006        }
4007    }
4008
4009    @Override
4010    public int getAppOrientation(IApplicationToken token) {
4011        synchronized(mWindowMap) {
4012            AppWindowToken wtoken = findAppWindowToken(token.asBinder());
4013            if (wtoken == null) {
4014                return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
4015            }
4016
4017            return wtoken.requestedOrientation;
4018        }
4019    }
4020
4021    @Override
4022    public void setFocusedApp(IBinder token, boolean moveFocusNow) {
4023        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4024                "setFocusedApp()")) {
4025            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4026        }
4027
4028        synchronized(mWindowMap) {
4029            boolean changed = false;
4030            if (token == null) {
4031                if (DEBUG_FOCUS) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
4032                changed = mFocusedApp != null;
4033                mFocusedApp = null;
4034                if (changed) {
4035                    mInputMonitor.setFocusedAppLw(null);
4036                }
4037            } else {
4038                AppWindowToken newFocus = findAppWindowToken(token);
4039                if (newFocus == null) {
4040                    Slog.w(TAG, "Attempted to set focus to non-existing app token: " + token);
4041                    return;
4042                }
4043                changed = mFocusedApp != newFocus;
4044                mFocusedApp = newFocus;
4045                if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp
4046                        + " moveFocusNow=" + moveFocusNow);
4047                if (changed) {
4048                    mInputMonitor.setFocusedAppLw(newFocus);
4049                }
4050            }
4051
4052            if (moveFocusNow && changed) {
4053                final long origId = Binder.clearCallingIdentity();
4054                updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
4055                Binder.restoreCallingIdentity(origId);
4056            }
4057        }
4058    }
4059
4060    @Override
4061    public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
4062        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4063                "prepareAppTransition()")) {
4064            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4065        }
4066
4067        synchronized(mWindowMap) {
4068            if (DEBUG_APP_TRANSITIONS) Slog.v(
4069                    TAG, "Prepare app transition: transit=" + transit
4070                    + " mNextAppTransition=" + mNextAppTransition
4071                    + " alwaysKeepCurrent=" + alwaysKeepCurrent
4072                    + " Callers=" + Debug.getCallers(3));
4073            if (okToDisplay()) {
4074                if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
4075                        || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
4076                    mNextAppTransition = transit;
4077                } else if (!alwaysKeepCurrent) {
4078                    if (transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
4079                            && mNextAppTransition == WindowManagerPolicy.TRANSIT_TASK_CLOSE) {
4080                        // Opening a new task always supersedes a close for the anim.
4081                        mNextAppTransition = transit;
4082                    } else if (transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
4083                            && mNextAppTransition == WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE) {
4084                        // Opening a new activity always supersedes a close for the anim.
4085                        mNextAppTransition = transit;
4086                    }
4087                }
4088                mAppTransitionReady = false;
4089                mAppTransitionTimeout = false;
4090                mStartingIconInTransition = false;
4091                mSkipAppTransitionAnimation = false;
4092                mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
4093                mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT),
4094                        5000);
4095            }
4096        }
4097    }
4098
4099    @Override
4100    public int getPendingAppTransition() {
4101        return mNextAppTransition;
4102    }
4103
4104    private void scheduleAnimationCallback(IRemoteCallback cb) {
4105        if (cb != null) {
4106            mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, cb));
4107        }
4108    }
4109
4110    @Override
4111    public void overridePendingAppTransition(String packageName,
4112            int enterAnim, int exitAnim, IRemoteCallback startedCallback) {
4113        synchronized(mWindowMap) {
4114            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4115                mNextAppTransitionType = ActivityOptions.ANIM_CUSTOM;
4116                mNextAppTransitionPackage = packageName;
4117                mNextAppTransitionThumbnail = null;
4118                mNextAppTransitionEnter = enterAnim;
4119                mNextAppTransitionExit = exitAnim;
4120                scheduleAnimationCallback(mNextAppTransitionCallback);
4121                mNextAppTransitionCallback = startedCallback;
4122            } else {
4123                scheduleAnimationCallback(startedCallback);
4124            }
4125        }
4126    }
4127
4128    @Override
4129    public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
4130            int startHeight) {
4131        synchronized(mWindowMap) {
4132            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4133                mNextAppTransitionType = ActivityOptions.ANIM_SCALE_UP;
4134                mNextAppTransitionPackage = null;
4135                mNextAppTransitionThumbnail = null;
4136                mNextAppTransitionStartX = startX;
4137                mNextAppTransitionStartY = startY;
4138                mNextAppTransitionStartWidth = startWidth;
4139                mNextAppTransitionStartHeight = startHeight;
4140                scheduleAnimationCallback(mNextAppTransitionCallback);
4141                mNextAppTransitionCallback = null;
4142            }
4143        }
4144    }
4145
4146    @Override
4147    public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
4148            int startY, IRemoteCallback startedCallback, boolean scaleUp) {
4149        synchronized(mWindowMap) {
4150            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4151                mNextAppTransitionType = scaleUp
4152                        ? ActivityOptions.ANIM_THUMBNAIL_SCALE_UP : ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
4153                mNextAppTransitionPackage = null;
4154                mNextAppTransitionThumbnail = srcThumb;
4155                mNextAppTransitionScaleUp = scaleUp;
4156                mNextAppTransitionStartX = startX;
4157                mNextAppTransitionStartY = startY;
4158                scheduleAnimationCallback(mNextAppTransitionCallback);
4159                mNextAppTransitionCallback = startedCallback;
4160            } else {
4161                scheduleAnimationCallback(startedCallback);
4162            }
4163        }
4164    }
4165
4166    @Override
4167    public void executeAppTransition() {
4168        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4169                "executeAppTransition()")) {
4170            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4171        }
4172
4173        synchronized(mWindowMap) {
4174            if (DEBUG_APP_TRANSITIONS) {
4175                RuntimeException e = new RuntimeException("here");
4176                e.fillInStackTrace();
4177                Slog.w(TAG, "Execute app transition: mNextAppTransition="
4178                        + mNextAppTransition, e);
4179            }
4180            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4181                mAppTransitionReady = true;
4182                final long origId = Binder.clearCallingIdentity();
4183                performLayoutAndPlaceSurfacesLocked();
4184                Binder.restoreCallingIdentity(origId);
4185            }
4186        }
4187    }
4188
4189    @Override
4190    public void setAppStartingWindow(IBinder token, String pkg,
4191            int theme, CompatibilityInfo compatInfo,
4192            CharSequence nonLocalizedLabel, int labelRes, int icon,
4193            int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
4194        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4195                "setAppStartingWindow()")) {
4196            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4197        }
4198
4199        synchronized(mWindowMap) {
4200            if (DEBUG_STARTING_WINDOW) Slog.v(
4201                    TAG, "setAppStartingWindow: token=" + token + " pkg=" + pkg
4202                    + " transferFrom=" + transferFrom);
4203
4204            AppWindowToken wtoken = findAppWindowToken(token);
4205            if (wtoken == null) {
4206                Slog.w(TAG, "Attempted to set icon of non-existing app token: " + token);
4207                return;
4208            }
4209
4210            // If the display is frozen, we won't do anything until the
4211            // actual window is displayed so there is no reason to put in
4212            // the starting window.
4213            if (!okToDisplay()) {
4214                return;
4215            }
4216
4217            if (wtoken.startingData != null) {
4218                return;
4219            }
4220
4221            if (transferFrom != null) {
4222                AppWindowToken ttoken = findAppWindowToken(transferFrom);
4223                if (ttoken != null) {
4224                    WindowState startingWindow = ttoken.startingWindow;
4225                    if (startingWindow != null) {
4226                        if (mStartingIconInTransition) {
4227                            // In this case, the starting icon has already
4228                            // been displayed, so start letting windows get
4229                            // shown immediately without any more transitions.
4230                            mSkipAppTransitionAnimation = true;
4231                        }
4232                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
4233                                "Moving existing starting " + startingWindow + " from " + ttoken
4234                                + " to " + wtoken);
4235                        final long origId = Binder.clearCallingIdentity();
4236
4237                        // Transfer the starting window over to the new
4238                        // token.
4239                        wtoken.startingData = ttoken.startingData;
4240                        wtoken.startingView = ttoken.startingView;
4241                        wtoken.startingDisplayed = ttoken.startingDisplayed;
4242                        ttoken.startingDisplayed = false;
4243                        wtoken.startingWindow = startingWindow;
4244                        wtoken.reportedVisible = ttoken.reportedVisible;
4245                        ttoken.startingData = null;
4246                        ttoken.startingView = null;
4247                        ttoken.startingWindow = null;
4248                        ttoken.startingMoved = true;
4249                        startingWindow.mToken = wtoken;
4250                        startingWindow.mRootToken = wtoken;
4251                        startingWindow.mAppToken = wtoken;
4252                        startingWindow.mWinAnimator.mAppAnimator = wtoken.mAppAnimator;
4253
4254                        if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) {
4255                            Slog.v(TAG, "Removing starting window: " + startingWindow);
4256                        }
4257                        startingWindow.getWindowList().remove(startingWindow);
4258                        mWindowsChanged = true;
4259                        if (DEBUG_ADD_REMOVE) Slog.v(TAG,
4260                                "Removing starting " + startingWindow + " from " + ttoken);
4261                        ttoken.windows.remove(startingWindow);
4262                        ttoken.allAppWindows.remove(startingWindow);
4263                        addWindowToListInOrderLocked(startingWindow, true);
4264
4265                        // Propagate other interesting state between the
4266                        // tokens.  If the old token is displayed, we should
4267                        // immediately force the new one to be displayed.  If
4268                        // it is animating, we need to move that animation to
4269                        // the new one.
4270                        if (ttoken.allDrawn) {
4271                            wtoken.allDrawn = true;
4272                        }
4273                        if (ttoken.firstWindowDrawn) {
4274                            wtoken.firstWindowDrawn = true;
4275                        }
4276                        if (!ttoken.hidden) {
4277                            wtoken.hidden = false;
4278                            wtoken.hiddenRequested = false;
4279                            wtoken.willBeHidden = false;
4280                        }
4281                        if (wtoken.clientHidden != ttoken.clientHidden) {
4282                            wtoken.clientHidden = ttoken.clientHidden;
4283                            wtoken.sendAppVisibilityToClients();
4284                        }
4285                        final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator;
4286                        final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator;
4287                        if (tAppAnimator.animation != null) {
4288                            wAppAnimator.animation = tAppAnimator.animation;
4289                            wAppAnimator.animating = tAppAnimator.animating;
4290                            wAppAnimator.animLayerAdjustment = tAppAnimator.animLayerAdjustment;
4291                            tAppAnimator.animation = null;
4292                            tAppAnimator.animLayerAdjustment = 0;
4293                            wAppAnimator.updateLayers();
4294                            tAppAnimator.updateLayers();
4295                        }
4296
4297                        updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4298                                true /*updateInputWindows*/);
4299                        getDefaultDisplayContentLocked().layoutNeeded = true;
4300                        performLayoutAndPlaceSurfacesLocked();
4301                        Binder.restoreCallingIdentity(origId);
4302                        return;
4303                    } else if (ttoken.startingData != null) {
4304                        // The previous app was getting ready to show a
4305                        // starting window, but hasn't yet done so.  Steal it!
4306                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
4307                                "Moving pending starting from " + ttoken
4308                                + " to " + wtoken);
4309                        wtoken.startingData = ttoken.startingData;
4310                        ttoken.startingData = null;
4311                        ttoken.startingMoved = true;
4312                        Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
4313                        // Note: we really want to do sendMessageAtFrontOfQueue() because we
4314                        // want to process the message ASAP, before any other queued
4315                        // messages.
4316                        mH.sendMessageAtFrontOfQueue(m);
4317                        return;
4318                    }
4319                    final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator;
4320                    final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator;
4321                    if (tAppAnimator.thumbnail != null) {
4322                        // The old token is animating with a thumbnail, transfer
4323                        // that to the new token.
4324                        if (wAppAnimator.thumbnail != null) {
4325                            wAppAnimator.thumbnail.destroy();
4326                        }
4327                        wAppAnimator.thumbnail = tAppAnimator.thumbnail;
4328                        wAppAnimator.thumbnailX = tAppAnimator.thumbnailX;
4329                        wAppAnimator.thumbnailY = tAppAnimator.thumbnailY;
4330                        wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
4331                        wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
4332                        tAppAnimator.thumbnail = null;
4333                    }
4334                }
4335            }
4336
4337            // There is no existing starting window, and the caller doesn't
4338            // want us to create one, so that's it!
4339            if (!createIfNeeded) {
4340                return;
4341            }
4342
4343            // If this is a translucent window, then don't
4344            // show a starting window -- the current effect (a full-screen
4345            // opaque starting window that fades away to the real contents
4346            // when it is ready) does not work for this.
4347            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Checking theme of starting window: 0x"
4348                    + Integer.toHexString(theme));
4349            if (theme != 0) {
4350                AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
4351                        com.android.internal.R.styleable.Window);
4352                if (ent == null) {
4353                    // Whoops!  App doesn't exist.  Um.  Okay.  We'll just
4354                    // pretend like we didn't see that.
4355                    return;
4356                }
4357                if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Translucent="
4358                        + ent.array.getBoolean(
4359                                com.android.internal.R.styleable.Window_windowIsTranslucent, false)
4360                        + " Floating="
4361                        + ent.array.getBoolean(
4362                                com.android.internal.R.styleable.Window_windowIsFloating, false)
4363                        + " ShowWallpaper="
4364                        + ent.array.getBoolean(
4365                                com.android.internal.R.styleable.Window_windowShowWallpaper, false));
4366                if (ent.array.getBoolean(
4367                        com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
4368                    return;
4369                }
4370                if (ent.array.getBoolean(
4371                        com.android.internal.R.styleable.Window_windowIsFloating, false)) {
4372                    return;
4373                }
4374                if (ent.array.getBoolean(
4375                        com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
4376                    if (mWallpaperTarget == null) {
4377                        // If this theme is requesting a wallpaper, and the wallpaper
4378                        // is not curently visible, then this effectively serves as
4379                        // an opaque window and our starting window transition animation
4380                        // can still work.  We just need to make sure the starting window
4381                        // is also showing the wallpaper.
4382                        windowFlags |= FLAG_SHOW_WALLPAPER;
4383                    } else {
4384                        return;
4385                    }
4386                }
4387            }
4388
4389            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Creating StartingData");
4390            mStartingIconInTransition = true;
4391            wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
4392                    labelRes, icon, windowFlags);
4393            Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
4394            // Note: we really want to do sendMessageAtFrontOfQueue() because we
4395            // want to process the message ASAP, before any other queued
4396            // messages.
4397            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING");
4398            mH.sendMessageAtFrontOfQueue(m);
4399        }
4400    }
4401
4402    public void setAppWillBeHidden(IBinder token) {
4403        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4404                "setAppWillBeHidden()")) {
4405            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4406        }
4407
4408        AppWindowToken wtoken;
4409
4410        synchronized(mWindowMap) {
4411            wtoken = findAppWindowToken(token);
4412            if (wtoken == null) {
4413                Slog.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
4414                return;
4415            }
4416            wtoken.willBeHidden = true;
4417        }
4418    }
4419
4420    boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
4421            boolean visible, int transit, boolean performLayout) {
4422        boolean delayed = false;
4423
4424        if (wtoken.clientHidden == visible) {
4425            wtoken.clientHidden = !visible;
4426            wtoken.sendAppVisibilityToClients();
4427        }
4428
4429        wtoken.willBeHidden = false;
4430        if (wtoken.hidden == visible) {
4431            boolean changed = false;
4432            if (DEBUG_APP_TRANSITIONS) Slog.v(
4433                TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
4434                + " performLayout=" + performLayout);
4435
4436            boolean runningAppAnimation = false;
4437
4438            if (transit != WindowManagerPolicy.TRANSIT_UNSET) {
4439                if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
4440                    wtoken.mAppAnimator.animation = null;
4441                }
4442                if (applyAnimationLocked(wtoken, lp, transit, visible)) {
4443                    delayed = runningAppAnimation = true;
4444                }
4445                WindowState window = wtoken.findMainWindow();
4446                if (window != null) {
4447                    scheduleNotifyWindowTranstionIfNeededLocked(window, transit);
4448                }
4449                changed = true;
4450            }
4451
4452            final int N = wtoken.allAppWindows.size();
4453            for (int i=0; i<N; i++) {
4454                WindowState win = wtoken.allAppWindows.get(i);
4455                if (win == wtoken.startingWindow) {
4456                    continue;
4457                }
4458
4459                //Slog.i(TAG, "Window " + win + ": vis=" + win.isVisible());
4460                //win.dump("  ");
4461                if (visible) {
4462                    if (!win.isVisibleNow()) {
4463                        if (!runningAppAnimation) {
4464                            win.mWinAnimator.applyAnimationLocked(
4465                                    WindowManagerPolicy.TRANSIT_ENTER, true);
4466                            scheduleNotifyWindowTranstionIfNeededLocked(win,
4467                                    WindowManagerPolicy.TRANSIT_ENTER);
4468                        }
4469                        changed = true;
4470                        win.mDisplayContent.layoutNeeded = true;
4471                    }
4472                } else if (win.isVisibleNow()) {
4473                    if (!runningAppAnimation) {
4474                        win.mWinAnimator.applyAnimationLocked(
4475                                WindowManagerPolicy.TRANSIT_EXIT, false);
4476                        scheduleNotifyWindowTranstionIfNeededLocked(win,
4477                                WindowManagerPolicy.TRANSIT_EXIT);
4478                    }
4479                    changed = true;
4480                    win.mDisplayContent.layoutNeeded = true;
4481                }
4482            }
4483
4484            wtoken.hidden = wtoken.hiddenRequested = !visible;
4485            if (!visible) {
4486                unsetAppFreezingScreenLocked(wtoken, true, true);
4487            } else {
4488                // If we are being set visible, and the starting window is
4489                // not yet displayed, then make sure it doesn't get displayed.
4490                WindowState swin = wtoken.startingWindow;
4491                if (swin != null && !swin.isDrawnLw()) {
4492                    swin.mPolicyVisibility = false;
4493                    swin.mPolicyVisibilityAfterAnim = false;
4494                 }
4495            }
4496
4497            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "setTokenVisibilityLocked: " + wtoken
4498                      + ": hidden=" + wtoken.hidden + " hiddenRequested="
4499                      + wtoken.hiddenRequested);
4500
4501            if (changed) {
4502                mInputMonitor.setUpdateInputWindowsNeededLw();
4503                if (performLayout) {
4504                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4505                            false /*updateInputWindows*/);
4506                    performLayoutAndPlaceSurfacesLocked();
4507                }
4508                mInputMonitor.updateInputWindowsLw(false /*force*/);
4509            }
4510        }
4511
4512        if (wtoken.mAppAnimator.animation != null) {
4513            delayed = true;
4514        }
4515
4516        for (int i = wtoken.allAppWindows.size() - 1; i >= 0 && !delayed; i--) {
4517            if (wtoken.allAppWindows.get(i).mWinAnimator.isWindowAnimating()) {
4518                delayed = true;
4519            }
4520        }
4521
4522        return delayed;
4523    }
4524
4525    public void setAppVisibility(IBinder token, boolean visible) {
4526        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4527                "setAppVisibility()")) {
4528            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4529        }
4530
4531        AppWindowToken wtoken;
4532
4533        synchronized(mWindowMap) {
4534            wtoken = findAppWindowToken(token);
4535            if (wtoken == null) {
4536                Slog.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
4537                return;
4538            }
4539
4540            if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
4541                RuntimeException e = null;
4542                if (!HIDE_STACK_CRAWLS) {
4543                    e = new RuntimeException();
4544                    e.fillInStackTrace();
4545                }
4546                Slog.v(TAG, "setAppVisibility(" + token + ", visible=" + visible
4547                        + "): mNextAppTransition=" + mNextAppTransition
4548                        + " hidden=" + wtoken.hidden
4549                        + " hiddenRequested=" + wtoken.hiddenRequested, e);
4550            }
4551
4552            // If we are preparing an app transition, then delay changing
4553            // the visibility of this token until we execute that transition.
4554            if (okToDisplay() && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4555                // Already in requested state, don't do anything more.
4556                if (wtoken.hiddenRequested != visible) {
4557                    return;
4558                }
4559                wtoken.hiddenRequested = !visible;
4560
4561                if (!wtoken.startingDisplayed) {
4562                    if (DEBUG_APP_TRANSITIONS) Slog.v(
4563                            TAG, "Setting dummy animation on: " + wtoken);
4564                    wtoken.mAppAnimator.setDummyAnimation();
4565                }
4566                mOpeningApps.remove(wtoken);
4567                mClosingApps.remove(wtoken);
4568                wtoken.waitingToShow = wtoken.waitingToHide = false;
4569                wtoken.inPendingTransaction = true;
4570                if (visible) {
4571                    mOpeningApps.add(wtoken);
4572                    wtoken.startingMoved = false;
4573
4574                    // If the token is currently hidden (should be the
4575                    // common case), then we need to set up to wait for
4576                    // its windows to be ready.
4577                    if (wtoken.hidden) {
4578                        wtoken.allDrawn = false;
4579                        wtoken.waitingToShow = true;
4580
4581                        if (wtoken.clientHidden) {
4582                            // In the case where we are making an app visible
4583                            // but holding off for a transition, we still need
4584                            // to tell the client to make its windows visible so
4585                            // they get drawn.  Otherwise, we will wait on
4586                            // performing the transition until all windows have
4587                            // been drawn, they never will be, and we are sad.
4588                            wtoken.clientHidden = false;
4589                            wtoken.sendAppVisibilityToClients();
4590                        }
4591                    }
4592                } else {
4593                    mClosingApps.add(wtoken);
4594
4595                    // If the token is currently visible (should be the
4596                    // common case), then set up to wait for it to be hidden.
4597                    if (!wtoken.hidden) {
4598                        wtoken.waitingToHide = true;
4599                    }
4600                }
4601                return;
4602            }
4603
4604            final long origId = Binder.clearCallingIdentity();
4605            setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET,
4606                    true);
4607            wtoken.updateReportedVisibilityLocked();
4608            Binder.restoreCallingIdentity(origId);
4609        }
4610    }
4611
4612    void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
4613            boolean unfreezeSurfaceNow, boolean force) {
4614        if (wtoken.mAppAnimator.freezingScreen) {
4615            if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + wtoken
4616                    + " force=" + force);
4617            final int N = wtoken.allAppWindows.size();
4618            boolean unfrozeWindows = false;
4619            for (int i=0; i<N; i++) {
4620                WindowState w = wtoken.allAppWindows.get(i);
4621                if (w.mAppFreezing) {
4622                    w.mAppFreezing = false;
4623                    if (w.mHasSurface && !w.mOrientationChanging) {
4624                        if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
4625                        w.mOrientationChanging = true;
4626                        mInnerFields.mOrientationChangeComplete = false;
4627                    }
4628                    unfrozeWindows = true;
4629                    w.mDisplayContent.layoutNeeded = true;
4630                }
4631            }
4632            if (force || unfrozeWindows) {
4633                if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken);
4634                wtoken.mAppAnimator.freezingScreen = false;
4635                mAppsFreezingScreen--;
4636            }
4637            if (unfreezeSurfaceNow) {
4638                if (unfrozeWindows) {
4639                    performLayoutAndPlaceSurfacesLocked();
4640                }
4641                stopFreezingDisplayLocked();
4642            }
4643        }
4644    }
4645
4646    public void startAppFreezingScreenLocked(AppWindowToken wtoken,
4647            int configChanges) {
4648        if (DEBUG_ORIENTATION) {
4649            RuntimeException e = null;
4650            if (!HIDE_STACK_CRAWLS) {
4651                e = new RuntimeException();
4652                e.fillInStackTrace();
4653            }
4654            Slog.i(TAG, "Set freezing of " + wtoken.appToken
4655                    + ": hidden=" + wtoken.hidden + " freezing="
4656                    + wtoken.mAppAnimator.freezingScreen, e);
4657        }
4658        if (!wtoken.hiddenRequested) {
4659            if (!wtoken.mAppAnimator.freezingScreen) {
4660                wtoken.mAppAnimator.freezingScreen = true;
4661                mAppsFreezingScreen++;
4662                if (mAppsFreezingScreen == 1) {
4663                    startFreezingDisplayLocked(false, 0, 0);
4664                    mH.removeMessages(H.APP_FREEZE_TIMEOUT);
4665                    mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT),
4666                            5000);
4667                }
4668            }
4669            final int N = wtoken.allAppWindows.size();
4670            for (int i=0; i<N; i++) {
4671                WindowState w = wtoken.allAppWindows.get(i);
4672                w.mAppFreezing = true;
4673            }
4674        }
4675    }
4676
4677    public void startAppFreezingScreen(IBinder token, int configChanges) {
4678        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4679                "setAppFreezingScreen()")) {
4680            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4681        }
4682
4683        synchronized(mWindowMap) {
4684            if (configChanges == 0 && okToDisplay()) {
4685                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping set freeze of " + token);
4686                return;
4687            }
4688
4689            AppWindowToken wtoken = findAppWindowToken(token);
4690            if (wtoken == null || wtoken.appToken == null) {
4691                Slog.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
4692                return;
4693            }
4694            final long origId = Binder.clearCallingIdentity();
4695            startAppFreezingScreenLocked(wtoken, configChanges);
4696            Binder.restoreCallingIdentity(origId);
4697        }
4698    }
4699
4700    public void stopAppFreezingScreen(IBinder token, boolean force) {
4701        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4702                "setAppFreezingScreen()")) {
4703            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4704        }
4705
4706        synchronized(mWindowMap) {
4707            AppWindowToken wtoken = findAppWindowToken(token);
4708            if (wtoken == null || wtoken.appToken == null) {
4709                return;
4710            }
4711            final long origId = Binder.clearCallingIdentity();
4712            if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + token
4713                    + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
4714            unsetAppFreezingScreenLocked(wtoken, true, force);
4715            Binder.restoreCallingIdentity(origId);
4716        }
4717    }
4718
4719    public void removeAppToken(IBinder token) {
4720        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4721                "removeAppToken()")) {
4722            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4723        }
4724
4725        AppWindowToken wtoken = null;
4726        AppWindowToken startingToken = null;
4727        boolean delayed = false;
4728
4729        final long origId = Binder.clearCallingIdentity();
4730        synchronized(mWindowMap) {
4731            WindowToken basewtoken = mTokenMap.remove(token);
4732            if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
4733                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
4734                delayed = setTokenVisibilityLocked(wtoken, null, false,
4735                        WindowManagerPolicy.TRANSIT_UNSET, true);
4736                wtoken.inPendingTransaction = false;
4737                mOpeningApps.remove(wtoken);
4738                wtoken.waitingToShow = false;
4739                if (mClosingApps.contains(wtoken)) {
4740                    delayed = true;
4741                } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4742                    mClosingApps.add(wtoken);
4743                    wtoken.waitingToHide = true;
4744                    delayed = true;
4745                }
4746                if (DEBUG_APP_TRANSITIONS) Slog.v(
4747                        TAG, "Removing app " + wtoken + " delayed=" + delayed
4748                        + " animation=" + wtoken.mAppAnimator.animation
4749                        + " animating=" + wtoken.mAppAnimator.animating);
4750                if (delayed) {
4751                    // set the token aside because it has an active animation to be finished
4752                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
4753                            "removeAppToken make exiting: " + wtoken);
4754                    mExitingAppTokens.add(wtoken);
4755                } else {
4756                    // Make sure there is no animation running on this token,
4757                    // so any windows associated with it will be removed as
4758                    // soon as their animations are complete
4759                    wtoken.mAppAnimator.clearAnimation();
4760                    wtoken.mAppAnimator.animating = false;
4761                }
4762                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
4763                        "removeAppToken: " + wtoken);
4764                mAppTokens.remove(wtoken);
4765                mAnimatingAppTokens.remove(wtoken);
4766                wtoken.removed = true;
4767                if (wtoken.startingData != null) {
4768                    startingToken = wtoken;
4769                }
4770                unsetAppFreezingScreenLocked(wtoken, true, true);
4771                if (mFocusedApp == wtoken) {
4772                    if (DEBUG_FOCUS) Slog.v(TAG, "Removing focused app token:" + wtoken);
4773                    mFocusedApp = null;
4774                    updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
4775                    mInputMonitor.setFocusedAppLw(null);
4776                }
4777            } else {
4778                Slog.w(TAG, "Attempted to remove non-existing app token: " + token);
4779            }
4780
4781            if (!delayed && wtoken != null) {
4782                wtoken.updateReportedVisibilityLocked();
4783            }
4784        }
4785        Binder.restoreCallingIdentity(origId);
4786
4787        if (startingToken != null) {
4788            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Schedule remove starting "
4789                    + startingToken + ": app token removed");
4790            Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
4791            mH.sendMessage(m);
4792        }
4793    }
4794
4795    private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
4796        final int NW = token.windows.size();
4797        if (NW > 0) {
4798            mWindowsChanged = true;
4799        }
4800        for (int i=0; i<NW; i++) {
4801            WindowState win = token.windows.get(i);
4802            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
4803            win.getWindowList().remove(win);
4804            int j = win.mChildWindows.size();
4805            while (j > 0) {
4806                j--;
4807                WindowState cwin = win.mChildWindows.get(j);
4808                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
4809                        "Tmp removing child window " + cwin);
4810                cwin.getWindowList().remove(cwin);
4811            }
4812        }
4813        return NW > 0;
4814    }
4815
4816    void dumpAppTokensLocked() {
4817        for (int i=mAppTokens.size()-1; i>=0; i--) {
4818            Slog.v(TAG, "  #" + i + ": " + mAppTokens.get(i).token);
4819        }
4820    }
4821
4822    void dumpAnimatingAppTokensLocked() {
4823        for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
4824            Slog.v(TAG, "  #" + i + ": " + mAnimatingAppTokens.get(i).token);
4825        }
4826    }
4827
4828    void dumpWindowsLocked() {
4829        int i = 0;
4830        final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
4831        while (iterator.hasNext()) {
4832            final WindowState w = iterator.next();
4833            Slog.v(TAG, "  #" + i++ + ": " + w);
4834        }
4835    }
4836
4837    private int findWindowOffsetLocked(WindowList windows, int tokenPos) {
4838        final int NW = windows.size();
4839
4840        if (tokenPos >= mAnimatingAppTokens.size()) {
4841            int i = NW;
4842            while (i > 0) {
4843                i--;
4844                WindowState win = windows.get(i);
4845                if (win.getAppToken() != null) {
4846                    return i+1;
4847                }
4848            }
4849        }
4850
4851        while (tokenPos > 0) {
4852            // Find the first app token below the new position that has
4853            // a window displayed.
4854            final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
4855            if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ "
4856                    + tokenPos + " -- " + wtoken.token);
4857            if (wtoken.sendingToBottom) {
4858                if (DEBUG_REORDER) Slog.v(TAG,
4859                        "Skipping token -- currently sending to bottom");
4860                tokenPos--;
4861                continue;
4862            }
4863            int i = wtoken.windows.size();
4864            while (i > 0) {
4865                i--;
4866                WindowState win = wtoken.windows.get(i);
4867                int j = win.mChildWindows.size();
4868                while (j > 0) {
4869                    j--;
4870                    WindowState cwin = win.mChildWindows.get(j);
4871                    if (cwin.mSubLayer >= 0) {
4872                        for (int pos=NW-1; pos>=0; pos--) {
4873                            if (windows.get(pos) == cwin) {
4874                                if (DEBUG_REORDER) Slog.v(TAG,
4875                                        "Found child win @" + (pos+1));
4876                                return pos+1;
4877                            }
4878                        }
4879                    }
4880                }
4881                for (int pos=NW-1; pos>=0; pos--) {
4882                    if (windows.get(pos) == win) {
4883                        if (DEBUG_REORDER) Slog.v(TAG, "Found win @" + (pos+1));
4884                        return pos+1;
4885                    }
4886                }
4887            }
4888            tokenPos--;
4889        }
4890
4891        return 0;
4892    }
4893
4894    private final int reAddWindowLocked(int index, WindowState win) {
4895        final WindowList windows = win.getWindowList();
4896        final int NCW = win.mChildWindows.size();
4897        boolean added = false;
4898        for (int j=0; j<NCW; j++) {
4899            WindowState cwin = win.mChildWindows.get(j);
4900            if (!added && cwin.mSubLayer >= 0) {
4901                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding child window at "
4902                        + index + ": " + cwin);
4903                win.mRebuilding = false;
4904                windows.add(index, win);
4905                index++;
4906                added = true;
4907            }
4908            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
4909                    + index + ": " + cwin);
4910            cwin.mRebuilding = false;
4911            windows.add(index, cwin);
4912            index++;
4913        }
4914        if (!added) {
4915            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
4916                    + index + ": " + win);
4917            win.mRebuilding = false;
4918            windows.add(index, win);
4919            index++;
4920        }
4921        mWindowsChanged = true;
4922        return index;
4923    }
4924
4925    private final int reAddAppWindowsLocked(final DisplayContent displayContent, int index,
4926                                            WindowToken token) {
4927        final int NW = token.windows.size();
4928        for (int i=0; i<NW; i++) {
4929            final WindowState win = token.windows.get(i);
4930            if (win.mDisplayContent == displayContent) {
4931                index = reAddWindowLocked(index, win);
4932            }
4933        }
4934        return index;
4935    }
4936
4937    public void moveAppToken(int index, IBinder token) {
4938        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4939                "moveAppToken()")) {
4940            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4941        }
4942
4943        synchronized(mWindowMap) {
4944            if (DEBUG_REORDER) Slog.v(TAG, "Initial app tokens:");
4945            if (DEBUG_REORDER) dumpAppTokensLocked();
4946            final AppWindowToken wtoken = findAppWindowToken(token);
4947            final int oldIndex = mAppTokens.indexOf(wtoken);
4948            if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
4949                    "Start moving token " + wtoken + " initially at "
4950                    + oldIndex);
4951            if (oldIndex > index && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET
4952                        && !mAppTransitionRunning) {
4953                // animation towards back has not started, copy old list for duration of animation.
4954                mAnimatingAppTokens.clear();
4955                mAnimatingAppTokens.addAll(mAppTokens);
4956            }
4957            if (wtoken == null || !mAppTokens.remove(wtoken)) {
4958                Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
4959                      + token + " (" + wtoken + ")");
4960                return;
4961            }
4962            mAppTokens.add(index, wtoken);
4963            if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":");
4964            else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index);
4965            if (DEBUG_REORDER) dumpAppTokensLocked();
4966            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET && !mAppTransitionRunning) {
4967                // Not animating, bring animating app list in line with mAppTokens.
4968                mAnimatingAppTokens.clear();
4969                mAnimatingAppTokens.addAll(mAppTokens);
4970
4971                // Bring window ordering, window focus and input window in line with new app token
4972                final long origId = Binder.clearCallingIdentity();
4973                if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":");
4974                if (DEBUG_REORDER) dumpWindowsLocked();
4975                if (tmpRemoveAppWindowsLocked(wtoken)) {
4976                    if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:");
4977                    if (DEBUG_REORDER) dumpWindowsLocked();
4978                    DisplayContentsIterator iterator = new DisplayContentsIterator();
4979                    while(iterator.hasNext()) {
4980                        final DisplayContent displayContent = iterator.next();
4981                        final WindowList windows = displayContent.getWindowList();
4982                        final int pos = findWindowOffsetLocked(windows, index);
4983                        final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
4984                        if (pos != newPos) {
4985                            displayContent.layoutNeeded = true;
4986                        }
4987                    }
4988                    if (DEBUG_REORDER) Slog.v(TAG, "Final window list:");
4989                    if (DEBUG_REORDER) dumpWindowsLocked();
4990                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4991                            false /*updateInputWindows*/);
4992                    mInputMonitor.setUpdateInputWindowsNeededLw();
4993                    performLayoutAndPlaceSurfacesLocked();
4994                    mInputMonitor.updateInputWindowsLw(false /*force*/);
4995                }
4996                Binder.restoreCallingIdentity(origId);
4997            }
4998        }
4999    }
5000
5001    private void removeAppTokensLocked(List<IBinder> tokens) {
5002        // XXX This should be done more efficiently!
5003        // (take advantage of the fact that both lists should be
5004        // ordered in the same way.)
5005        int N = tokens.size();
5006        for (int i=0; i<N; i++) {
5007            IBinder token = tokens.get(i);
5008            final AppWindowToken wtoken = findAppWindowToken(token);
5009            if (DEBUG_REORDER || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
5010                    "Temporarily removing " + wtoken + " from " + mAppTokens.indexOf(wtoken));
5011            if (!mAppTokens.remove(wtoken)) {
5012                Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
5013                      + token + " (" + wtoken + ")");
5014                i--;
5015                N--;
5016            }
5017        }
5018    }
5019
5020    private void moveAppWindowsLocked(AppWindowToken wtoken, int tokenPos,
5021            boolean updateFocusAndLayout) {
5022        // First remove all of the windows from the list.
5023        tmpRemoveAppWindowsLocked(wtoken);
5024
5025        // And now add them back at the correct place.
5026        DisplayContentsIterator iterator = new DisplayContentsIterator();
5027        while (iterator.hasNext()) {
5028            final DisplayContent displayContent = iterator.next();
5029            final WindowList windows = displayContent.getWindowList();
5030            final int pos = findWindowOffsetLocked(windows, tokenPos);
5031            final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
5032            if (pos != newPos) {
5033                displayContent.layoutNeeded = true;
5034            }
5035
5036            if (updateFocusAndLayout && !updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
5037                    false /*updateInputWindows*/)) {
5038                assignLayersLocked(windows);
5039            }
5040        }
5041
5042        if (updateFocusAndLayout) {
5043            mInputMonitor.setUpdateInputWindowsNeededLw();
5044
5045            // Note that the above updateFocusedWindowLocked conditional used to sit here.
5046
5047            if (!mInLayout) {
5048                performLayoutAndPlaceSurfacesLocked();
5049            }
5050            mInputMonitor.updateInputWindowsLw(false /*force*/);
5051        }
5052    }
5053
5054    private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
5055        // First remove all of the windows from the list.
5056        final int N = tokens.size();
5057        int i;
5058        for (i=0; i<N; i++) {
5059            WindowToken token = mTokenMap.get(tokens.get(i));
5060            if (token != null) {
5061                tmpRemoveAppWindowsLocked(token);
5062            }
5063        }
5064
5065        // And now add them back at the correct place.
5066        DisplayContentsIterator iterator = new DisplayContentsIterator();
5067        while (iterator.hasNext()) {
5068            final DisplayContent displayContent = iterator.next();
5069            final WindowList windows = displayContent.getWindowList();
5070            // Where to start adding?
5071            int pos = findWindowOffsetLocked(windows, tokenPos);
5072            for (i=0; i<N; i++) {
5073                WindowToken token = mTokenMap.get(tokens.get(i));
5074                if (token != null) {
5075                    final int newPos = reAddAppWindowsLocked(displayContent, pos, token);
5076                    if (newPos != pos) {
5077                        displayContent.layoutNeeded = true;
5078                    }
5079                    pos = newPos;
5080                }
5081            }
5082            if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
5083                    false /*updateInputWindows*/)) {
5084                assignLayersLocked(windows);
5085            }
5086        }
5087
5088        mInputMonitor.setUpdateInputWindowsNeededLw();
5089
5090        // Note that the above updateFocusedWindowLocked used to sit here.
5091
5092        performLayoutAndPlaceSurfacesLocked();
5093        mInputMonitor.updateInputWindowsLw(false /*force*/);
5094
5095        //dump();
5096    }
5097
5098    public void moveAppTokensToTop(List<IBinder> tokens) {
5099        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
5100                "moveAppTokensToTop()")) {
5101            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
5102        }
5103
5104        final long origId = Binder.clearCallingIdentity();
5105        synchronized(mWindowMap) {
5106            removeAppTokensLocked(tokens);
5107            final int N = tokens.size();
5108            for (int i=0; i<N; i++) {
5109                AppWindowToken wt = findAppWindowToken(tokens.get(i));
5110                if (wt != null) {
5111                    if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
5112                            "Adding next to top: " + wt);
5113                    mAppTokens.add(wt);
5114                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
5115                        wt.sendingToBottom = false;
5116                    }
5117                }
5118            }
5119
5120            if (!mAppTransitionRunning) {
5121                mAnimatingAppTokens.clear();
5122                mAnimatingAppTokens.addAll(mAppTokens);
5123                moveAppWindowsLocked(tokens, mAppTokens.size());
5124            }
5125        }
5126        Binder.restoreCallingIdentity(origId);
5127    }
5128
5129    @Override
5130    public void moveAppTokensToBottom(List<IBinder> tokens) {
5131        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
5132                "moveAppTokensToBottom()")) {
5133            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
5134        }
5135
5136        final long origId = Binder.clearCallingIdentity();
5137        synchronized(mWindowMap) {
5138            final int N = tokens.size();
5139            if (N > 0 && !mAppTransitionRunning) {
5140                // animating towards back, hang onto old list for duration of animation.
5141                mAnimatingAppTokens.clear();
5142                mAnimatingAppTokens.addAll(mAppTokens);
5143            }
5144            removeAppTokensLocked(tokens);
5145            int pos = 0;
5146            for (int i=0; i<N; i++) {
5147                AppWindowToken wt = findAppWindowToken(tokens.get(i));
5148                if (wt != null) {
5149                    if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
5150                            "Adding next to bottom: " + wt + " at " + pos);
5151                    mAppTokens.add(pos, wt);
5152                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
5153                        wt.sendingToBottom = true;
5154                    }
5155                    pos++;
5156                }
5157            }
5158
5159            if (!mAppTransitionRunning) {
5160                mAnimatingAppTokens.clear();
5161                mAnimatingAppTokens.addAll(mAppTokens);
5162                moveAppWindowsLocked(tokens, 0);
5163            }
5164        }
5165        Binder.restoreCallingIdentity(origId);
5166    }
5167
5168    // -------------------------------------------------------------
5169    // Misc IWindowSession methods
5170    // -------------------------------------------------------------
5171
5172    @Override
5173    public void startFreezingScreen(int exitAnim, int enterAnim) {
5174        if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
5175                "startFreezingScreen()")) {
5176            throw new SecurityException("Requires FREEZE_SCREEN permission");
5177        }
5178
5179        synchronized(mWindowMap) {
5180            if (!mClientFreezingScreen) {
5181                mClientFreezingScreen = true;
5182                final long origId = Binder.clearCallingIdentity();
5183                try {
5184                    startFreezingDisplayLocked(false, exitAnim, enterAnim);
5185                    mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
5186                    mH.sendMessageDelayed(mH.obtainMessage(H.CLIENT_FREEZE_TIMEOUT),
5187                            5000);
5188                } finally {
5189                    Binder.restoreCallingIdentity(origId);
5190                }
5191            }
5192        }
5193    }
5194
5195    @Override
5196    public void stopFreezingScreen() {
5197        if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
5198                "stopFreezingScreen()")) {
5199            throw new SecurityException("Requires FREEZE_SCREEN permission");
5200        }
5201
5202        synchronized(mWindowMap) {
5203            if (mClientFreezingScreen) {
5204                mClientFreezingScreen = false;
5205                final long origId = Binder.clearCallingIdentity();
5206                try {
5207                    stopFreezingDisplayLocked();
5208                } finally {
5209                    Binder.restoreCallingIdentity(origId);
5210                }
5211            }
5212        }
5213    }
5214
5215    @Override
5216    public void disableKeyguard(IBinder token, String tag) {
5217        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5218            != PackageManager.PERMISSION_GRANTED) {
5219            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5220        }
5221
5222        mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
5223                KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag)));
5224    }
5225
5226    @Override
5227    public void reenableKeyguard(IBinder token) {
5228        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5229            != PackageManager.PERMISSION_GRANTED) {
5230            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5231        }
5232
5233        mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
5234                KeyguardDisableHandler.KEYGUARD_REENABLE, token));
5235    }
5236
5237    /**
5238     * @see android.app.KeyguardManager#exitKeyguardSecurely
5239     */
5240    public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
5241        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5242            != PackageManager.PERMISSION_GRANTED) {
5243            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5244        }
5245        mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
5246            public void onKeyguardExitResult(boolean success) {
5247                try {
5248                    callback.onKeyguardExitResult(success);
5249                } catch (RemoteException e) {
5250                    // Client has died, we don't care.
5251                }
5252            }
5253        });
5254    }
5255
5256    public boolean inKeyguardRestrictedInputMode() {
5257        return mPolicy.inKeyguardRestrictedKeyInputMode();
5258    }
5259
5260    public boolean isKeyguardLocked() {
5261        return mPolicy.isKeyguardLocked();
5262    }
5263
5264    public boolean isKeyguardSecure() {
5265        return mPolicy.isKeyguardSecure();
5266    }
5267
5268    public void dismissKeyguard() {
5269        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5270                != PackageManager.PERMISSION_GRANTED) {
5271            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5272        }
5273        synchronized(mWindowMap) {
5274            mPolicy.dismissKeyguardLw();
5275        }
5276    }
5277
5278    public void closeSystemDialogs(String reason) {
5279        synchronized(mWindowMap) {
5280            final AllWindowsIterator iterator = new AllWindowsIterator();
5281            while (iterator.hasNext()) {
5282                final WindowState w = iterator.next();
5283                if (w.mHasSurface) {
5284                    try {
5285                        w.mClient.closeSystemDialogs(reason);
5286                    } catch (RemoteException e) {
5287                    }
5288                }
5289            }
5290        }
5291    }
5292
5293    static float fixScale(float scale) {
5294        if (scale < 0) scale = 0;
5295        else if (scale > 20) scale = 20;
5296        return Math.abs(scale);
5297    }
5298
5299    public void setAnimationScale(int which, float scale) {
5300        if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
5301                "setAnimationScale()")) {
5302            throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
5303        }
5304
5305        if (scale < 0) scale = 0;
5306        else if (scale > 20) scale = 20;
5307        scale = Math.abs(scale);
5308        switch (which) {
5309            case 0: mWindowAnimationScale = fixScale(scale); break;
5310            case 1: mTransitionAnimationScale = fixScale(scale); break;
5311            case 2: mAnimatorDurationScale = fixScale(scale); break;
5312        }
5313
5314        // Persist setting
5315        mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
5316    }
5317
5318    public void setAnimationScales(float[] scales) {
5319        if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
5320                "setAnimationScale()")) {
5321            throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
5322        }
5323
5324        if (scales != null) {
5325            if (scales.length >= 1) {
5326                mWindowAnimationScale = fixScale(scales[0]);
5327            }
5328            if (scales.length >= 2) {
5329                mTransitionAnimationScale = fixScale(scales[1]);
5330            }
5331            if (scales.length >= 3) {
5332                setAnimatorDurationScale(fixScale(scales[2]));
5333            }
5334        }
5335
5336        // Persist setting
5337        mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
5338    }
5339
5340    private void setAnimatorDurationScale(float scale) {
5341        mAnimatorDurationScale = scale;
5342        ValueAnimator.setDurationScale(scale);
5343    }
5344
5345    public float getAnimationScale(int which) {
5346        switch (which) {
5347            case 0: return mWindowAnimationScale;
5348            case 1: return mTransitionAnimationScale;
5349            case 2: return mAnimatorDurationScale;
5350        }
5351        return 0;
5352    }
5353
5354    public float[] getAnimationScales() {
5355        return new float[] { mWindowAnimationScale, mTransitionAnimationScale,
5356                mAnimatorDurationScale };
5357    }
5358
5359    // Called by window manager policy. Not exposed externally.
5360    @Override
5361    public int getLidState() {
5362        int sw = mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY,
5363                InputManagerService.SW_LID);
5364        if (sw > 0) {
5365            // Switch state: AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL.
5366            return LID_CLOSED;
5367        } else if (sw == 0) {
5368            // Switch state: AKEY_STATE_UP.
5369            return LID_OPEN;
5370        } else {
5371            // Switch state: AKEY_STATE_UNKNOWN.
5372            return LID_ABSENT;
5373        }
5374    }
5375
5376    // Called by window manager policy.  Not exposed externally.
5377    @Override
5378    public InputChannel monitorInput(String inputChannelName) {
5379        return mInputManager.monitorInput(inputChannelName);
5380    }
5381
5382    // Called by window manager policy.  Not exposed externally.
5383    @Override
5384    public void switchKeyboardLayout(int deviceId, int direction) {
5385        mInputManager.switchKeyboardLayout(deviceId, direction);
5386    }
5387
5388    // Called by window manager policy.  Not exposed externally.
5389    @Override
5390    public void shutdown(boolean confirm) {
5391        ShutdownThread.shutdown(mContext, confirm);
5392    }
5393
5394    // Called by window manager policy.  Not exposed externally.
5395    @Override
5396    public void rebootSafeMode(boolean confirm) {
5397        ShutdownThread.rebootSafeMode(mContext, confirm);
5398    }
5399
5400    public void setInputFilter(IInputFilter filter) {
5401        if (!checkCallingPermission(android.Manifest.permission.FILTER_EVENTS, "setInputFilter()")) {
5402            throw new SecurityException("Requires FILTER_EVENTS permission");
5403        }
5404        mInputManager.setInputFilter(filter);
5405    }
5406
5407    public void setCurrentUser(final int newUserId) {
5408        synchronized (mWindowMap) {
5409            mCurrentUserId = newUserId;
5410            mPolicy.setCurrentUserLw(newUserId);
5411
5412            // Hide windows that should not be seen by the new user.
5413            DisplayContentsIterator iterator = new DisplayContentsIterator();
5414            while (iterator.hasNext()) {
5415                final WindowList windows = iterator.next().getWindowList();
5416                for (int i = 0; i < windows.size(); i++) {
5417                    final WindowState win = windows.get(i);
5418                    if (win.isHiddenFromUserLocked()) {
5419                        Slog.w(TAG, "current user violation " + newUserId + " hiding "
5420                                + win + ", attrs=" + win.mAttrs.type + ", belonging to "
5421                                + win.mOwnerUid);
5422                        win.hideLw(false);
5423                    }
5424                }
5425            }
5426            performLayoutAndPlaceSurfacesLocked();
5427        }
5428    }
5429
5430    public void enableScreenAfterBoot() {
5431        synchronized(mWindowMap) {
5432            if (DEBUG_BOOT) {
5433                RuntimeException here = new RuntimeException("here");
5434                here.fillInStackTrace();
5435                Slog.i(TAG, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled
5436                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5437                        + " mShowingBootMessages=" + mShowingBootMessages
5438                        + " mSystemBooted=" + mSystemBooted, here);
5439            }
5440            if (mSystemBooted) {
5441                return;
5442            }
5443            mSystemBooted = true;
5444            hideBootMessagesLocked();
5445            // If the screen still doesn't come up after 30 seconds, give
5446            // up and turn it on.
5447            Message msg = mH.obtainMessage(H.BOOT_TIMEOUT);
5448            mH.sendMessageDelayed(msg, 30*1000);
5449        }
5450
5451        mPolicy.systemBooted();
5452
5453        performEnableScreen();
5454    }
5455
5456    void enableScreenIfNeededLocked() {
5457        if (DEBUG_BOOT) {
5458            RuntimeException here = new RuntimeException("here");
5459            here.fillInStackTrace();
5460            Slog.i(TAG, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled
5461                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5462                    + " mShowingBootMessages=" + mShowingBootMessages
5463                    + " mSystemBooted=" + mSystemBooted, here);
5464        }
5465        if (mDisplayEnabled) {
5466            return;
5467        }
5468        if (!mSystemBooted && !mShowingBootMessages) {
5469            return;
5470        }
5471        mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
5472    }
5473
5474    public void performBootTimeout() {
5475        synchronized(mWindowMap) {
5476            if (mDisplayEnabled || mHeadless) {
5477                return;
5478            }
5479            Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
5480            mForceDisplayEnabled = true;
5481        }
5482        performEnableScreen();
5483    }
5484
5485    public void performEnableScreen() {
5486        synchronized(mWindowMap) {
5487            if (DEBUG_BOOT) {
5488                RuntimeException here = new RuntimeException("here");
5489                here.fillInStackTrace();
5490                Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
5491                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5492                        + " mShowingBootMessages=" + mShowingBootMessages
5493                        + " mSystemBooted=" + mSystemBooted
5494                        + " mOnlyCore=" + mOnlyCore, here);
5495            }
5496            if (mDisplayEnabled) {
5497                return;
5498            }
5499            if (!mSystemBooted && !mShowingBootMessages) {
5500                return;
5501            }
5502
5503            if (!mForceDisplayEnabled) {
5504                // Don't enable the screen until all existing windows
5505                // have been drawn.
5506                boolean haveBootMsg = false;
5507                boolean haveApp = false;
5508                // if the wallpaper service is disabled on the device, we're never going to have
5509                // wallpaper, don't bother waiting for it
5510                boolean haveWallpaper = false;
5511                boolean wallpaperEnabled = mContext.getResources().getBoolean(
5512                        com.android.internal.R.bool.config_enableWallpaperService)
5513                        && !mOnlyCore;
5514                boolean haveKeyguard = true;
5515                // TODO(multidisplay): Expand to all displays?
5516                final WindowList windows = getDefaultWindowListLocked();
5517                final int N = windows.size();
5518                for (int i=0; i<N; i++) {
5519                    WindowState w = windows.get(i);
5520                    if (w.mAttrs.type == TYPE_KEYGUARD) {
5521                        // Only if there is a keyguard attached to the window manager
5522                        // will we consider ourselves as having a keyguard.  If it
5523                        // isn't attached, we don't know if it wants to be shown or
5524                        // hidden.  If it is attached, we will say we have a keyguard
5525                        // if the window doesn't want to be visible, because in that
5526                        // case it explicitly doesn't want to be shown so we should
5527                        // not delay turning the screen on for it.
5528                        boolean vis = w.mViewVisibility == View.VISIBLE
5529                                && w.mPolicyVisibility;
5530                        haveKeyguard = !vis;
5531                    }
5532                    if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
5533                        return;
5534                    }
5535                    if (w.isDrawnLw()) {
5536                        if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
5537                            haveBootMsg = true;
5538                        } else if (w.mAttrs.type == TYPE_APPLICATION) {
5539                            haveApp = true;
5540                        } else if (w.mAttrs.type == TYPE_WALLPAPER) {
5541                            haveWallpaper = true;
5542                        } else if (w.mAttrs.type == TYPE_KEYGUARD) {
5543                            haveKeyguard = true;
5544                        }
5545                    }
5546                }
5547
5548                if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
5549                    Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
5550                            + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
5551                            + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
5552                            + " haveKeyguard=" + haveKeyguard);
5553                }
5554
5555                // If we are turning on the screen to show the boot message,
5556                // don't do it until the boot message is actually displayed.
5557                if (!mSystemBooted && !haveBootMsg) {
5558                    return;
5559                }
5560
5561                // If we are turning on the screen after the boot is completed
5562                // normally, don't do so until we have the application and
5563                // wallpaper.
5564                if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
5565                        (wallpaperEnabled && !haveWallpaper))) {
5566                    return;
5567                }
5568            }
5569
5570            mDisplayEnabled = true;
5571            if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
5572            if (false) {
5573                StringWriter sw = new StringWriter();
5574                PrintWriter pw = new PrintWriter(sw);
5575                this.dump(null, pw, null);
5576                Slog.i(TAG, sw.toString());
5577            }
5578            try {
5579                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
5580                if (surfaceFlinger != null) {
5581                    //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
5582                    Parcel data = Parcel.obtain();
5583                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
5584                    surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
5585                                            data, null, 0);
5586                    data.recycle();
5587                }
5588            } catch (RemoteException ex) {
5589                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
5590            }
5591
5592            // Enable input dispatch.
5593            mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
5594        }
5595
5596        mPolicy.enableScreenAfterBoot();
5597
5598        // Make sure the last requested orientation has been applied.
5599        updateRotationUnchecked(false, false);
5600    }
5601
5602    public void showBootMessage(final CharSequence msg, final boolean always) {
5603        boolean first = false;
5604        synchronized(mWindowMap) {
5605            if (DEBUG_BOOT) {
5606                RuntimeException here = new RuntimeException("here");
5607                here.fillInStackTrace();
5608                Slog.i(TAG, "showBootMessage: msg=" + msg + " always=" + always
5609                        + " mAllowBootMessages=" + mAllowBootMessages
5610                        + " mShowingBootMessages=" + mShowingBootMessages
5611                        + " mSystemBooted=" + mSystemBooted, here);
5612            }
5613            if (!mAllowBootMessages) {
5614                return;
5615            }
5616            if (!mShowingBootMessages) {
5617                if (!always) {
5618                    return;
5619                }
5620                first = true;
5621            }
5622            if (mSystemBooted) {
5623                return;
5624            }
5625            mShowingBootMessages = true;
5626            mPolicy.showBootMessage(msg, always);
5627        }
5628        if (first) {
5629            performEnableScreen();
5630        }
5631    }
5632
5633    public void hideBootMessagesLocked() {
5634        if (DEBUG_BOOT) {
5635            RuntimeException here = new RuntimeException("here");
5636            here.fillInStackTrace();
5637            Slog.i(TAG, "hideBootMessagesLocked: mDisplayEnabled=" + mDisplayEnabled
5638                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5639                    + " mShowingBootMessages=" + mShowingBootMessages
5640                    + " mSystemBooted=" + mSystemBooted, here);
5641        }
5642        if (mShowingBootMessages) {
5643            mShowingBootMessages = false;
5644            mPolicy.hideBootMessages();
5645        }
5646    }
5647
5648    public void setInTouchMode(boolean mode) {
5649        synchronized(mWindowMap) {
5650            mInTouchMode = mode;
5651        }
5652    }
5653
5654    // TODO: more accounting of which pid(s) turned it on, keep count,
5655    // only allow disables from pids which have count on, etc.
5656    @Override
5657    public void showStrictModeViolation(boolean on) {
5658        if (mHeadless) return;
5659        int pid = Binder.getCallingPid();
5660        mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid));
5661    }
5662
5663    private void showStrictModeViolation(int arg, int pid) {
5664        final boolean on = arg != 0;
5665        synchronized(mWindowMap) {
5666            // Ignoring requests to enable the red border from clients
5667            // which aren't on screen.  (e.g. Broadcast Receivers in
5668            // the background..)
5669            if (on) {
5670                boolean isVisible = false;
5671                final AllWindowsIterator iterator = new AllWindowsIterator();
5672                while (iterator.hasNext()) {
5673                    final WindowState ws = iterator.next();
5674                    if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
5675                        isVisible = true;
5676                        break;
5677                    }
5678                }
5679                if (!isVisible) {
5680                    return;
5681                }
5682            }
5683
5684            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5685                    ">>> OPEN TRANSACTION showStrictModeViolation");
5686            Surface.openTransaction();
5687            try {
5688                // TODO(multi-display): support multiple displays
5689                if (mStrictModeFlash == null) {
5690                    mStrictModeFlash = new StrictModeFlash(
5691                            getDefaultDisplayContentLocked().getDisplay(), mFxSession);
5692                }
5693                mStrictModeFlash.setVisibility(on);
5694            } finally {
5695                Surface.closeTransaction();
5696                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5697                        "<<< CLOSE TRANSACTION showStrictModeViolation");
5698            }
5699        }
5700    }
5701
5702    public void setStrictModeVisualIndicatorPreference(String value) {
5703        SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
5704    }
5705
5706    /**
5707     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
5708     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
5709     * of the target image.
5710     *
5711     * @param displayId the Display to take a screenshot of.
5712     * @param width the width of the target bitmap
5713     * @param height the height of the target bitmap
5714     */
5715    public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height) {
5716        if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
5717                "screenshotApplications()")) {
5718            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
5719        }
5720
5721        Bitmap rawss;
5722
5723        int maxLayer = 0;
5724        final Rect frame = new Rect();
5725
5726        float scale;
5727        int dw, dh;
5728        int rot;
5729
5730        synchronized(mWindowMap) {
5731            long ident = Binder.clearCallingIdentity();
5732
5733            final DisplayContent displayContent = getDisplayContentLocked(displayId);
5734            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
5735            dw = displayInfo.logicalWidth;
5736            dh = displayInfo.logicalHeight;
5737
5738            int aboveAppLayer = mPolicy.windowTypeToLayerLw(TYPE_APPLICATION)
5739                    * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
5740            aboveAppLayer += TYPE_LAYER_MULTIPLIER;
5741
5742            boolean isImeTarget = mInputMethodTarget != null
5743                    && mInputMethodTarget.mAppToken != null
5744                    && mInputMethodTarget.mAppToken.appToken != null
5745                    && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
5746
5747            // Figure out the part of the screen that is actually the app.
5748            boolean including = false;
5749            final WindowList windows = displayContent.getWindowList();
5750            for (int i = windows.size() - 1; i >= 0; i--) {
5751                WindowState ws = windows.get(i);
5752                if (!ws.mHasSurface) {
5753                    continue;
5754                }
5755                if (ws.mLayer >= aboveAppLayer) {
5756                    continue;
5757                }
5758                // When we will skip windows: when we are not including
5759                // ones behind a window we didn't skip, and we are actually
5760                // taking a screenshot of a specific app.
5761                if (!including && appToken != null) {
5762                    // Also, we can possibly skip this window if it is not
5763                    // an IME target or the application for the screenshot
5764                    // is not the current IME target.
5765                    if (!ws.mIsImWindow || !isImeTarget) {
5766                        // And finally, this window is of no interest if it
5767                        // is not associated with the screenshot app.
5768                        if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
5769                            continue;
5770                        }
5771                    }
5772                }
5773
5774                // We keep on including windows until we go past a full-screen
5775                // window.
5776                including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
5777
5778                if (maxLayer < ws.mWinAnimator.mSurfaceLayer) {
5779                    maxLayer = ws.mWinAnimator.mSurfaceLayer;
5780                }
5781
5782                // Don't include wallpaper in bounds calculation
5783                if (!ws.mIsWallpaper) {
5784                    final Rect wf = ws.mFrame;
5785                    final Rect cr = ws.mContentInsets;
5786                    int left = wf.left + cr.left;
5787                    int top = wf.top + cr.top;
5788                    int right = wf.right - cr.right;
5789                    int bottom = wf.bottom - cr.bottom;
5790                    frame.union(left, top, right, bottom);
5791                }
5792            }
5793            Binder.restoreCallingIdentity(ident);
5794
5795            // Constrain frame to the screen size.
5796            frame.intersect(0, 0, dw, dh);
5797
5798            if (frame.isEmpty() || maxLayer == 0) {
5799                return null;
5800            }
5801
5802            // The screenshot API does not apply the current screen rotation.
5803            rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
5804            int fw = frame.width();
5805            int fh = frame.height();
5806
5807            // Constrain thumbnail to smaller of screen width or height. Assumes aspect
5808            // of thumbnail is the same as the screen (in landscape) or square.
5809            float targetWidthScale = width / (float) fw;
5810            float targetHeightScale = height / (float) fh;
5811            if (dw <= dh) {
5812                scale = targetWidthScale;
5813                // If aspect of thumbnail is the same as the screen (in landscape),
5814                // select the slightly larger value so we fill the entire bitmap
5815                if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
5816                    scale = targetHeightScale;
5817                }
5818            } else {
5819                scale = targetHeightScale;
5820                // If aspect of thumbnail is the same as the screen (in landscape),
5821                // select the slightly larger value so we fill the entire bitmap
5822                if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
5823                    scale = targetWidthScale;
5824                }
5825            }
5826
5827            // The screen shot will contain the entire screen.
5828            dw = (int)(dw*scale);
5829            dh = (int)(dh*scale);
5830            if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
5831                int tmp = dw;
5832                dw = dh;
5833                dh = tmp;
5834                rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
5835            }
5836            if (DEBUG_SCREENSHOT) {
5837                Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from 0 to " + maxLayer);
5838                for (int i = 0; i < windows.size(); i++) {
5839                    WindowState win = windows.get(i);
5840                    Slog.i(TAG, win + ": " + win.mLayer
5841                            + " animLayer=" + win.mWinAnimator.mAnimLayer
5842                            + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
5843                }
5844            }
5845            rawss = Surface.screenshot(dw, dh, 0, maxLayer);
5846        }
5847
5848        if (rawss == null) {
5849            Slog.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh
5850                    + ") to layer " + maxLayer);
5851            return null;
5852        }
5853
5854        Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
5855        Matrix matrix = new Matrix();
5856        ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
5857        matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
5858        Canvas canvas = new Canvas(bm);
5859        canvas.drawBitmap(rawss, matrix, null);
5860        canvas.setBitmap(null);
5861
5862        rawss.recycle();
5863        return bm;
5864    }
5865
5866    /**
5867     * Freeze rotation changes.  (Enable "rotation lock".)
5868     * Persists across reboots.
5869     * @param rotation The desired rotation to freeze to, or -1 to use the
5870     * current rotation.
5871     */
5872    public void freezeRotation(int rotation) {
5873        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5874                "freezeRotation()")) {
5875            throw new SecurityException("Requires SET_ORIENTATION permission");
5876        }
5877        if (rotation < -1 || rotation > Surface.ROTATION_270) {
5878            throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
5879                    + "rotation constant.");
5880        }
5881
5882        if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
5883
5884        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
5885                rotation == -1 ? mRotation : rotation);
5886        updateRotationUnchecked(false, false);
5887    }
5888
5889    /**
5890     * Thaw rotation changes.  (Disable "rotation lock".)
5891     * Persists across reboots.
5892     */
5893    public void thawRotation() {
5894        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5895                "thawRotation()")) {
5896            throw new SecurityException("Requires SET_ORIENTATION permission");
5897        }
5898
5899        if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
5900
5901        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used
5902        updateRotationUnchecked(false, false);
5903    }
5904
5905    /**
5906     * Recalculate the current rotation.
5907     *
5908     * Called by the window manager policy whenever the state of the system changes
5909     * such that the current rotation might need to be updated, such as when the
5910     * device is docked or rotated into a new posture.
5911     */
5912    public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
5913        updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
5914    }
5915
5916    /**
5917     * Temporarily pauses rotation changes until resumed.
5918     *
5919     * This can be used to prevent rotation changes from occurring while the user is
5920     * performing certain operations, such as drag and drop.
5921     *
5922     * This call nests and must be matched by an equal number of calls to {@link #resumeRotation}.
5923     */
5924    void pauseRotationLocked() {
5925        mDeferredRotationPauseCount += 1;
5926    }
5927
5928    /**
5929     * Resumes normal rotation changes after being paused.
5930     */
5931    void resumeRotationLocked() {
5932        if (mDeferredRotationPauseCount > 0) {
5933            mDeferredRotationPauseCount -= 1;
5934            if (mDeferredRotationPauseCount == 0) {
5935                boolean changed = updateRotationUncheckedLocked(false);
5936                if (changed) {
5937                    mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
5938                }
5939            }
5940        }
5941    }
5942
5943    public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
5944        if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked("
5945                   + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")");
5946
5947        long origId = Binder.clearCallingIdentity();
5948        boolean changed;
5949        synchronized(mWindowMap) {
5950            changed = updateRotationUncheckedLocked(false);
5951            if (!changed || forceRelayout) {
5952                getDefaultDisplayContentLocked().layoutNeeded = true;
5953                performLayoutAndPlaceSurfacesLocked();
5954            }
5955        }
5956
5957        if (changed || alwaysSendConfiguration) {
5958            sendNewConfiguration();
5959        }
5960
5961        Binder.restoreCallingIdentity(origId);
5962    }
5963
5964    // TODO(multidisplay): Rotate any display?
5965    /**
5966     * Updates the current rotation.
5967     *
5968     * Returns true if the rotation has been changed.  In this case YOU
5969     * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN.
5970     */
5971    public boolean updateRotationUncheckedLocked(boolean inTransaction) {
5972        if (mDeferredRotationPauseCount > 0) {
5973            // Rotation updates have been paused temporarily.  Defer the update until
5974            // updates have been resumed.
5975            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused.");
5976            return false;
5977        }
5978
5979        ScreenRotationAnimation screenRotationAnimation =
5980                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
5981        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
5982            // Rotation updates cannot be performed while the previous rotation change
5983            // animation is still in progress.  Skip this update.  We will try updating
5984            // again after the animation is finished and the display is unfrozen.
5985            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress.");
5986            return false;
5987        }
5988
5989        if (!mDisplayEnabled) {
5990            // No point choosing a rotation if the display is not enabled.
5991            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled.");
5992            return false;
5993        }
5994
5995        // TODO: Implement forced rotation changes.
5996        //       Set mAltOrientation to indicate that the application is receiving
5997        //       an orientation that has different metrics than it expected.
5998        //       eg. Portrait instead of Landscape.
5999
6000        int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);
6001        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
6002                mForcedAppOrientation, rotation);
6003
6004        if (DEBUG_ORIENTATION) {
6005            Slog.v(TAG, "Application requested orientation "
6006                    + mForcedAppOrientation + ", got rotation " + rotation
6007                    + " which has " + (altOrientation ? "incompatible" : "compatible")
6008                    + " metrics");
6009        }
6010
6011        if (mRotation == rotation && mAltOrientation == altOrientation) {
6012            // No change.
6013            return false;
6014        }
6015
6016        if (DEBUG_ORIENTATION) {
6017            Slog.v(TAG,
6018                "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
6019                + " from " + mRotation + (mAltOrientation ? " (alt)" : "")
6020                + ", forceApp=" + mForcedAppOrientation);
6021        }
6022
6023        mRotation = rotation;
6024        mAltOrientation = altOrientation;
6025        mPolicy.setRotationLw(mRotation);
6026
6027        mWindowsFreezingScreen = true;
6028        mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
6029        mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
6030                WINDOW_FREEZE_TIMEOUT_DURATION);
6031        mWaitingForConfig = true;
6032        getDefaultDisplayContentLocked().layoutNeeded = true;
6033        startFreezingDisplayLocked(inTransaction, 0, 0);
6034        // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
6035        screenRotationAnimation =
6036                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
6037
6038        // We need to update our screen size information to match the new
6039        // rotation.  Note that this is redundant with the later call to
6040        // sendNewConfiguration() that must be called after this function
6041        // returns...  however we need to do the screen size part of that
6042        // before then so we have the correct size to use when initializing
6043        // the rotation animation for the new rotation.
6044        computeScreenConfigurationLocked(null);
6045
6046        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6047        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
6048        if (!inTransaction) {
6049            if (SHOW_TRANSACTIONS) {
6050                Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");
6051            }
6052            Surface.openTransaction();
6053        }
6054        try {
6055            // NOTE: We disable the rotation in the emulator because
6056            //       it doesn't support hardware OpenGL emulation yet.
6057            if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
6058                    && screenRotationAnimation.hasScreenshot()) {
6059                if (screenRotationAnimation.setRotationInTransaction(
6060                        rotation, mFxSession,
6061                        MAX_ANIMATION_DURATION, mTransitionAnimationScale,
6062                        displayInfo.logicalWidth, displayInfo.logicalHeight)) {
6063                    updateLayoutToAnimationLocked();
6064                }
6065            }
6066
6067            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
6068        } finally {
6069            if (!inTransaction) {
6070                Surface.closeTransaction();
6071                if (SHOW_LIGHT_TRANSACTIONS) {
6072                    Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");
6073                }
6074            }
6075        }
6076
6077        final WindowList windows = displayContent.getWindowList();
6078        for (int i = windows.size() - 1; i >= 0; i--) {
6079            WindowState w = windows.get(i);
6080            if (w.mHasSurface) {
6081                if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
6082                w.mOrientationChanging = true;
6083                mInnerFields.mOrientationChangeComplete = false;
6084            }
6085        }
6086
6087        for (int i=mRotationWatchers.size()-1; i>=0; i--) {
6088            try {
6089                mRotationWatchers.get(i).onRotationChanged(rotation);
6090            } catch (RemoteException e) {
6091            }
6092        }
6093
6094        scheduleNotifyRotationChangedIfNeededLocked(displayContent, rotation);
6095
6096        return true;
6097    }
6098
6099    public int getRotation() {
6100        return mRotation;
6101    }
6102
6103    public int watchRotation(IRotationWatcher watcher) {
6104        final IBinder watcherBinder = watcher.asBinder();
6105        IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
6106            public void binderDied() {
6107                synchronized (mWindowMap) {
6108                    for (int i=0; i<mRotationWatchers.size(); i++) {
6109                        if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
6110                            IRotationWatcher removed = mRotationWatchers.remove(i);
6111                            if (removed != null) {
6112                                removed.asBinder().unlinkToDeath(this, 0);
6113                            }
6114                            i--;
6115                        }
6116                    }
6117                }
6118            }
6119        };
6120
6121        synchronized (mWindowMap) {
6122            try {
6123                watcher.asBinder().linkToDeath(dr, 0);
6124                mRotationWatchers.add(watcher);
6125            } catch (RemoteException e) {
6126                // Client died, no cleanup needed.
6127            }
6128
6129            return mRotation;
6130        }
6131    }
6132
6133    /**
6134     * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
6135     * theme attribute) on devices that feature a physical options menu key attempt to position
6136     * their menu panel window along the edge of the screen nearest the physical menu key.
6137     * This lowers the travel distance between invoking the menu panel and selecting
6138     * a menu option.
6139     *
6140     * This method helps control where that menu is placed. Its current implementation makes
6141     * assumptions about the menu key and its relationship to the screen based on whether
6142     * the device's natural orientation is portrait (width < height) or landscape.
6143     *
6144     * The menu key is assumed to be located along the bottom edge of natural-portrait
6145     * devices and along the right edge of natural-landscape devices. If these assumptions
6146     * do not hold for the target device, this method should be changed to reflect that.
6147     *
6148     * @return A {@link Gravity} value for placing the options menu window
6149     */
6150    public int getPreferredOptionsPanelGravity() {
6151        synchronized (mWindowMap) {
6152            final int rotation = getRotation();
6153
6154            // TODO(multidisplay): Assume that such devices physical keys are on the main screen.
6155            final DisplayContent displayContent = getDefaultDisplayContentLocked();
6156            if (displayContent.mInitialDisplayWidth < displayContent.mInitialDisplayHeight) {
6157                // On devices with a natural orientation of portrait
6158                switch (rotation) {
6159                    default:
6160                    case Surface.ROTATION_0:
6161                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6162                    case Surface.ROTATION_90:
6163                        return Gravity.RIGHT | Gravity.BOTTOM;
6164                    case Surface.ROTATION_180:
6165                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6166                    case Surface.ROTATION_270:
6167                        return Gravity.START | Gravity.BOTTOM;
6168                }
6169            } else {
6170                // On devices with a natural orientation of landscape
6171                switch (rotation) {
6172                    default:
6173                    case Surface.ROTATION_0:
6174                        return Gravity.RIGHT | Gravity.BOTTOM;
6175                    case Surface.ROTATION_90:
6176                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6177                    case Surface.ROTATION_180:
6178                        return Gravity.START | Gravity.BOTTOM;
6179                    case Surface.ROTATION_270:
6180                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6181                }
6182            }
6183        }
6184    }
6185
6186    /**
6187     * Starts the view server on the specified port.
6188     *
6189     * @param port The port to listener to.
6190     *
6191     * @return True if the server was successfully started, false otherwise.
6192     *
6193     * @see com.android.server.wm.ViewServer
6194     * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
6195     */
6196    public boolean startViewServer(int port) {
6197        if (isSystemSecure()) {
6198            return false;
6199        }
6200
6201        if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
6202            return false;
6203        }
6204
6205        if (port < 1024) {
6206            return false;
6207        }
6208
6209        if (mViewServer != null) {
6210            if (!mViewServer.isRunning()) {
6211                try {
6212                    return mViewServer.start();
6213                } catch (IOException e) {
6214                    Slog.w(TAG, "View server did not start");
6215                }
6216            }
6217            return false;
6218        }
6219
6220        try {
6221            mViewServer = new ViewServer(this, port);
6222            return mViewServer.start();
6223        } catch (IOException e) {
6224            Slog.w(TAG, "View server did not start");
6225        }
6226        return false;
6227    }
6228
6229    private boolean isSystemSecure() {
6230        return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
6231                "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
6232    }
6233
6234    /**
6235     * Stops the view server if it exists.
6236     *
6237     * @return True if the server stopped, false if it wasn't started or
6238     *         couldn't be stopped.
6239     *
6240     * @see com.android.server.wm.ViewServer
6241     */
6242    public boolean stopViewServer() {
6243        if (isSystemSecure()) {
6244            return false;
6245        }
6246
6247        if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
6248            return false;
6249        }
6250
6251        if (mViewServer != null) {
6252            return mViewServer.stop();
6253        }
6254        return false;
6255    }
6256
6257    /**
6258     * Indicates whether the view server is running.
6259     *
6260     * @return True if the server is running, false otherwise.
6261     *
6262     * @see com.android.server.wm.ViewServer
6263     */
6264    public boolean isViewServerRunning() {
6265        if (isSystemSecure()) {
6266            return false;
6267        }
6268
6269        if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
6270            return false;
6271        }
6272
6273        return mViewServer != null && mViewServer.isRunning();
6274    }
6275
6276    /**
6277     * Lists all availble windows in the system. The listing is written in the
6278     * specified Socket's output stream with the following syntax:
6279     * windowHashCodeInHexadecimal windowName
6280     * Each line of the ouput represents a different window.
6281     *
6282     * @param client The remote client to send the listing to.
6283     * @return False if an error occured, true otherwise.
6284     */
6285    boolean viewServerListWindows(Socket client) {
6286        if (isSystemSecure()) {
6287            return false;
6288        }
6289
6290        boolean result = true;
6291
6292        WindowList windows = new WindowList();
6293        synchronized (mWindowMap) {
6294            //noinspection unchecked
6295            DisplayContentsIterator iterator = new DisplayContentsIterator();
6296            while(iterator.hasNext()) {
6297                windows.addAll(iterator.next().getWindowList());
6298            }
6299        }
6300
6301        BufferedWriter out = null;
6302
6303        // Any uncaught exception will crash the system process
6304        try {
6305            OutputStream clientStream = client.getOutputStream();
6306            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
6307
6308            final int count = windows.size();
6309            for (int i = 0; i < count; i++) {
6310                final WindowState w = windows.get(i);
6311                out.write(Integer.toHexString(System.identityHashCode(w)));
6312                out.write(' ');
6313                out.append(w.mAttrs.getTitle());
6314                out.write('\n');
6315            }
6316
6317            out.write("DONE.\n");
6318            out.flush();
6319        } catch (Exception e) {
6320            result = false;
6321        } finally {
6322            if (out != null) {
6323                try {
6324                    out.close();
6325                } catch (IOException e) {
6326                    result = false;
6327                }
6328            }
6329        }
6330
6331        return result;
6332    }
6333
6334    // TODO(multidisplay): Extend to multiple displays.
6335    /**
6336     * Returns the focused window in the following format:
6337     * windowHashCodeInHexadecimal windowName
6338     *
6339     * @param client The remote client to send the listing to.
6340     * @return False if an error occurred, true otherwise.
6341     */
6342    boolean viewServerGetFocusedWindow(Socket client) {
6343        if (isSystemSecure()) {
6344            return false;
6345        }
6346
6347        boolean result = true;
6348
6349        WindowState focusedWindow = getFocusedWindow();
6350
6351        BufferedWriter out = null;
6352
6353        // Any uncaught exception will crash the system process
6354        try {
6355            OutputStream clientStream = client.getOutputStream();
6356            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
6357
6358            if(focusedWindow != null) {
6359                out.write(Integer.toHexString(System.identityHashCode(focusedWindow)));
6360                out.write(' ');
6361                out.append(focusedWindow.mAttrs.getTitle());
6362            }
6363            out.write('\n');
6364            out.flush();
6365        } catch (Exception e) {
6366            result = false;
6367        } finally {
6368            if (out != null) {
6369                try {
6370                    out.close();
6371                } catch (IOException e) {
6372                    result = false;
6373                }
6374            }
6375        }
6376
6377        return result;
6378    }
6379
6380    /**
6381     * Sends a command to a target window. The result of the command, if any, will be
6382     * written in the output stream of the specified socket.
6383     *
6384     * The parameters must follow this syntax:
6385     * windowHashcode extra
6386     *
6387     * Where XX is the length in characeters of the windowTitle.
6388     *
6389     * The first parameter is the target window. The window with the specified hashcode
6390     * will be the target. If no target can be found, nothing happens. The extra parameters
6391     * will be delivered to the target window and as parameters to the command itself.
6392     *
6393     * @param client The remote client to sent the result, if any, to.
6394     * @param command The command to execute.
6395     * @param parameters The command parameters.
6396     *
6397     * @return True if the command was successfully delivered, false otherwise. This does
6398     *         not indicate whether the command itself was successful.
6399     */
6400    boolean viewServerWindowCommand(Socket client, String command, String parameters) {
6401        if (isSystemSecure()) {
6402            return false;
6403        }
6404
6405        boolean success = true;
6406        Parcel data = null;
6407        Parcel reply = null;
6408
6409        BufferedWriter out = null;
6410
6411        // Any uncaught exception will crash the system process
6412        try {
6413            // Find the hashcode of the window
6414            int index = parameters.indexOf(' ');
6415            if (index == -1) {
6416                index = parameters.length();
6417            }
6418            final String code = parameters.substring(0, index);
6419            int hashCode = (int) Long.parseLong(code, 16);
6420
6421            // Extract the command's parameter after the window description
6422            if (index < parameters.length()) {
6423                parameters = parameters.substring(index + 1);
6424            } else {
6425                parameters = "";
6426            }
6427
6428            final WindowState window = findWindow(hashCode);
6429            if (window == null) {
6430                return false;
6431            }
6432
6433            data = Parcel.obtain();
6434            data.writeInterfaceToken("android.view.IWindow");
6435            data.writeString(command);
6436            data.writeString(parameters);
6437            data.writeInt(1);
6438            ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
6439
6440            reply = Parcel.obtain();
6441
6442            final IBinder binder = window.mClient.asBinder();
6443            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
6444            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
6445
6446            reply.readException();
6447
6448            if (!client.isOutputShutdown()) {
6449                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
6450                out.write("DONE\n");
6451                out.flush();
6452            }
6453
6454        } catch (Exception e) {
6455            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
6456            success = false;
6457        } finally {
6458            if (data != null) {
6459                data.recycle();
6460            }
6461            if (reply != null) {
6462                reply.recycle();
6463            }
6464            if (out != null) {
6465                try {
6466                    out.close();
6467                } catch (IOException e) {
6468
6469                }
6470            }
6471        }
6472
6473        return success;
6474    }
6475
6476    public void addDisplayContentChangeListener(int displayId,
6477            IDisplayContentChangeListener listener) {
6478        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
6479                "addDisplayContentChangeListener()")) {
6480            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission");
6481        }
6482        synchronized(mWindowMap) {
6483            DisplayContent displayContent = getDisplayContentLocked(displayId);
6484            if (displayContent.mDisplayContentChangeListeners == null) {
6485                displayContent.mDisplayContentChangeListeners =
6486                        new RemoteCallbackList<IDisplayContentChangeListener>();
6487            displayContent.mDisplayContentChangeListeners.register(listener);
6488            }
6489        }
6490    }
6491
6492    public void removeDisplayContentChangeListener(int displayId,
6493            IDisplayContentChangeListener listener) {
6494        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
6495                "removeDisplayContentChangeListener()")) {
6496            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission");
6497        }
6498        synchronized(mWindowMap) {
6499            DisplayContent displayContent = getDisplayContentLocked(displayId);
6500            if (displayContent.mDisplayContentChangeListeners != null) {
6501                displayContent.mDisplayContentChangeListeners.unregister(listener);
6502                if (displayContent.mDisplayContentChangeListeners
6503                        .getRegisteredCallbackCount() == 0) {
6504                    displayContent.mDisplayContentChangeListeners = null;
6505                }
6506            }
6507        }
6508    }
6509
6510    void scheduleNotifyWindowTranstionIfNeededLocked(WindowState window, int transition) {
6511        DisplayContent displayContent = window.mDisplayContent;
6512        if (displayContent.mDisplayContentChangeListeners != null) {
6513            WindowInfo info = getWindowInfoForWindowStateLocked(window);
6514            mH.obtainMessage(H.NOTIFY_WINDOW_TRANSITION, transition, 0, info).sendToTarget();
6515        }
6516    }
6517
6518    private void handleNotifyWindowTranstion(int transition, WindowInfo info) {
6519        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
6520        synchronized (mWindowMap) {
6521            DisplayContent displayContent = getDisplayContentLocked(info.displayId);
6522            if (displayContent == null) {
6523                return;
6524            }
6525            callbacks = displayContent.mDisplayContentChangeListeners;
6526            if (callbacks == null) {
6527                return;
6528            }
6529        }
6530        final int callbackCount = callbacks.beginBroadcast();
6531        try {
6532            for (int i = 0; i < callbackCount; i++) {
6533                try {
6534                    callbacks.getBroadcastItem(i).onWindowTransition(info.displayId,
6535                            transition, info);
6536                } catch (RemoteException re) {
6537                    /* ignore */
6538                }
6539            }
6540        } finally {
6541            callbacks.finishBroadcast();
6542        }
6543    }
6544
6545    private void scheduleNotifyRotationChangedIfNeededLocked(DisplayContent displayContent,
6546            int rotation) {
6547        if (displayContent.mDisplayContentChangeListeners != null
6548                && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) {
6549            mH.obtainMessage(H.NOTIFY_ROTATION_CHANGED, displayContent.getDisplayId(),
6550                    rotation).sendToTarget();
6551        }
6552    }
6553
6554    private void handleNotifyRotationChanged(int displayId, int rotation) {
6555        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
6556        synchronized (mWindowMap) {
6557            DisplayContent displayContent = getDisplayContentLocked(displayId);
6558            if (displayContent == null) {
6559                return;
6560            }
6561            callbacks = displayContent.mDisplayContentChangeListeners;
6562            if (callbacks == null) {
6563                return;
6564            }
6565        }
6566        try {
6567            final int watcherCount = callbacks.beginBroadcast();
6568            for (int i = 0; i < watcherCount; i++) {
6569                try {
6570                    callbacks.getBroadcastItem(i).onRotationChanged(rotation);
6571                } catch (RemoteException re) {
6572                    /* ignore */
6573                }
6574            }
6575        } finally {
6576            callbacks.finishBroadcast();
6577        }
6578    }
6579
6580    private void scheduleNotifyWindowLayersChangedIfNeededLocked(DisplayContent displayContent) {
6581        if (displayContent.mDisplayContentChangeListeners != null
6582                && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) {
6583            mH.obtainMessage(H.NOTIFY_WINDOW_LAYERS_CHANGED, displayContent) .sendToTarget();
6584        }
6585    }
6586
6587    private void handleNotifyWindowLayersChanged(DisplayContent displayContent) {
6588        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
6589        synchronized (mWindowMap) {
6590            callbacks = displayContent.mDisplayContentChangeListeners;
6591            if (callbacks == null) {
6592                return;
6593            }
6594        }
6595        try {
6596            final int watcherCount = callbacks.beginBroadcast();
6597            for (int i = 0; i < watcherCount; i++) {
6598                try {
6599                    callbacks.getBroadcastItem(i).onWindowLayersChanged(
6600                            displayContent.getDisplayId());
6601                } catch (RemoteException re) {
6602                    /* ignore */
6603                }
6604            }
6605        } finally {
6606            callbacks.finishBroadcast();
6607        }
6608    }
6609
6610    public void addWindowChangeListener(WindowChangeListener listener) {
6611        synchronized(mWindowMap) {
6612            mWindowChangeListeners.add(listener);
6613        }
6614    }
6615
6616    public void removeWindowChangeListener(WindowChangeListener listener) {
6617        synchronized(mWindowMap) {
6618            mWindowChangeListeners.remove(listener);
6619        }
6620    }
6621
6622    private void notifyWindowsChanged() {
6623        WindowChangeListener[] windowChangeListeners;
6624        synchronized(mWindowMap) {
6625            if(mWindowChangeListeners.isEmpty()) {
6626                return;
6627            }
6628            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6629            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6630        }
6631        int N = windowChangeListeners.length;
6632        for(int i = 0; i < N; i++) {
6633            windowChangeListeners[i].windowsChanged();
6634        }
6635    }
6636
6637    private void notifyFocusChanged() {
6638        WindowChangeListener[] windowChangeListeners;
6639        synchronized(mWindowMap) {
6640            if(mWindowChangeListeners.isEmpty()) {
6641                return;
6642            }
6643            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6644            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6645        }
6646        int N = windowChangeListeners.length;
6647        for(int i = 0; i < N; i++) {
6648            windowChangeListeners[i].focusChanged();
6649        }
6650    }
6651
6652    private WindowState findWindow(int hashCode) {
6653        if (hashCode == -1) {
6654            // TODO(multidisplay): Extend to multiple displays.
6655            return getFocusedWindow();
6656        }
6657
6658        synchronized (mWindowMap) {
6659            final AllWindowsIterator iterator = new AllWindowsIterator();
6660            while (iterator.hasNext()) {
6661                final WindowState w = iterator.next();
6662                if (System.identityHashCode(w) == hashCode) {
6663                    return w;
6664                }
6665            }
6666        }
6667
6668        return null;
6669    }
6670
6671    /*
6672     * Instruct the Activity Manager to fetch the current configuration and broadcast
6673     * that to config-changed listeners if appropriate.
6674     */
6675    void sendNewConfiguration() {
6676        try {
6677            mActivityManager.updateConfiguration(null);
6678        } catch (RemoteException e) {
6679        }
6680    }
6681
6682    public Configuration computeNewConfiguration() {
6683        synchronized (mWindowMap) {
6684            Configuration config = computeNewConfigurationLocked();
6685            if (config == null && mWaitingForConfig) {
6686                // Nothing changed but we are waiting for something... stop that!
6687                mWaitingForConfig = false;
6688                performLayoutAndPlaceSurfacesLocked();
6689            }
6690            return config;
6691        }
6692    }
6693
6694    Configuration computeNewConfigurationLocked() {
6695        Configuration config = new Configuration();
6696        config.fontScale = 0;
6697        if (!computeScreenConfigurationLocked(config)) {
6698            return null;
6699        }
6700        return config;
6701    }
6702
6703    private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) {
6704        // TODO: Multidisplay: for now only use with default display.
6705        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
6706        if (width < displayInfo.smallestNominalAppWidth) {
6707            displayInfo.smallestNominalAppWidth = width;
6708        }
6709        if (width > displayInfo.largestNominalAppWidth) {
6710            displayInfo.largestNominalAppWidth = width;
6711        }
6712        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation);
6713        if (height < displayInfo.smallestNominalAppHeight) {
6714            displayInfo.smallestNominalAppHeight = height;
6715        }
6716        if (height > displayInfo.largestNominalAppHeight) {
6717            displayInfo.largestNominalAppHeight = height;
6718        }
6719    }
6720
6721    private int reduceConfigLayout(int curLayout, int rotation, float density,
6722            int dw, int dh) {
6723        // TODO: Multidisplay: for now only use with default display.
6724        // Get the app screen size at this rotation.
6725        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6726        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6727
6728        // Compute the screen layout size class for this rotation.
6729        int longSize = w;
6730        int shortSize = h;
6731        if (longSize < shortSize) {
6732            int tmp = longSize;
6733            longSize = shortSize;
6734            shortSize = tmp;
6735        }
6736        longSize = (int)(longSize/density);
6737        shortSize = (int)(shortSize/density);
6738        return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
6739    }
6740
6741    private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
6742                  int dw, int dh, float density, Configuration outConfig) {
6743        // TODO: Multidisplay: for now only use with default display.
6744
6745        // We need to determine the smallest width that will occur under normal
6746        // operation.  To this, start with the base screen size and compute the
6747        // width under the different possible rotations.  We need to un-rotate
6748        // the current screen dimensions before doing this.
6749        int unrotDw, unrotDh;
6750        if (rotated) {
6751            unrotDw = dh;
6752            unrotDh = dw;
6753        } else {
6754            unrotDw = dw;
6755            unrotDh = dh;
6756        }
6757        displayInfo.smallestNominalAppWidth = 1<<30;
6758        displayInfo.smallestNominalAppHeight = 1<<30;
6759        displayInfo.largestNominalAppWidth = 0;
6760        displayInfo.largestNominalAppHeight = 0;
6761        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh);
6762        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw);
6763        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh);
6764        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw);
6765        int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
6766        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
6767        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
6768        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
6769        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
6770        outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
6771        outConfig.screenLayout = sl;
6772    }
6773
6774    private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
6775            int dw, int dh) {
6776        // TODO: Multidisplay: for now only use with default display.
6777        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6778        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6779        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
6780        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
6781        if (curSize == 0 || size < curSize) {
6782            curSize = size;
6783        }
6784        return curSize;
6785    }
6786
6787    private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
6788        // TODO: Multidisplay: for now only use with default display.
6789        mTmpDisplayMetrics.setTo(dm);
6790        final DisplayMetrics tmpDm = mTmpDisplayMetrics;
6791        final int unrotDw, unrotDh;
6792        if (rotated) {
6793            unrotDw = dh;
6794            unrotDh = dw;
6795        } else {
6796            unrotDw = dw;
6797            unrotDh = dh;
6798        }
6799        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh);
6800        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw);
6801        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh);
6802        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw);
6803        return sw;
6804    }
6805
6806    boolean computeScreenConfigurationLocked(Configuration config) {
6807        if (!mDisplayReady) {
6808            return false;
6809        }
6810
6811        // TODO(multidisplay): For now, apply Configuration to main screen only.
6812        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6813
6814        // Use the effective "visual" dimensions based on current rotation
6815        final boolean rotated = (mRotation == Surface.ROTATION_90
6816                || mRotation == Surface.ROTATION_270);
6817        final int realdw = rotated ?
6818                displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
6819        final int realdh = rotated ?
6820                displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
6821        int dw = realdw;
6822        int dh = realdh;
6823
6824        if (mAltOrientation) {
6825            if (realdw > realdh) {
6826                // Turn landscape into portrait.
6827                int maxw = (int)(realdh/1.3f);
6828                if (maxw < realdw) {
6829                    dw = maxw;
6830                }
6831            } else {
6832                // Turn portrait into landscape.
6833                int maxh = (int)(realdw/1.3f);
6834                if (maxh < realdh) {
6835                    dh = maxh;
6836                }
6837            }
6838        }
6839
6840        if (config != null) {
6841            config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
6842                    Configuration.ORIENTATION_LANDSCAPE;
6843        }
6844
6845        // Update application display metrics.
6846        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
6847        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
6848        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
6849        synchronized(displayContent.mDisplaySizeLock) {
6850            displayInfo.rotation = mRotation;
6851            displayInfo.logicalWidth = dw;
6852            displayInfo.logicalHeight = dh;
6853            displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
6854            displayInfo.appWidth = appWidth;
6855            displayInfo.appHeight = appHeight;
6856            displayInfo.getLogicalMetrics(mRealDisplayMetrics, null);
6857            displayInfo.getAppMetrics(mDisplayMetrics, null);
6858            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
6859                    displayContent.getDisplayId(), displayInfo);
6860
6861            mAnimator.setDisplayDimensions(dw, dh, appWidth, appHeight);
6862        }
6863        if (false) {
6864            Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);
6865        }
6866
6867        final DisplayMetrics dm = mDisplayMetrics;
6868        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
6869                mCompatDisplayMetrics);
6870
6871        if (config != null) {
6872            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
6873                    / dm.density);
6874            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
6875                    / dm.density);
6876            computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);
6877
6878            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
6879            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
6880            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
6881            config.densityDpi = displayContent.mBaseDisplayDensity;
6882
6883            // Update the configuration based on available input devices, lid switch,
6884            // and platform configuration.
6885            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6886            config.keyboard = Configuration.KEYBOARD_NOKEYS;
6887            config.navigation = Configuration.NAVIGATION_NONAV;
6888
6889            int keyboardPresence = 0;
6890            int navigationPresence = 0;
6891            final InputDevice[] devices = mInputManager.getInputDevices();
6892            final int len = devices.length;
6893            for (int i = 0; i < len; i++) {
6894                InputDevice device = devices[i];
6895                if (!device.isVirtual()) {
6896                    final int sources = device.getSources();
6897                    final int presenceFlag = device.isExternal() ?
6898                            WindowManagerPolicy.PRESENCE_EXTERNAL :
6899                                    WindowManagerPolicy.PRESENCE_INTERNAL;
6900
6901                    if (mIsTouchDevice) {
6902                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
6903                                InputDevice.SOURCE_TOUCHSCREEN) {
6904                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
6905                        }
6906                    } else {
6907                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6908                    }
6909
6910                    if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
6911                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
6912                        navigationPresence |= presenceFlag;
6913                    } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
6914                            && config.navigation == Configuration.NAVIGATION_NONAV) {
6915                        config.navigation = Configuration.NAVIGATION_DPAD;
6916                        navigationPresence |= presenceFlag;
6917                    }
6918
6919                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
6920                        config.keyboard = Configuration.KEYBOARD_QWERTY;
6921                        keyboardPresence |= presenceFlag;
6922                    }
6923                }
6924            }
6925
6926            // Determine whether a hard keyboard is available and enabled.
6927            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6928            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6929                mHardKeyboardAvailable = hardKeyboardAvailable;
6930                mHardKeyboardEnabled = hardKeyboardAvailable;
6931                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6932                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6933            }
6934            if (!mHardKeyboardEnabled) {
6935                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6936            }
6937
6938            // Let the policy update hidden states.
6939            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6940            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6941            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6942            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
6943        }
6944
6945        return true;
6946    }
6947
6948    public boolean isHardKeyboardAvailable() {
6949        synchronized (mWindowMap) {
6950            return mHardKeyboardAvailable;
6951        }
6952    }
6953
6954    public boolean isHardKeyboardEnabled() {
6955        synchronized (mWindowMap) {
6956            return mHardKeyboardEnabled;
6957        }
6958    }
6959
6960    public void setHardKeyboardEnabled(boolean enabled) {
6961        synchronized (mWindowMap) {
6962            if (mHardKeyboardEnabled != enabled) {
6963                mHardKeyboardEnabled = enabled;
6964                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6965            }
6966        }
6967    }
6968
6969    public void setOnHardKeyboardStatusChangeListener(
6970            OnHardKeyboardStatusChangeListener listener) {
6971        synchronized (mWindowMap) {
6972            mHardKeyboardStatusChangeListener = listener;
6973        }
6974    }
6975
6976    void notifyHardKeyboardStatusChange() {
6977        final boolean available, enabled;
6978        final OnHardKeyboardStatusChangeListener listener;
6979        synchronized (mWindowMap) {
6980            listener = mHardKeyboardStatusChangeListener;
6981            available = mHardKeyboardAvailable;
6982            enabled = mHardKeyboardEnabled;
6983        }
6984        if (listener != null) {
6985            listener.onHardKeyboardStatusChange(available, enabled);
6986        }
6987    }
6988
6989    // -------------------------------------------------------------
6990    // Drag and drop
6991    // -------------------------------------------------------------
6992
6993    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
6994            int flags, int width, int height, Surface outSurface) {
6995        if (DEBUG_DRAG) {
6996            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
6997                    + " flags=" + Integer.toHexString(flags) + " win=" + window
6998                    + " asbinder=" + window.asBinder());
6999        }
7000
7001        final int callerPid = Binder.getCallingPid();
7002        final long origId = Binder.clearCallingIdentity();
7003        IBinder token = null;
7004
7005        try {
7006            synchronized (mWindowMap) {
7007                try {
7008                    if (mDragState == null) {
7009                        // TODO(multi-display): support other displays
7010                        final DisplayContent displayContent = getDefaultDisplayContentLocked();
7011                        final Display display = displayContent.getDisplay();
7012                        Surface surface = new Surface(session, "drag surface",
7013                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
7014                        surface.setLayerStack(display.getLayerStack());
7015                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
7016                                + surface + ": CREATE");
7017                        outSurface.copyFrom(surface);
7018                        final IBinder winBinder = window.asBinder();
7019                        token = new Binder();
7020                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
7021                        token = mDragState.mToken = new Binder();
7022
7023                        // 5 second timeout for this window to actually begin the drag
7024                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
7025                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
7026                        mH.sendMessageDelayed(msg, 5000);
7027                    } else {
7028                        Slog.w(TAG, "Drag already in progress");
7029                    }
7030                } catch (Surface.OutOfResourcesException e) {
7031                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
7032                    if (mDragState != null) {
7033                        mDragState.reset();
7034                        mDragState = null;
7035                    }
7036                }
7037            }
7038        } finally {
7039            Binder.restoreCallingIdentity(origId);
7040        }
7041
7042        return token;
7043    }
7044
7045    // -------------------------------------------------------------
7046    // Input Events and Focus Management
7047    // -------------------------------------------------------------
7048
7049    final InputMonitor mInputMonitor = new InputMonitor(this);
7050    private boolean mEventDispatchingEnabled;
7051
7052    public void pauseKeyDispatching(IBinder _token) {
7053        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7054                "pauseKeyDispatching()")) {
7055            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7056        }
7057
7058        synchronized (mWindowMap) {
7059            WindowToken token = mTokenMap.get(_token);
7060            if (token != null) {
7061                mInputMonitor.pauseDispatchingLw(token);
7062            }
7063        }
7064    }
7065
7066    public void resumeKeyDispatching(IBinder _token) {
7067        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7068                "resumeKeyDispatching()")) {
7069            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7070        }
7071
7072        synchronized (mWindowMap) {
7073            WindowToken token = mTokenMap.get(_token);
7074            if (token != null) {
7075                mInputMonitor.resumeDispatchingLw(token);
7076            }
7077        }
7078    }
7079
7080    public void setEventDispatching(boolean enabled) {
7081        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7082                "setEventDispatching()")) {
7083            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7084        }
7085
7086        synchronized (mWindowMap) {
7087            mEventDispatchingEnabled = enabled;
7088            if (mDisplayEnabled) {
7089                mInputMonitor.setEventDispatchingLw(enabled);
7090            }
7091            sendScreenStatusToClientsLocked();
7092        }
7093    }
7094
7095    public IBinder getFocusedWindowToken() {
7096        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
7097                "getFocusedWindowToken()")) {
7098            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
7099        }
7100        synchronized (mWindowMap) {
7101            WindowState windowState = getFocusedWindowLocked();
7102            if (windowState != null) {
7103                return windowState.mClient.asBinder();
7104            }
7105            return null;
7106        }
7107    }
7108
7109    private WindowState getFocusedWindow() {
7110        synchronized (mWindowMap) {
7111            return getFocusedWindowLocked();
7112        }
7113    }
7114
7115    private WindowState getFocusedWindowLocked() {
7116        return mCurrentFocus;
7117    }
7118
7119    public boolean detectSafeMode() {
7120        if (!mInputMonitor.waitForInputDevicesReady(
7121                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
7122            Slog.w(TAG, "Devices still not ready after waiting "
7123                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
7124                   + " milliseconds before attempting to detect safe mode.");
7125        }
7126
7127        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
7128                KeyEvent.KEYCODE_MENU);
7129        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
7130        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
7131                KeyEvent.KEYCODE_DPAD_CENTER);
7132        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
7133                InputManagerService.BTN_MOUSE);
7134        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
7135                KeyEvent.KEYCODE_VOLUME_DOWN);
7136        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
7137                || volumeDownState > 0;
7138        try {
7139            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
7140                mSafeMode = true;
7141                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
7142            }
7143        } catch (IllegalArgumentException e) {
7144        }
7145        if (mSafeMode) {
7146            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
7147                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
7148        } else {
7149            Log.i(TAG, "SAFE MODE not enabled");
7150        }
7151        mPolicy.setSafeMode(mSafeMode);
7152        return mSafeMode;
7153    }
7154
7155    public void displayReady() {
7156        displayReady(Display.DEFAULT_DISPLAY);
7157
7158        synchronized(mWindowMap) {
7159            final DisplayContent displayContent = getDefaultDisplayContentLocked();
7160            final Display display = displayContent.getDisplay();
7161            readForcedDisplaySizeAndDensityLocked(displayContent);
7162
7163            mDisplayReady = true;
7164            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
7165                    PackageManager.FEATURE_TOUCHSCREEN);
7166
7167            final DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
7168            mAnimator.setDisplayDimensions(
7169                    displayInfo.logicalWidth, displayInfo.logicalHeight,
7170                    displayInfo.appWidth, displayInfo.appHeight);
7171
7172            mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
7173                    displayContent.mInitialDisplayWidth,
7174                    displayContent.mInitialDisplayHeight,
7175                    displayContent.mInitialDisplayDensity);
7176        }
7177
7178        try {
7179            mActivityManager.updateConfiguration(null);
7180        } catch (RemoteException e) {
7181        }
7182    }
7183
7184    public void displayReady(int displayId) {
7185        synchronized(mWindowMap) {
7186            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7187            final DisplayInfo displayInfo;
7188            mAnimator.addDisplayLocked(displayId);
7189            synchronized(displayContent.mDisplaySizeLock) {
7190                // Bootstrap the default logical display from the display manager.
7191                displayInfo = displayContent.getDisplayInfo();
7192                DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId);
7193                if (newDisplayInfo != null) {
7194                    displayInfo.copyFrom(newDisplayInfo);
7195                }
7196                displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
7197                displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
7198                displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
7199                displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
7200                displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
7201                displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
7202            }
7203        }
7204    }
7205
7206    public void systemReady() {
7207        mPolicy.systemReady();
7208    }
7209
7210    // TODO(multidisplay): Call isScreenOn for each display.
7211    private void sendScreenStatusToClientsLocked() {
7212        final boolean on = mPowerManager.isScreenOn();
7213        final AllWindowsIterator iterator = new AllWindowsIterator();
7214        while (iterator.hasNext()) {
7215            try {
7216                iterator.next().mClient.dispatchScreenState(on);
7217            } catch (RemoteException e) {
7218                // Ignored
7219            }
7220        }
7221    }
7222
7223    // -------------------------------------------------------------
7224    // Async Handler
7225    // -------------------------------------------------------------
7226
7227    final class H extends Handler {
7228        public static final int REPORT_FOCUS_CHANGE = 2;
7229        public static final int REPORT_LOSING_FOCUS = 3;
7230        public static final int DO_TRAVERSAL = 4;
7231        public static final int ADD_STARTING = 5;
7232        public static final int REMOVE_STARTING = 6;
7233        public static final int FINISHED_STARTING = 7;
7234        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
7235        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
7236        public static final int WINDOW_FREEZE_TIMEOUT = 11;
7237
7238        public static final int APP_TRANSITION_TIMEOUT = 13;
7239        public static final int PERSIST_ANIMATION_SCALE = 14;
7240        public static final int FORCE_GC = 15;
7241        public static final int ENABLE_SCREEN = 16;
7242        public static final int APP_FREEZE_TIMEOUT = 17;
7243        public static final int SEND_NEW_CONFIGURATION = 18;
7244        public static final int REPORT_WINDOWS_CHANGE = 19;
7245        public static final int DRAG_START_TIMEOUT = 20;
7246        public static final int DRAG_END_TIMEOUT = 21;
7247        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
7248        public static final int BOOT_TIMEOUT = 23;
7249        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
7250        public static final int UPDATE_ANIM_PARAMETERS = 25;
7251        public static final int SHOW_STRICT_MODE_VIOLATION = 26;
7252        public static final int DO_ANIMATION_CALLBACK = 27;
7253        public static final int NOTIFY_ROTATION_CHANGED = 28;
7254        public static final int NOTIFY_WINDOW_TRANSITION = 29;
7255        public static final int NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 30;
7256        public static final int NOTIFY_WINDOW_LAYERS_CHANGED = 31;
7257
7258        public static final int DO_DISPLAY_ADDED = 32;
7259        public static final int DO_DISPLAY_REMOVED = 33;
7260        public static final int DO_DISPLAY_CHANGED = 34;
7261
7262        public static final int CLIENT_FREEZE_TIMEOUT = 35;
7263
7264        public static final int ANIMATOR_WHAT_OFFSET = 100000;
7265        public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
7266        public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
7267
7268        public H() {
7269        }
7270
7271        @Override
7272        public void handleMessage(Message msg) {
7273            if (DEBUG_WINDOW_TRACE) {
7274                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
7275            }
7276            switch (msg.what) {
7277                case REPORT_FOCUS_CHANGE: {
7278                    WindowState lastFocus;
7279                    WindowState newFocus;
7280
7281                    synchronized(mWindowMap) {
7282                        lastFocus = mLastFocus;
7283                        newFocus = mCurrentFocus;
7284                        if (lastFocus == newFocus) {
7285                            // Focus is not changing, so nothing to do.
7286                            return;
7287                        }
7288                        mLastFocus = newFocus;
7289                        //Slog.i(TAG, "Focus moving from " + lastFocus
7290                        //        + " to " + newFocus);
7291                        if (newFocus != null && lastFocus != null
7292                                && !newFocus.isDisplayedLw()) {
7293                            //Slog.i(TAG, "Delaying loss of focus...");
7294                            mLosingFocus.add(lastFocus);
7295                            lastFocus = null;
7296                        }
7297                    }
7298
7299                    if (lastFocus != newFocus) {
7300                        //System.out.println("Changing focus from " + lastFocus
7301                        //                   + " to " + newFocus);
7302                        if (newFocus != null) {
7303                            try {
7304                                //Slog.i(TAG, "Gaining focus: " + newFocus);
7305                                newFocus.mClient.windowFocusChanged(true, mInTouchMode);
7306                            } catch (RemoteException e) {
7307                                // Ignore if process has died.
7308                            }
7309                            notifyFocusChanged();
7310                        }
7311
7312                        if (lastFocus != null) {
7313                            try {
7314                                //Slog.i(TAG, "Losing focus: " + lastFocus);
7315                                lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
7316                            } catch (RemoteException e) {
7317                                // Ignore if process has died.
7318                            }
7319                        }
7320                    }
7321                } break;
7322
7323                case REPORT_LOSING_FOCUS: {
7324                    ArrayList<WindowState> losers;
7325
7326                    synchronized(mWindowMap) {
7327                        losers = mLosingFocus;
7328                        mLosingFocus = new ArrayList<WindowState>();
7329                    }
7330
7331                    final int N = losers.size();
7332                    for (int i=0; i<N; i++) {
7333                        try {
7334                            //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
7335                            losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
7336                        } catch (RemoteException e) {
7337                             // Ignore if process has died.
7338                        }
7339                    }
7340                } break;
7341
7342                case DO_TRAVERSAL: {
7343                    synchronized(mWindowMap) {
7344                        mTraversalScheduled = false;
7345                        performLayoutAndPlaceSurfacesLocked();
7346                    }
7347                } break;
7348
7349                case ADD_STARTING: {
7350                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7351                    final StartingData sd = wtoken.startingData;
7352
7353                    if (sd == null) {
7354                        // Animation has been canceled... do nothing.
7355                        return;
7356                    }
7357
7358                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
7359                            + wtoken + ": pkg=" + sd.pkg);
7360
7361                    View view = null;
7362                    try {
7363                        view = mPolicy.addStartingWindow(
7364                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
7365                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
7366                    } catch (Exception e) {
7367                        Slog.w(TAG, "Exception when adding starting window", e);
7368                    }
7369
7370                    if (view != null) {
7371                        boolean abort = false;
7372
7373                        synchronized(mWindowMap) {
7374                            if (wtoken.removed || wtoken.startingData == null) {
7375                                // If the window was successfully added, then
7376                                // we need to remove it.
7377                                if (wtoken.startingWindow != null) {
7378                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7379                                            "Aborted starting " + wtoken
7380                                            + ": removed=" + wtoken.removed
7381                                            + " startingData=" + wtoken.startingData);
7382                                    wtoken.startingWindow = null;
7383                                    wtoken.startingData = null;
7384                                    abort = true;
7385                                }
7386                            } else {
7387                                wtoken.startingView = view;
7388                            }
7389                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
7390                                    "Added starting " + wtoken
7391                                    + ": startingWindow="
7392                                    + wtoken.startingWindow + " startingView="
7393                                    + wtoken.startingView);
7394                        }
7395
7396                        if (abort) {
7397                            try {
7398                                mPolicy.removeStartingWindow(wtoken.token, view);
7399                            } catch (Exception e) {
7400                                Slog.w(TAG, "Exception when removing starting window", e);
7401                            }
7402                        }
7403                    }
7404                } break;
7405
7406                case REMOVE_STARTING: {
7407                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7408                    IBinder token = null;
7409                    View view = null;
7410                    synchronized (mWindowMap) {
7411                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
7412                                + wtoken + ": startingWindow="
7413                                + wtoken.startingWindow + " startingView="
7414                                + wtoken.startingView);
7415                        if (wtoken.startingWindow != null) {
7416                            view = wtoken.startingView;
7417                            token = wtoken.token;
7418                            wtoken.startingData = null;
7419                            wtoken.startingView = null;
7420                            wtoken.startingWindow = null;
7421                            wtoken.startingDisplayed = false;
7422                        }
7423                    }
7424                    if (view != null) {
7425                        try {
7426                            mPolicy.removeStartingWindow(token, view);
7427                        } catch (Exception e) {
7428                            Slog.w(TAG, "Exception when removing starting window", e);
7429                        }
7430                    }
7431                } break;
7432
7433                case FINISHED_STARTING: {
7434                    IBinder token = null;
7435                    View view = null;
7436                    while (true) {
7437                        synchronized (mWindowMap) {
7438                            final int N = mFinishedStarting.size();
7439                            if (N <= 0) {
7440                                break;
7441                            }
7442                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7443
7444                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7445                                    "Finished starting " + wtoken
7446                                    + ": startingWindow=" + wtoken.startingWindow
7447                                    + " startingView=" + wtoken.startingView);
7448
7449                            if (wtoken.startingWindow == null) {
7450                                continue;
7451                            }
7452
7453                            view = wtoken.startingView;
7454                            token = wtoken.token;
7455                            wtoken.startingData = null;
7456                            wtoken.startingView = null;
7457                            wtoken.startingWindow = null;
7458                            wtoken.startingDisplayed = false;
7459                        }
7460
7461                        try {
7462                            mPolicy.removeStartingWindow(token, view);
7463                        } catch (Exception e) {
7464                            Slog.w(TAG, "Exception when removing starting window", e);
7465                        }
7466                    }
7467                } break;
7468
7469                case REPORT_APPLICATION_TOKEN_DRAWN: {
7470                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7471
7472                    try {
7473                        if (DEBUG_VISIBILITY) Slog.v(
7474                                TAG, "Reporting drawn in " + wtoken);
7475                        wtoken.appToken.windowsDrawn();
7476                    } catch (RemoteException ex) {
7477                    }
7478                } break;
7479
7480                case REPORT_APPLICATION_TOKEN_WINDOWS: {
7481                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7482
7483                    boolean nowVisible = msg.arg1 != 0;
7484                    boolean nowGone = msg.arg2 != 0;
7485
7486                    try {
7487                        if (DEBUG_VISIBILITY) Slog.v(
7488                                TAG, "Reporting visible in " + wtoken
7489                                + " visible=" + nowVisible
7490                                + " gone=" + nowGone);
7491                        if (nowVisible) {
7492                            wtoken.appToken.windowsVisible();
7493                        } else {
7494                            wtoken.appToken.windowsGone();
7495                        }
7496                    } catch (RemoteException ex) {
7497                    }
7498                } break;
7499
7500                case WINDOW_FREEZE_TIMEOUT: {
7501                    // TODO(multidisplay): Can non-default displays rotate?
7502                    synchronized (mWindowMap) {
7503                        Slog.w(TAG, "Window freeze timeout expired.");
7504                        final WindowList windows = getDefaultWindowListLocked();
7505                        int i = windows.size();
7506                        while (i > 0) {
7507                            i--;
7508                            WindowState w = windows.get(i);
7509                            if (w.mOrientationChanging) {
7510                                w.mOrientationChanging = false;
7511                                Slog.w(TAG, "Force clearing orientation change: " + w);
7512                            }
7513                        }
7514                        performLayoutAndPlaceSurfacesLocked();
7515                    }
7516                    break;
7517                }
7518
7519                case APP_TRANSITION_TIMEOUT: {
7520                    synchronized (mWindowMap) {
7521                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
7522                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7523                                    "*** APP TRANSITION TIMEOUT");
7524                            mAppTransitionReady = true;
7525                            mAppTransitionTimeout = true;
7526                            mAnimatingAppTokens.clear();
7527                            mAnimatingAppTokens.addAll(mAppTokens);
7528                            performLayoutAndPlaceSurfacesLocked();
7529                        }
7530                    }
7531                    break;
7532                }
7533
7534                case PERSIST_ANIMATION_SCALE: {
7535                    Settings.Global.putFloat(mContext.getContentResolver(),
7536                            Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7537                    Settings.Global.putFloat(mContext.getContentResolver(),
7538                            Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7539                    Settings.Global.putFloat(mContext.getContentResolver(),
7540                            Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
7541                    break;
7542                }
7543
7544                case FORCE_GC: {
7545                    synchronized (mWindowMap) {
7546                        synchronized (mAnimator) {
7547                            // Since we're holding both mWindowMap and mAnimator we don't need to
7548                            // hold mAnimator.mLayoutToAnim.
7549                            if (mAnimator.mAnimating || mLayoutToAnim.mAnimationScheduled) {
7550                                // If we are animating, don't do the gc now but
7551                                // delay a bit so we don't interrupt the animation.
7552                                mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
7553                                        2000);
7554                                return;
7555                            }
7556                            // If we are currently rotating the display, it will
7557                            // schedule a new message when done.
7558                            if (mDisplayFrozen) {
7559                                return;
7560                            }
7561                        }
7562                    }
7563                    Runtime.getRuntime().gc();
7564                    break;
7565                }
7566
7567                case ENABLE_SCREEN: {
7568                    performEnableScreen();
7569                    break;
7570                }
7571
7572                case APP_FREEZE_TIMEOUT: {
7573                    synchronized (mWindowMap) {
7574                        synchronized (mAnimator) {
7575                            Slog.w(TAG, "App freeze timeout expired.");
7576                            int i = mAppTokens.size();
7577                            while (i > 0) {
7578                                i--;
7579                                AppWindowToken tok = mAppTokens.get(i);
7580                                if (tok.mAppAnimator.freezingScreen) {
7581                                    Slog.w(TAG, "Force clearing freeze: " + tok);
7582                                    unsetAppFreezingScreenLocked(tok, true, true);
7583                                }
7584                            }
7585                        }
7586                    }
7587                    break;
7588                }
7589
7590                case CLIENT_FREEZE_TIMEOUT: {
7591                    synchronized (mWindowMap) {
7592                        if (mClientFreezingScreen) {
7593                            mClientFreezingScreen = false;
7594                            stopFreezingDisplayLocked();
7595                        }
7596                    }
7597                    break;
7598                }
7599
7600                case SEND_NEW_CONFIGURATION: {
7601                    removeMessages(SEND_NEW_CONFIGURATION);
7602                    sendNewConfiguration();
7603                    break;
7604                }
7605
7606                case REPORT_WINDOWS_CHANGE: {
7607                    if (mWindowsChanged) {
7608                        synchronized (mWindowMap) {
7609                            mWindowsChanged = false;
7610                        }
7611                        notifyWindowsChanged();
7612                    }
7613                    break;
7614                }
7615
7616                case DRAG_START_TIMEOUT: {
7617                    IBinder win = (IBinder)msg.obj;
7618                    if (DEBUG_DRAG) {
7619                        Slog.w(TAG, "Timeout starting drag by win " + win);
7620                    }
7621                    synchronized (mWindowMap) {
7622                        // !!! TODO: ANR the app that has failed to start the drag in time
7623                        if (mDragState != null) {
7624                            mDragState.unregister();
7625                            mInputMonitor.updateInputWindowsLw(true /*force*/);
7626                            mDragState.reset();
7627                            mDragState = null;
7628                        }
7629                    }
7630                    break;
7631                }
7632
7633                case DRAG_END_TIMEOUT: {
7634                    IBinder win = (IBinder)msg.obj;
7635                    if (DEBUG_DRAG) {
7636                        Slog.w(TAG, "Timeout ending drag to win " + win);
7637                    }
7638                    synchronized (mWindowMap) {
7639                        // !!! TODO: ANR the drag-receiving app
7640                        if (mDragState != null) {
7641                            mDragState.mDragResult = false;
7642                            mDragState.endDragLw();
7643                        }
7644                    }
7645                    break;
7646                }
7647
7648                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
7649                    notifyHardKeyboardStatusChange();
7650                    break;
7651                }
7652
7653                case BOOT_TIMEOUT: {
7654                    performBootTimeout();
7655                    break;
7656                }
7657
7658                case WAITING_FOR_DRAWN_TIMEOUT: {
7659                    Pair<WindowState, IRemoteCallback> pair;
7660                    synchronized (mWindowMap) {
7661                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
7662                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
7663                        if (!mWaitingForDrawn.remove(pair)) {
7664                            return;
7665                        }
7666                    }
7667                    try {
7668                        pair.second.sendResult(null);
7669                    } catch (RemoteException e) {
7670                    }
7671                    break;
7672                }
7673
7674                case UPDATE_ANIM_PARAMETERS: {
7675                    // Used to send multiple changes from the animation side to the layout side.
7676                    synchronized (mWindowMap) {
7677                        if (copyAnimToLayoutParamsLocked()) {
7678                            mH.sendEmptyMessage(CLEAR_PENDING_ACTIONS);
7679                            performLayoutAndPlaceSurfacesLocked();
7680                        }
7681                    }
7682                    break;
7683                }
7684
7685                case SHOW_STRICT_MODE_VIOLATION: {
7686                    showStrictModeViolation(msg.arg1, msg.arg2);
7687                    break;
7688                }
7689
7690                // Animation messages. Move to Window{State}Animator
7691                case SET_TRANSPARENT_REGION: {
7692                    Pair<WindowStateAnimator, Region> pair =
7693                                (Pair<WindowStateAnimator, Region>) msg.obj;
7694                    final WindowStateAnimator winAnimator = pair.first;
7695                    winAnimator.setTransparentRegionHint(pair.second);
7696                    break;
7697                }
7698
7699                case CLEAR_PENDING_ACTIONS: {
7700                    mAnimator.clearPendingActions();
7701                    break;
7702                }
7703
7704                case DO_ANIMATION_CALLBACK: {
7705                    try {
7706                        ((IRemoteCallback)msg.obj).sendResult(null);
7707                    } catch (RemoteException e) {
7708                    }
7709                    break;
7710                }
7711
7712                case NOTIFY_ROTATION_CHANGED: {
7713                    final int displayId = msg.arg1;
7714                    final int rotation = msg.arg2;
7715                    handleNotifyRotationChanged(displayId, rotation);
7716                    break;
7717                }
7718
7719                case NOTIFY_WINDOW_TRANSITION: {
7720                    final int transition = msg.arg1;
7721                    WindowInfo info = (WindowInfo) msg.obj;
7722                    handleNotifyWindowTranstion(transition, info);
7723                    break;
7724                }
7725
7726                case NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
7727                    final int displayId = msg.arg1;
7728                    final boolean immediate = (msg.arg2 == 1);
7729                    Rect rectangle = (Rect) msg.obj;
7730                    handleNotifyRectangleOnScreenRequested(displayId, rectangle, immediate);
7731                    break;
7732                }
7733
7734                case NOTIFY_WINDOW_LAYERS_CHANGED: {
7735                    DisplayContent displayContent = (DisplayContent) msg.obj;
7736                    handleNotifyWindowLayersChanged(displayContent);
7737                    break;
7738                }
7739
7740                case DO_DISPLAY_ADDED:
7741                    synchronized (mWindowMap) {
7742                        handleDisplayAddedLocked(msg.arg1);
7743                    }
7744                    break;
7745
7746                case DO_DISPLAY_REMOVED:
7747                    synchronized (mWindowMap) {
7748                        handleDisplayRemovedLocked(msg.arg1);
7749                    }
7750                    break;
7751
7752                case DO_DISPLAY_CHANGED:
7753                    synchronized (mWindowMap) {
7754                        handleDisplayChangedLocked(msg.arg1);
7755                    }
7756                    break;
7757            }
7758            if (DEBUG_WINDOW_TRACE) {
7759                Slog.v(TAG, "handleMessage: exit");
7760            }
7761        }
7762    }
7763
7764    // -------------------------------------------------------------
7765    // IWindowManager API
7766    // -------------------------------------------------------------
7767
7768    @Override
7769    public IWindowSession openSession(IInputMethodClient client,
7770            IInputContext inputContext) {
7771        if (client == null) throw new IllegalArgumentException("null client");
7772        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7773        Session session = new Session(this, client, inputContext);
7774        return session;
7775    }
7776
7777    @Override
7778    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7779        synchronized (mWindowMap) {
7780            // The focus for the client is the window immediately below
7781            // where we would place the input method window.
7782            int idx = findDesiredInputMethodWindowIndexLocked(false);
7783            if (idx > 0) {
7784                // TODO(multidisplay): IMEs are only supported on the default display.
7785                WindowState imFocus = getDefaultWindowListLocked().get(idx-1);
7786                if (DEBUG_INPUT_METHOD) {
7787                    Slog.i(TAG, "Desired input method target: " + imFocus);
7788                    Slog.i(TAG, "Current focus: " + mCurrentFocus);
7789                    Slog.i(TAG, "Last focus: " + mLastFocus);
7790                }
7791                if (imFocus != null) {
7792                    // This may be a starting window, in which case we still want
7793                    // to count it as okay.
7794                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
7795                            && imFocus.mAppToken != null) {
7796                        // The client has definitely started, so it really should
7797                        // have a window in this app token.  Let's look for it.
7798                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
7799                            WindowState w = imFocus.mAppToken.windows.get(i);
7800                            if (w != imFocus) {
7801                                Log.i(TAG, "Switching to real app window: " + w);
7802                                imFocus = w;
7803                                break;
7804                            }
7805                        }
7806                    }
7807                    if (DEBUG_INPUT_METHOD) {
7808                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
7809                        if (imFocus.mSession.mClient != null) {
7810                            Slog.i(TAG, "IM target client binder: "
7811                                    + imFocus.mSession.mClient.asBinder());
7812                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
7813                        }
7814                    }
7815                    if (imFocus.mSession.mClient != null &&
7816                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7817                        return true;
7818                    }
7819                }
7820            }
7821
7822            // Okay, how about this...  what is the current focus?
7823            // It seems in some cases we may not have moved the IM
7824            // target window, such as when it was in a pop-up window,
7825            // so let's also look at the current focus.  (An example:
7826            // go to Gmail, start searching so the keyboard goes up,
7827            // press home.  Sometimes the IME won't go down.)
7828            // Would be nice to fix this more correctly, but it's
7829            // way at the end of a release, and this should be good enough.
7830            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
7831                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7832                return true;
7833            }
7834        }
7835        return false;
7836    }
7837
7838    public void getInitialDisplaySize(int displayId, Point size) {
7839        // TODO(cmautner): Access to DisplayContent should be locked on mWindowMap. Doing that
7840        //  could lead to deadlock since this is called from ActivityManager.
7841        final DisplayContent displayContent = getDisplayContentLocked(displayId);
7842        synchronized(displayContent.mDisplaySizeLock) {
7843            size.x = displayContent.mInitialDisplayWidth;
7844            size.y = displayContent.mInitialDisplayHeight;
7845        }
7846    }
7847
7848    public void setForcedDisplaySize(int displayId, int width, int height) {
7849        synchronized(mWindowMap) {
7850            // Set some sort of reasonable bounds on the size of the display that we
7851            // will try to emulate.
7852            final int MIN_WIDTH = 200;
7853            final int MIN_HEIGHT = 200;
7854            final int MAX_SCALE = 2;
7855            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7856
7857            width = Math.min(Math.max(width, MIN_WIDTH),
7858                    displayContent.mInitialDisplayWidth * MAX_SCALE);
7859            height = Math.min(Math.max(height, MIN_HEIGHT),
7860                    displayContent.mInitialDisplayHeight * MAX_SCALE);
7861            setForcedDisplaySizeLocked(displayContent, width, height);
7862            Settings.Global.putString(mContext.getContentResolver(),
7863                    Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
7864        }
7865    }
7866
7867    private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) {
7868        final String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
7869                Settings.Global.DISPLAY_SIZE_FORCED);
7870        if (sizeStr != null && sizeStr.length() > 0) {
7871            final int pos = sizeStr.indexOf(',');
7872            if (pos > 0 && sizeStr.lastIndexOf(',') == pos) {
7873                int width, height;
7874                try {
7875                    width = Integer.parseInt(sizeStr.substring(0, pos));
7876                    height = Integer.parseInt(sizeStr.substring(pos+1));
7877                    synchronized(displayContent.mDisplaySizeLock) {
7878                        if (displayContent.mBaseDisplayWidth != width
7879                                || displayContent.mBaseDisplayHeight != height) {
7880                            Slog.i(TAG, "FORCED DISPLAY SIZE: " + width + "x" + height);
7881                            displayContent.mBaseDisplayWidth = width;
7882                            displayContent.mBaseDisplayHeight = height;
7883                        }
7884                    }
7885                } catch (NumberFormatException ex) {
7886                }
7887            }
7888        }
7889        final String densityStr = Settings.Global.getString(mContext.getContentResolver(),
7890                Settings.Global.DISPLAY_DENSITY_FORCED);
7891        if (densityStr != null && densityStr.length() > 0) {
7892            int density;
7893            try {
7894                density = Integer.parseInt(densityStr);
7895                synchronized(displayContent.mDisplaySizeLock) {
7896                    if (displayContent.mBaseDisplayDensity != density) {
7897                        Slog.i(TAG, "FORCED DISPLAY DENSITY: " + density);
7898                        displayContent.mBaseDisplayDensity = density;
7899                    }
7900                }
7901            } catch (NumberFormatException ex) {
7902            }
7903        }
7904    }
7905
7906    private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
7907        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7908
7909        synchronized(displayContent.mDisplaySizeLock) {
7910            displayContent.mBaseDisplayWidth = width;
7911            displayContent.mBaseDisplayHeight = height;
7912        }
7913        reconfigureDisplayLocked(displayContent);
7914    }
7915
7916    public void clearForcedDisplaySize(int displayId) {
7917        synchronized(mWindowMap) {
7918            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7919            setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
7920                    displayContent.mInitialDisplayHeight);
7921            Settings.Global.putString(mContext.getContentResolver(),
7922                    Settings.Global.DISPLAY_SIZE_FORCED, "");
7923        }
7924    }
7925
7926    public void setForcedDisplayDensity(int displayId, int density) {
7927        synchronized(mWindowMap) {
7928            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7929            setForcedDisplayDensityLocked(displayContent, density);
7930            Settings.Global.putString(mContext.getContentResolver(),
7931                    Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
7932        }
7933    }
7934
7935    private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) {
7936        Slog.i(TAG, "Using new display density: " + density);
7937
7938        synchronized(displayContent.mDisplaySizeLock) {
7939            displayContent.mBaseDisplayDensity = density;
7940        }
7941        reconfigureDisplayLocked(displayContent);
7942    }
7943
7944    public void clearForcedDisplayDensity(int displayId) {
7945        synchronized(mWindowMap) {
7946            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7947            setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity);
7948            Settings.Global.putString(mContext.getContentResolver(),
7949                    Settings.Global.DISPLAY_DENSITY_FORCED, "");
7950        }
7951    }
7952
7953    private void reconfigureDisplayLocked(DisplayContent displayContent) {
7954        // TODO: Multidisplay: for now only use with default display.
7955        mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
7956                displayContent.mBaseDisplayWidth,
7957                displayContent.mBaseDisplayHeight,
7958                displayContent.mBaseDisplayDensity);
7959
7960        displayContent.layoutNeeded = true;
7961
7962        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7963        mTempConfiguration.setToDefaults();
7964        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7965        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7966            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7967                configChanged = true;
7968            }
7969        }
7970
7971        if (configChanged) {
7972            mWaitingForConfig = true;
7973            startFreezingDisplayLocked(false, 0, 0);
7974            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7975        }
7976
7977        performLayoutAndPlaceSurfacesLocked();
7978    }
7979
7980    public boolean hasSystemNavBar() {
7981        return mPolicy.hasSystemNavBar();
7982    }
7983
7984    // -------------------------------------------------------------
7985    // Internals
7986    // -------------------------------------------------------------
7987
7988    final WindowState windowForClientLocked(Session session, IWindow client,
7989            boolean throwOnError) {
7990        return windowForClientLocked(session, client.asBinder(), throwOnError);
7991    }
7992
7993    final WindowState windowForClientLocked(Session session, IBinder client,
7994            boolean throwOnError) {
7995        WindowState win = mWindowMap.get(client);
7996        if (localLOGV) Slog.v(
7997            TAG, "Looking up client " + client + ": " + win);
7998        if (win == null) {
7999            RuntimeException ex = new IllegalArgumentException(
8000                    "Requested window " + client + " does not exist");
8001            if (throwOnError) {
8002                throw ex;
8003            }
8004            Slog.w(TAG, "Failed looking up window", ex);
8005            return null;
8006        }
8007        if (session != null && win.mSession != session) {
8008            RuntimeException ex = new IllegalArgumentException(
8009                    "Requested window " + client + " is in session " +
8010                    win.mSession + ", not " + session);
8011            if (throwOnError) {
8012                throw ex;
8013            }
8014            Slog.w(TAG, "Failed looking up window", ex);
8015            return null;
8016        }
8017
8018        return win;
8019    }
8020
8021    final void rebuildAppWindowListLocked() {
8022        DisplayContentsIterator iterator = new DisplayContentsIterator();
8023        while (iterator.hasNext()) {
8024            rebuildAppWindowListLocked(iterator.next());
8025        }
8026    }
8027
8028    private void rebuildAppWindowListLocked(final DisplayContent displayContent) {
8029        final WindowList windows = displayContent.getWindowList();
8030        int NW = windows.size();
8031        int i;
8032        int lastBelow = -1;
8033        int numRemoved = 0;
8034
8035        if (mRebuildTmp.length < NW) {
8036            mRebuildTmp = new WindowState[NW+10];
8037        }
8038
8039        // First remove all existing app windows.
8040        i=0;
8041        while (i < NW) {
8042            WindowState w = windows.get(i);
8043            if (w.mAppToken != null) {
8044                WindowState win = windows.remove(i);
8045                win.mRebuilding = true;
8046                mRebuildTmp[numRemoved] = win;
8047                mWindowsChanged = true;
8048                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
8049                        "Rebuild removing window: " + win);
8050                NW--;
8051                numRemoved++;
8052                continue;
8053            } else if (lastBelow == i-1) {
8054                if (w.mAttrs.type == TYPE_WALLPAPER || w.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
8055                    lastBelow = i;
8056                }
8057            }
8058            i++;
8059        }
8060
8061        // Keep whatever windows were below the app windows still below,
8062        // by skipping them.
8063        lastBelow++;
8064        i = lastBelow;
8065
8066        // First add all of the exiting app tokens...  these are no longer
8067        // in the main app list, but still have windows shown.  We put them
8068        // in the back because now that the animation is over we no longer
8069        // will care about them.
8070        int NT = mExitingAppTokens.size();
8071        for (int j=0; j<NT; j++) {
8072            i = reAddAppWindowsLocked(displayContent, i, mExitingAppTokens.get(j));
8073        }
8074
8075        // And add in the still active app tokens in Z order.
8076        NT = mAnimatingAppTokens.size();
8077        for (int j=0; j<NT; j++) {
8078            i = reAddAppWindowsLocked(displayContent, i, mAnimatingAppTokens.get(j));
8079        }
8080
8081        i -= lastBelow;
8082        if (i != numRemoved) {
8083            Slog.w(TAG, "Rebuild removed " + numRemoved
8084                    + " windows but added " + i);
8085            for (i=0; i<numRemoved; i++) {
8086                WindowState ws = mRebuildTmp[i];
8087                if (ws.mRebuilding) {
8088                    StringWriter sw = new StringWriter();
8089                    PrintWriter pw = new PrintWriter(sw);
8090                    ws.dump(pw, "", true);
8091                    pw.flush();
8092                    Slog.w(TAG, "This window was lost: " + ws);
8093                    Slog.w(TAG, sw.toString());
8094                    ws.mWinAnimator.destroySurfaceLocked();
8095                }
8096            }
8097            Slog.w(TAG, "Current app token list:");
8098            dumpAnimatingAppTokensLocked();
8099            Slog.w(TAG, "Final window list:");
8100            dumpWindowsLocked();
8101        }
8102    }
8103
8104    private final void assignLayersLocked(WindowList windows) {
8105        int N = windows.size();
8106        int curBaseLayer = 0;
8107        int curLayer = 0;
8108        int i;
8109
8110        if (DEBUG_LAYERS) {
8111            RuntimeException here = new RuntimeException("here");
8112            here.fillInStackTrace();
8113            Slog.v(TAG, "Assigning layers", here);
8114        }
8115
8116        boolean anyLayerChanged = false;
8117
8118        for (i=0; i<N; i++) {
8119            final WindowState w = windows.get(i);
8120            final WindowStateAnimator winAnimator = w.mWinAnimator;
8121            boolean layerChanged = false;
8122            int oldLayer = w.mLayer;
8123            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
8124                    || (i > 0 && w.mIsWallpaper)) {
8125                curLayer += WINDOW_LAYER_MULTIPLIER;
8126                w.mLayer = curLayer;
8127            } else {
8128                curBaseLayer = curLayer = w.mBaseLayer;
8129                w.mLayer = curLayer;
8130            }
8131            if (w.mLayer != oldLayer) {
8132                layerChanged = true;
8133                anyLayerChanged = true;
8134            }
8135            oldLayer = winAnimator.mAnimLayer;
8136            if (w.mTargetAppToken != null) {
8137                winAnimator.mAnimLayer =
8138                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
8139            } else if (w.mAppToken != null) {
8140                winAnimator.mAnimLayer =
8141                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
8142            } else {
8143                winAnimator.mAnimLayer = w.mLayer;
8144            }
8145            if (w.mIsImWindow) {
8146                winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
8147            } else if (w.mIsWallpaper) {
8148                winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
8149            }
8150            if (winAnimator.mAnimLayer != oldLayer) {
8151                layerChanged = true;
8152                anyLayerChanged = true;
8153            }
8154            if (layerChanged && mAnimator.isDimmingLocked(winAnimator)) {
8155                // Force an animation pass just to update the mDimAnimator layer.
8156                updateLayoutToAnimationLocked();
8157            }
8158            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
8159                    + "mBase=" + w.mBaseLayer
8160                    + " mLayer=" + w.mLayer
8161                    + (w.mAppToken == null ?
8162                            "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
8163                    + " =mAnimLayer=" + winAnimator.mAnimLayer);
8164            //System.out.println(
8165            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
8166        }
8167
8168        if (anyLayerChanged) {
8169            scheduleNotifyWindowLayersChangedIfNeededLocked(getDefaultDisplayContentLocked());
8170        }
8171    }
8172
8173    private final void performLayoutAndPlaceSurfacesLocked() {
8174        do {
8175            mTraversalScheduled = false;
8176            performLayoutAndPlaceSurfacesLockedLoop();
8177            mH.removeMessages(H.DO_TRAVERSAL);
8178        } while (mTraversalScheduled);
8179    }
8180
8181    private boolean mInLayout = false;
8182    private final void performLayoutAndPlaceSurfacesLockedLoop() {
8183        if (mInLayout) {
8184            if (DEBUG) {
8185                throw new RuntimeException("Recursive call!");
8186            }
8187            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
8188                    + Debug.getCallers(3));
8189            return;
8190        }
8191
8192        if (mWaitingForConfig) {
8193            // Our configuration has changed (most likely rotation), but we
8194            // don't yet have the complete configuration to report to
8195            // applications.  Don't do any window layout until we have it.
8196            return;
8197        }
8198
8199        if (!mDisplayReady) {
8200            // Not yet initialized, nothing to do.
8201            return;
8202        }
8203
8204        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
8205        mInLayout = true;
8206        boolean recoveringMemory = false;
8207
8208        try {
8209            if (mForceRemoves != null) {
8210                recoveringMemory = true;
8211                // Wait a little bit for things to settle down, and off we go.
8212                for (int i=0; i<mForceRemoves.size(); i++) {
8213                    WindowState ws = mForceRemoves.get(i);
8214                    Slog.i(TAG, "Force removing: " + ws);
8215                    removeWindowInnerLocked(ws.mSession, ws);
8216                }
8217                mForceRemoves = null;
8218                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
8219                Object tmp = new Object();
8220                synchronized (tmp) {
8221                    try {
8222                        tmp.wait(250);
8223                    } catch (InterruptedException e) {
8224                    }
8225                }
8226            }
8227        } catch (RuntimeException e) {
8228            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
8229        }
8230
8231        try {
8232            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
8233
8234            mInLayout = false;
8235
8236            if (needsLayout()) {
8237                if (++mLayoutRepeatCount < 6) {
8238                    requestTraversalLocked();
8239                } else {
8240                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
8241                    mLayoutRepeatCount = 0;
8242                }
8243            } else {
8244                mLayoutRepeatCount = 0;
8245            }
8246
8247            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
8248                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
8249                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
8250            }
8251        } catch (RuntimeException e) {
8252            mInLayout = false;
8253            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
8254        }
8255
8256        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
8257    }
8258
8259    private final void performLayoutLockedInner(final DisplayContent displayContent,
8260                                    boolean initial, boolean updateInputWindows) {
8261        if (!displayContent.layoutNeeded) {
8262            return;
8263        }
8264        displayContent.layoutNeeded = false;
8265        WindowList windows = displayContent.getWindowList();
8266        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
8267
8268        DisplayInfo displayInfo = displayContent.getDisplayInfo();
8269        final int dw = displayInfo.logicalWidth;
8270        final int dh = displayInfo.logicalHeight;
8271
8272        final int NFW = mFakeWindows.size();
8273        for (int i=0; i<NFW; i++) {
8274            mFakeWindows.get(i).layout(dw, dh);
8275        }
8276
8277        final int N = windows.size();
8278        int i;
8279
8280        if (DEBUG_LAYOUT) {
8281            Slog.v(TAG, "-------------------------------------");
8282            Slog.v(TAG, "performLayout: needed="
8283                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
8284        }
8285
8286        WindowStateAnimator universeBackground = null;
8287
8288        mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
8289        if (isDefaultDisplay) {
8290            // Not needed on non-default displays.
8291            mSystemDecorLayer = mPolicy.getSystemDecorRectLw(mSystemDecorRect);
8292            mScreenRect.set(0, 0, dw, dh);
8293        }
8294
8295        int seq = mLayoutSeq+1;
8296        if (seq < 0) seq = 0;
8297        mLayoutSeq = seq;
8298
8299        boolean behindDream = false;
8300
8301        // First perform layout of any root windows (not attached
8302        // to another window).
8303        int topAttached = -1;
8304        for (i = N-1; i >= 0; i--) {
8305            final WindowState win = windows.get(i);
8306
8307            // Don't do layout of a window if it is not visible, or
8308            // soon won't be visible, to avoid wasting time and funky
8309            // changes while a window is animating away.
8310            final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
8311                    || win.isGoneForLayoutLw();
8312
8313            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
8314                Slog.v(TAG, "1ST PASS " + win
8315                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
8316                        + " mLayoutAttached=" + win.mLayoutAttached
8317                        + " screen changed=" + win.isConfigChanged());
8318                final AppWindowToken atoken = win.mAppToken;
8319                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
8320                        + win.mViewVisibility + " mRelayoutCalled="
8321                        + win.mRelayoutCalled + " hidden="
8322                        + win.mRootToken.hidden + " hiddenRequested="
8323                        + (atoken != null && atoken.hiddenRequested)
8324                        + " mAttachedHidden=" + win.mAttachedHidden);
8325                else Slog.v(TAG, "  VIS: mViewVisibility="
8326                        + win.mViewVisibility + " mRelayoutCalled="
8327                        + win.mRelayoutCalled + " hidden="
8328                        + win.mRootToken.hidden + " hiddenRequested="
8329                        + (atoken != null && atoken.hiddenRequested)
8330                        + " mAttachedHidden=" + win.mAttachedHidden);
8331            }
8332
8333            // If this view is GONE, then skip it -- keep the current
8334            // frame, and let the caller know so they can ignore it
8335            // if they want.  (We do the normal layout for INVISIBLE
8336            // windows, since that means "perform layout as normal,
8337            // just don't display").
8338            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
8339                    || win.isConfigChanged()
8340                    || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
8341                if (!win.mLayoutAttached) {
8342                    if (initial) {
8343                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8344                        win.mContentChanged = false;
8345                    }
8346                    if (win.mAttrs.type == TYPE_DREAM) {
8347                        // Don't layout windows behind a dream, so that if it
8348                        // does stuff like hide the status bar we won't get a
8349                        // bad transition when it goes away.
8350                        behindDream = true;
8351                    }
8352                    win.mLayoutNeeded = false;
8353                    win.prelayout();
8354                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
8355                    win.mLayoutSeq = seq;
8356                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8357                            + win.mFrame + " mContainingFrame="
8358                            + win.mContainingFrame + " mDisplayFrame="
8359                            + win.mDisplayFrame);
8360                } else {
8361                    if (topAttached < 0) topAttached = i;
8362                }
8363            }
8364            if (win.mViewVisibility == View.VISIBLE
8365                    && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND
8366                    && universeBackground == null) {
8367                universeBackground = win.mWinAnimator;
8368            }
8369        }
8370
8371        if (mAnimator.mUniverseBackground  != universeBackground) {
8372            mFocusMayChange = true;
8373            mAnimator.mUniverseBackground = universeBackground;
8374        }
8375
8376        boolean attachedBehindDream = false;
8377
8378        // Now perform layout of attached windows, which usually
8379        // depend on the position of the window they are attached to.
8380        // XXX does not deal with windows that are attached to windows
8381        // that are themselves attached.
8382        for (i = topAttached; i >= 0; i--) {
8383            final WindowState win = windows.get(i);
8384
8385            if (win.mLayoutAttached) {
8386                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
8387                        + " mHaveFrame=" + win.mHaveFrame
8388                        + " mViewVisibility=" + win.mViewVisibility
8389                        + " mRelayoutCalled=" + win.mRelayoutCalled);
8390                // If this view is GONE, then skip it -- keep the current
8391                // frame, and let the caller know so they can ignore it
8392                // if they want.  (We do the normal layout for INVISIBLE
8393                // windows, since that means "perform layout as normal,
8394                // just don't display").
8395                if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
8396                    continue;
8397                }
8398                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
8399                        || !win.mHaveFrame || win.mLayoutNeeded) {
8400                    if (initial) {
8401                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8402                        win.mContentChanged = false;
8403                    }
8404                    win.mLayoutNeeded = false;
8405                    win.prelayout();
8406                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
8407                    win.mLayoutSeq = seq;
8408                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8409                            + win.mFrame + " mContainingFrame="
8410                            + win.mContainingFrame + " mDisplayFrame="
8411                            + win.mDisplayFrame);
8412                }
8413            } else if (win.mAttrs.type == TYPE_DREAM) {
8414                // Don't layout windows behind a dream, so that if it
8415                // does stuff like hide the status bar we won't get a
8416                // bad transition when it goes away.
8417                attachedBehindDream = behindDream;
8418            }
8419        }
8420
8421        // Window frames may have changed.  Tell the input dispatcher about it.
8422        mInputMonitor.setUpdateInputWindowsNeededLw();
8423        if (updateInputWindows) {
8424            mInputMonitor.updateInputWindowsLw(false /*force*/);
8425        }
8426
8427        mPolicy.finishLayoutLw();
8428    }
8429
8430    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
8431        // If the screen is currently frozen or off, then keep
8432        // it frozen/off until this window draws at its new
8433        // orientation.
8434        if (!okToDisplay()) {
8435            if (DEBUG_ORIENTATION) Slog.v(TAG,
8436                    "Changing surface while display frozen: " + w);
8437            w.mOrientationChanging = true;
8438            mInnerFields.mOrientationChangeComplete = false;
8439            if (!mWindowsFreezingScreen) {
8440                mWindowsFreezingScreen = true;
8441                // XXX should probably keep timeout from
8442                // when we first froze the display.
8443                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8444                mH.sendMessageDelayed(mH.obtainMessage(
8445                        H.WINDOW_FREEZE_TIMEOUT), WINDOW_FREEZE_TIMEOUT_DURATION);
8446            }
8447        }
8448    }
8449
8450    /**
8451     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8452     * @param windows List of windows on default display.
8453     * @return bitmap indicating if another pass through layout must be made.
8454     */
8455    public int handleAppTransitionReadyLocked(WindowList windows) {
8456        int changes = 0;
8457        int i;
8458        int NN = mOpeningApps.size();
8459        boolean goodToGo = true;
8460        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8461                "Checking " + NN + " opening apps (frozen="
8462                + mDisplayFrozen + " timeout="
8463                + mAppTransitionTimeout + ")...");
8464        if (!mDisplayFrozen && !mAppTransitionTimeout) {
8465            // If the display isn't frozen, wait to do anything until
8466            // all of the apps are ready.  Otherwise just go because
8467            // we'll unfreeze the display when everyone is ready.
8468            for (i=0; i<NN && goodToGo; i++) {
8469                AppWindowToken wtoken = mOpeningApps.get(i);
8470                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8471                        "Check opening app=" + wtoken + ": allDrawn="
8472                        + wtoken.allDrawn + " startingDisplayed="
8473                        + wtoken.startingDisplayed + " startingMoved="
8474                        + wtoken.startingMoved);
8475                if (!wtoken.allDrawn && !wtoken.startingDisplayed
8476                        && !wtoken.startingMoved) {
8477                    goodToGo = false;
8478                }
8479            }
8480        }
8481        if (goodToGo) {
8482            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
8483            int transit = mNextAppTransition;
8484            if (mSkipAppTransitionAnimation) {
8485                transit = WindowManagerPolicy.TRANSIT_UNSET;
8486            }
8487            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
8488            mAppTransitionReady = false;
8489            mAppTransitionRunning = true;
8490            mAppTransitionTimeout = false;
8491            mStartingIconInTransition = false;
8492            mSkipAppTransitionAnimation = false;
8493
8494            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8495
8496            rebuildAppWindowListLocked();
8497
8498            // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
8499            WindowState oldWallpaper =
8500                    mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
8501                        && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
8502                    ? null : mWallpaperTarget;
8503
8504            adjustWallpaperWindowsLocked();
8505            mInnerFields.mWallpaperMayChange = false;
8506
8507            // The top-most window will supply the layout params,
8508            // and we will determine it below.
8509            LayoutParams animLp = null;
8510            int bestAnimLayer = -1;
8511            boolean fullscreenAnim = false;
8512
8513            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8514                    "New wallpaper target=" + mWallpaperTarget
8515                    + ", oldWallpaper=" + oldWallpaper
8516                    + ", lower target=" + mLowerWallpaperTarget
8517                    + ", upper target=" + mUpperWallpaperTarget);
8518            int foundWallpapers = 0;
8519            // Do a first pass through the tokens for two
8520            // things:
8521            // (1) Determine if both the closing and opening
8522            // app token sets are wallpaper targets, in which
8523            // case special animations are needed
8524            // (since the wallpaper needs to stay static
8525            // behind them).
8526            // (2) Find the layout params of the top-most
8527            // application window in the tokens, which is
8528            // what will control the animation theme.
8529            final int NC = mClosingApps.size();
8530            NN = NC + mOpeningApps.size();
8531            for (i=0; i<NN; i++) {
8532                AppWindowToken wtoken;
8533                int mode;
8534                if (i < NC) {
8535                    wtoken = mClosingApps.get(i);
8536                    mode = 1;
8537                } else {
8538                    wtoken = mOpeningApps.get(i-NC);
8539                    mode = 2;
8540                }
8541                if (mLowerWallpaperTarget != null) {
8542                    if (mLowerWallpaperTarget.mAppToken == wtoken
8543                            || mUpperWallpaperTarget.mAppToken == wtoken) {
8544                        foundWallpapers |= mode;
8545                    }
8546                }
8547                if (wtoken.appFullscreen) {
8548                    WindowState ws = wtoken.findMainWindow();
8549                    if (ws != null) {
8550                        animLp = ws.mAttrs;
8551                        bestAnimLayer = ws.mLayer;
8552                        fullscreenAnim = true;
8553                    }
8554                } else if (!fullscreenAnim) {
8555                    WindowState ws = wtoken.findMainWindow();
8556                    if (ws != null) {
8557                        if (ws.mLayer > bestAnimLayer) {
8558                            animLp = ws.mAttrs;
8559                            bestAnimLayer = ws.mLayer;
8560                        }
8561                    }
8562                }
8563            }
8564
8565            if (foundWallpapers == 3) {
8566                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8567                        "Wallpaper animation!");
8568                switch (transit) {
8569                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
8570                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
8571                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
8572                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
8573                        break;
8574                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
8575                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
8576                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
8577                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
8578                        break;
8579                }
8580                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8581                        "New transit: " + transit);
8582            } else if ((oldWallpaper != null) && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
8583                // We are transitioning from an activity with
8584                // a wallpaper to one without.
8585                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
8586                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8587                        "New transit away from wallpaper: " + transit);
8588            } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
8589                // We are transitioning from an activity without
8590                // a wallpaper to now showing the wallpaper
8591                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
8592                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8593                        "New transit into wallpaper: " + transit);
8594            }
8595
8596            // If all closing windows are obscured, then there is
8597            // no need to do an animation.  This is the case, for
8598            // example, when this transition is being done behind
8599            // the lock screen.
8600            if (!mPolicy.allowAppAnimationsLw()) {
8601                animLp = null;
8602            }
8603
8604            AppWindowToken topOpeningApp = null;
8605            int topOpeningLayer = 0;
8606
8607            NN = mOpeningApps.size();
8608            for (i=0; i<NN; i++) {
8609                AppWindowToken wtoken = mOpeningApps.get(i);
8610                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
8611                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
8612                appAnimator.clearThumbnail();
8613                wtoken.reportedVisible = false;
8614                wtoken.inPendingTransaction = false;
8615                appAnimator.animation = null;
8616                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
8617                wtoken.updateReportedVisibilityLocked();
8618                wtoken.waitingToShow = false;
8619
8620                appAnimator.mAllAppWinAnimators.clear();
8621                final int N = wtoken.allAppWindows.size();
8622                for (int j = 0; j < N; j++) {
8623                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
8624                }
8625                mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
8626
8627                if (animLp != null) {
8628                    int layer = -1;
8629                    for (int j=0; j<wtoken.windows.size(); j++) {
8630                        WindowState win = wtoken.windows.get(j);
8631                        if (win.mWinAnimator.mAnimLayer > layer) {
8632                            layer = win.mWinAnimator.mAnimLayer;
8633                        }
8634                    }
8635                    if (topOpeningApp == null || layer > topOpeningLayer) {
8636                        topOpeningApp = wtoken;
8637                        topOpeningLayer = layer;
8638                    }
8639                }
8640            }
8641            NN = mClosingApps.size();
8642            for (i=0; i<NN; i++) {
8643                AppWindowToken wtoken = mClosingApps.get(i);
8644                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8645                        "Now closing app " + wtoken);
8646                wtoken.mAppAnimator.clearThumbnail();
8647                wtoken.inPendingTransaction = false;
8648                wtoken.mAppAnimator.animation = null;
8649                setTokenVisibilityLocked(wtoken, animLp, false,
8650                        transit, false);
8651                wtoken.updateReportedVisibilityLocked();
8652                wtoken.waitingToHide = false;
8653                // Force the allDrawn flag, because we want to start
8654                // this guy's animations regardless of whether it's
8655                // gotten drawn.
8656                wtoken.allDrawn = true;
8657            }
8658
8659            if (mNextAppTransitionThumbnail != null && topOpeningApp != null
8660                    && topOpeningApp.mAppAnimator.animation != null) {
8661                // This thumbnail animation is very special, we need to have
8662                // an extra surface with the thumbnail included with the animation.
8663                Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
8664                        mNextAppTransitionThumbnail.getHeight());
8665                try {
8666                    // TODO(multi-display): support other displays
8667                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
8668                    final Display display = displayContent.getDisplay();
8669                    Surface surface = new Surface(mFxSession,
8670                            "thumbnail anim",
8671                            dirty.width(), dirty.height(),
8672                            PixelFormat.TRANSLUCENT, Surface.HIDDEN);
8673                    surface.setLayerStack(display.getLayerStack());
8674                    topOpeningApp.mAppAnimator.thumbnail = surface;
8675                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
8676                            + surface + ": CREATE");
8677                    Surface drawSurface = new Surface();
8678                    drawSurface.copyFrom(surface);
8679                    Canvas c = drawSurface.lockCanvas(dirty);
8680                    c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
8681                    drawSurface.unlockCanvasAndPost(c);
8682                    drawSurface.release();
8683                    topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
8684                    Animation anim = createThumbnailAnimationLocked(
8685                            transit, true, true, mNextAppTransitionScaleUp);
8686                    topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
8687                    anim.restrictDuration(MAX_ANIMATION_DURATION);
8688                    anim.scaleCurrentDuration(mTransitionAnimationScale);
8689                    topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX;
8690                    topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY;
8691                } catch (Surface.OutOfResourcesException e) {
8692                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
8693                            + " h=" + dirty.height(), e);
8694                    topOpeningApp.mAppAnimator.clearThumbnail();
8695                }
8696            }
8697
8698            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
8699            mNextAppTransitionPackage = null;
8700            mNextAppTransitionThumbnail = null;
8701            scheduleAnimationCallback(mNextAppTransitionCallback);
8702            mNextAppTransitionCallback = null;
8703
8704            mOpeningApps.clear();
8705            mClosingApps.clear();
8706
8707            // This has changed the visibility of windows, so perform
8708            // a new layout to get them all up-to-date.
8709            changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
8710                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8711            getDefaultDisplayContentLocked().layoutNeeded = true;
8712
8713            // TODO(multidisplay): IMEs are only supported on the default display.
8714            if (windows == getDefaultWindowListLocked()
8715                    && !moveInputMethodWindowsIfNeededLocked(true)) {
8716                assignLayersLocked(windows);
8717            }
8718            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, false /*updateInputWindows*/);
8719            mFocusMayChange = false;
8720        }
8721
8722        return changes;
8723    }
8724
8725    /**
8726     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8727     * @return bitmap indicating if another pass through layout must be made.
8728     */
8729    private int handleAnimatingStoppedAndTransitionLocked() {
8730        int changes = 0;
8731
8732        mAppTransitionRunning = false;
8733        // Restore window app tokens to the ActivityManager views
8734        for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) {
8735            mAnimatingAppTokens.get(i).sendingToBottom = false;
8736        }
8737        mAnimatingAppTokens.clear();
8738        mAnimatingAppTokens.addAll(mAppTokens);
8739        rebuildAppWindowListLocked();
8740
8741        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8742        mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
8743        moveInputMethodWindowsIfNeededLocked(true);
8744        mInnerFields.mWallpaperMayChange = true;
8745        // Since the window list has been rebuilt, focus might
8746        // have to be recomputed since the actual order of windows
8747        // might have changed again.
8748        mFocusMayChange = true;
8749
8750        return changes;
8751    }
8752
8753    /**
8754     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8755     *
8756     * @return bitmap indicating if another pass through layout must be made.
8757     */
8758    private int animateAwayWallpaperLocked() {
8759        int changes = 0;
8760        WindowState oldWallpaper = mWallpaperTarget;
8761        if (mLowerWallpaperTarget != null
8762                && mLowerWallpaperTarget.mAppToken != null) {
8763            if (DEBUG_WALLPAPER) Slog.v(TAG,
8764                    "wallpaperForceHiding changed with lower="
8765                    + mLowerWallpaperTarget);
8766            if (DEBUG_WALLPAPER) Slog.v(TAG,
8767                    "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
8768                    " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
8769            if (mLowerWallpaperTarget.mAppToken.hidden) {
8770                // The lower target has become hidden before we
8771                // actually started the animation...  let's completely
8772                // re-evaluate everything.
8773                mLowerWallpaperTarget = mUpperWallpaperTarget = null;
8774                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8775            }
8776        }
8777        mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8778        if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
8779                + " NEW: " + mWallpaperTarget
8780                + " LOWER: " + mLowerWallpaperTarget);
8781        return changes;
8782    }
8783
8784    private void updateResizingWindows(final WindowState w) {
8785        final WindowStateAnimator winAnimator = w.mWinAnimator;
8786        if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
8787            w.mContentInsetsChanged |=
8788                    !w.mLastContentInsets.equals(w.mContentInsets);
8789            w.mVisibleInsetsChanged |=
8790                    !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8791            boolean configChanged = w.isConfigChanged();
8792            if (DEBUG_CONFIGURATION && configChanged) {
8793                Slog.v(TAG, "Win " + w + " config changed: "
8794                        + mCurConfiguration);
8795            }
8796            if (localLOGV) Slog.v(TAG, "Resizing " + w
8797                    + ": configChanged=" + configChanged
8798                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8799            w.mLastFrame.set(w.mFrame);
8800            if (w.mContentInsetsChanged
8801                    || w.mVisibleInsetsChanged
8802                    || winAnimator.mSurfaceResized
8803                    || configChanged) {
8804                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8805                    Slog.v(TAG, "Resize reasons: "
8806                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8807                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8808                            + " surfaceResized=" + winAnimator.mSurfaceResized
8809                            + " configChanged=" + configChanged);
8810                }
8811
8812                w.mLastContentInsets.set(w.mContentInsets);
8813                w.mLastVisibleInsets.set(w.mVisibleInsets);
8814                makeWindowFreezingScreenIfNeededLocked(w);
8815                // If the orientation is changing, then we need to
8816                // hold off on unfreezing the display until this
8817                // window has been redrawn; to do that, we need
8818                // to go through the process of getting informed
8819                // by the application when it has finished drawing.
8820                if (w.mOrientationChanging) {
8821                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
8822                            "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
8823                            + w + ", surface " + winAnimator.mSurface);
8824                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8825                    if (w.mAppToken != null) {
8826                        w.mAppToken.allDrawn = false;
8827                    }
8828                }
8829                if (!mResizingWindows.contains(w)) {
8830                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8831                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8832                            + "x" + winAnimator.mSurfaceH);
8833                    mResizingWindows.add(w);
8834                }
8835            } else if (w.mOrientationChanging) {
8836                if (w.isDrawnLw()) {
8837                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8838                            "Orientation not waiting for draw in "
8839                            + w + ", surface " + winAnimator.mSurface);
8840                    w.mOrientationChanging = false;
8841                }
8842            }
8843        }
8844    }
8845
8846    /**
8847     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8848     *
8849     * @param w WindowState this method is applied to.
8850     * @param currentTime The time which animations use for calculating transitions.
8851     * @param innerDw Width of app window.
8852     * @param innerDh Height of app window.
8853     */
8854    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8855                                         final int innerDw, final int innerDh) {
8856        final WindowManager.LayoutParams attrs = w.mAttrs;
8857        final int attrFlags = attrs.flags;
8858        final boolean canBeSeen = w.isDisplayedLw();
8859
8860        if (w.mHasSurface) {
8861            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8862                mInnerFields.mHoldScreen = w.mSession;
8863            }
8864            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8865                    && mInnerFields.mScreenBrightness < 0) {
8866                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8867            }
8868            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8869                    && mInnerFields.mButtonBrightness < 0) {
8870                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8871            }
8872            if (!mInnerFields.mSyswin && w.mAttrs.userActivityTimeout >= 0
8873                    && mInnerFields.mUserActivityTimeout < 0) {
8874                mInnerFields.mUserActivityTimeout = w.mAttrs.userActivityTimeout;
8875            }
8876
8877            final int type = attrs.type;
8878            if (canBeSeen
8879                    && (type == TYPE_SYSTEM_DIALOG
8880                     || type == TYPE_RECENTS_OVERLAY
8881                     || type == TYPE_KEYGUARD
8882                     || type == TYPE_SYSTEM_ERROR)) {
8883                mInnerFields.mSyswin = true;
8884            }
8885
8886            if (canBeSeen) {
8887                if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
8888                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_MIRROR;
8889                } else if (mInnerFields.mDisplayHasContent
8890                        == LayoutFields.DISPLAY_CONTENT_UNKNOWN) {
8891                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNIQUE;
8892                }
8893            }
8894        }
8895
8896        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8897        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8898            // This window completely covers everything behind it,
8899            // so we want to leave all of them as undimmed (for
8900            // performance reasons).
8901            mInnerFields.mObscured = true;
8902        } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0
8903                && !(w.mAppToken != null && w.mAppToken.hiddenRequested)
8904                && !w.mExiting) {
8905            if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured);
8906            if (!mInnerFields.mDimming) {
8907                //Slog.i(TAG, "DIM BEHIND: " + w);
8908                mInnerFields.mDimming = true;
8909                final WindowStateAnimator winAnimator = w.mWinAnimator;
8910                if (!mAnimator.isDimmingLocked(winAnimator)) {
8911                    final int width, height;
8912                    if (attrs.type == TYPE_BOOT_PROGRESS) {
8913                        final DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo();
8914                        width = displayInfo.logicalWidth;
8915                        height = displayInfo.logicalHeight;
8916                    } else {
8917                        width = innerDw;
8918                        height = innerDh;
8919                    }
8920                    startDimmingLocked(
8921                        winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount, width, height);
8922                }
8923            }
8924        }
8925    }
8926
8927    private void updateAllDrawnLocked() {
8928        // See if any windows have been drawn, so they (and others
8929        // associated with them) can now be shown.
8930        final ArrayList<AppWindowToken> appTokens = mAnimatingAppTokens;
8931        final int NT = appTokens.size();
8932        for (int i=0; i<NT; i++) {
8933            AppWindowToken wtoken = appTokens.get(i);
8934            if (!wtoken.allDrawn) {
8935                int numInteresting = wtoken.numInterestingWindows;
8936                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8937                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
8938                            "allDrawn: " + wtoken
8939                            + " interesting=" + numInteresting
8940                            + " drawn=" + wtoken.numDrawnWindows);
8941                    wtoken.allDrawn = true;
8942                }
8943            }
8944        }
8945    }
8946
8947    // "Something has changed!  Let's make it correct now."
8948    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
8949        if (DEBUG_WINDOW_TRACE) {
8950            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8951                    + Debug.getCallers(3));
8952        }
8953
8954        final long currentTime = SystemClock.uptimeMillis();
8955
8956        int i;
8957
8958        if (mFocusMayChange) {
8959            mFocusMayChange = false;
8960            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8961                    false /*updateInputWindows*/);
8962        }
8963
8964        // Initialize state of exiting tokens.
8965        for (i=mExitingTokens.size()-1; i>=0; i--) {
8966            mExitingTokens.get(i).hasVisible = false;
8967        }
8968
8969        // Initialize state of exiting applications.
8970        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8971            mExitingAppTokens.get(i).hasVisible = false;
8972        }
8973
8974        mInnerFields.mHoldScreen = null;
8975        mInnerFields.mScreenBrightness = -1;
8976        mInnerFields.mButtonBrightness = -1;
8977        mInnerFields.mUserActivityTimeout = -1;
8978        mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
8979
8980        mTransactionSequence++;
8981
8982        final DisplayContent defaultDisplay = getDefaultDisplayContentLocked();
8983        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
8984        final int defaultDw = defaultInfo.logicalWidth;
8985        final int defaultDh = defaultInfo.logicalHeight;
8986
8987        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8988                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8989        Surface.openTransaction();
8990        try {
8991
8992            if (mWatermark != null) {
8993                mWatermark.positionSurface(defaultDw, defaultDh);
8994            }
8995            if (mStrictModeFlash != null) {
8996                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
8997            }
8998
8999            boolean focusDisplayed = false;
9000            boolean updateAllDrawn = false;
9001
9002            DisplayContentsIterator iterator = new DisplayContentsIterator();
9003            while (iterator.hasNext()) {
9004                final DisplayContent displayContent = iterator.next();
9005                WindowList windows = displayContent.getWindowList();
9006                DisplayInfo displayInfo = displayContent.getDisplayInfo();
9007                final int displayId = displayContent.getDisplayId();
9008                final int dw = displayInfo.logicalWidth;
9009                final int dh = displayInfo.logicalHeight;
9010                final int innerDw = displayInfo.appWidth;
9011                final int innerDh = displayInfo.appHeight;
9012                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
9013
9014                // Reset for each display unless we are forcing mirroring.
9015                if (mInnerFields.mDisplayHasContent != LayoutFields.DISPLAY_CONTENT_MIRROR) {
9016                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
9017                }
9018
9019                int repeats = 0;
9020                do {
9021                    repeats++;
9022                    if (repeats > 6) {
9023                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
9024                        displayContent.layoutNeeded = false;
9025                        break;
9026                    }
9027
9028                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
9029                        displayContent.pendingLayoutChanges);
9030
9031                    if (isDefaultDisplay && ((displayContent.pendingLayoutChanges
9032                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0)
9033                            && ((adjustWallpaperWindowsLocked()
9034                                    & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0)) {
9035                        assignLayersLocked(windows);
9036                        displayContent.layoutNeeded = true;
9037                    }
9038
9039                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
9040                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
9041                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
9042                        if (updateOrientationFromAppTokensLocked(true)) {
9043                            displayContent.layoutNeeded = true;
9044                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9045                        }
9046                    }
9047
9048                    if ((displayContent.pendingLayoutChanges
9049                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9050                        displayContent.layoutNeeded = true;
9051                    }
9052
9053                    // FIRST LOOP: Perform a layout, if needed.
9054                    if (repeats < 4) {
9055                        performLayoutLockedInner(displayContent, repeats == 1,
9056                                false /*updateInputWindows*/);
9057                    } else {
9058                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
9059                    }
9060
9061                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
9062                    // it is animating.
9063                    displayContent.pendingLayoutChanges = 0;
9064
9065                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
9066                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
9067
9068                    if (isDefaultDisplay) {
9069                        mPolicy.beginPostLayoutPolicyLw(dw, dh);
9070                        for (i = windows.size() - 1; i >= 0; i--) {
9071                            WindowState w = windows.get(i);
9072                            if (w.mHasSurface) {
9073                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
9074                            }
9075                        }
9076                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
9077                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
9078                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
9079                    }
9080                } while (displayContent.pendingLayoutChanges != 0);
9081
9082                mInnerFields.mObscured = false;
9083                mInnerFields.mDimming = false;
9084                mInnerFields.mSyswin = false;
9085
9086                // Only used if default window
9087                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
9088
9089                final int N = windows.size();
9090                for (i=N-1; i>=0; i--) {
9091                    WindowState w = windows.get(i);
9092
9093                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
9094
9095                    // Update effect.
9096                    w.mObscured = mInnerFields.mObscured;
9097                    if (!mInnerFields.mObscured) {
9098                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
9099                    }
9100
9101                    if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
9102                            && w.isVisibleLw()) {
9103                        // This is the wallpaper target and its obscured state
9104                        // changed... make sure the current wallaper's visibility
9105                        // has been updated accordingly.
9106                        updateWallpaperVisibilityLocked();
9107                    }
9108
9109                    final WindowStateAnimator winAnimator = w.mWinAnimator;
9110
9111                    // If the window has moved due to its containing
9112                    // content frame changing, then we'd like to animate
9113                    // it.
9114                    if (w.mHasSurface && w.shouldAnimateMove()) {
9115                        // Frame has moved, containing content frame
9116                        // has also moved, and we're not currently animating...
9117                        // let's do something.
9118                        Animation a = AnimationUtils.loadAnimation(mContext,
9119                                com.android.internal.R.anim.window_move_from_decor);
9120                        winAnimator.setAnimation(a);
9121                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
9122                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
9123                        try {
9124                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
9125                        } catch (RemoteException e) {
9126                        }
9127                    }
9128
9129                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
9130                    w.mContentChanged = false;
9131
9132                    // Moved from updateWindowsAndWallpaperLocked().
9133                    if (w.mHasSurface) {
9134                        // Take care of the window being ready to display.
9135                        final boolean committed =
9136                                winAnimator.commitFinishDrawingLocked(currentTime);
9137                        if (isDefaultDisplay && committed) {
9138                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
9139                                if (DEBUG_WALLPAPER) Slog.v(TAG,
9140                                        "First draw done in potential wallpaper target " + w);
9141                                mInnerFields.mWallpaperMayChange = true;
9142                                displayContent.pendingLayoutChanges |=
9143                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9144                                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
9145                                    debugLayoutRepeats(
9146                                        "wallpaper and commitFinishDrawingLocked true",
9147                                        displayContent.pendingLayoutChanges);
9148                                }
9149                            }
9150                        }
9151
9152                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
9153
9154                        final AppWindowToken atoken = w.mAppToken;
9155                        if (DEBUG_STARTING_WINDOW && atoken != null
9156                                && w == atoken.startingWindow) {
9157                            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
9158                                + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
9159                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
9160                        }
9161                        if (atoken != null
9162                                && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
9163                            if (atoken.lastTransactionSequence != mTransactionSequence) {
9164                                atoken.lastTransactionSequence = mTransactionSequence;
9165                                atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
9166                                atoken.startingDisplayed = false;
9167                            }
9168                            if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
9169                                    && !w.mExiting && !w.mDestroying) {
9170                                if (WindowManagerService.DEBUG_VISIBILITY ||
9171                                        WindowManagerService.DEBUG_ORIENTATION) {
9172                                    Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
9173                                            + ", isAnimating=" + winAnimator.isAnimating());
9174                                    if (!w.isDrawnLw()) {
9175                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
9176                                                + " pv=" + w.mPolicyVisibility
9177                                                + " mDrawState=" + winAnimator.mDrawState
9178                                                + " ah=" + w.mAttachedHidden
9179                                                + " th=" + atoken.hiddenRequested
9180                                                + " a=" + winAnimator.mAnimating);
9181                                    }
9182                                }
9183                                if (w != atoken.startingWindow) {
9184                                    if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
9185                                        atoken.numInterestingWindows++;
9186                                        if (w.isDrawnLw()) {
9187                                            atoken.numDrawnWindows++;
9188                                            if (WindowManagerService.DEBUG_VISIBILITY ||
9189                                                    WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
9190                                                    "tokenMayBeDrawn: " + atoken
9191                                                    + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
9192                                                    + " mAppFreezing=" + w.mAppFreezing);
9193                                            updateAllDrawn = true;
9194                                        }
9195                                    }
9196                                } else if (w.isDrawnLw()) {
9197                                    atoken.startingDisplayed = true;
9198                                }
9199                            }
9200                        }
9201                    }
9202
9203                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
9204                            && w.isDisplayedLw()) {
9205                        focusDisplayed = true;
9206                    }
9207
9208                    updateResizingWindows(w);
9209                }
9210
9211                final boolean hasUniqueContent;
9212                switch (mInnerFields.mDisplayHasContent) {
9213                    case LayoutFields.DISPLAY_CONTENT_MIRROR:
9214                        hasUniqueContent = isDefaultDisplay;
9215                        break;
9216                    case LayoutFields.DISPLAY_CONTENT_UNIQUE:
9217                        hasUniqueContent = true;
9218                        break;
9219                    case LayoutFields.DISPLAY_CONTENT_UNKNOWN:
9220                    default:
9221                        hasUniqueContent = false;
9222                        break;
9223                }
9224                mDisplayManagerService.setDisplayHasContent(displayId, hasUniqueContent,
9225                        true /* inTraversal, must call performTraversalInTrans... below */);
9226
9227                if (!mInnerFields.mDimming && mAnimator.isDimmingLocked(displayId)) {
9228                    stopDimmingLocked(displayId);
9229                }
9230            }
9231
9232            if (updateAllDrawn) {
9233                updateAllDrawnLocked();
9234            }
9235
9236            if (focusDisplayed) {
9237                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
9238            }
9239
9240            // Give the display manager a chance to adjust properties
9241            // like display rotation if it needs to.
9242            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
9243
9244        } catch (RuntimeException e) {
9245            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
9246        } finally {
9247            Surface.closeTransaction();
9248        }
9249
9250        final WindowList defaultWindows = defaultDisplay.getWindowList();
9251
9252        // If we are ready to perform an app transition, check through
9253        // all of the app tokens to be shown and see if they are ready
9254        // to go.
9255        if (mAppTransitionReady) {
9256            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
9257            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
9258                defaultDisplay.pendingLayoutChanges);
9259        }
9260
9261        mInnerFields.mAdjResult = 0;
9262
9263        if (!mAnimator.mAnimating && mAppTransitionRunning) {
9264            // We have finished the animation of an app transition.  To do
9265            // this, we have delayed a lot of operations like showing and
9266            // hiding apps, moving apps in Z-order, etc.  The app token list
9267            // reflects the correct Z-order, but the window list may now
9268            // be out of sync with it.  So here we will just rebuild the
9269            // entire app window list.  Fun!
9270            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
9271            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
9272                defaultDisplay.pendingLayoutChanges);
9273        }
9274
9275        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
9276                && !mAppTransitionReady) {
9277            // At this point, there was a window with a wallpaper that
9278            // was force hiding other windows behind it, but now it
9279            // is going away.  This may be simple -- just animate
9280            // away the wallpaper and its window -- or it may be
9281            // hard -- the wallpaper now needs to be shown behind
9282            // something that was hidden.
9283            defaultDisplay.pendingLayoutChanges |= animateAwayWallpaperLocked();
9284            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
9285                defaultDisplay.pendingLayoutChanges);
9286        }
9287        mInnerFields.mWallpaperForceHidingChanged = false;
9288
9289        if (mInnerFields.mWallpaperMayChange) {
9290            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
9291                    "Wallpaper may change!  Adjusting");
9292            mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
9293        }
9294
9295        if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
9296            if (DEBUG_WALLPAPER) Slog.v(TAG,
9297                    "Wallpaper layer changed: assigning layers + relayout");
9298            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9299            assignLayersLocked(defaultWindows);
9300        } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
9301            if (DEBUG_WALLPAPER) Slog.v(TAG,
9302                    "Wallpaper visibility changed: relayout");
9303            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9304        }
9305
9306        if (mFocusMayChange) {
9307            mFocusMayChange = false;
9308            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
9309                    false /*updateInputWindows*/)) {
9310                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
9311                mInnerFields.mAdjResult = 0;
9312            }
9313        }
9314
9315        if (needsLayout()) {
9316            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9317            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
9318                    defaultDisplay.pendingLayoutChanges);
9319        }
9320
9321        for (i = mResizingWindows.size() - 1; i >= 0; i--) {
9322            WindowState win = mResizingWindows.get(i);
9323            if (win.mAppFreezing) {
9324                // Don't remove this window until rotation has completed.
9325                continue;
9326            }
9327            final WindowStateAnimator winAnimator = win.mWinAnimator;
9328            try {
9329                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
9330                        "Reporting new frame to " + win + ": " + win.mCompatFrame);
9331                int diff = 0;
9332                boolean configChanged = win.isConfigChanged();
9333                if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION
9334                        // TODO: Remove once b/7094175 is fixed
9335                        || ((String)win.mAttrs.getTitle()).contains("Keyguard"))
9336                        && configChanged) {
9337                    Slog.i(TAG, "Sending new config to window " + win + ": "
9338                            + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
9339                            + " / " + mCurConfiguration + " / 0x"
9340                            + Integer.toHexString(diff));
9341                }
9342                win.mConfiguration = mCurConfiguration;
9343                if (DEBUG_ORIENTATION &&
9344                        winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
9345                        TAG, "Resizing " + win + " WITH DRAW PENDING");
9346                win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
9347                        winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
9348                        configChanged ? win.mConfiguration : null);
9349                win.mContentInsetsChanged = false;
9350                win.mVisibleInsetsChanged = false;
9351                winAnimator.mSurfaceResized = false;
9352            } catch (RemoteException e) {
9353                win.mOrientationChanging = false;
9354            }
9355            mResizingWindows.remove(i);
9356        }
9357
9358        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
9359                "With display frozen, orientationChangeComplete="
9360                + mInnerFields.mOrientationChangeComplete);
9361        if (mInnerFields.mOrientationChangeComplete) {
9362            if (mWindowsFreezingScreen) {
9363                mWindowsFreezingScreen = false;
9364                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
9365            }
9366            stopFreezingDisplayLocked();
9367        }
9368
9369        // Destroy the surface of any windows that are no longer visible.
9370        boolean wallpaperDestroyed = false;
9371        i = mDestroySurface.size();
9372        if (i > 0) {
9373            do {
9374                i--;
9375                WindowState win = mDestroySurface.get(i);
9376                win.mDestroying = false;
9377                if (mInputMethodWindow == win) {
9378                    mInputMethodWindow = null;
9379                }
9380                if (win == mWallpaperTarget) {
9381                    wallpaperDestroyed = true;
9382                }
9383                win.mWinAnimator.destroySurfaceLocked();
9384            } while (i > 0);
9385            mDestroySurface.clear();
9386        }
9387
9388        // Time to remove any exiting tokens?
9389        for (i=mExitingTokens.size()-1; i>=0; i--) {
9390            WindowToken token = mExitingTokens.get(i);
9391            if (!token.hasVisible) {
9392                mExitingTokens.remove(i);
9393                if (token.windowType == TYPE_WALLPAPER) {
9394                    mWallpaperTokens.remove(token);
9395                    updateLayoutToAnimWallpaperTokens();
9396                }
9397            }
9398        }
9399
9400        // Time to remove any exiting applications?
9401        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
9402            AppWindowToken token = mExitingAppTokens.get(i);
9403            if (!token.hasVisible && !mClosingApps.contains(token)) {
9404                // Make sure there is no animation running on this token,
9405                // so any windows associated with it will be removed as
9406                // soon as their animations are complete
9407                token.mAppAnimator.clearAnimation();
9408                token.mAppAnimator.animating = false;
9409                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
9410                        "performLayout: App token exiting now removed" + token);
9411                mAppTokens.remove(token);
9412                mAnimatingAppTokens.remove(token);
9413                mExitingAppTokens.remove(i);
9414            }
9415        }
9416
9417        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
9418            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
9419                try {
9420                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
9421                } catch (RemoteException e) {
9422                }
9423            }
9424            mRelayoutWhileAnimating.clear();
9425        }
9426
9427        if (wallpaperDestroyed && (adjustWallpaperWindowsLocked() != 0)) {
9428            getDefaultDisplayContentLocked().layoutNeeded = true;
9429        }
9430
9431        DisplayContentsIterator iterator = new DisplayContentsIterator();
9432        while (iterator.hasNext()) {
9433            DisplayContent displayContent = iterator.next();
9434            if (displayContent.pendingLayoutChanges != 0) {
9435                displayContent.layoutNeeded = true;
9436            }
9437        }
9438
9439        // Finally update all input windows now that the window changes have stabilized.
9440        mInputMonitor.updateInputWindowsLw(true /*force*/);
9441
9442        setHoldScreenLocked(mInnerFields.mHoldScreen);
9443        if (!mDisplayFrozen) {
9444            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
9445                mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
9446            } else {
9447                mPowerManager.setScreenBrightnessOverrideFromWindowManager(
9448                        toBrightnessOverride(mInnerFields.mScreenBrightness));
9449            }
9450            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
9451                mPowerManager.setButtonBrightnessOverrideFromWindowManager(-1);
9452            } else {
9453                mPowerManager.setButtonBrightnessOverrideFromWindowManager(
9454                        toBrightnessOverride(mInnerFields.mButtonBrightness));
9455            }
9456            mPowerManager.setUserActivityTimeoutOverrideFromWindowManager(
9457                    mInnerFields.mUserActivityTimeout);
9458        }
9459
9460        if (mTurnOnScreen) {
9461            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
9462            mPowerManager.wakeUp(SystemClock.uptimeMillis());
9463            mTurnOnScreen = false;
9464        }
9465
9466        if (mInnerFields.mUpdateRotation) {
9467            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9468            if (updateRotationUncheckedLocked(false)) {
9469                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9470            } else {
9471                mInnerFields.mUpdateRotation = false;
9472            }
9473        }
9474
9475        if (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded
9476                && !mInnerFields.mUpdateRotation) {
9477            checkDrawnWindowsLocked();
9478        }
9479
9480        final int N = mPendingRemove.size();
9481        if (N > 0) {
9482            if (mPendingRemoveTmp.length < N) {
9483                mPendingRemoveTmp = new WindowState[N+10];
9484            }
9485            mPendingRemove.toArray(mPendingRemoveTmp);
9486            mPendingRemove.clear();
9487            DisplayContentList displayList = new DisplayContentList();
9488            for (i = 0; i < N; i++) {
9489                WindowState w = mPendingRemoveTmp[i];
9490                removeWindowInnerLocked(w.mSession, w);
9491                if (!displayList.contains(w.mDisplayContent)) {
9492                    displayList.add(w.mDisplayContent);
9493                }
9494            }
9495
9496            for (DisplayContent displayContent : displayList) {
9497                assignLayersLocked(displayContent.getWindowList());
9498                displayContent.layoutNeeded = true;
9499            }
9500        }
9501
9502        // Check to see if we are now in a state where the screen should
9503        // be enabled, because the window obscured flags have changed.
9504        enableScreenIfNeededLocked();
9505
9506        updateLayoutToAnimationLocked();
9507
9508        if (DEBUG_WINDOW_TRACE) {
9509            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
9510                    + mAnimator.mAnimating);
9511        }
9512    }
9513
9514    private int toBrightnessOverride(float value) {
9515        return (int)(value * PowerManager.BRIGHTNESS_ON);
9516    }
9517
9518    void checkDrawnWindowsLocked() {
9519        if (mWaitingForDrawn.size() > 0) {
9520            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
9521                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
9522                WindowState win = pair.first;
9523                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
9524                //        + win.mRemoved + " visible=" + win.isVisibleLw()
9525                //        + " shown=" + win.mSurfaceShown);
9526                if (win.mRemoved || !win.isVisibleLw()) {
9527                    // Window has been removed or made invisible; no draw
9528                    // will now happen, so stop waiting.
9529                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
9530                    try {
9531                        pair.second.sendResult(null);
9532                    } catch (RemoteException e) {
9533                    }
9534                    mWaitingForDrawn.remove(pair);
9535                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9536                } else if (win.mWinAnimator.mSurfaceShown) {
9537                    // Window is now drawn (and shown).
9538                    try {
9539                        pair.second.sendResult(null);
9540                    } catch (RemoteException e) {
9541                    }
9542                    mWaitingForDrawn.remove(pair);
9543                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9544                }
9545            }
9546        }
9547    }
9548
9549    public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
9550        if (token != null && callback != null) {
9551            synchronized (mWindowMap) {
9552                WindowState win = windowForClientLocked(null, token, true);
9553                if (win != null) {
9554                    Pair<WindowState, IRemoteCallback> pair =
9555                            new Pair<WindowState, IRemoteCallback>(win, callback);
9556                    Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9557                    mH.sendMessageDelayed(m, 2000);
9558                    mWaitingForDrawn.add(pair);
9559                    checkDrawnWindowsLocked();
9560                    return true;
9561                }
9562            }
9563        }
9564        return false;
9565    }
9566
9567    void setHoldScreenLocked(final Session newHoldScreen) {
9568        final boolean hold = newHoldScreen != null;
9569
9570        if (hold && mHoldingScreenOn != newHoldScreen) {
9571            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
9572        }
9573        mHoldingScreenOn = newHoldScreen;
9574
9575        final boolean state = mHoldingScreenWakeLock.isHeld();
9576        if (hold != state) {
9577            if (hold) {
9578                mHoldingScreenWakeLock.acquire();
9579                mPolicy.keepScreenOnStartedLw();
9580            } else {
9581                mPolicy.keepScreenOnStoppedLw();
9582                mHoldingScreenWakeLock.release();
9583            }
9584        }
9585    }
9586
9587    @Override
9588    public void requestTraversal() {
9589        synchronized (mWindowMap) {
9590            requestTraversalLocked();
9591        }
9592    }
9593
9594    void requestTraversalLocked() {
9595        if (!mTraversalScheduled) {
9596            mTraversalScheduled = true;
9597            mH.sendEmptyMessage(H.DO_TRAVERSAL);
9598        }
9599    }
9600
9601    /** Note that Locked in this case is on mLayoutToAnim */
9602    void scheduleAnimationLocked() {
9603        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
9604        if (!layoutToAnim.mAnimationScheduled) {
9605            layoutToAnim.mAnimationScheduled = true;
9606            mChoreographer.postCallback(
9607                    Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
9608        }
9609    }
9610
9611    void updateLayoutToAnimationLocked() {
9612        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
9613        synchronized (layoutToAnim) {
9614            // Copy local params to transfer params.
9615            SparseArray<WinAnimatorList> allWinAnimatorLists = layoutToAnim.mWinAnimatorLists;
9616            allWinAnimatorLists.clear();
9617            DisplayContentsIterator iterator = new DisplayContentsIterator();
9618            while (iterator.hasNext()) {
9619                final DisplayContent displayContent = iterator.next();
9620                WinAnimatorList winAnimatorList = new WinAnimatorList();
9621                final WindowList windows = displayContent.getWindowList();
9622                int N = windows.size();
9623                for (int i = 0; i < N; i++) {
9624                    final WindowStateAnimator winAnimator = windows.get(i).mWinAnimator;
9625                    if (winAnimator.mSurface != null) {
9626                        winAnimatorList.add(winAnimator);
9627                    }
9628                }
9629                allWinAnimatorLists.put(displayContent.getDisplayId(), winAnimatorList);
9630            }
9631
9632            layoutToAnim.mWallpaperTarget = mWallpaperTarget;
9633            layoutToAnim.mLowerWallpaperTarget = mLowerWallpaperTarget;
9634            layoutToAnim.mUpperWallpaperTarget = mUpperWallpaperTarget;
9635
9636            final ArrayList<AppWindowAnimParams> paramList = layoutToAnim.mAppWindowAnimParams;
9637            paramList.clear();
9638            int N = mAnimatingAppTokens.size();
9639            for (int i = 0; i < N; i++) {
9640                paramList.add(new AppWindowAnimParams(mAnimatingAppTokens.get(i).mAppAnimator));
9641            }
9642
9643            layoutToAnim.mParamsModified = true;
9644            scheduleAnimationLocked();
9645        }
9646    }
9647
9648    void updateLayoutToAnimWallpaperTokens() {
9649        synchronized(mLayoutToAnim) {
9650            mLayoutToAnim.mWallpaperTokens = new ArrayList<WindowToken>(mWallpaperTokens);
9651            mLayoutToAnim.mChanges |= LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED;
9652        }
9653    }
9654
9655    void setAnimDimParams(int displayId, DimAnimator.Parameters params) {
9656        synchronized (mLayoutToAnim) {
9657            mLayoutToAnim.mDimParams.put(displayId, params);
9658            scheduleAnimationLocked();
9659        }
9660    }
9661
9662    void startDimmingLocked(final WindowStateAnimator winAnimator, final float target,
9663                      final int width, final int height) {
9664        setAnimDimParams(winAnimator.mWin.getDisplayId(),
9665                new DimAnimator.Parameters(winAnimator, width, height, target));
9666    }
9667
9668    void stopDimmingLocked(int displayId) {
9669        setAnimDimParams(displayId, null);
9670    }
9671
9672    private boolean needsLayout() {
9673        DisplayContentsIterator iterator = new DisplayContentsIterator();
9674        while (iterator.hasNext()) {
9675            if (iterator.next().layoutNeeded) {
9676                return true;
9677            }
9678        }
9679        return false;
9680    }
9681
9682    private boolean copyAnimToLayoutParamsLocked() {
9683        boolean doRequest = false;
9684        final WindowAnimator.AnimatorToLayoutParams animToLayout = mAnimator.mAnimToLayout;
9685        synchronized (animToLayout) {
9686            animToLayout.mUpdateQueued = false;
9687            final int bulkUpdateParams = animToLayout.mBulkUpdateParams;
9688            // TODO(cmautner): As the number of bits grows, use masks of bit groups to
9689            //  eliminate unnecessary tests.
9690            if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
9691                mInnerFields.mUpdateRotation = true;
9692                doRequest = true;
9693            }
9694            if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
9695                mInnerFields.mWallpaperMayChange = true;
9696                doRequest = true;
9697            }
9698            if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
9699                mInnerFields.mWallpaperForceHidingChanged = true;
9700                doRequest = true;
9701            }
9702            if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
9703                mInnerFields.mOrientationChangeComplete = false;
9704            } else {
9705                mInnerFields.mOrientationChangeComplete = true;
9706                if (mWindowsFreezingScreen) {
9707                    doRequest = true;
9708                }
9709            }
9710            if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
9711                mTurnOnScreen = true;
9712            }
9713
9714            SparseIntArray pendingLayouts = animToLayout.mPendingLayoutChanges;
9715            final int count = pendingLayouts.size();
9716            if (count > 0) {
9717                doRequest = true;
9718            }
9719            for (int i = 0; i < count; ++i) {
9720                final DisplayContent displayContent =
9721                        getDisplayContentLocked(pendingLayouts.keyAt(i));
9722                displayContent.pendingLayoutChanges |= pendingLayouts.valueAt(i);
9723            }
9724
9725            mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper;
9726        }
9727        return doRequest;
9728    }
9729
9730    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
9731                                           boolean secure) {
9732        final Surface surface = winAnimator.mSurface;
9733        boolean leakedSurface = false;
9734        boolean killedApps = false;
9735
9736        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
9737                winAnimator.mSession.mPid, operation);
9738
9739        if (mForceRemoves == null) {
9740            mForceRemoves = new ArrayList<WindowState>();
9741        }
9742
9743        long callingIdentity = Binder.clearCallingIdentity();
9744        try {
9745            // There was some problem...   first, do a sanity check of the
9746            // window list to make sure we haven't left any dangling surfaces
9747            // around.
9748
9749            AllWindowsIterator iterator = new AllWindowsIterator();
9750            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
9751            while (iterator.hasNext()) {
9752                WindowState ws = iterator.next();
9753                WindowStateAnimator wsa = ws.mWinAnimator;
9754                if (wsa.mSurface != null) {
9755                    if (!mSessions.contains(wsa.mSession)) {
9756                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
9757                                + ws + " surface=" + wsa.mSurface
9758                                + " token=" + ws.mToken
9759                                + " pid=" + ws.mSession.mPid
9760                                + " uid=" + ws.mSession.mUid);
9761                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9762                        wsa.mSurface.destroy();
9763                        wsa.mSurfaceShown = false;
9764                        wsa.mSurface = null;
9765                        ws.mHasSurface = false;
9766                        mForceRemoves.add(ws);
9767                        leakedSurface = true;
9768                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
9769                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
9770                                + ws + " surface=" + wsa.mSurface
9771                                + " token=" + ws.mAppToken);
9772                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9773                        wsa.mSurface.destroy();
9774                        wsa.mSurfaceShown = false;
9775                        wsa.mSurface = null;
9776                        ws.mHasSurface = false;
9777                        leakedSurface = true;
9778                    }
9779                }
9780            }
9781
9782            if (!leakedSurface) {
9783                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
9784                SparseIntArray pidCandidates = new SparseIntArray();
9785                iterator = new AllWindowsIterator();
9786                while (iterator.hasNext()) {
9787                    WindowState ws = iterator.next();
9788                    if (mForceRemoves.contains(ws)) {
9789                        continue;
9790                    }
9791                    WindowStateAnimator wsa = ws.mWinAnimator;
9792                    if (wsa.mSurface != null) {
9793                        pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
9794                    }
9795                }
9796                if (pidCandidates.size() > 0) {
9797                    int[] pids = new int[pidCandidates.size()];
9798                    for (int i=0; i<pids.length; i++) {
9799                        pids[i] = pidCandidates.keyAt(i);
9800                    }
9801                    try {
9802                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
9803                            killedApps = true;
9804                        }
9805                    } catch (RemoteException e) {
9806                    }
9807                }
9808            }
9809
9810            if (leakedSurface || killedApps) {
9811                // We managed to reclaim some memory, so get rid of the trouble
9812                // surface and ask the app to request another one.
9813                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9814                if (surface != null) {
9815                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
9816                            "RECOVER DESTROY", null);
9817                    surface.destroy();
9818                    winAnimator.mSurfaceShown = false;
9819                    winAnimator.mSurface = null;
9820                    winAnimator.mWin.mHasSurface = false;
9821                }
9822
9823                try {
9824                    winAnimator.mWin.mClient.dispatchGetNewSurface();
9825                } catch (RemoteException e) {
9826                }
9827            }
9828        } finally {
9829            Binder.restoreCallingIdentity(callingIdentity);
9830        }
9831
9832        return leakedSurface || killedApps;
9833    }
9834
9835    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9836        WindowState newFocus = computeFocusedWindowLocked();
9837        if (mCurrentFocus != newFocus) {
9838            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
9839            // This check makes sure that we don't already have the focus
9840            // change message pending.
9841            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9842            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9843            if (localLOGV) Slog.v(
9844                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
9845            final WindowState oldFocus = mCurrentFocus;
9846            mCurrentFocus = newFocus;
9847            mAnimator.setCurrentFocus(newFocus);
9848            mLosingFocus.remove(newFocus);
9849            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9850
9851            // TODO(multidisplay): Focused windows on default display only.
9852            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9853
9854            final WindowState imWindow = mInputMethodWindow;
9855            if (newFocus != imWindow && oldFocus != imWindow) {
9856                if (moveInputMethodWindowsIfNeededLocked(
9857                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
9858                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
9859                    displayContent.layoutNeeded = true;
9860                }
9861                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9862                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9863                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9864                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9865                    // Client will do the layout, but we need to assign layers
9866                    // for handleNewWindowLocked() below.
9867                    assignLayersLocked(displayContent.getWindowList());
9868                }
9869            }
9870
9871            if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9872                // The change in focus caused us to need to do a layout.  Okay.
9873                displayContent.layoutNeeded = true;
9874                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9875                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9876                }
9877            }
9878
9879            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9880                // If we defer assigning layers, then the caller is responsible for
9881                // doing this part.
9882                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9883            }
9884
9885            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
9886            return true;
9887        }
9888        return false;
9889    }
9890
9891    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9892        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9893    }
9894
9895    private WindowState computeFocusedWindowLocked() {
9896        if (mAnimator.mUniverseBackground != null
9897                && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) {
9898            return mAnimator.mUniverseBackground.mWin;
9899        }
9900
9901        final int displayCount = mDisplayContents.size();
9902        for (int i = 0; i < displayCount; i++) {
9903            final DisplayContent displayContent = mDisplayContents.valueAt(i);
9904            WindowState win = findFocusedWindowLocked(displayContent);
9905            if (win != null) {
9906                return win;
9907            }
9908        }
9909        return null;
9910    }
9911
9912    private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
9913        int nextAppIndex = mAppTokens.size()-1;
9914        WindowToken nextApp = nextAppIndex >= 0 ? mAppTokens.get(nextAppIndex) : null;
9915
9916        final WindowList windows = displayContent.getWindowList();
9917        for (int i = windows.size() - 1; i >= 0; i--) {
9918            final WindowState win = windows.get(i);
9919
9920            if (localLOGV || DEBUG_FOCUS) Slog.v(
9921                TAG, "Looking for focus: " + i
9922                + " = " + win
9923                + ", flags=" + win.mAttrs.flags
9924                + ", canReceive=" + win.canReceiveKeys());
9925
9926            AppWindowToken thisApp = win.mAppToken;
9927
9928            // If this window's application has been removed, just skip it.
9929            if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
9930                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping app because " + (thisApp.removed
9931                        ? "removed" : "sendingToBottom"));
9932                continue;
9933            }
9934
9935            // If there is a focused app, don't allow focus to go to any
9936            // windows below it.  If this is an application window, step
9937            // through the app tokens until we find its app.
9938            if (thisApp != null && nextApp != null && thisApp != nextApp
9939                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
9940                int origAppIndex = nextAppIndex;
9941                while (nextAppIndex > 0) {
9942                    if (nextApp == mFocusedApp) {
9943                        // Whoops, we are below the focused app...  no focus
9944                        // for you!
9945                        if (localLOGV || DEBUG_FOCUS) Slog.v(
9946                            TAG, "Reached focused app: " + mFocusedApp);
9947                        return null;
9948                    }
9949                    nextAppIndex--;
9950                    nextApp = mAppTokens.get(nextAppIndex);
9951                    if (nextApp == thisApp) {
9952                        break;
9953                    }
9954                }
9955                if (thisApp != nextApp) {
9956                    // Uh oh, the app token doesn't exist!  This shouldn't
9957                    // happen, but if it does we can get totally hosed...
9958                    // so restart at the original app.
9959                    nextAppIndex = origAppIndex;
9960                    nextApp = mAppTokens.get(nextAppIndex);
9961                }
9962            }
9963
9964            // Dispatch to this window if it is wants key events.
9965            if (win.canReceiveKeys()) {
9966                if (DEBUG_FOCUS) Slog.v(
9967                        TAG, "Found focus @ " + i + " = " + win);
9968                return win;
9969            }
9970        }
9971        return null;
9972    }
9973
9974    private void startFreezingDisplayLocked(boolean inTransaction,
9975            int exitAnim, int enterAnim) {
9976        if (mDisplayFrozen) {
9977            return;
9978        }
9979
9980        if (!mDisplayReady || !mPolicy.isScreenOnFully()) {
9981            // No need to freeze the screen before the system is ready or if
9982            // the screen is off.
9983            return;
9984        }
9985
9986        mScreenFrozenLock.acquire();
9987
9988        mDisplayFrozen = true;
9989
9990        mInputMonitor.freezeInputDispatchingLw();
9991
9992        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
9993            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
9994            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
9995            mNextAppTransitionPackage = null;
9996            mNextAppTransitionThumbnail = null;
9997            mAppTransitionReady = true;
9998        }
9999
10000        if (PROFILE_ORIENTATION) {
10001            File file = new File("/data/system/frozen");
10002            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
10003        }
10004
10005        if (CUSTOM_SCREEN_ROTATION) {
10006            final DisplayContent displayContent = getDefaultDisplayContentLocked();
10007            final int displayId = displayContent.getDisplayId();
10008            ScreenRotationAnimation screenRotationAnimation =
10009                    mAnimator.getScreenRotationAnimationLocked(displayId);
10010            if (screenRotationAnimation != null) {
10011                screenRotationAnimation.kill();
10012            }
10013
10014            // TODO(multidisplay): rotation on main screen only.
10015            final Display display = displayContent.getDisplay();
10016            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
10017            screenRotationAnimation = new ScreenRotationAnimation(mContext,
10018                    display, mFxSession, inTransaction, displayInfo.logicalWidth,
10019                    displayInfo.logicalHeight, display.getRotation(),
10020                    exitAnim, enterAnim);
10021            mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
10022        }
10023    }
10024
10025    private void stopFreezingDisplayLocked() {
10026        if (!mDisplayFrozen) {
10027            return;
10028        }
10029
10030        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
10031                || mClientFreezingScreen) {
10032            if (DEBUG_ORIENTATION) Slog.d(TAG,
10033                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
10034                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
10035                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
10036                + ", mClientFreezingScreen=" + mClientFreezingScreen);
10037            return;
10038        }
10039
10040        mDisplayFrozen = false;
10041        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
10042        mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
10043        if (PROFILE_ORIENTATION) {
10044            Debug.stopMethodTracing();
10045        }
10046
10047        boolean updateRotation = false;
10048
10049        final DisplayContent displayContent = getDefaultDisplayContentLocked();
10050        final int displayId = displayContent.getDisplayId();
10051        ScreenRotationAnimation screenRotationAnimation =
10052                mAnimator.getScreenRotationAnimationLocked(displayId);
10053        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
10054                && screenRotationAnimation.hasScreenshot()) {
10055            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
10056            // TODO(multidisplay): rotation on main screen only.
10057            DisplayInfo displayInfo = displayContent.getDisplayInfo();
10058            if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
10059                    mTransitionAnimationScale, displayInfo.logicalWidth,
10060                        displayInfo.logicalHeight)) {
10061                updateLayoutToAnimationLocked();
10062            } else {
10063                screenRotationAnimation.kill();
10064                screenRotationAnimation = null;
10065                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
10066                updateRotation = true;
10067            }
10068        } else {
10069            if (screenRotationAnimation != null) {
10070                screenRotationAnimation.kill();
10071                screenRotationAnimation = null;
10072                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
10073            }
10074            updateRotation = true;
10075        }
10076
10077        mInputMonitor.thawInputDispatchingLw();
10078
10079        boolean configChanged;
10080
10081        // While the display is frozen we don't re-compute the orientation
10082        // to avoid inconsistent states.  However, something interesting
10083        // could have actually changed during that time so re-evaluate it
10084        // now to catch that.
10085        configChanged = updateOrientationFromAppTokensLocked(false);
10086
10087        // A little kludge: a lot could have happened while the
10088        // display was frozen, so now that we are coming back we
10089        // do a gc so that any remote references the system
10090        // processes holds on others can be released if they are
10091        // no longer needed.
10092        mH.removeMessages(H.FORCE_GC);
10093        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
10094                2000);
10095
10096        mScreenFrozenLock.release();
10097
10098        if (updateRotation) {
10099            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
10100            configChanged |= updateRotationUncheckedLocked(false);
10101        }
10102
10103        if (configChanged) {
10104            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
10105        }
10106    }
10107
10108    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
10109            DisplayMetrics dm) {
10110        if (index < tokens.length) {
10111            String str = tokens[index];
10112            if (str != null && str.length() > 0) {
10113                try {
10114                    int val = Integer.parseInt(str);
10115                    return val;
10116                } catch (Exception e) {
10117                }
10118            }
10119        }
10120        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
10121            return defDps;
10122        }
10123        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
10124        return val;
10125    }
10126
10127    void createWatermarkInTransaction() {
10128        if (mWatermark != null) {
10129            return;
10130        }
10131
10132        File file = new File("/system/etc/setup.conf");
10133        FileInputStream in = null;
10134        try {
10135            in = new FileInputStream(file);
10136            DataInputStream ind = new DataInputStream(in);
10137            String line = ind.readLine();
10138            if (line != null) {
10139                String[] toks = line.split("%");
10140                if (toks != null && toks.length > 0) {
10141                    mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
10142                            mRealDisplayMetrics, mFxSession, toks);
10143                }
10144            }
10145        } catch (FileNotFoundException e) {
10146        } catch (IOException e) {
10147        } finally {
10148            if (in != null) {
10149                try {
10150                    in.close();
10151                } catch (IOException e) {
10152                }
10153            }
10154        }
10155    }
10156
10157    @Override
10158    public void statusBarVisibilityChanged(int visibility) {
10159        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
10160                != PackageManager.PERMISSION_GRANTED) {
10161            throw new SecurityException("Caller does not hold permission "
10162                    + android.Manifest.permission.STATUS_BAR);
10163        }
10164
10165        synchronized (mWindowMap) {
10166            mLastStatusBarVisibility = visibility;
10167            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
10168            updateStatusBarVisibilityLocked(visibility);
10169        }
10170    }
10171
10172    // TOOD(multidisplay): StatusBar on multiple screens?
10173    void updateStatusBarVisibilityLocked(int visibility) {
10174        mInputManager.setSystemUiVisibility(visibility);
10175        final WindowList windows = getDefaultWindowListLocked();
10176        final int N = windows.size();
10177        for (int i = 0; i < N; i++) {
10178            WindowState ws = windows.get(i);
10179            try {
10180                int curValue = ws.mSystemUiVisibility;
10181                int diff = curValue ^ visibility;
10182                // We are only interested in differences of one of the
10183                // clearable flags...
10184                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
10185                // ...if it has actually been cleared.
10186                diff &= ~visibility;
10187                int newValue = (curValue&~diff) | (visibility&diff);
10188                if (newValue != curValue) {
10189                    ws.mSeq++;
10190                    ws.mSystemUiVisibility = newValue;
10191                }
10192                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
10193                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
10194                            visibility, newValue, diff);
10195                }
10196            } catch (RemoteException e) {
10197                // so sorry
10198            }
10199        }
10200    }
10201
10202    @Override
10203    public void reevaluateStatusBarVisibility() {
10204        synchronized (mWindowMap) {
10205            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
10206            updateStatusBarVisibilityLocked(visibility);
10207            performLayoutAndPlaceSurfacesLocked();
10208        }
10209    }
10210
10211    @Override
10212    public FakeWindow addFakeWindow(Looper looper,
10213            InputEventReceiver.Factory inputEventReceiverFactory,
10214            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
10215            boolean hasFocus, boolean touchFullscreen) {
10216        synchronized (mWindowMap) {
10217            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
10218                    name, windowType,
10219                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
10220            int i=0;
10221            while (i<mFakeWindows.size()) {
10222                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
10223                    break;
10224                }
10225            }
10226            mFakeWindows.add(i, fw);
10227            mInputMonitor.updateInputWindowsLw(true);
10228            return fw;
10229        }
10230    }
10231
10232    boolean removeFakeWindowLocked(FakeWindow window) {
10233        synchronized (mWindowMap) {
10234            if (mFakeWindows.remove(window)) {
10235                mInputMonitor.updateInputWindowsLw(true);
10236                return true;
10237            }
10238            return false;
10239        }
10240    }
10241
10242    // It is assumed that this method is called only by InputMethodManagerService.
10243    public void saveLastInputMethodWindowForTransition() {
10244        synchronized (mWindowMap) {
10245            // TODO(multidisplay): Pass in the displayID.
10246            DisplayContent displayContent = getDefaultDisplayContentLocked();
10247            if (mInputMethodWindow != null) {
10248                mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
10249            }
10250        }
10251    }
10252
10253    @Override
10254    public boolean hasNavigationBar() {
10255        return mPolicy.hasNavigationBar();
10256    }
10257
10258    public void lockNow(Bundle options) {
10259        mPolicy.lockNow(options);
10260    }
10261
10262    void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
10263        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
10264        mPolicy.dump("    ", pw, args);
10265    }
10266
10267    void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
10268        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
10269        if (mTokenMap.size() > 0) {
10270            pw.println("  All tokens:");
10271            Iterator<WindowToken> it = mTokenMap.values().iterator();
10272            while (it.hasNext()) {
10273                WindowToken token = it.next();
10274                pw.print("  Token "); pw.print(token.token);
10275                if (dumpAll) {
10276                    pw.println(':');
10277                    token.dump(pw, "    ");
10278                } else {
10279                    pw.println();
10280                }
10281            }
10282        }
10283        if (mWallpaperTokens.size() > 0) {
10284            pw.println();
10285            pw.println("  Wallpaper tokens:");
10286            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
10287                WindowToken token = mWallpaperTokens.get(i);
10288                pw.print("  Wallpaper #"); pw.print(i);
10289                        pw.print(' '); pw.print(token);
10290                if (dumpAll) {
10291                    pw.println(':');
10292                    token.dump(pw, "    ");
10293                } else {
10294                    pw.println();
10295                }
10296            }
10297        }
10298        if (mAppTokens.size() > 0) {
10299            pw.println();
10300            pw.println("  Application tokens in Z order:");
10301            for (int i=mAppTokens.size()-1; i>=0; i--) {
10302                pw.print("  App #"); pw.print(i); pw.println(": ");
10303                        mAppTokens.get(i).dump(pw, "    ");
10304            }
10305        }
10306        if (mFinishedStarting.size() > 0) {
10307            pw.println();
10308            pw.println("  Finishing start of application tokens:");
10309            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
10310                WindowToken token = mFinishedStarting.get(i);
10311                pw.print("  Finished Starting #"); pw.print(i);
10312                        pw.print(' '); pw.print(token);
10313                if (dumpAll) {
10314                    pw.println(':');
10315                    token.dump(pw, "    ");
10316                } else {
10317                    pw.println();
10318                }
10319            }
10320        }
10321        if (mExitingTokens.size() > 0) {
10322            pw.println();
10323            pw.println("  Exiting tokens:");
10324            for (int i=mExitingTokens.size()-1; i>=0; i--) {
10325                WindowToken token = mExitingTokens.get(i);
10326                pw.print("  Exiting #"); pw.print(i);
10327                        pw.print(' '); pw.print(token);
10328                if (dumpAll) {
10329                    pw.println(':');
10330                    token.dump(pw, "    ");
10331                } else {
10332                    pw.println();
10333                }
10334            }
10335        }
10336        if (mExitingAppTokens.size() > 0) {
10337            pw.println();
10338            pw.println("  Exiting application tokens:");
10339            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
10340                WindowToken token = mExitingAppTokens.get(i);
10341                pw.print("  Exiting App #"); pw.print(i);
10342                        pw.print(' '); pw.print(token);
10343                if (dumpAll) {
10344                    pw.println(':');
10345                    token.dump(pw, "    ");
10346                } else {
10347                    pw.println();
10348                }
10349            }
10350        }
10351        if (mAppTransitionRunning && mAnimatingAppTokens.size() > 0) {
10352            pw.println();
10353            pw.println("  Application tokens during animation:");
10354            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
10355                WindowToken token = mAnimatingAppTokens.get(i);
10356                pw.print("  App moving to bottom #"); pw.print(i);
10357                        pw.print(' '); pw.print(token);
10358                if (dumpAll) {
10359                    pw.println(':');
10360                    token.dump(pw, "    ");
10361                } else {
10362                    pw.println();
10363                }
10364            }
10365        }
10366        if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
10367            pw.println();
10368            if (mOpeningApps.size() > 0) {
10369                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
10370            }
10371            if (mClosingApps.size() > 0) {
10372                pw.print("  mClosingApps="); pw.println(mClosingApps);
10373            }
10374        }
10375    }
10376
10377    void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
10378        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
10379        if (mSessions.size() > 0) {
10380            Iterator<Session> it = mSessions.iterator();
10381            while (it.hasNext()) {
10382                Session s = it.next();
10383                pw.print("  Session "); pw.print(s); pw.println(':');
10384                s.dump(pw, "    ");
10385            }
10386        }
10387    }
10388
10389    void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
10390            ArrayList<WindowState> windows) {
10391        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
10392        dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
10393    }
10394
10395    void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
10396            ArrayList<WindowState> windows) {
10397        int j = 0;
10398        final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10399        while (iterator.hasNext()) {
10400            final WindowState w = iterator.next();
10401            if (windows == null || windows.contains(w)) {
10402                pw.print("  Window #"); pw.print(j++); pw.print(' ');
10403                        pw.print(w); pw.println(":");
10404                w.dump(pw, "    ", dumpAll || windows != null);
10405            }
10406        }
10407        if (mInputMethodDialogs.size() > 0) {
10408            pw.println();
10409            pw.println("  Input method dialogs:");
10410            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
10411                WindowState w = mInputMethodDialogs.get(i);
10412                if (windows == null || windows.contains(w)) {
10413                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
10414                }
10415            }
10416        }
10417        if (mPendingRemove.size() > 0) {
10418            pw.println();
10419            pw.println("  Remove pending for:");
10420            for (int i=mPendingRemove.size()-1; i>=0; i--) {
10421                WindowState w = mPendingRemove.get(i);
10422                if (windows == null || windows.contains(w)) {
10423                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
10424                            pw.print(w);
10425                    if (dumpAll) {
10426                        pw.println(":");
10427                        w.dump(pw, "    ", true);
10428                    } else {
10429                        pw.println();
10430                    }
10431                }
10432            }
10433        }
10434        if (mForceRemoves != null && mForceRemoves.size() > 0) {
10435            pw.println();
10436            pw.println("  Windows force removing:");
10437            for (int i=mForceRemoves.size()-1; i>=0; i--) {
10438                WindowState w = mForceRemoves.get(i);
10439                pw.print("  Removing #"); pw.print(i); pw.print(' ');
10440                        pw.print(w);
10441                if (dumpAll) {
10442                    pw.println(":");
10443                    w.dump(pw, "    ", true);
10444                } else {
10445                    pw.println();
10446                }
10447            }
10448        }
10449        if (mDestroySurface.size() > 0) {
10450            pw.println();
10451            pw.println("  Windows waiting to destroy their surface:");
10452            for (int i=mDestroySurface.size()-1; i>=0; i--) {
10453                WindowState w = mDestroySurface.get(i);
10454                if (windows == null || windows.contains(w)) {
10455                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
10456                            pw.print(w);
10457                    if (dumpAll) {
10458                        pw.println(":");
10459                        w.dump(pw, "    ", true);
10460                    } else {
10461                        pw.println();
10462                    }
10463                }
10464            }
10465        }
10466        if (mLosingFocus.size() > 0) {
10467            pw.println();
10468            pw.println("  Windows losing focus:");
10469            for (int i=mLosingFocus.size()-1; i>=0; i--) {
10470                WindowState w = mLosingFocus.get(i);
10471                if (windows == null || windows.contains(w)) {
10472                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
10473                            pw.print(w);
10474                    if (dumpAll) {
10475                        pw.println(":");
10476                        w.dump(pw, "    ", true);
10477                    } else {
10478                        pw.println();
10479                    }
10480                }
10481            }
10482        }
10483        if (mResizingWindows.size() > 0) {
10484            pw.println();
10485            pw.println("  Windows waiting to resize:");
10486            for (int i=mResizingWindows.size()-1; i>=0; i--) {
10487                WindowState w = mResizingWindows.get(i);
10488                if (windows == null || windows.contains(w)) {
10489                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
10490                            pw.print(w);
10491                    if (dumpAll) {
10492                        pw.println(":");
10493                        w.dump(pw, "    ", true);
10494                    } else {
10495                        pw.println();
10496                    }
10497                }
10498            }
10499        }
10500        if (mWaitingForDrawn.size() > 0) {
10501            pw.println();
10502            pw.println("  Clients waiting for these windows to be drawn:");
10503            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
10504                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
10505                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
10506                        pw.print(": "); pw.println(pair.second);
10507            }
10508        }
10509        pw.println("  DisplayContents");
10510        if (mDisplayReady) {
10511            DisplayContentsIterator dCIterator = new DisplayContentsIterator();
10512            while (dCIterator.hasNext()) {
10513                dCIterator.next().dump("    ", pw);
10514            }
10515        } else {
10516            pw.println("  NO DISPLAY");
10517        }
10518        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
10519        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
10520        if (mLastFocus != mCurrentFocus) {
10521            pw.print("  mLastFocus="); pw.println(mLastFocus);
10522        }
10523        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
10524        if (mInputMethodTarget != null) {
10525            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
10526        }
10527        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
10528                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
10529        if (dumpAll) {
10530            pw.print("  mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
10531                    pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
10532                    pw.print(" mScreenRecr="); pw.println(mScreenRect.toShortString());
10533            if (mLastStatusBarVisibility != 0) {
10534                pw.print("  mLastStatusBarVisibility=0x");
10535                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
10536            }
10537            if (mInputMethodWindow != null) {
10538                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
10539            }
10540            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
10541            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
10542                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
10543                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
10544            }
10545            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
10546                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
10547            if (mInputMethodAnimLayerAdjustment != 0 ||
10548                    mWallpaperAnimLayerAdjustment != 0) {
10549                pw.print("  mInputMethodAnimLayerAdjustment=");
10550                        pw.print(mInputMethodAnimLayerAdjustment);
10551                        pw.print("  mWallpaperAnimLayerAdjustment=");
10552                        pw.println(mWallpaperAnimLayerAdjustment);
10553            }
10554            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
10555                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
10556            if (needsLayout()) {
10557                pw.print("  layoutNeeded on displays=");
10558                DisplayContentsIterator dcIterator = new DisplayContentsIterator();
10559                while (dcIterator.hasNext()) {
10560                    final DisplayContent displayContent = dcIterator.next();
10561                    if (displayContent.layoutNeeded) {
10562                        pw.print(displayContent.getDisplayId());
10563                    }
10564                }
10565                pw.println();
10566            }
10567            pw.print("  mTransactionSequence="); pw.println(mTransactionSequence);
10568            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
10569                    pw.print(" windows="); pw.print(mWindowsFreezingScreen);
10570                    pw.print(" client="); pw.print(mClientFreezingScreen);
10571                    pw.print(" apps="); pw.print(mAppsFreezingScreen);
10572                    pw.print(" waitingForConfig="); pw.println(mWaitingForConfig);
10573            pw.print("  mRotation="); pw.print(mRotation);
10574                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
10575            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
10576                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
10577            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
10578            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
10579                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
10580                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
10581            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
10582                    pw.print(" mNextAppTransition=0x");
10583                    pw.print(Integer.toHexString(mNextAppTransition));
10584                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
10585            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
10586                    pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout);
10587            if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) {
10588                pw.print("  mNextAppTransitionType="); pw.println(mNextAppTransitionType);
10589            }
10590            switch (mNextAppTransitionType) {
10591                case ActivityOptions.ANIM_CUSTOM:
10592                    pw.print("  mNextAppTransitionPackage=");
10593                            pw.println(mNextAppTransitionPackage);
10594                    pw.print("  mNextAppTransitionEnter=0x");
10595                            pw.print(Integer.toHexString(mNextAppTransitionEnter));
10596                            pw.print(" mNextAppTransitionExit=0x");
10597                            pw.println(Integer.toHexString(mNextAppTransitionExit));
10598                    break;
10599                case ActivityOptions.ANIM_SCALE_UP:
10600                    pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
10601                            pw.print(" mNextAppTransitionStartY=");
10602                            pw.println(mNextAppTransitionStartY);
10603                    pw.print("  mNextAppTransitionStartWidth=");
10604                            pw.print(mNextAppTransitionStartWidth);
10605                            pw.print(" mNextAppTransitionStartHeight=");
10606                            pw.println(mNextAppTransitionStartHeight);
10607                    break;
10608                case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP:
10609                case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN:
10610                    pw.print("  mNextAppTransitionThumbnail=");
10611                            pw.print(mNextAppTransitionThumbnail);
10612                            pw.print(" mNextAppTransitionStartX=");
10613                            pw.print(mNextAppTransitionStartX);
10614                            pw.print(" mNextAppTransitionStartY=");
10615                            pw.println(mNextAppTransitionStartY);
10616                    pw.print("  mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp);
10617                    break;
10618            }
10619            if (mNextAppTransitionCallback != null) {
10620                pw.print("  mNextAppTransitionCallback=");
10621                        pw.println(mNextAppTransitionCallback);
10622            }
10623            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
10624                    pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
10625            pw.println("  Window Animator:");
10626            mAnimator.dumpLocked(pw, "    ", dumpAll);
10627        }
10628    }
10629
10630    boolean dumpWindows(PrintWriter pw, String name, String[] args,
10631            int opti, boolean dumpAll) {
10632        WindowList windows = new WindowList();
10633        if ("visible".equals(name)) {
10634            synchronized(mWindowMap) {
10635                final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10636                while (iterator.hasNext()) {
10637                    final WindowState w = iterator.next();
10638                    if (w.mWinAnimator.mSurfaceShown) {
10639                        windows.add(w);
10640                    }
10641                }
10642            }
10643        } else {
10644            int objectId = 0;
10645            // See if this is an object ID.
10646            try {
10647                objectId = Integer.parseInt(name, 16);
10648                name = null;
10649            } catch (RuntimeException e) {
10650            }
10651            synchronized(mWindowMap) {
10652                final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10653                while (iterator.hasNext()) {
10654                    final WindowState w = iterator.next();
10655                    if (name != null) {
10656                        if (w.mAttrs.getTitle().toString().contains(name)) {
10657                            windows.add(w);
10658                        }
10659                    } else if (System.identityHashCode(w) == objectId) {
10660                        windows.add(w);
10661                    }
10662                }
10663            }
10664        }
10665
10666        if (windows.size() <= 0) {
10667            return false;
10668        }
10669
10670        synchronized(mWindowMap) {
10671            dumpWindowsLocked(pw, dumpAll, windows);
10672        }
10673        return true;
10674    }
10675
10676    void dumpLastANRLocked(PrintWriter pw) {
10677        pw.println("WINDOW MANAGER LAST ANR (dumpsys window lastanr)");
10678        if (mLastANRState == null) {
10679            pw.println("  <no ANR has occurred since boot>");
10680        } else {
10681            pw.println(mLastANRState);
10682        }
10683    }
10684
10685    /**
10686     * Saves information about the state of the window manager at
10687     * the time an ANR occurred before anything else in the system changes
10688     * in response.
10689     *
10690     * @param appWindowToken The application that ANR'd, may be null.
10691     * @param windowState The window that ANR'd, may be null.
10692     */
10693    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState) {
10694        StringWriter sw = new StringWriter();
10695        PrintWriter pw = new PrintWriter(sw);
10696        pw.println("  ANR time: " + DateFormat.getInstance().format(new Date()));
10697        if (appWindowToken != null) {
10698            pw.println("  Application at fault: " + appWindowToken.stringName);
10699        }
10700        if (windowState != null) {
10701            pw.println("  Window at fault: " + windowState.mAttrs.getTitle());
10702        }
10703        pw.println();
10704        dumpWindowsNoHeaderLocked(pw, true, null);
10705        pw.close();
10706        mLastANRState = sw.toString();
10707    }
10708
10709    @Override
10710    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
10711        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
10712                != PackageManager.PERMISSION_GRANTED) {
10713            pw.println("Permission Denial: can't dump WindowManager from from pid="
10714                    + Binder.getCallingPid()
10715                    + ", uid=" + Binder.getCallingUid());
10716            return;
10717        }
10718
10719        boolean dumpAll = false;
10720
10721        int opti = 0;
10722        while (opti < args.length) {
10723            String opt = args[opti];
10724            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
10725                break;
10726            }
10727            opti++;
10728            if ("-a".equals(opt)) {
10729                dumpAll = true;
10730            } else if ("-h".equals(opt)) {
10731                pw.println("Window manager dump options:");
10732                pw.println("  [-a] [-h] [cmd] ...");
10733                pw.println("  cmd may be one of:");
10734                pw.println("    l[astanr]: last ANR information");
10735                pw.println("    p[policy]: policy state");
10736                pw.println("    s[essions]: active sessions");
10737                pw.println("    t[okens]: token list");
10738                pw.println("    w[indows]: window list");
10739                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
10740                pw.println("    be a partial substring in a window name, a");
10741                pw.println("    Window hex object identifier, or");
10742                pw.println("    \"all\" for all windows, or");
10743                pw.println("    \"visible\" for the visible windows.");
10744                pw.println("  -a: include all available server state.");
10745                return;
10746            } else {
10747                pw.println("Unknown argument: " + opt + "; use -h for help");
10748            }
10749        }
10750
10751        // Is the caller requesting to dump a particular piece of data?
10752        if (opti < args.length) {
10753            String cmd = args[opti];
10754            opti++;
10755            if ("lastanr".equals(cmd) || "l".equals(cmd)) {
10756                synchronized(mWindowMap) {
10757                    dumpLastANRLocked(pw);
10758                }
10759                return;
10760            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
10761                synchronized(mWindowMap) {
10762                    dumpPolicyLocked(pw, args, true);
10763                }
10764                return;
10765            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
10766                synchronized(mWindowMap) {
10767                    dumpSessionsLocked(pw, true);
10768                }
10769                return;
10770            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
10771                synchronized(mWindowMap) {
10772                    dumpTokensLocked(pw, true);
10773                }
10774                return;
10775            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
10776                synchronized(mWindowMap) {
10777                    dumpWindowsLocked(pw, true, null);
10778                }
10779                return;
10780            } else if ("all".equals(cmd) || "a".equals(cmd)) {
10781                synchronized(mWindowMap) {
10782                    dumpWindowsLocked(pw, true, null);
10783                }
10784                return;
10785            } else {
10786                // Dumping a single name?
10787                if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
10788                    pw.println("Bad window command, or no windows match: " + cmd);
10789                    pw.println("Use -h for help.");
10790                }
10791                return;
10792            }
10793        }
10794
10795        synchronized(mWindowMap) {
10796            pw.println();
10797            if (dumpAll) {
10798                pw.println("-------------------------------------------------------------------------------");
10799            }
10800            dumpLastANRLocked(pw);
10801            pw.println();
10802            if (dumpAll) {
10803                pw.println("-------------------------------------------------------------------------------");
10804            }
10805            dumpPolicyLocked(pw, args, dumpAll);
10806            pw.println();
10807            if (dumpAll) {
10808                pw.println("-------------------------------------------------------------------------------");
10809            }
10810            dumpSessionsLocked(pw, dumpAll);
10811            pw.println();
10812            if (dumpAll) {
10813                pw.println("-------------------------------------------------------------------------------");
10814            }
10815            dumpTokensLocked(pw, dumpAll);
10816            pw.println();
10817            if (dumpAll) {
10818                pw.println("-------------------------------------------------------------------------------");
10819            }
10820            dumpWindowsLocked(pw, dumpAll, null);
10821        }
10822    }
10823
10824    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
10825    public void monitor() {
10826        synchronized (mWindowMap) { }
10827    }
10828
10829    public interface OnHardKeyboardStatusChangeListener {
10830        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
10831    }
10832
10833    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
10834        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
10835            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
10836                    Integer.toHexString(pendingLayoutChanges));
10837        }
10838    }
10839
10840    public void createDisplayContentLocked(final Display display) {
10841        if (display == null) {
10842            throw new IllegalArgumentException("getDisplayContent: display must not be null");
10843        }
10844        final DisplayContent displayContent = new DisplayContent(display);
10845        mDisplayContents.put(display.getDisplayId(), displayContent);
10846    }
10847
10848    public DisplayContent getDisplayContentLocked(final int displayId) {
10849        DisplayContent displayContent = mDisplayContents.get(displayId);
10850        if (displayContent == null) {
10851            displayContent = new DisplayContent(mDisplayManager.getDisplay(displayId));
10852            mDisplayContents.put(displayId, displayContent);
10853        }
10854        return displayContent;
10855    }
10856
10857    class DisplayContentsIterator implements Iterator<DisplayContent> {
10858        private int cur;
10859
10860        @Override
10861        public boolean hasNext() {
10862            return cur < mDisplayContents.size();
10863        }
10864
10865        @Override
10866        public DisplayContent next() {
10867            if (hasNext()) {
10868                return mDisplayContents.valueAt(cur++);
10869            }
10870            throw new NoSuchElementException();
10871        }
10872
10873        @Override
10874        public void remove() {
10875            throw new IllegalArgumentException("AllDisplayContentIterator.remove not implemented");
10876        }
10877    }
10878
10879    final static boolean REVERSE_ITERATOR = true;
10880    class AllWindowsIterator implements Iterator<WindowState> {
10881        private DisplayContent mDisplayContent;
10882        private DisplayContentsIterator mDisplayContentsIterator;
10883        private WindowList mWindowList;
10884        private int mWindowListIndex;
10885        private boolean mReverse;
10886
10887        AllWindowsIterator() {
10888            mDisplayContentsIterator = new DisplayContentsIterator();
10889            mDisplayContent = mDisplayContentsIterator.next();
10890            mWindowList = mDisplayContent.getWindowList();
10891        }
10892
10893        AllWindowsIterator(boolean reverse) {
10894            this();
10895            mReverse = reverse;
10896            mWindowListIndex = reverse ? mWindowList.size() - 1 : 0;
10897        }
10898
10899        @Override
10900        public boolean hasNext() {
10901            if (mReverse) {
10902                return mWindowListIndex >= 0;
10903            }
10904            return mWindowListIndex < mWindowList.size();
10905        }
10906
10907        @Override
10908        public WindowState next() {
10909            if (hasNext()) {
10910                WindowState win = mWindowList.get(mWindowListIndex);
10911                if (mReverse) {
10912                    mWindowListIndex--;
10913                    if (mWindowListIndex < 0 && mDisplayContentsIterator.hasNext()) {
10914                        mDisplayContent = mDisplayContentsIterator.next();
10915                        mWindowList = mDisplayContent.getWindowList();
10916                        mWindowListIndex = mWindowList.size() - 1;
10917                    }
10918                } else {
10919                    mWindowListIndex++;
10920                    if (mWindowListIndex >= mWindowList.size()
10921                            && mDisplayContentsIterator.hasNext()) {
10922                        mDisplayContent = mDisplayContentsIterator.next();
10923                        mWindowList = mDisplayContent.getWindowList();
10924                        mWindowListIndex = 0;
10925                    }
10926                }
10927                return win;
10928            }
10929            throw new NoSuchElementException();
10930        }
10931
10932        @Override
10933        public void remove() {
10934            throw new IllegalArgumentException("AllWindowsIterator.remove not implemented");
10935        }
10936    }
10937
10938    public DisplayContent getDefaultDisplayContentLocked() {
10939        return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
10940    }
10941
10942    public WindowList getDefaultWindowListLocked() {
10943        return getDefaultDisplayContentLocked().getWindowList();
10944    }
10945
10946    public DisplayInfo getDefaultDisplayInfoLocked() {
10947        return getDefaultDisplayContentLocked().getDisplayInfo();
10948    }
10949
10950    public WindowList getWindowListLocked(final Display display) {
10951        return getDisplayContentLocked(display.getDisplayId()).getWindowList();
10952    }
10953
10954    @Override
10955    public void onDisplayAdded(int displayId) {
10956        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
10957    }
10958
10959    private void handleDisplayAddedLocked(int displayId) {
10960        createDisplayContentLocked(mDisplayManager.getDisplay(displayId));
10961        displayReady(displayId);
10962    }
10963
10964    @Override
10965    public void onDisplayRemoved(int displayId) {
10966        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
10967    }
10968
10969    private void handleDisplayRemovedLocked(int displayId) {
10970        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10971        mDisplayContents.delete(displayId);
10972        WindowList windows = displayContent.getWindowList();
10973        while (!windows.isEmpty()) {
10974            final WindowState win = windows.get(windows.size() - 1);
10975            removeWindowLocked(win.mSession, win);
10976        }
10977        mAnimator.removeDisplayLocked(displayId);
10978    }
10979
10980    @Override
10981    public void onDisplayChanged(int displayId) {
10982        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
10983    }
10984
10985    private void handleDisplayChangedLocked(int displayId) {
10986        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10987        if (displayContent != null) {
10988            displayContent.updateDisplayInfo();
10989        }
10990    }
10991}
10992