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