WindowManagerService.java revision 55468c64bc4f3c4b16bf144f66907d75bb656b0a
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    private void scheduleNotifyWindowLayersChangedIfNeededLocked(DisplayContent displayContent) {
6580        if (displayContent.mDisplayContentChangeListeners != null
6581                && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) {
6582            mH.obtainMessage(H.NOTIFY_WINDOW_LAYERS_CHANGED, displayContent) .sendToTarget();
6583        }
6584    }
6585
6586    private void handleNotifyWindowLayersChanged(DisplayContent displayContent) {
6587        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
6588        synchronized (mWindowMap) {
6589            callbacks = displayContent.mDisplayContentChangeListeners;
6590            if (callbacks == null) {
6591                return;
6592            }
6593        }
6594        try {
6595            final int watcherCount = callbacks.beginBroadcast();
6596            for (int i = 0; i < watcherCount; i++) {
6597                try {
6598                    callbacks.getBroadcastItem(i).onWindowLayersChanged(
6599                            displayContent.getDisplayId());
6600                } catch (RemoteException re) {
6601                    /* ignore */
6602                }
6603            }
6604        } finally {
6605            callbacks.finishBroadcast();
6606        }
6607    }
6608
6609    public void addWindowChangeListener(WindowChangeListener listener) {
6610        synchronized(mWindowMap) {
6611            mWindowChangeListeners.add(listener);
6612        }
6613    }
6614
6615    public void removeWindowChangeListener(WindowChangeListener listener) {
6616        synchronized(mWindowMap) {
6617            mWindowChangeListeners.remove(listener);
6618        }
6619    }
6620
6621    private void notifyWindowsChanged() {
6622        WindowChangeListener[] windowChangeListeners;
6623        synchronized(mWindowMap) {
6624            if(mWindowChangeListeners.isEmpty()) {
6625                return;
6626            }
6627            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6628            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6629        }
6630        int N = windowChangeListeners.length;
6631        for(int i = 0; i < N; i++) {
6632            windowChangeListeners[i].windowsChanged();
6633        }
6634    }
6635
6636    private void notifyFocusChanged() {
6637        WindowChangeListener[] windowChangeListeners;
6638        synchronized(mWindowMap) {
6639            if(mWindowChangeListeners.isEmpty()) {
6640                return;
6641            }
6642            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6643            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6644        }
6645        int N = windowChangeListeners.length;
6646        for(int i = 0; i < N; i++) {
6647            windowChangeListeners[i].focusChanged();
6648        }
6649    }
6650
6651    private WindowState findWindow(int hashCode) {
6652        if (hashCode == -1) {
6653            // TODO(multidisplay): Extend to multiple displays.
6654            return getFocusedWindow();
6655        }
6656
6657        synchronized (mWindowMap) {
6658            final AllWindowsIterator iterator = new AllWindowsIterator();
6659            while (iterator.hasNext()) {
6660                final WindowState w = iterator.next();
6661                if (System.identityHashCode(w) == hashCode) {
6662                    return w;
6663                }
6664            }
6665        }
6666
6667        return null;
6668    }
6669
6670    /*
6671     * Instruct the Activity Manager to fetch the current configuration and broadcast
6672     * that to config-changed listeners if appropriate.
6673     */
6674    void sendNewConfiguration() {
6675        try {
6676            mActivityManager.updateConfiguration(null);
6677        } catch (RemoteException e) {
6678        }
6679    }
6680
6681    public Configuration computeNewConfiguration() {
6682        synchronized (mWindowMap) {
6683            Configuration config = computeNewConfigurationLocked();
6684            if (config == null && mWaitingForConfig) {
6685                // Nothing changed but we are waiting for something... stop that!
6686                mWaitingForConfig = false;
6687                performLayoutAndPlaceSurfacesLocked();
6688            }
6689            return config;
6690        }
6691    }
6692
6693    Configuration computeNewConfigurationLocked() {
6694        Configuration config = new Configuration();
6695        config.fontScale = 0;
6696        if (!computeScreenConfigurationLocked(config)) {
6697            return null;
6698        }
6699        return config;
6700    }
6701
6702    private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) {
6703        // TODO: Multidisplay: for now only use with default display.
6704        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
6705        if (width < displayInfo.smallestNominalAppWidth) {
6706            displayInfo.smallestNominalAppWidth = width;
6707        }
6708        if (width > displayInfo.largestNominalAppWidth) {
6709            displayInfo.largestNominalAppWidth = width;
6710        }
6711        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation);
6712        if (height < displayInfo.smallestNominalAppHeight) {
6713            displayInfo.smallestNominalAppHeight = height;
6714        }
6715        if (height > displayInfo.largestNominalAppHeight) {
6716            displayInfo.largestNominalAppHeight = height;
6717        }
6718    }
6719
6720    private int reduceConfigLayout(int curLayout, int rotation, float density,
6721            int dw, int dh) {
6722        // TODO: Multidisplay: for now only use with default display.
6723        // Get the app screen size at this rotation.
6724        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6725        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6726
6727        // Compute the screen layout size class for this rotation.
6728        int longSize = w;
6729        int shortSize = h;
6730        if (longSize < shortSize) {
6731            int tmp = longSize;
6732            longSize = shortSize;
6733            shortSize = tmp;
6734        }
6735        longSize = (int)(longSize/density);
6736        shortSize = (int)(shortSize/density);
6737        return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
6738    }
6739
6740    private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
6741                  int dw, int dh, float density, Configuration outConfig) {
6742        // TODO: Multidisplay: for now only use with default display.
6743
6744        // We need to determine the smallest width that will occur under normal
6745        // operation.  To this, start with the base screen size and compute the
6746        // width under the different possible rotations.  We need to un-rotate
6747        // the current screen dimensions before doing this.
6748        int unrotDw, unrotDh;
6749        if (rotated) {
6750            unrotDw = dh;
6751            unrotDh = dw;
6752        } else {
6753            unrotDw = dw;
6754            unrotDh = dh;
6755        }
6756        displayInfo.smallestNominalAppWidth = 1<<30;
6757        displayInfo.smallestNominalAppHeight = 1<<30;
6758        displayInfo.largestNominalAppWidth = 0;
6759        displayInfo.largestNominalAppHeight = 0;
6760        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh);
6761        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw);
6762        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh);
6763        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw);
6764        int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
6765        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
6766        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
6767        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
6768        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
6769        outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
6770        outConfig.screenLayout = sl;
6771    }
6772
6773    private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
6774            int dw, int dh) {
6775        // TODO: Multidisplay: for now only use with default display.
6776        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6777        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6778        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
6779        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
6780        if (curSize == 0 || size < curSize) {
6781            curSize = size;
6782        }
6783        return curSize;
6784    }
6785
6786    private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
6787        // TODO: Multidisplay: for now only use with default display.
6788        mTmpDisplayMetrics.setTo(dm);
6789        final DisplayMetrics tmpDm = mTmpDisplayMetrics;
6790        final int unrotDw, unrotDh;
6791        if (rotated) {
6792            unrotDw = dh;
6793            unrotDh = dw;
6794        } else {
6795            unrotDw = dw;
6796            unrotDh = dh;
6797        }
6798        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh);
6799        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw);
6800        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh);
6801        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw);
6802        return sw;
6803    }
6804
6805    boolean computeScreenConfigurationLocked(Configuration config) {
6806        if (!mDisplayReady) {
6807            return false;
6808        }
6809
6810        // TODO(multidisplay): For now, apply Configuration to main screen only.
6811        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6812
6813        // Use the effective "visual" dimensions based on current rotation
6814        final boolean rotated = (mRotation == Surface.ROTATION_90
6815                || mRotation == Surface.ROTATION_270);
6816        final int realdw = rotated ?
6817                displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
6818        final int realdh = rotated ?
6819                displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
6820        int dw = realdw;
6821        int dh = realdh;
6822
6823        if (mAltOrientation) {
6824            if (realdw > realdh) {
6825                // Turn landscape into portrait.
6826                int maxw = (int)(realdh/1.3f);
6827                if (maxw < realdw) {
6828                    dw = maxw;
6829                }
6830            } else {
6831                // Turn portrait into landscape.
6832                int maxh = (int)(realdw/1.3f);
6833                if (maxh < realdh) {
6834                    dh = maxh;
6835                }
6836            }
6837        }
6838
6839        if (config != null) {
6840            config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
6841                    Configuration.ORIENTATION_LANDSCAPE;
6842        }
6843
6844        // Update application display metrics.
6845        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
6846        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
6847        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
6848        synchronized(displayContent.mDisplaySizeLock) {
6849            displayInfo.rotation = mRotation;
6850            displayInfo.logicalWidth = dw;
6851            displayInfo.logicalHeight = dh;
6852            displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
6853            displayInfo.appWidth = appWidth;
6854            displayInfo.appHeight = appHeight;
6855            displayInfo.getLogicalMetrics(mRealDisplayMetrics, null);
6856            displayInfo.getAppMetrics(mDisplayMetrics, null);
6857            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
6858                    displayContent.getDisplayId(), displayInfo);
6859
6860            mAnimator.setDisplayDimensions(dw, dh, appWidth, appHeight);
6861        }
6862        if (false) {
6863            Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);
6864        }
6865
6866        final DisplayMetrics dm = mDisplayMetrics;
6867        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
6868                mCompatDisplayMetrics);
6869
6870        if (config != null) {
6871            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
6872                    / dm.density);
6873            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
6874                    / dm.density);
6875            computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);
6876
6877            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
6878            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
6879            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
6880            config.densityDpi = displayContent.mBaseDisplayDensity;
6881
6882            // Update the configuration based on available input devices, lid switch,
6883            // and platform configuration.
6884            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6885            config.keyboard = Configuration.KEYBOARD_NOKEYS;
6886            config.navigation = Configuration.NAVIGATION_NONAV;
6887
6888            int keyboardPresence = 0;
6889            int navigationPresence = 0;
6890            final InputDevice[] devices = mInputManager.getInputDevices();
6891            final int len = devices.length;
6892            for (int i = 0; i < len; i++) {
6893                InputDevice device = devices[i];
6894                if (!device.isVirtual()) {
6895                    final int sources = device.getSources();
6896                    final int presenceFlag = device.isExternal() ?
6897                            WindowManagerPolicy.PRESENCE_EXTERNAL :
6898                                    WindowManagerPolicy.PRESENCE_INTERNAL;
6899
6900                    if (mIsTouchDevice) {
6901                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
6902                                InputDevice.SOURCE_TOUCHSCREEN) {
6903                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
6904                        }
6905                    } else {
6906                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6907                    }
6908
6909                    if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
6910                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
6911                        navigationPresence |= presenceFlag;
6912                    } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
6913                            && config.navigation == Configuration.NAVIGATION_NONAV) {
6914                        config.navigation = Configuration.NAVIGATION_DPAD;
6915                        navigationPresence |= presenceFlag;
6916                    }
6917
6918                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
6919                        config.keyboard = Configuration.KEYBOARD_QWERTY;
6920                        keyboardPresence |= presenceFlag;
6921                    }
6922                }
6923            }
6924
6925            // Determine whether a hard keyboard is available and enabled.
6926            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6927            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6928                mHardKeyboardAvailable = hardKeyboardAvailable;
6929                mHardKeyboardEnabled = hardKeyboardAvailable;
6930                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6931                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6932            }
6933            if (!mHardKeyboardEnabled) {
6934                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6935            }
6936
6937            // Let the policy update hidden states.
6938            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6939            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6940            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6941            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
6942        }
6943
6944        return true;
6945    }
6946
6947    public boolean isHardKeyboardAvailable() {
6948        synchronized (mWindowMap) {
6949            return mHardKeyboardAvailable;
6950        }
6951    }
6952
6953    public boolean isHardKeyboardEnabled() {
6954        synchronized (mWindowMap) {
6955            return mHardKeyboardEnabled;
6956        }
6957    }
6958
6959    public void setHardKeyboardEnabled(boolean enabled) {
6960        synchronized (mWindowMap) {
6961            if (mHardKeyboardEnabled != enabled) {
6962                mHardKeyboardEnabled = enabled;
6963                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6964            }
6965        }
6966    }
6967
6968    public void setOnHardKeyboardStatusChangeListener(
6969            OnHardKeyboardStatusChangeListener listener) {
6970        synchronized (mWindowMap) {
6971            mHardKeyboardStatusChangeListener = listener;
6972        }
6973    }
6974
6975    void notifyHardKeyboardStatusChange() {
6976        final boolean available, enabled;
6977        final OnHardKeyboardStatusChangeListener listener;
6978        synchronized (mWindowMap) {
6979            listener = mHardKeyboardStatusChangeListener;
6980            available = mHardKeyboardAvailable;
6981            enabled = mHardKeyboardEnabled;
6982        }
6983        if (listener != null) {
6984            listener.onHardKeyboardStatusChange(available, enabled);
6985        }
6986    }
6987
6988    // -------------------------------------------------------------
6989    // Drag and drop
6990    // -------------------------------------------------------------
6991
6992    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
6993            int flags, int width, int height, Surface outSurface) {
6994        if (DEBUG_DRAG) {
6995            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
6996                    + " flags=" + Integer.toHexString(flags) + " win=" + window
6997                    + " asbinder=" + window.asBinder());
6998        }
6999
7000        final int callerPid = Binder.getCallingPid();
7001        final long origId = Binder.clearCallingIdentity();
7002        IBinder token = null;
7003
7004        try {
7005            synchronized (mWindowMap) {
7006                try {
7007                    if (mDragState == null) {
7008                        // TODO(multi-display): support other displays
7009                        final DisplayContent displayContent = getDefaultDisplayContentLocked();
7010                        final Display display = displayContent.getDisplay();
7011                        Surface surface = new Surface(session, "drag surface",
7012                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
7013                        surface.setLayerStack(display.getLayerStack());
7014                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
7015                                + surface + ": CREATE");
7016                        outSurface.copyFrom(surface);
7017                        final IBinder winBinder = window.asBinder();
7018                        token = new Binder();
7019                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
7020                        token = mDragState.mToken = new Binder();
7021
7022                        // 5 second timeout for this window to actually begin the drag
7023                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
7024                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
7025                        mH.sendMessageDelayed(msg, 5000);
7026                    } else {
7027                        Slog.w(TAG, "Drag already in progress");
7028                    }
7029                } catch (Surface.OutOfResourcesException e) {
7030                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
7031                    if (mDragState != null) {
7032                        mDragState.reset();
7033                        mDragState = null;
7034                    }
7035                }
7036            }
7037        } finally {
7038            Binder.restoreCallingIdentity(origId);
7039        }
7040
7041        return token;
7042    }
7043
7044    // -------------------------------------------------------------
7045    // Input Events and Focus Management
7046    // -------------------------------------------------------------
7047
7048    final InputMonitor mInputMonitor = new InputMonitor(this);
7049    private boolean mEventDispatchingEnabled;
7050
7051    public void pauseKeyDispatching(IBinder _token) {
7052        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7053                "pauseKeyDispatching()")) {
7054            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7055        }
7056
7057        synchronized (mWindowMap) {
7058            WindowToken token = mTokenMap.get(_token);
7059            if (token != null) {
7060                mInputMonitor.pauseDispatchingLw(token);
7061            }
7062        }
7063    }
7064
7065    public void resumeKeyDispatching(IBinder _token) {
7066        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7067                "resumeKeyDispatching()")) {
7068            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7069        }
7070
7071        synchronized (mWindowMap) {
7072            WindowToken token = mTokenMap.get(_token);
7073            if (token != null) {
7074                mInputMonitor.resumeDispatchingLw(token);
7075            }
7076        }
7077    }
7078
7079    public void setEventDispatching(boolean enabled) {
7080        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7081                "setEventDispatching()")) {
7082            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7083        }
7084
7085        synchronized (mWindowMap) {
7086            mEventDispatchingEnabled = enabled;
7087            if (mDisplayEnabled) {
7088                mInputMonitor.setEventDispatchingLw(enabled);
7089            }
7090            sendScreenStatusToClientsLocked();
7091        }
7092    }
7093
7094    public IBinder getFocusedWindowToken() {
7095        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
7096                "getFocusedWindowToken()")) {
7097            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
7098        }
7099        synchronized (mWindowMap) {
7100            WindowState windowState = getFocusedWindowLocked();
7101            if (windowState != null) {
7102                return windowState.mClient.asBinder();
7103            }
7104            return null;
7105        }
7106    }
7107
7108    private WindowState getFocusedWindow() {
7109        synchronized (mWindowMap) {
7110            return getFocusedWindowLocked();
7111        }
7112    }
7113
7114    private WindowState getFocusedWindowLocked() {
7115        return mCurrentFocus;
7116    }
7117
7118    public boolean detectSafeMode() {
7119        if (!mInputMonitor.waitForInputDevicesReady(
7120                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
7121            Slog.w(TAG, "Devices still not ready after waiting "
7122                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
7123                   + " milliseconds before attempting to detect safe mode.");
7124        }
7125
7126        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
7127                KeyEvent.KEYCODE_MENU);
7128        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
7129        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
7130                KeyEvent.KEYCODE_DPAD_CENTER);
7131        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
7132                InputManagerService.BTN_MOUSE);
7133        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
7134                KeyEvent.KEYCODE_VOLUME_DOWN);
7135        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
7136                || volumeDownState > 0;
7137        try {
7138            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
7139                mSafeMode = true;
7140                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
7141            }
7142        } catch (IllegalArgumentException e) {
7143        }
7144        if (mSafeMode) {
7145            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
7146                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
7147        } else {
7148            Log.i(TAG, "SAFE MODE not enabled");
7149        }
7150        mPolicy.setSafeMode(mSafeMode);
7151        return mSafeMode;
7152    }
7153
7154    public void displayReady() {
7155        displayReady(Display.DEFAULT_DISPLAY);
7156
7157        synchronized(mWindowMap) {
7158            final DisplayContent displayContent = getDefaultDisplayContentLocked();
7159            final Display display = displayContent.getDisplay();
7160            readForcedDisplaySizeAndDensityLocked(displayContent);
7161
7162            mDisplayReady = true;
7163            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
7164                    PackageManager.FEATURE_TOUCHSCREEN);
7165
7166            final DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
7167            mAnimator.setDisplayDimensions(
7168                    displayInfo.logicalWidth, displayInfo.logicalHeight,
7169                    displayInfo.appWidth, displayInfo.appHeight);
7170
7171            mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
7172                    displayContent.mInitialDisplayWidth,
7173                    displayContent.mInitialDisplayHeight,
7174                    displayContent.mInitialDisplayDensity);
7175        }
7176
7177        try {
7178            mActivityManager.updateConfiguration(null);
7179        } catch (RemoteException e) {
7180        }
7181    }
7182
7183    public void displayReady(int displayId) {
7184        synchronized(mWindowMap) {
7185            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7186            final DisplayInfo displayInfo;
7187            mAnimator.addDisplayLocked(displayId);
7188            synchronized(displayContent.mDisplaySizeLock) {
7189                // Bootstrap the default logical display from the display manager.
7190                displayInfo = displayContent.getDisplayInfo();
7191                DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId);
7192                if (newDisplayInfo != null) {
7193                    displayInfo.copyFrom(newDisplayInfo);
7194                }
7195                displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
7196                displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
7197                displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
7198                displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
7199                displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
7200                displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
7201            }
7202        }
7203    }
7204
7205    public void systemReady() {
7206        mPolicy.systemReady();
7207    }
7208
7209    // TODO(multidisplay): Call isScreenOn for each display.
7210    private void sendScreenStatusToClientsLocked() {
7211        final boolean on = mPowerManager.isScreenOn();
7212        final AllWindowsIterator iterator = new AllWindowsIterator();
7213        while (iterator.hasNext()) {
7214            try {
7215                iterator.next().mClient.dispatchScreenState(on);
7216            } catch (RemoteException e) {
7217                // Ignored
7218            }
7219        }
7220    }
7221
7222    // -------------------------------------------------------------
7223    // Async Handler
7224    // -------------------------------------------------------------
7225
7226    final class H extends Handler {
7227        public static final int REPORT_FOCUS_CHANGE = 2;
7228        public static final int REPORT_LOSING_FOCUS = 3;
7229        public static final int DO_TRAVERSAL = 4;
7230        public static final int ADD_STARTING = 5;
7231        public static final int REMOVE_STARTING = 6;
7232        public static final int FINISHED_STARTING = 7;
7233        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
7234        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
7235        public static final int WINDOW_FREEZE_TIMEOUT = 11;
7236
7237        public static final int APP_TRANSITION_TIMEOUT = 13;
7238        public static final int PERSIST_ANIMATION_SCALE = 14;
7239        public static final int FORCE_GC = 15;
7240        public static final int ENABLE_SCREEN = 16;
7241        public static final int APP_FREEZE_TIMEOUT = 17;
7242        public static final int SEND_NEW_CONFIGURATION = 18;
7243        public static final int REPORT_WINDOWS_CHANGE = 19;
7244        public static final int DRAG_START_TIMEOUT = 20;
7245        public static final int DRAG_END_TIMEOUT = 21;
7246        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
7247        public static final int BOOT_TIMEOUT = 23;
7248        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
7249        public static final int UPDATE_ANIM_PARAMETERS = 25;
7250        public static final int SHOW_STRICT_MODE_VIOLATION = 26;
7251        public static final int DO_ANIMATION_CALLBACK = 27;
7252        public static final int NOTIFY_ROTATION_CHANGED = 28;
7253        public static final int NOTIFY_WINDOW_TRANSITION = 29;
7254        public static final int NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 30;
7255        public static final int NOTIFY_WINDOW_LAYERS_CHANGED = 31;
7256
7257        public static final int DO_DISPLAY_ADDED = 32;
7258        public static final int DO_DISPLAY_REMOVED = 33;
7259        public static final int DO_DISPLAY_CHANGED = 34;
7260
7261        public static final int CLIENT_FREEZE_TIMEOUT = 35;
7262
7263        public static final int ANIMATOR_WHAT_OFFSET = 100000;
7264        public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
7265        public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
7266
7267        public H() {
7268        }
7269
7270        @Override
7271        public void handleMessage(Message msg) {
7272            if (DEBUG_WINDOW_TRACE) {
7273                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
7274            }
7275            switch (msg.what) {
7276                case REPORT_FOCUS_CHANGE: {
7277                    WindowState lastFocus;
7278                    WindowState newFocus;
7279
7280                    synchronized(mWindowMap) {
7281                        lastFocus = mLastFocus;
7282                        newFocus = mCurrentFocus;
7283                        if (lastFocus == newFocus) {
7284                            // Focus is not changing, so nothing to do.
7285                            return;
7286                        }
7287                        mLastFocus = newFocus;
7288                        //Slog.i(TAG, "Focus moving from " + lastFocus
7289                        //        + " to " + newFocus);
7290                        if (newFocus != null && lastFocus != null
7291                                && !newFocus.isDisplayedLw()) {
7292                            //Slog.i(TAG, "Delaying loss of focus...");
7293                            mLosingFocus.add(lastFocus);
7294                            lastFocus = null;
7295                        }
7296                    }
7297
7298                    if (lastFocus != newFocus) {
7299                        //System.out.println("Changing focus from " + lastFocus
7300                        //                   + " to " + newFocus);
7301                        if (newFocus != null) {
7302                            try {
7303                                //Slog.i(TAG, "Gaining focus: " + newFocus);
7304                                newFocus.mClient.windowFocusChanged(true, mInTouchMode);
7305                            } catch (RemoteException e) {
7306                                // Ignore if process has died.
7307                            }
7308                            notifyFocusChanged();
7309                        }
7310
7311                        if (lastFocus != null) {
7312                            try {
7313                                //Slog.i(TAG, "Losing focus: " + lastFocus);
7314                                lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
7315                            } catch (RemoteException e) {
7316                                // Ignore if process has died.
7317                            }
7318                        }
7319                    }
7320                } break;
7321
7322                case REPORT_LOSING_FOCUS: {
7323                    ArrayList<WindowState> losers;
7324
7325                    synchronized(mWindowMap) {
7326                        losers = mLosingFocus;
7327                        mLosingFocus = new ArrayList<WindowState>();
7328                    }
7329
7330                    final int N = losers.size();
7331                    for (int i=0; i<N; i++) {
7332                        try {
7333                            //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
7334                            losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
7335                        } catch (RemoteException e) {
7336                             // Ignore if process has died.
7337                        }
7338                    }
7339                } break;
7340
7341                case DO_TRAVERSAL: {
7342                    synchronized(mWindowMap) {
7343                        mTraversalScheduled = false;
7344                        performLayoutAndPlaceSurfacesLocked();
7345                    }
7346                } break;
7347
7348                case ADD_STARTING: {
7349                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7350                    final StartingData sd = wtoken.startingData;
7351
7352                    if (sd == null) {
7353                        // Animation has been canceled... do nothing.
7354                        return;
7355                    }
7356
7357                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
7358                            + wtoken + ": pkg=" + sd.pkg);
7359
7360                    View view = null;
7361                    try {
7362                        view = mPolicy.addStartingWindow(
7363                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
7364                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
7365                    } catch (Exception e) {
7366                        Slog.w(TAG, "Exception when adding starting window", e);
7367                    }
7368
7369                    if (view != null) {
7370                        boolean abort = false;
7371
7372                        synchronized(mWindowMap) {
7373                            if (wtoken.removed || wtoken.startingData == null) {
7374                                // If the window was successfully added, then
7375                                // we need to remove it.
7376                                if (wtoken.startingWindow != null) {
7377                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7378                                            "Aborted starting " + wtoken
7379                                            + ": removed=" + wtoken.removed
7380                                            + " startingData=" + wtoken.startingData);
7381                                    wtoken.startingWindow = null;
7382                                    wtoken.startingData = null;
7383                                    abort = true;
7384                                }
7385                            } else {
7386                                wtoken.startingView = view;
7387                            }
7388                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
7389                                    "Added starting " + wtoken
7390                                    + ": startingWindow="
7391                                    + wtoken.startingWindow + " startingView="
7392                                    + wtoken.startingView);
7393                        }
7394
7395                        if (abort) {
7396                            try {
7397                                mPolicy.removeStartingWindow(wtoken.token, view);
7398                            } catch (Exception e) {
7399                                Slog.w(TAG, "Exception when removing starting window", e);
7400                            }
7401                        }
7402                    }
7403                } break;
7404
7405                case REMOVE_STARTING: {
7406                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7407                    IBinder token = null;
7408                    View view = null;
7409                    synchronized (mWindowMap) {
7410                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
7411                                + wtoken + ": startingWindow="
7412                                + wtoken.startingWindow + " startingView="
7413                                + wtoken.startingView);
7414                        if (wtoken.startingWindow != null) {
7415                            view = wtoken.startingView;
7416                            token = wtoken.token;
7417                            wtoken.startingData = null;
7418                            wtoken.startingView = null;
7419                            wtoken.startingWindow = null;
7420                            wtoken.startingDisplayed = false;
7421                        }
7422                    }
7423                    if (view != null) {
7424                        try {
7425                            mPolicy.removeStartingWindow(token, view);
7426                        } catch (Exception e) {
7427                            Slog.w(TAG, "Exception when removing starting window", e);
7428                        }
7429                    }
7430                } break;
7431
7432                case FINISHED_STARTING: {
7433                    IBinder token = null;
7434                    View view = null;
7435                    while (true) {
7436                        synchronized (mWindowMap) {
7437                            final int N = mFinishedStarting.size();
7438                            if (N <= 0) {
7439                                break;
7440                            }
7441                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7442
7443                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7444                                    "Finished starting " + wtoken
7445                                    + ": startingWindow=" + wtoken.startingWindow
7446                                    + " startingView=" + wtoken.startingView);
7447
7448                            if (wtoken.startingWindow == null) {
7449                                continue;
7450                            }
7451
7452                            view = wtoken.startingView;
7453                            token = wtoken.token;
7454                            wtoken.startingData = null;
7455                            wtoken.startingView = null;
7456                            wtoken.startingWindow = null;
7457                            wtoken.startingDisplayed = false;
7458                        }
7459
7460                        try {
7461                            mPolicy.removeStartingWindow(token, view);
7462                        } catch (Exception e) {
7463                            Slog.w(TAG, "Exception when removing starting window", e);
7464                        }
7465                    }
7466                } break;
7467
7468                case REPORT_APPLICATION_TOKEN_DRAWN: {
7469                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7470
7471                    try {
7472                        if (DEBUG_VISIBILITY) Slog.v(
7473                                TAG, "Reporting drawn in " + wtoken);
7474                        wtoken.appToken.windowsDrawn();
7475                    } catch (RemoteException ex) {
7476                    }
7477                } break;
7478
7479                case REPORT_APPLICATION_TOKEN_WINDOWS: {
7480                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7481
7482                    boolean nowVisible = msg.arg1 != 0;
7483                    boolean nowGone = msg.arg2 != 0;
7484
7485                    try {
7486                        if (DEBUG_VISIBILITY) Slog.v(
7487                                TAG, "Reporting visible in " + wtoken
7488                                + " visible=" + nowVisible
7489                                + " gone=" + nowGone);
7490                        if (nowVisible) {
7491                            wtoken.appToken.windowsVisible();
7492                        } else {
7493                            wtoken.appToken.windowsGone();
7494                        }
7495                    } catch (RemoteException ex) {
7496                    }
7497                } break;
7498
7499                case WINDOW_FREEZE_TIMEOUT: {
7500                    // TODO(multidisplay): Can non-default displays rotate?
7501                    synchronized (mWindowMap) {
7502                        Slog.w(TAG, "Window freeze timeout expired.");
7503                        final WindowList windows = getDefaultWindowListLocked();
7504                        int i = windows.size();
7505                        while (i > 0) {
7506                            i--;
7507                            WindowState w = windows.get(i);
7508                            if (w.mOrientationChanging) {
7509                                w.mOrientationChanging = false;
7510                                Slog.w(TAG, "Force clearing orientation change: " + w);
7511                            }
7512                        }
7513                        performLayoutAndPlaceSurfacesLocked();
7514                    }
7515                    break;
7516                }
7517
7518                case APP_TRANSITION_TIMEOUT: {
7519                    synchronized (mWindowMap) {
7520                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
7521                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7522                                    "*** APP TRANSITION TIMEOUT");
7523                            mAppTransitionReady = true;
7524                            mAppTransitionTimeout = true;
7525                            mAnimatingAppTokens.clear();
7526                            mAnimatingAppTokens.addAll(mAppTokens);
7527                            performLayoutAndPlaceSurfacesLocked();
7528                        }
7529                    }
7530                    break;
7531                }
7532
7533                case PERSIST_ANIMATION_SCALE: {
7534                    Settings.Global.putFloat(mContext.getContentResolver(),
7535                            Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7536                    Settings.Global.putFloat(mContext.getContentResolver(),
7537                            Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7538                    Settings.Global.putFloat(mContext.getContentResolver(),
7539                            Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
7540                    break;
7541                }
7542
7543                case FORCE_GC: {
7544                    synchronized (mWindowMap) {
7545                        synchronized (mAnimator) {
7546                            // Since we're holding both mWindowMap and mAnimator we don't need to
7547                            // hold mAnimator.mLayoutToAnim.
7548                            if (mAnimator.mAnimating || mLayoutToAnim.mAnimationScheduled) {
7549                                // If we are animating, don't do the gc now but
7550                                // delay a bit so we don't interrupt the animation.
7551                                mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
7552                                        2000);
7553                                return;
7554                            }
7555                            // If we are currently rotating the display, it will
7556                            // schedule a new message when done.
7557                            if (mDisplayFrozen) {
7558                                return;
7559                            }
7560                        }
7561                    }
7562                    Runtime.getRuntime().gc();
7563                    break;
7564                }
7565
7566                case ENABLE_SCREEN: {
7567                    performEnableScreen();
7568                    break;
7569                }
7570
7571                case APP_FREEZE_TIMEOUT: {
7572                    synchronized (mWindowMap) {
7573                        synchronized (mAnimator) {
7574                            Slog.w(TAG, "App freeze timeout expired.");
7575                            int i = mAppTokens.size();
7576                            while (i > 0) {
7577                                i--;
7578                                AppWindowToken tok = mAppTokens.get(i);
7579                                if (tok.mAppAnimator.freezingScreen) {
7580                                    Slog.w(TAG, "Force clearing freeze: " + tok);
7581                                    unsetAppFreezingScreenLocked(tok, true, true);
7582                                }
7583                            }
7584                        }
7585                    }
7586                    break;
7587                }
7588
7589                case CLIENT_FREEZE_TIMEOUT: {
7590                    synchronized (mWindowMap) {
7591                        if (mClientFreezingScreen) {
7592                            mClientFreezingScreen = false;
7593                            stopFreezingDisplayLocked();
7594                        }
7595                    }
7596                    break;
7597                }
7598
7599                case SEND_NEW_CONFIGURATION: {
7600                    removeMessages(SEND_NEW_CONFIGURATION);
7601                    sendNewConfiguration();
7602                    break;
7603                }
7604
7605                case REPORT_WINDOWS_CHANGE: {
7606                    if (mWindowsChanged) {
7607                        synchronized (mWindowMap) {
7608                            mWindowsChanged = false;
7609                        }
7610                        notifyWindowsChanged();
7611                    }
7612                    break;
7613                }
7614
7615                case DRAG_START_TIMEOUT: {
7616                    IBinder win = (IBinder)msg.obj;
7617                    if (DEBUG_DRAG) {
7618                        Slog.w(TAG, "Timeout starting drag by win " + win);
7619                    }
7620                    synchronized (mWindowMap) {
7621                        // !!! TODO: ANR the app that has failed to start the drag in time
7622                        if (mDragState != null) {
7623                            mDragState.unregister();
7624                            mInputMonitor.updateInputWindowsLw(true /*force*/);
7625                            mDragState.reset();
7626                            mDragState = null;
7627                        }
7628                    }
7629                    break;
7630                }
7631
7632                case DRAG_END_TIMEOUT: {
7633                    IBinder win = (IBinder)msg.obj;
7634                    if (DEBUG_DRAG) {
7635                        Slog.w(TAG, "Timeout ending drag to win " + win);
7636                    }
7637                    synchronized (mWindowMap) {
7638                        // !!! TODO: ANR the drag-receiving app
7639                        if (mDragState != null) {
7640                            mDragState.mDragResult = false;
7641                            mDragState.endDragLw();
7642                        }
7643                    }
7644                    break;
7645                }
7646
7647                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
7648                    notifyHardKeyboardStatusChange();
7649                    break;
7650                }
7651
7652                case BOOT_TIMEOUT: {
7653                    performBootTimeout();
7654                    break;
7655                }
7656
7657                case WAITING_FOR_DRAWN_TIMEOUT: {
7658                    Pair<WindowState, IRemoteCallback> pair;
7659                    synchronized (mWindowMap) {
7660                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
7661                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
7662                        if (!mWaitingForDrawn.remove(pair)) {
7663                            return;
7664                        }
7665                    }
7666                    try {
7667                        pair.second.sendResult(null);
7668                    } catch (RemoteException e) {
7669                    }
7670                    break;
7671                }
7672
7673                case UPDATE_ANIM_PARAMETERS: {
7674                    // Used to send multiple changes from the animation side to the layout side.
7675                    synchronized (mWindowMap) {
7676                        if (copyAnimToLayoutParamsLocked()) {
7677                            mH.sendEmptyMessage(CLEAR_PENDING_ACTIONS);
7678                            performLayoutAndPlaceSurfacesLocked();
7679                        }
7680                    }
7681                    break;
7682                }
7683
7684                case SHOW_STRICT_MODE_VIOLATION: {
7685                    showStrictModeViolation(msg.arg1, msg.arg2);
7686                    break;
7687                }
7688
7689                // Animation messages. Move to Window{State}Animator
7690                case SET_TRANSPARENT_REGION: {
7691                    Pair<WindowStateAnimator, Region> pair =
7692                                (Pair<WindowStateAnimator, Region>) msg.obj;
7693                    final WindowStateAnimator winAnimator = pair.first;
7694                    winAnimator.setTransparentRegionHint(pair.second);
7695                    break;
7696                }
7697
7698                case CLEAR_PENDING_ACTIONS: {
7699                    mAnimator.clearPendingActions();
7700                    break;
7701                }
7702
7703                case DO_ANIMATION_CALLBACK: {
7704                    try {
7705                        ((IRemoteCallback)msg.obj).sendResult(null);
7706                    } catch (RemoteException e) {
7707                    }
7708                    break;
7709                }
7710
7711                case NOTIFY_ROTATION_CHANGED: {
7712                    final int displayId = msg.arg1;
7713                    final int rotation = msg.arg2;
7714                    handleNotifyRotationChanged(displayId, rotation);
7715                    break;
7716                }
7717
7718                case NOTIFY_WINDOW_TRANSITION: {
7719                    final int transition = msg.arg1;
7720                    WindowInfo info = (WindowInfo) msg.obj;
7721                    handleNotifyWindowTranstion(transition, info);
7722                    break;
7723                }
7724
7725                case NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
7726                    final int displayId = msg.arg1;
7727                    final boolean immediate = (msg.arg2 == 1);
7728                    Rect rectangle = (Rect) msg.obj;
7729                    handleNotifyRectangleOnScreenRequested(displayId, rectangle, immediate);
7730                    break;
7731                }
7732
7733                case NOTIFY_WINDOW_LAYERS_CHANGED: {
7734                    DisplayContent displayContent = (DisplayContent) msg.obj;
7735                    handleNotifyWindowLayersChanged(displayContent);
7736                    break;
7737                }
7738
7739                case DO_DISPLAY_ADDED:
7740                    synchronized (mWindowMap) {
7741                        handleDisplayAddedLocked(msg.arg1);
7742                    }
7743                    break;
7744
7745                case DO_DISPLAY_REMOVED:
7746                    synchronized (mWindowMap) {
7747                        handleDisplayRemovedLocked(msg.arg1);
7748                    }
7749                    break;
7750
7751                case DO_DISPLAY_CHANGED:
7752                    synchronized (mWindowMap) {
7753                        handleDisplayChangedLocked(msg.arg1);
7754                    }
7755                    break;
7756            }
7757            if (DEBUG_WINDOW_TRACE) {
7758                Slog.v(TAG, "handleMessage: exit");
7759            }
7760        }
7761    }
7762
7763    // -------------------------------------------------------------
7764    // IWindowManager API
7765    // -------------------------------------------------------------
7766
7767    @Override
7768    public IWindowSession openSession(IInputMethodClient client,
7769            IInputContext inputContext) {
7770        if (client == null) throw new IllegalArgumentException("null client");
7771        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7772        Session session = new Session(this, client, inputContext);
7773        return session;
7774    }
7775
7776    @Override
7777    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7778        synchronized (mWindowMap) {
7779            // The focus for the client is the window immediately below
7780            // where we would place the input method window.
7781            int idx = findDesiredInputMethodWindowIndexLocked(false);
7782            if (idx > 0) {
7783                // TODO(multidisplay): IMEs are only supported on the default display.
7784                WindowState imFocus = getDefaultWindowListLocked().get(idx-1);
7785                if (DEBUG_INPUT_METHOD) {
7786                    Slog.i(TAG, "Desired input method target: " + imFocus);
7787                    Slog.i(TAG, "Current focus: " + mCurrentFocus);
7788                    Slog.i(TAG, "Last focus: " + mLastFocus);
7789                }
7790                if (imFocus != null) {
7791                    // This may be a starting window, in which case we still want
7792                    // to count it as okay.
7793                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
7794                            && imFocus.mAppToken != null) {
7795                        // The client has definitely started, so it really should
7796                        // have a window in this app token.  Let's look for it.
7797                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
7798                            WindowState w = imFocus.mAppToken.windows.get(i);
7799                            if (w != imFocus) {
7800                                Log.i(TAG, "Switching to real app window: " + w);
7801                                imFocus = w;
7802                                break;
7803                            }
7804                        }
7805                    }
7806                    if (DEBUG_INPUT_METHOD) {
7807                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
7808                        if (imFocus.mSession.mClient != null) {
7809                            Slog.i(TAG, "IM target client binder: "
7810                                    + imFocus.mSession.mClient.asBinder());
7811                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
7812                        }
7813                    }
7814                    if (imFocus.mSession.mClient != null &&
7815                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7816                        return true;
7817                    }
7818                }
7819            }
7820
7821            // Okay, how about this...  what is the current focus?
7822            // It seems in some cases we may not have moved the IM
7823            // target window, such as when it was in a pop-up window,
7824            // so let's also look at the current focus.  (An example:
7825            // go to Gmail, start searching so the keyboard goes up,
7826            // press home.  Sometimes the IME won't go down.)
7827            // Would be nice to fix this more correctly, but it's
7828            // way at the end of a release, and this should be good enough.
7829            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
7830                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7831                return true;
7832            }
7833        }
7834        return false;
7835    }
7836
7837    public void getInitialDisplaySize(int displayId, Point size) {
7838        // TODO(cmautner): Access to DisplayContent should be locked on mWindowMap. Doing that
7839        //  could lead to deadlock since this is called from ActivityManager.
7840        final DisplayContent displayContent = getDisplayContentLocked(displayId);
7841        synchronized(displayContent.mDisplaySizeLock) {
7842            size.x = displayContent.mInitialDisplayWidth;
7843            size.y = displayContent.mInitialDisplayHeight;
7844        }
7845    }
7846
7847    public void setForcedDisplaySize(int displayId, int width, int height) {
7848        synchronized(mWindowMap) {
7849            // Set some sort of reasonable bounds on the size of the display that we
7850            // will try to emulate.
7851            final int MIN_WIDTH = 200;
7852            final int MIN_HEIGHT = 200;
7853            final int MAX_SCALE = 2;
7854            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7855
7856            width = Math.min(Math.max(width, MIN_WIDTH),
7857                    displayContent.mInitialDisplayWidth * MAX_SCALE);
7858            height = Math.min(Math.max(height, MIN_HEIGHT),
7859                    displayContent.mInitialDisplayHeight * MAX_SCALE);
7860            setForcedDisplaySizeLocked(displayContent, width, height);
7861            Settings.Global.putString(mContext.getContentResolver(),
7862                    Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
7863        }
7864    }
7865
7866    private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) {
7867        final String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
7868                Settings.Global.DISPLAY_SIZE_FORCED);
7869        if (sizeStr != null && sizeStr.length() > 0) {
7870            final int pos = sizeStr.indexOf(',');
7871            if (pos > 0 && sizeStr.lastIndexOf(',') == pos) {
7872                int width, height;
7873                try {
7874                    width = Integer.parseInt(sizeStr.substring(0, pos));
7875                    height = Integer.parseInt(sizeStr.substring(pos+1));
7876                    synchronized(displayContent.mDisplaySizeLock) {
7877                        if (displayContent.mBaseDisplayWidth != width
7878                                || displayContent.mBaseDisplayHeight != height) {
7879                            Slog.i(TAG, "FORCED DISPLAY SIZE: " + width + "x" + height);
7880                            displayContent.mBaseDisplayWidth = width;
7881                            displayContent.mBaseDisplayHeight = height;
7882                        }
7883                    }
7884                } catch (NumberFormatException ex) {
7885                }
7886            }
7887        }
7888        final String densityStr = Settings.Global.getString(mContext.getContentResolver(),
7889                Settings.Global.DISPLAY_DENSITY_FORCED);
7890        if (densityStr != null && densityStr.length() > 0) {
7891            int density;
7892            try {
7893                density = Integer.parseInt(densityStr);
7894                synchronized(displayContent.mDisplaySizeLock) {
7895                    if (displayContent.mBaseDisplayDensity != density) {
7896                        Slog.i(TAG, "FORCED DISPLAY DENSITY: " + density);
7897                        displayContent.mBaseDisplayDensity = density;
7898                    }
7899                }
7900            } catch (NumberFormatException ex) {
7901            }
7902        }
7903    }
7904
7905    private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
7906        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7907
7908        synchronized(displayContent.mDisplaySizeLock) {
7909            displayContent.mBaseDisplayWidth = width;
7910            displayContent.mBaseDisplayHeight = height;
7911        }
7912        reconfigureDisplayLocked(displayContent);
7913    }
7914
7915    public void clearForcedDisplaySize(int displayId) {
7916        synchronized(mWindowMap) {
7917            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7918            setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
7919                    displayContent.mInitialDisplayHeight);
7920            Settings.Global.putString(mContext.getContentResolver(),
7921                    Settings.Global.DISPLAY_SIZE_FORCED, "");
7922        }
7923    }
7924
7925    public void setForcedDisplayDensity(int displayId, int density) {
7926        synchronized(mWindowMap) {
7927            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7928            setForcedDisplayDensityLocked(displayContent, density);
7929            Settings.Global.putString(mContext.getContentResolver(),
7930                    Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
7931        }
7932    }
7933
7934    private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) {
7935        Slog.i(TAG, "Using new display density: " + density);
7936
7937        synchronized(displayContent.mDisplaySizeLock) {
7938            displayContent.mBaseDisplayDensity = density;
7939        }
7940        reconfigureDisplayLocked(displayContent);
7941    }
7942
7943    public void clearForcedDisplayDensity(int displayId) {
7944        synchronized(mWindowMap) {
7945            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7946            setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity);
7947            Settings.Global.putString(mContext.getContentResolver(),
7948                    Settings.Global.DISPLAY_DENSITY_FORCED, "");
7949        }
7950    }
7951
7952    private void reconfigureDisplayLocked(DisplayContent displayContent) {
7953        // TODO: Multidisplay: for now only use with default display.
7954        mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
7955                displayContent.mBaseDisplayWidth,
7956                displayContent.mBaseDisplayHeight,
7957                displayContent.mBaseDisplayDensity);
7958
7959        displayContent.layoutNeeded = true;
7960
7961        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7962        mTempConfiguration.setToDefaults();
7963        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7964        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7965            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7966                configChanged = true;
7967            }
7968        }
7969
7970        if (configChanged) {
7971            mWaitingForConfig = true;
7972            startFreezingDisplayLocked(false, 0, 0);
7973            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7974        }
7975
7976        performLayoutAndPlaceSurfacesLocked();
7977    }
7978
7979    public boolean hasSystemNavBar() {
7980        return mPolicy.hasSystemNavBar();
7981    }
7982
7983    // -------------------------------------------------------------
7984    // Internals
7985    // -------------------------------------------------------------
7986
7987    final WindowState windowForClientLocked(Session session, IWindow client,
7988            boolean throwOnError) {
7989        return windowForClientLocked(session, client.asBinder(), throwOnError);
7990    }
7991
7992    final WindowState windowForClientLocked(Session session, IBinder client,
7993            boolean throwOnError) {
7994        WindowState win = mWindowMap.get(client);
7995        if (localLOGV) Slog.v(
7996            TAG, "Looking up client " + client + ": " + win);
7997        if (win == null) {
7998            RuntimeException ex = new IllegalArgumentException(
7999                    "Requested window " + client + " does not exist");
8000            if (throwOnError) {
8001                throw ex;
8002            }
8003            Slog.w(TAG, "Failed looking up window", ex);
8004            return null;
8005        }
8006        if (session != null && win.mSession != session) {
8007            RuntimeException ex = new IllegalArgumentException(
8008                    "Requested window " + client + " is in session " +
8009                    win.mSession + ", not " + session);
8010            if (throwOnError) {
8011                throw ex;
8012            }
8013            Slog.w(TAG, "Failed looking up window", ex);
8014            return null;
8015        }
8016
8017        return win;
8018    }
8019
8020    final void rebuildAppWindowListLocked() {
8021        DisplayContentsIterator iterator = new DisplayContentsIterator();
8022        while (iterator.hasNext()) {
8023            rebuildAppWindowListLocked(iterator.next());
8024        }
8025    }
8026
8027    private void rebuildAppWindowListLocked(final DisplayContent displayContent) {
8028        final WindowList windows = displayContent.getWindowList();
8029        int NW = windows.size();
8030        int i;
8031        int lastBelow = -1;
8032        int numRemoved = 0;
8033
8034        if (mRebuildTmp.length < NW) {
8035            mRebuildTmp = new WindowState[NW+10];
8036        }
8037
8038        // First remove all existing app windows.
8039        i=0;
8040        while (i < NW) {
8041            WindowState w = windows.get(i);
8042            if (w.mAppToken != null) {
8043                WindowState win = windows.remove(i);
8044                win.mRebuilding = true;
8045                mRebuildTmp[numRemoved] = win;
8046                mWindowsChanged = true;
8047                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
8048                        "Rebuild removing window: " + win);
8049                NW--;
8050                numRemoved++;
8051                continue;
8052            } else if (lastBelow == i-1) {
8053                if (w.mAttrs.type == TYPE_WALLPAPER || w.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
8054                    lastBelow = i;
8055                }
8056            }
8057            i++;
8058        }
8059
8060        // Keep whatever windows were below the app windows still below,
8061        // by skipping them.
8062        lastBelow++;
8063        i = lastBelow;
8064
8065        // First add all of the exiting app tokens...  these are no longer
8066        // in the main app list, but still have windows shown.  We put them
8067        // in the back because now that the animation is over we no longer
8068        // will care about them.
8069        int NT = mExitingAppTokens.size();
8070        for (int j=0; j<NT; j++) {
8071            i = reAddAppWindowsLocked(displayContent, i, mExitingAppTokens.get(j));
8072        }
8073
8074        // And add in the still active app tokens in Z order.
8075        NT = mAnimatingAppTokens.size();
8076        for (int j=0; j<NT; j++) {
8077            i = reAddAppWindowsLocked(displayContent, i, mAnimatingAppTokens.get(j));
8078        }
8079
8080        i -= lastBelow;
8081        if (i != numRemoved) {
8082            Slog.w(TAG, "Rebuild removed " + numRemoved
8083                    + " windows but added " + i);
8084            for (i=0; i<numRemoved; i++) {
8085                WindowState ws = mRebuildTmp[i];
8086                if (ws.mRebuilding) {
8087                    StringWriter sw = new StringWriter();
8088                    PrintWriter pw = new PrintWriter(sw);
8089                    ws.dump(pw, "", true);
8090                    pw.flush();
8091                    Slog.w(TAG, "This window was lost: " + ws);
8092                    Slog.w(TAG, sw.toString());
8093                    ws.mWinAnimator.destroySurfaceLocked();
8094                }
8095            }
8096            Slog.w(TAG, "Current app token list:");
8097            dumpAnimatingAppTokensLocked();
8098            Slog.w(TAG, "Final window list:");
8099            dumpWindowsLocked();
8100        }
8101    }
8102
8103    private final void assignLayersLocked(WindowList windows) {
8104        int N = windows.size();
8105        int curBaseLayer = 0;
8106        int curLayer = 0;
8107        int i;
8108
8109        if (DEBUG_LAYERS) {
8110            RuntimeException here = new RuntimeException("here");
8111            here.fillInStackTrace();
8112            Slog.v(TAG, "Assigning layers", here);
8113        }
8114
8115        boolean anyLayerChanged = false;
8116
8117        for (i=0; i<N; i++) {
8118            final WindowState w = windows.get(i);
8119            final WindowStateAnimator winAnimator = w.mWinAnimator;
8120            boolean layerChanged = false;
8121            int oldLayer = w.mLayer;
8122            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
8123                    || (i > 0 && w.mIsWallpaper)) {
8124                curLayer += WINDOW_LAYER_MULTIPLIER;
8125                w.mLayer = curLayer;
8126            } else {
8127                curBaseLayer = curLayer = w.mBaseLayer;
8128                w.mLayer = curLayer;
8129            }
8130            if (w.mLayer != oldLayer) {
8131                layerChanged = true;
8132                anyLayerChanged = true;
8133            }
8134            oldLayer = winAnimator.mAnimLayer;
8135            if (w.mTargetAppToken != null) {
8136                winAnimator.mAnimLayer =
8137                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
8138            } else if (w.mAppToken != null) {
8139                winAnimator.mAnimLayer =
8140                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
8141            } else {
8142                winAnimator.mAnimLayer = w.mLayer;
8143            }
8144            if (w.mIsImWindow) {
8145                winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
8146            } else if (w.mIsWallpaper) {
8147                winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
8148            }
8149            if (winAnimator.mAnimLayer != oldLayer) {
8150                layerChanged = true;
8151                anyLayerChanged = true;
8152            }
8153            if (layerChanged && mAnimator.isDimmingLocked(winAnimator)) {
8154                // Force an animation pass just to update the mDimAnimator layer.
8155                updateLayoutToAnimationLocked();
8156            }
8157            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
8158                    + "mBase=" + w.mBaseLayer
8159                    + " mLayer=" + w.mLayer
8160                    + (w.mAppToken == null ?
8161                            "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
8162                    + " =mAnimLayer=" + winAnimator.mAnimLayer);
8163            //System.out.println(
8164            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
8165        }
8166
8167        if (anyLayerChanged) {
8168            scheduleNotifyWindowLayersChangedIfNeededLocked(getDefaultDisplayContentLocked());
8169        }
8170    }
8171
8172    private boolean mInLayout = false;
8173    private final void performLayoutAndPlaceSurfacesLocked() {
8174        if (mInLayout) {
8175            if (DEBUG) {
8176                throw new RuntimeException("Recursive call!");
8177            }
8178            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
8179                    + Debug.getCallers(3));
8180            return;
8181        }
8182
8183        if (mWaitingForConfig) {
8184            // Our configuration has changed (most likely rotation), but we
8185            // don't yet have the complete configuration to report to
8186            // applications.  Don't do any window layout until we have it.
8187            return;
8188        }
8189
8190        if (!mDisplayReady) {
8191            // Not yet initialized, nothing to do.
8192            return;
8193        }
8194
8195        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
8196        mInLayout = true;
8197        boolean recoveringMemory = false;
8198
8199        try {
8200            if (mForceRemoves != null) {
8201                recoveringMemory = true;
8202                // Wait a little bit for things to settle down, and off we go.
8203                for (int i=0; i<mForceRemoves.size(); i++) {
8204                    WindowState ws = mForceRemoves.get(i);
8205                    Slog.i(TAG, "Force removing: " + ws);
8206                    removeWindowInnerLocked(ws.mSession, ws);
8207                }
8208                mForceRemoves = null;
8209                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
8210                Object tmp = new Object();
8211                synchronized (tmp) {
8212                    try {
8213                        tmp.wait(250);
8214                    } catch (InterruptedException e) {
8215                    }
8216                }
8217            }
8218        } catch (RuntimeException e) {
8219            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
8220        }
8221
8222        try {
8223            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
8224
8225            mInLayout = false;
8226
8227            if (needsLayout()) {
8228                if (++mLayoutRepeatCount < 6) {
8229                    requestTraversalLocked();
8230                } else {
8231                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
8232                    mLayoutRepeatCount = 0;
8233                }
8234            } else {
8235                mLayoutRepeatCount = 0;
8236            }
8237
8238            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
8239                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
8240                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
8241            }
8242        } catch (RuntimeException e) {
8243            mInLayout = false;
8244            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
8245        }
8246
8247        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
8248    }
8249
8250    private final void performLayoutLockedInner(final DisplayContent displayContent,
8251                                    boolean initial, boolean updateInputWindows) {
8252        if (!displayContent.layoutNeeded) {
8253            return;
8254        }
8255        displayContent.layoutNeeded = false;
8256        WindowList windows = displayContent.getWindowList();
8257        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
8258
8259        DisplayInfo displayInfo = displayContent.getDisplayInfo();
8260        final int dw = displayInfo.logicalWidth;
8261        final int dh = displayInfo.logicalHeight;
8262
8263        final int NFW = mFakeWindows.size();
8264        for (int i=0; i<NFW; i++) {
8265            mFakeWindows.get(i).layout(dw, dh);
8266        }
8267
8268        final int N = windows.size();
8269        int i;
8270
8271        if (DEBUG_LAYOUT) {
8272            Slog.v(TAG, "-------------------------------------");
8273            Slog.v(TAG, "performLayout: needed="
8274                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
8275        }
8276
8277        WindowStateAnimator universeBackground = null;
8278
8279        mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
8280        if (isDefaultDisplay) {
8281            // Not needed on non-default displays.
8282            mSystemDecorLayer = mPolicy.getSystemDecorRectLw(mSystemDecorRect);
8283            mScreenRect.set(0, 0, dw, dh);
8284        }
8285
8286        int seq = mLayoutSeq+1;
8287        if (seq < 0) seq = 0;
8288        mLayoutSeq = seq;
8289
8290        boolean behindDream = false;
8291
8292        // First perform layout of any root windows (not attached
8293        // to another window).
8294        int topAttached = -1;
8295        for (i = N-1; i >= 0; i--) {
8296            final WindowState win = windows.get(i);
8297
8298            // Don't do layout of a window if it is not visible, or
8299            // soon won't be visible, to avoid wasting time and funky
8300            // changes while a window is animating away.
8301            final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
8302                    || win.isGoneForLayoutLw();
8303
8304            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
8305                Slog.v(TAG, "1ST PASS " + win
8306                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
8307                        + " mLayoutAttached=" + win.mLayoutAttached
8308                        + " screen changed=" + win.isConfigDiff(ActivityInfo.CONFIG_SCREEN_SIZE));
8309                final AppWindowToken atoken = win.mAppToken;
8310                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
8311                        + win.mViewVisibility + " mRelayoutCalled="
8312                        + win.mRelayoutCalled + " hidden="
8313                        + win.mRootToken.hidden + " hiddenRequested="
8314                        + (atoken != null && atoken.hiddenRequested)
8315                        + " mAttachedHidden=" + win.mAttachedHidden);
8316                else Slog.v(TAG, "  VIS: mViewVisibility="
8317                        + win.mViewVisibility + " mRelayoutCalled="
8318                        + win.mRelayoutCalled + " hidden="
8319                        + win.mRootToken.hidden + " hiddenRequested="
8320                        + (atoken != null && atoken.hiddenRequested)
8321                        + " mAttachedHidden=" + win.mAttachedHidden);
8322            }
8323
8324            // If this view is GONE, then skip it -- keep the current
8325            // frame, and let the caller know so they can ignore it
8326            // if they want.  (We do the normal layout for INVISIBLE
8327            // windows, since that means "perform layout as normal,
8328            // just don't display").
8329            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
8330                    || win.isConfigDiff(ActivityInfo.CONFIG_SCREEN_SIZE)
8331                    || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
8332                if (!win.mLayoutAttached) {
8333                    if (initial) {
8334                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8335                        win.mContentChanged = false;
8336                    }
8337                    if (win.mAttrs.type == TYPE_DREAM) {
8338                        // Don't layout windows behind a dream, so that if it
8339                        // does stuff like hide the status bar we won't get a
8340                        // bad transition when it goes away.
8341                        behindDream = true;
8342                    }
8343                    win.mLayoutNeeded = false;
8344                    win.prelayout();
8345                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
8346                    win.mLayoutSeq = seq;
8347                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8348                            + win.mFrame + " mContainingFrame="
8349                            + win.mContainingFrame + " mDisplayFrame="
8350                            + win.mDisplayFrame);
8351                } else {
8352                    if (topAttached < 0) topAttached = i;
8353                }
8354            }
8355            if (win.mViewVisibility == View.VISIBLE
8356                    && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND
8357                    && universeBackground == null) {
8358                universeBackground = win.mWinAnimator;
8359            }
8360        }
8361
8362        if (mAnimator.mUniverseBackground  != universeBackground) {
8363            mFocusMayChange = true;
8364            mAnimator.mUniverseBackground = universeBackground;
8365        }
8366
8367        boolean attachedBehindDream = false;
8368
8369        // Now perform layout of attached windows, which usually
8370        // depend on the position of the window they are attached to.
8371        // XXX does not deal with windows that are attached to windows
8372        // that are themselves attached.
8373        for (i = topAttached; i >= 0; i--) {
8374            final WindowState win = windows.get(i);
8375
8376            if (win.mLayoutAttached) {
8377                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
8378                        + " mHaveFrame=" + win.mHaveFrame
8379                        + " mViewVisibility=" + win.mViewVisibility
8380                        + " mRelayoutCalled=" + win.mRelayoutCalled);
8381                // If this view is GONE, then skip it -- keep the current
8382                // frame, and let the caller know so they can ignore it
8383                // if they want.  (We do the normal layout for INVISIBLE
8384                // windows, since that means "perform layout as normal,
8385                // just don't display").
8386                if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
8387                    continue;
8388                }
8389                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
8390                        || !win.mHaveFrame || win.mLayoutNeeded) {
8391                    if (initial) {
8392                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8393                        win.mContentChanged = false;
8394                    }
8395                    win.mLayoutNeeded = false;
8396                    win.prelayout();
8397                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
8398                    win.mLayoutSeq = seq;
8399                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8400                            + win.mFrame + " mContainingFrame="
8401                            + win.mContainingFrame + " mDisplayFrame="
8402                            + win.mDisplayFrame);
8403                }
8404            } else if (win.mAttrs.type == TYPE_DREAM) {
8405                // Don't layout windows behind a dream, so that if it
8406                // does stuff like hide the status bar we won't get a
8407                // bad transition when it goes away.
8408                attachedBehindDream = behindDream;
8409            }
8410        }
8411
8412        // Window frames may have changed.  Tell the input dispatcher about it.
8413        mInputMonitor.setUpdateInputWindowsNeededLw();
8414        if (updateInputWindows) {
8415            mInputMonitor.updateInputWindowsLw(false /*force*/);
8416        }
8417
8418        mPolicy.finishLayoutLw();
8419    }
8420
8421    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
8422        // If the screen is currently frozen or off, then keep
8423        // it frozen/off until this window draws at its new
8424        // orientation.
8425        if (!okToDisplay()) {
8426            if (DEBUG_ORIENTATION) Slog.v(TAG,
8427                    "Changing surface while display frozen: " + w);
8428            w.mOrientationChanging = true;
8429            mInnerFields.mOrientationChangeComplete = false;
8430            if (!mWindowsFreezingScreen) {
8431                mWindowsFreezingScreen = true;
8432                // XXX should probably keep timeout from
8433                // when we first froze the display.
8434                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8435                mH.sendMessageDelayed(mH.obtainMessage(
8436                        H.WINDOW_FREEZE_TIMEOUT), WINDOW_FREEZE_TIMEOUT_DURATION);
8437            }
8438        }
8439    }
8440
8441    /**
8442     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8443     * @param windows List of windows on default display.
8444     * @return bitmap indicating if another pass through layout must be made.
8445     */
8446    public int handleAppTransitionReadyLocked(WindowList windows) {
8447        int changes = 0;
8448        int i;
8449        int NN = mOpeningApps.size();
8450        boolean goodToGo = true;
8451        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8452                "Checking " + NN + " opening apps (frozen="
8453                + mDisplayFrozen + " timeout="
8454                + mAppTransitionTimeout + ")...");
8455        if (!mDisplayFrozen && !mAppTransitionTimeout) {
8456            // If the display isn't frozen, wait to do anything until
8457            // all of the apps are ready.  Otherwise just go because
8458            // we'll unfreeze the display when everyone is ready.
8459            for (i=0; i<NN && goodToGo; i++) {
8460                AppWindowToken wtoken = mOpeningApps.get(i);
8461                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8462                        "Check opening app=" + wtoken + ": allDrawn="
8463                        + wtoken.allDrawn + " startingDisplayed="
8464                        + wtoken.startingDisplayed + " startingMoved="
8465                        + wtoken.startingMoved);
8466                if (!wtoken.allDrawn && !wtoken.startingDisplayed
8467                        && !wtoken.startingMoved) {
8468                    goodToGo = false;
8469                }
8470            }
8471        }
8472        if (goodToGo) {
8473            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
8474            int transit = mNextAppTransition;
8475            if (mSkipAppTransitionAnimation) {
8476                transit = WindowManagerPolicy.TRANSIT_UNSET;
8477            }
8478            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
8479            mAppTransitionReady = false;
8480            mAppTransitionRunning = true;
8481            mAppTransitionTimeout = false;
8482            mStartingIconInTransition = false;
8483            mSkipAppTransitionAnimation = false;
8484
8485            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8486
8487            rebuildAppWindowListLocked();
8488
8489            // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
8490            WindowState oldWallpaper =
8491                    mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
8492                        && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
8493                    ? null : mWallpaperTarget;
8494
8495            adjustWallpaperWindowsLocked();
8496            mInnerFields.mWallpaperMayChange = false;
8497
8498            // The top-most window will supply the layout params,
8499            // and we will determine it below.
8500            LayoutParams animLp = null;
8501            int bestAnimLayer = -1;
8502            boolean fullscreenAnim = false;
8503
8504            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8505                    "New wallpaper target=" + mWallpaperTarget
8506                    + ", oldWallpaper=" + oldWallpaper
8507                    + ", lower target=" + mLowerWallpaperTarget
8508                    + ", upper target=" + mUpperWallpaperTarget);
8509            int foundWallpapers = 0;
8510            // Do a first pass through the tokens for two
8511            // things:
8512            // (1) Determine if both the closing and opening
8513            // app token sets are wallpaper targets, in which
8514            // case special animations are needed
8515            // (since the wallpaper needs to stay static
8516            // behind them).
8517            // (2) Find the layout params of the top-most
8518            // application window in the tokens, which is
8519            // what will control the animation theme.
8520            final int NC = mClosingApps.size();
8521            NN = NC + mOpeningApps.size();
8522            for (i=0; i<NN; i++) {
8523                AppWindowToken wtoken;
8524                int mode;
8525                if (i < NC) {
8526                    wtoken = mClosingApps.get(i);
8527                    mode = 1;
8528                } else {
8529                    wtoken = mOpeningApps.get(i-NC);
8530                    mode = 2;
8531                }
8532                if (mLowerWallpaperTarget != null) {
8533                    if (mLowerWallpaperTarget.mAppToken == wtoken
8534                            || mUpperWallpaperTarget.mAppToken == wtoken) {
8535                        foundWallpapers |= mode;
8536                    }
8537                }
8538                if (wtoken.appFullscreen) {
8539                    WindowState ws = wtoken.findMainWindow();
8540                    if (ws != null) {
8541                        animLp = ws.mAttrs;
8542                        bestAnimLayer = ws.mLayer;
8543                        fullscreenAnim = true;
8544                    }
8545                } else if (!fullscreenAnim) {
8546                    WindowState ws = wtoken.findMainWindow();
8547                    if (ws != null) {
8548                        if (ws.mLayer > bestAnimLayer) {
8549                            animLp = ws.mAttrs;
8550                            bestAnimLayer = ws.mLayer;
8551                        }
8552                    }
8553                }
8554            }
8555
8556            if (foundWallpapers == 3) {
8557                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8558                        "Wallpaper animation!");
8559                switch (transit) {
8560                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
8561                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
8562                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
8563                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
8564                        break;
8565                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
8566                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
8567                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
8568                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
8569                        break;
8570                }
8571                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8572                        "New transit: " + transit);
8573            } else if ((oldWallpaper != null) && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
8574                // We are transitioning from an activity with
8575                // a wallpaper to one without.
8576                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
8577                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8578                        "New transit away from wallpaper: " + transit);
8579            } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
8580                // We are transitioning from an activity without
8581                // a wallpaper to now showing the wallpaper
8582                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
8583                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8584                        "New transit into wallpaper: " + transit);
8585            }
8586
8587            // If all closing windows are obscured, then there is
8588            // no need to do an animation.  This is the case, for
8589            // example, when this transition is being done behind
8590            // the lock screen.
8591            if (!mPolicy.allowAppAnimationsLw()) {
8592                animLp = null;
8593            }
8594
8595            AppWindowToken topOpeningApp = null;
8596            int topOpeningLayer = 0;
8597
8598            NN = mOpeningApps.size();
8599            for (i=0; i<NN; i++) {
8600                AppWindowToken wtoken = mOpeningApps.get(i);
8601                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
8602                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
8603                appAnimator.clearThumbnail();
8604                wtoken.reportedVisible = false;
8605                wtoken.inPendingTransaction = false;
8606                appAnimator.animation = null;
8607                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
8608                wtoken.updateReportedVisibilityLocked();
8609                wtoken.waitingToShow = false;
8610
8611                appAnimator.mAllAppWinAnimators.clear();
8612                final int N = wtoken.allAppWindows.size();
8613                for (int j = 0; j < N; j++) {
8614                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
8615                }
8616                mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
8617
8618                if (animLp != null) {
8619                    int layer = -1;
8620                    for (int j=0; j<wtoken.windows.size(); j++) {
8621                        WindowState win = wtoken.windows.get(j);
8622                        if (win.mWinAnimator.mAnimLayer > layer) {
8623                            layer = win.mWinAnimator.mAnimLayer;
8624                        }
8625                    }
8626                    if (topOpeningApp == null || layer > topOpeningLayer) {
8627                        topOpeningApp = wtoken;
8628                        topOpeningLayer = layer;
8629                    }
8630                }
8631            }
8632            NN = mClosingApps.size();
8633            for (i=0; i<NN; i++) {
8634                AppWindowToken wtoken = mClosingApps.get(i);
8635                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8636                        "Now closing app " + wtoken);
8637                wtoken.mAppAnimator.clearThumbnail();
8638                wtoken.inPendingTransaction = false;
8639                wtoken.mAppAnimator.animation = null;
8640                setTokenVisibilityLocked(wtoken, animLp, false,
8641                        transit, false);
8642                wtoken.updateReportedVisibilityLocked();
8643                wtoken.waitingToHide = false;
8644                // Force the allDrawn flag, because we want to start
8645                // this guy's animations regardless of whether it's
8646                // gotten drawn.
8647                wtoken.allDrawn = true;
8648            }
8649
8650            if (mNextAppTransitionThumbnail != null && topOpeningApp != null
8651                    && topOpeningApp.mAppAnimator.animation != null) {
8652                // This thumbnail animation is very special, we need to have
8653                // an extra surface with the thumbnail included with the animation.
8654                Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
8655                        mNextAppTransitionThumbnail.getHeight());
8656                try {
8657                    // TODO(multi-display): support other displays
8658                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
8659                    final Display display = displayContent.getDisplay();
8660                    Surface surface = new Surface(mFxSession,
8661                            "thumbnail anim",
8662                            dirty.width(), dirty.height(),
8663                            PixelFormat.TRANSLUCENT, Surface.HIDDEN);
8664                    surface.setLayerStack(display.getLayerStack());
8665                    topOpeningApp.mAppAnimator.thumbnail = surface;
8666                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
8667                            + surface + ": CREATE");
8668                    Surface drawSurface = new Surface();
8669                    drawSurface.copyFrom(surface);
8670                    Canvas c = drawSurface.lockCanvas(dirty);
8671                    c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
8672                    drawSurface.unlockCanvasAndPost(c);
8673                    drawSurface.release();
8674                    topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
8675                    Animation anim = createThumbnailAnimationLocked(
8676                            transit, true, true, mNextAppTransitionScaleUp);
8677                    topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
8678                    anim.restrictDuration(MAX_ANIMATION_DURATION);
8679                    anim.scaleCurrentDuration(mTransitionAnimationScale);
8680                    topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX;
8681                    topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY;
8682                } catch (Surface.OutOfResourcesException e) {
8683                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
8684                            + " h=" + dirty.height(), e);
8685                    topOpeningApp.mAppAnimator.clearThumbnail();
8686                }
8687            }
8688
8689            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
8690            mNextAppTransitionPackage = null;
8691            mNextAppTransitionThumbnail = null;
8692            scheduleAnimationCallback(mNextAppTransitionCallback);
8693            mNextAppTransitionCallback = null;
8694
8695            mOpeningApps.clear();
8696            mClosingApps.clear();
8697
8698            // This has changed the visibility of windows, so perform
8699            // a new layout to get them all up-to-date.
8700            changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
8701                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8702            getDefaultDisplayContentLocked().layoutNeeded = true;
8703
8704            // TODO(multidisplay): IMEs are only supported on the default display.
8705            if (windows == getDefaultWindowListLocked()
8706                    && !moveInputMethodWindowsIfNeededLocked(true)) {
8707                assignLayersLocked(windows);
8708            }
8709            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, false /*updateInputWindows*/);
8710            mFocusMayChange = false;
8711        }
8712
8713        return changes;
8714    }
8715
8716    /**
8717     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8718     * @return bitmap indicating if another pass through layout must be made.
8719     */
8720    private int handleAnimatingStoppedAndTransitionLocked() {
8721        int changes = 0;
8722
8723        mAppTransitionRunning = false;
8724        // Restore window app tokens to the ActivityManager views
8725        for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) {
8726            mAnimatingAppTokens.get(i).sendingToBottom = false;
8727        }
8728        mAnimatingAppTokens.clear();
8729        mAnimatingAppTokens.addAll(mAppTokens);
8730        rebuildAppWindowListLocked();
8731
8732        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8733        mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
8734        moveInputMethodWindowsIfNeededLocked(true);
8735        mInnerFields.mWallpaperMayChange = true;
8736        // Since the window list has been rebuilt, focus might
8737        // have to be recomputed since the actual order of windows
8738        // might have changed again.
8739        mFocusMayChange = true;
8740
8741        return changes;
8742    }
8743
8744    /**
8745     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8746     *
8747     * @return bitmap indicating if another pass through layout must be made.
8748     */
8749    private int animateAwayWallpaperLocked() {
8750        int changes = 0;
8751        WindowState oldWallpaper = mWallpaperTarget;
8752        if (mLowerWallpaperTarget != null
8753                && mLowerWallpaperTarget.mAppToken != null) {
8754            if (DEBUG_WALLPAPER) Slog.v(TAG,
8755                    "wallpaperForceHiding changed with lower="
8756                    + mLowerWallpaperTarget);
8757            if (DEBUG_WALLPAPER) Slog.v(TAG,
8758                    "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
8759                    " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
8760            if (mLowerWallpaperTarget.mAppToken.hidden) {
8761                // The lower target has become hidden before we
8762                // actually started the animation...  let's completely
8763                // re-evaluate everything.
8764                mLowerWallpaperTarget = mUpperWallpaperTarget = null;
8765                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8766            }
8767        }
8768        mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8769        if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
8770                + " NEW: " + mWallpaperTarget
8771                + " LOWER: " + mLowerWallpaperTarget);
8772        return changes;
8773    }
8774
8775    private void updateResizingWindows(final WindowState w) {
8776        final WindowStateAnimator winAnimator = w.mWinAnimator;
8777        if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
8778            w.mContentInsetsChanged |=
8779                    !w.mLastContentInsets.equals(w.mContentInsets);
8780            w.mVisibleInsetsChanged |=
8781                    !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8782            boolean configChanged = w.isConfigChanged();
8783            if (DEBUG_CONFIGURATION && configChanged) {
8784                Slog.v(TAG, "Win " + w + " config changed: "
8785                        + mCurConfiguration);
8786            }
8787            if (localLOGV) Slog.v(TAG, "Resizing " + w
8788                    + ": configChanged=" + configChanged
8789                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8790            w.mLastFrame.set(w.mFrame);
8791            if (w.mContentInsetsChanged
8792                    || w.mVisibleInsetsChanged
8793                    || winAnimator.mSurfaceResized
8794                    || configChanged) {
8795                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8796                    Slog.v(TAG, "Resize reasons: "
8797                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8798                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8799                            + " surfaceResized=" + winAnimator.mSurfaceResized
8800                            + " configChanged=" + configChanged);
8801                }
8802
8803                w.mLastContentInsets.set(w.mContentInsets);
8804                w.mLastVisibleInsets.set(w.mVisibleInsets);
8805                makeWindowFreezingScreenIfNeededLocked(w);
8806                // If the orientation is changing, then we need to
8807                // hold off on unfreezing the display until this
8808                // window has been redrawn; to do that, we need
8809                // to go through the process of getting informed
8810                // by the application when it has finished drawing.
8811                if (w.mOrientationChanging) {
8812                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
8813                            "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
8814                            + w + ", surface " + winAnimator.mSurface);
8815                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8816                    if (w.mAppToken != null) {
8817                        w.mAppToken.allDrawn = false;
8818                    }
8819                }
8820                if (!mResizingWindows.contains(w)) {
8821                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8822                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8823                            + "x" + winAnimator.mSurfaceH);
8824                    mResizingWindows.add(w);
8825                }
8826            } else if (w.mOrientationChanging) {
8827                if (w.isDrawnLw()) {
8828                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8829                            "Orientation not waiting for draw in "
8830                            + w + ", surface " + winAnimator.mSurface);
8831                    w.mOrientationChanging = false;
8832                }
8833            }
8834        }
8835    }
8836
8837    /**
8838     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8839     *
8840     * @param w WindowState this method is applied to.
8841     * @param currentTime The time which animations use for calculating transitions.
8842     * @param innerDw Width of app window.
8843     * @param innerDh Height of app window.
8844     */
8845    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8846                                         final int innerDw, final int innerDh) {
8847        final WindowManager.LayoutParams attrs = w.mAttrs;
8848        final int attrFlags = attrs.flags;
8849        final boolean canBeSeen = w.isDisplayedLw();
8850
8851        if (w.mHasSurface) {
8852            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8853                mInnerFields.mHoldScreen = w.mSession;
8854            }
8855            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8856                    && mInnerFields.mScreenBrightness < 0) {
8857                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8858            }
8859            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8860                    && mInnerFields.mButtonBrightness < 0) {
8861                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8862            }
8863            if (!mInnerFields.mSyswin && w.mAttrs.userActivityTimeout >= 0
8864                    && mInnerFields.mUserActivityTimeout < 0) {
8865                mInnerFields.mUserActivityTimeout = w.mAttrs.userActivityTimeout;
8866            }
8867
8868            final int type = attrs.type;
8869            if (canBeSeen
8870                    && (type == TYPE_SYSTEM_DIALOG
8871                     || type == TYPE_RECENTS_OVERLAY
8872                     || type == TYPE_KEYGUARD
8873                     || type == TYPE_SYSTEM_ERROR)) {
8874                mInnerFields.mSyswin = true;
8875            }
8876
8877            if (canBeSeen) {
8878                if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
8879                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_MIRROR;
8880                } else if (mInnerFields.mDisplayHasContent
8881                        == LayoutFields.DISPLAY_CONTENT_UNKNOWN) {
8882                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNIQUE;
8883                }
8884            }
8885        }
8886
8887        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8888        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8889            // This window completely covers everything behind it,
8890            // so we want to leave all of them as undimmed (for
8891            // performance reasons).
8892            mInnerFields.mObscured = true;
8893        } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0
8894                && !(w.mAppToken != null && w.mAppToken.hiddenRequested)
8895                && !w.mExiting) {
8896            if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured);
8897            if (!mInnerFields.mDimming) {
8898                //Slog.i(TAG, "DIM BEHIND: " + w);
8899                mInnerFields.mDimming = true;
8900                final WindowStateAnimator winAnimator = w.mWinAnimator;
8901                if (!mAnimator.isDimmingLocked(winAnimator)) {
8902                    final int width, height;
8903                    if (attrs.type == TYPE_BOOT_PROGRESS) {
8904                        final DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo();
8905                        width = displayInfo.logicalWidth;
8906                        height = displayInfo.logicalHeight;
8907                    } else {
8908                        width = innerDw;
8909                        height = innerDh;
8910                    }
8911                    startDimmingLocked(
8912                        winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount, width, height);
8913                }
8914            }
8915        }
8916    }
8917
8918    private void updateAllDrawnLocked() {
8919        // See if any windows have been drawn, so they (and others
8920        // associated with them) can now be shown.
8921        final ArrayList<AppWindowToken> appTokens = mAnimatingAppTokens;
8922        final int NT = appTokens.size();
8923        for (int i=0; i<NT; i++) {
8924            AppWindowToken wtoken = appTokens.get(i);
8925            if (!wtoken.allDrawn) {
8926                int numInteresting = wtoken.numInterestingWindows;
8927                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8928                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
8929                            "allDrawn: " + wtoken
8930                            + " interesting=" + numInteresting
8931                            + " drawn=" + wtoken.numDrawnWindows);
8932                    wtoken.allDrawn = true;
8933                }
8934            }
8935        }
8936    }
8937
8938    // "Something has changed!  Let's make it correct now."
8939    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
8940        if (DEBUG_WINDOW_TRACE) {
8941            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8942                    + Debug.getCallers(3));
8943        }
8944
8945        final long currentTime = SystemClock.uptimeMillis();
8946
8947        int i;
8948
8949        if (mFocusMayChange) {
8950            mFocusMayChange = false;
8951            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8952                    false /*updateInputWindows*/);
8953        }
8954
8955        // Initialize state of exiting tokens.
8956        for (i=mExitingTokens.size()-1; i>=0; i--) {
8957            mExitingTokens.get(i).hasVisible = false;
8958        }
8959
8960        // Initialize state of exiting applications.
8961        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8962            mExitingAppTokens.get(i).hasVisible = false;
8963        }
8964
8965        mInnerFields.mHoldScreen = null;
8966        mInnerFields.mScreenBrightness = -1;
8967        mInnerFields.mButtonBrightness = -1;
8968        mInnerFields.mUserActivityTimeout = -1;
8969        mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
8970
8971        mTransactionSequence++;
8972
8973        final DisplayContent defaultDisplay = getDefaultDisplayContentLocked();
8974        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
8975        final int defaultDw = defaultInfo.logicalWidth;
8976        final int defaultDh = defaultInfo.logicalHeight;
8977
8978        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8979                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8980        Surface.openTransaction();
8981        try {
8982
8983            if (mWatermark != null) {
8984                mWatermark.positionSurface(defaultDw, defaultDh);
8985            }
8986            if (mStrictModeFlash != null) {
8987                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
8988            }
8989
8990            boolean focusDisplayed = false;
8991            boolean updateAllDrawn = false;
8992
8993            DisplayContentsIterator iterator = new DisplayContentsIterator();
8994            while (iterator.hasNext()) {
8995                final DisplayContent displayContent = iterator.next();
8996                WindowList windows = displayContent.getWindowList();
8997                DisplayInfo displayInfo = displayContent.getDisplayInfo();
8998                final int displayId = displayContent.getDisplayId();
8999                final int dw = displayInfo.logicalWidth;
9000                final int dh = displayInfo.logicalHeight;
9001                final int innerDw = displayInfo.appWidth;
9002                final int innerDh = displayInfo.appHeight;
9003                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
9004
9005                // Reset for each display unless we are forcing mirroring.
9006                if (mInnerFields.mDisplayHasContent != LayoutFields.DISPLAY_CONTENT_MIRROR) {
9007                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
9008                }
9009
9010                int repeats = 0;
9011                do {
9012                    repeats++;
9013                    if (repeats > 6) {
9014                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
9015                        displayContent.layoutNeeded = false;
9016                        break;
9017                    }
9018
9019                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
9020                        displayContent.pendingLayoutChanges);
9021
9022                    if (isDefaultDisplay && ((displayContent.pendingLayoutChanges
9023                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0)
9024                            && ((adjustWallpaperWindowsLocked()
9025                                    & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0)) {
9026                        assignLayersLocked(windows);
9027                        displayContent.layoutNeeded = true;
9028                    }
9029
9030                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
9031                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
9032                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
9033                        if (updateOrientationFromAppTokensLocked(true)) {
9034                            displayContent.layoutNeeded = true;
9035                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9036                        }
9037                    }
9038
9039                    if ((displayContent.pendingLayoutChanges
9040                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9041                        displayContent.layoutNeeded = true;
9042                    }
9043
9044                    // FIRST LOOP: Perform a layout, if needed.
9045                    if (repeats < 4) {
9046                        performLayoutLockedInner(displayContent, repeats == 1,
9047                                false /*updateInputWindows*/);
9048                    } else {
9049                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
9050                    }
9051
9052                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
9053                    // it is animating.
9054                    displayContent.pendingLayoutChanges = 0;
9055
9056                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
9057                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
9058
9059                    if (isDefaultDisplay) {
9060                        mPolicy.beginPostLayoutPolicyLw(dw, dh);
9061                        for (i = windows.size() - 1; i >= 0; i--) {
9062                            WindowState w = windows.get(i);
9063                            if (w.mHasSurface) {
9064                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
9065                            }
9066                        }
9067                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
9068                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
9069                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
9070                    }
9071                } while (displayContent.pendingLayoutChanges != 0);
9072
9073                mInnerFields.mObscured = false;
9074                mInnerFields.mDimming = false;
9075                mInnerFields.mSyswin = false;
9076
9077                // Only used if default window
9078                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
9079
9080                final int N = windows.size();
9081                for (i=N-1; i>=0; i--) {
9082                    WindowState w = windows.get(i);
9083
9084                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
9085
9086                    // Update effect.
9087                    w.mObscured = mInnerFields.mObscured;
9088                    if (!mInnerFields.mObscured) {
9089                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
9090                    }
9091
9092                    if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
9093                            && w.isVisibleLw()) {
9094                        // This is the wallpaper target and its obscured state
9095                        // changed... make sure the current wallaper's visibility
9096                        // has been updated accordingly.
9097                        updateWallpaperVisibilityLocked();
9098                    }
9099
9100                    final WindowStateAnimator winAnimator = w.mWinAnimator;
9101
9102                    // If the window has moved due to its containing
9103                    // content frame changing, then we'd like to animate
9104                    // it.
9105                    if (w.mHasSurface && w.shouldAnimateMove()) {
9106                        // Frame has moved, containing content frame
9107                        // has also moved, and we're not currently animating...
9108                        // let's do something.
9109                        Animation a = AnimationUtils.loadAnimation(mContext,
9110                                com.android.internal.R.anim.window_move_from_decor);
9111                        winAnimator.setAnimation(a);
9112                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
9113                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
9114                        try {
9115                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
9116                        } catch (RemoteException e) {
9117                        }
9118                    }
9119
9120                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
9121                    w.mContentChanged = false;
9122
9123                    // Moved from updateWindowsAndWallpaperLocked().
9124                    if (w.mHasSurface) {
9125                        // Take care of the window being ready to display.
9126                        final boolean committed =
9127                                winAnimator.commitFinishDrawingLocked(currentTime);
9128                        if (isDefaultDisplay && committed) {
9129                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
9130                                if (DEBUG_WALLPAPER) Slog.v(TAG,
9131                                        "First draw done in potential wallpaper target " + w);
9132                                mInnerFields.mWallpaperMayChange = true;
9133                                displayContent.pendingLayoutChanges |=
9134                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9135                                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
9136                                    debugLayoutRepeats(
9137                                        "wallpaper and commitFinishDrawingLocked true",
9138                                        displayContent.pendingLayoutChanges);
9139                                }
9140                            }
9141                        }
9142
9143                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
9144
9145                        final AppWindowToken atoken = w.mAppToken;
9146                        if (DEBUG_STARTING_WINDOW && atoken != null
9147                                && w == atoken.startingWindow) {
9148                            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
9149                                + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
9150                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
9151                        }
9152                        if (atoken != null
9153                                && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
9154                            if (atoken.lastTransactionSequence != mTransactionSequence) {
9155                                atoken.lastTransactionSequence = mTransactionSequence;
9156                                atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
9157                                atoken.startingDisplayed = false;
9158                            }
9159                            if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
9160                                    && !w.mExiting && !w.mDestroying) {
9161                                if (WindowManagerService.DEBUG_VISIBILITY ||
9162                                        WindowManagerService.DEBUG_ORIENTATION) {
9163                                    Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
9164                                            + ", isAnimating=" + winAnimator.isAnimating());
9165                                    if (!w.isDrawnLw()) {
9166                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
9167                                                + " pv=" + w.mPolicyVisibility
9168                                                + " mDrawState=" + winAnimator.mDrawState
9169                                                + " ah=" + w.mAttachedHidden
9170                                                + " th=" + atoken.hiddenRequested
9171                                                + " a=" + winAnimator.mAnimating);
9172                                    }
9173                                }
9174                                if (w != atoken.startingWindow) {
9175                                    if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
9176                                        atoken.numInterestingWindows++;
9177                                        if (w.isDrawnLw()) {
9178                                            atoken.numDrawnWindows++;
9179                                            if (WindowManagerService.DEBUG_VISIBILITY ||
9180                                                    WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
9181                                                    "tokenMayBeDrawn: " + atoken
9182                                                    + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
9183                                                    + " mAppFreezing=" + w.mAppFreezing);
9184                                            updateAllDrawn = true;
9185                                        }
9186                                    }
9187                                } else if (w.isDrawnLw()) {
9188                                    atoken.startingDisplayed = true;
9189                                }
9190                            }
9191                        }
9192                    }
9193
9194                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
9195                            && w.isDisplayedLw()) {
9196                        focusDisplayed = true;
9197                    }
9198
9199                    updateResizingWindows(w);
9200                }
9201
9202                final boolean hasUniqueContent;
9203                switch (mInnerFields.mDisplayHasContent) {
9204                    case LayoutFields.DISPLAY_CONTENT_MIRROR:
9205                        hasUniqueContent = isDefaultDisplay;
9206                        break;
9207                    case LayoutFields.DISPLAY_CONTENT_UNIQUE:
9208                        hasUniqueContent = true;
9209                        break;
9210                    case LayoutFields.DISPLAY_CONTENT_UNKNOWN:
9211                    default:
9212                        hasUniqueContent = false;
9213                        break;
9214                }
9215                mDisplayManagerService.setDisplayHasContent(displayId, hasUniqueContent,
9216                        true /* inTraversal, must call performTraversalInTrans... below */);
9217
9218                if (!mInnerFields.mDimming && mAnimator.isDimmingLocked(displayId)) {
9219                    stopDimmingLocked(displayId);
9220                }
9221            }
9222
9223            if (updateAllDrawn) {
9224                updateAllDrawnLocked();
9225            }
9226
9227            if (focusDisplayed) {
9228                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
9229            }
9230
9231            // Give the display manager a chance to adjust properties
9232            // like display rotation if it needs to.
9233            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
9234
9235        } catch (RuntimeException e) {
9236            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
9237        } finally {
9238            Surface.closeTransaction();
9239        }
9240
9241        final WindowList defaultWindows = defaultDisplay.getWindowList();
9242
9243        // If we are ready to perform an app transition, check through
9244        // all of the app tokens to be shown and see if they are ready
9245        // to go.
9246        if (mAppTransitionReady) {
9247            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
9248            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
9249                defaultDisplay.pendingLayoutChanges);
9250        }
9251
9252        mInnerFields.mAdjResult = 0;
9253
9254        if (!mAnimator.mAnimating && mAppTransitionRunning) {
9255            // We have finished the animation of an app transition.  To do
9256            // this, we have delayed a lot of operations like showing and
9257            // hiding apps, moving apps in Z-order, etc.  The app token list
9258            // reflects the correct Z-order, but the window list may now
9259            // be out of sync with it.  So here we will just rebuild the
9260            // entire app window list.  Fun!
9261            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
9262            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
9263                defaultDisplay.pendingLayoutChanges);
9264        }
9265
9266        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
9267                && !mAppTransitionReady) {
9268            // At this point, there was a window with a wallpaper that
9269            // was force hiding other windows behind it, but now it
9270            // is going away.  This may be simple -- just animate
9271            // away the wallpaper and its window -- or it may be
9272            // hard -- the wallpaper now needs to be shown behind
9273            // something that was hidden.
9274            defaultDisplay.pendingLayoutChanges |= animateAwayWallpaperLocked();
9275            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
9276                defaultDisplay.pendingLayoutChanges);
9277        }
9278        mInnerFields.mWallpaperForceHidingChanged = false;
9279
9280        if (mInnerFields.mWallpaperMayChange) {
9281            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
9282                    "Wallpaper may change!  Adjusting");
9283            mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
9284        }
9285
9286        if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
9287            if (DEBUG_WALLPAPER) Slog.v(TAG,
9288                    "Wallpaper layer changed: assigning layers + relayout");
9289            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9290            assignLayersLocked(defaultWindows);
9291        } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
9292            if (DEBUG_WALLPAPER) Slog.v(TAG,
9293                    "Wallpaper visibility changed: relayout");
9294            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9295        }
9296
9297        if (mFocusMayChange) {
9298            mFocusMayChange = false;
9299            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
9300                    false /*updateInputWindows*/)) {
9301                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
9302                mInnerFields.mAdjResult = 0;
9303            }
9304        }
9305
9306        if (needsLayout()) {
9307            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9308            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
9309                    defaultDisplay.pendingLayoutChanges);
9310        }
9311
9312        for (i = mResizingWindows.size() - 1; i >= 0; i--) {
9313            WindowState win = mResizingWindows.get(i);
9314            if (win.mAppFreezing) {
9315                // Don't remove this window until rotation has completed.
9316                continue;
9317            }
9318            final WindowStateAnimator winAnimator = win.mWinAnimator;
9319            try {
9320                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
9321                        "Reporting new frame to " + win + ": " + win.mCompatFrame);
9322                int diff = 0;
9323                boolean configChanged = win.isConfigChanged();
9324                if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION
9325                        // TODO: Remove once b/7094175 is fixed
9326                        || ((String)win.mAttrs.getTitle()).contains("Keyguard"))
9327                        && configChanged) {
9328                    Slog.i(TAG, "Sending new config to window " + win + ": "
9329                            + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
9330                            + " / " + mCurConfiguration + " / 0x"
9331                            + Integer.toHexString(diff));
9332                }
9333                win.mConfiguration = mCurConfiguration;
9334                if (DEBUG_ORIENTATION &&
9335                        winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
9336                        TAG, "Resizing " + win + " WITH DRAW PENDING");
9337                win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
9338                        winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
9339                        configChanged ? win.mConfiguration : null);
9340                win.mContentInsetsChanged = false;
9341                win.mVisibleInsetsChanged = false;
9342                winAnimator.mSurfaceResized = false;
9343            } catch (RemoteException e) {
9344                win.mOrientationChanging = false;
9345            }
9346            mResizingWindows.remove(i);
9347        }
9348
9349        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
9350                "With display frozen, orientationChangeComplete="
9351                + mInnerFields.mOrientationChangeComplete);
9352        if (mInnerFields.mOrientationChangeComplete) {
9353            if (mWindowsFreezingScreen) {
9354                mWindowsFreezingScreen = false;
9355                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
9356            }
9357            stopFreezingDisplayLocked();
9358        }
9359
9360        // Destroy the surface of any windows that are no longer visible.
9361        boolean wallpaperDestroyed = false;
9362        i = mDestroySurface.size();
9363        if (i > 0) {
9364            do {
9365                i--;
9366                WindowState win = mDestroySurface.get(i);
9367                win.mDestroying = false;
9368                if (mInputMethodWindow == win) {
9369                    mInputMethodWindow = null;
9370                }
9371                if (win == mWallpaperTarget) {
9372                    wallpaperDestroyed = true;
9373                }
9374                win.mWinAnimator.destroySurfaceLocked();
9375            } while (i > 0);
9376            mDestroySurface.clear();
9377        }
9378
9379        // Time to remove any exiting tokens?
9380        for (i=mExitingTokens.size()-1; i>=0; i--) {
9381            WindowToken token = mExitingTokens.get(i);
9382            if (!token.hasVisible) {
9383                mExitingTokens.remove(i);
9384                if (token.windowType == TYPE_WALLPAPER) {
9385                    mWallpaperTokens.remove(token);
9386                    updateLayoutToAnimWallpaperTokens();
9387                }
9388            }
9389        }
9390
9391        // Time to remove any exiting applications?
9392        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
9393            AppWindowToken token = mExitingAppTokens.get(i);
9394            if (!token.hasVisible && !mClosingApps.contains(token)) {
9395                // Make sure there is no animation running on this token,
9396                // so any windows associated with it will be removed as
9397                // soon as their animations are complete
9398                token.mAppAnimator.clearAnimation();
9399                token.mAppAnimator.animating = false;
9400                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
9401                        "performLayout: App token exiting now removed" + token);
9402                mAppTokens.remove(token);
9403                mAnimatingAppTokens.remove(token);
9404                mExitingAppTokens.remove(i);
9405            }
9406        }
9407
9408        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
9409            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
9410                try {
9411                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
9412                } catch (RemoteException e) {
9413                }
9414            }
9415            mRelayoutWhileAnimating.clear();
9416        }
9417
9418        if (wallpaperDestroyed && (adjustWallpaperWindowsLocked() != 0)) {
9419            getDefaultDisplayContentLocked().layoutNeeded = true;
9420        }
9421
9422        DisplayContentsIterator iterator = new DisplayContentsIterator();
9423        while (iterator.hasNext()) {
9424            DisplayContent displayContent = iterator.next();
9425            if (displayContent.pendingLayoutChanges != 0) {
9426                displayContent.layoutNeeded = true;
9427            }
9428        }
9429
9430        // Finally update all input windows now that the window changes have stabilized.
9431        mInputMonitor.updateInputWindowsLw(true /*force*/);
9432
9433        setHoldScreenLocked(mInnerFields.mHoldScreen);
9434        if (!mDisplayFrozen) {
9435            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
9436                mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
9437            } else {
9438                mPowerManager.setScreenBrightnessOverrideFromWindowManager(
9439                        toBrightnessOverride(mInnerFields.mScreenBrightness));
9440            }
9441            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
9442                mPowerManager.setButtonBrightnessOverrideFromWindowManager(-1);
9443            } else {
9444                mPowerManager.setButtonBrightnessOverrideFromWindowManager(
9445                        toBrightnessOverride(mInnerFields.mButtonBrightness));
9446            }
9447            mPowerManager.setUserActivityTimeoutOverrideFromWindowManager(
9448                    mInnerFields.mUserActivityTimeout);
9449        }
9450
9451        if (mTurnOnScreen) {
9452            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
9453            mPowerManager.wakeUp(SystemClock.uptimeMillis());
9454            mTurnOnScreen = false;
9455        }
9456
9457        if (mInnerFields.mUpdateRotation) {
9458            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9459            if (updateRotationUncheckedLocked(false)) {
9460                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9461            } else {
9462                mInnerFields.mUpdateRotation = false;
9463            }
9464        }
9465
9466        if (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded
9467                && !mInnerFields.mUpdateRotation) {
9468            checkDrawnWindowsLocked();
9469        }
9470
9471        final int N = mPendingRemove.size();
9472        if (N > 0) {
9473            if (mPendingRemoveTmp.length < N) {
9474                mPendingRemoveTmp = new WindowState[N+10];
9475            }
9476            mPendingRemove.toArray(mPendingRemoveTmp);
9477            mPendingRemove.clear();
9478            DisplayContentList displayList = new DisplayContentList();
9479            for (i = 0; i < N; i++) {
9480                WindowState w = mPendingRemoveTmp[i];
9481                removeWindowInnerLocked(w.mSession, w);
9482                if (!displayList.contains(w.mDisplayContent)) {
9483                    displayList.add(w.mDisplayContent);
9484                }
9485            }
9486
9487            for (DisplayContent displayContent : displayList) {
9488                assignLayersLocked(displayContent.getWindowList());
9489                displayContent.layoutNeeded = true;
9490            }
9491        }
9492
9493        // Check to see if we are now in a state where the screen should
9494        // be enabled, because the window obscured flags have changed.
9495        enableScreenIfNeededLocked();
9496
9497        updateLayoutToAnimationLocked();
9498
9499        if (DEBUG_WINDOW_TRACE) {
9500            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
9501                    + mAnimator.mAnimating);
9502        }
9503    }
9504
9505    private int toBrightnessOverride(float value) {
9506        return (int)(value * PowerManager.BRIGHTNESS_ON);
9507    }
9508
9509    void checkDrawnWindowsLocked() {
9510        if (mWaitingForDrawn.size() > 0) {
9511            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
9512                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
9513                WindowState win = pair.first;
9514                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
9515                //        + win.mRemoved + " visible=" + win.isVisibleLw()
9516                //        + " shown=" + win.mSurfaceShown);
9517                if (win.mRemoved || !win.isVisibleLw()) {
9518                    // Window has been removed or made invisible; no draw
9519                    // will now happen, so stop waiting.
9520                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
9521                    try {
9522                        pair.second.sendResult(null);
9523                    } catch (RemoteException e) {
9524                    }
9525                    mWaitingForDrawn.remove(pair);
9526                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9527                } else if (win.mWinAnimator.mSurfaceShown) {
9528                    // Window is now drawn (and shown).
9529                    try {
9530                        pair.second.sendResult(null);
9531                    } catch (RemoteException e) {
9532                    }
9533                    mWaitingForDrawn.remove(pair);
9534                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9535                }
9536            }
9537        }
9538    }
9539
9540    public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
9541        if (token != null && callback != null) {
9542            synchronized (mWindowMap) {
9543                WindowState win = windowForClientLocked(null, token, true);
9544                if (win != null) {
9545                    Pair<WindowState, IRemoteCallback> pair =
9546                            new Pair<WindowState, IRemoteCallback>(win, callback);
9547                    Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9548                    mH.sendMessageDelayed(m, 2000);
9549                    mWaitingForDrawn.add(pair);
9550                    checkDrawnWindowsLocked();
9551                    return true;
9552                }
9553            }
9554        }
9555        return false;
9556    }
9557
9558    void setHoldScreenLocked(final Session newHoldScreen) {
9559        final boolean hold = newHoldScreen != null;
9560
9561        if (hold && mHoldingScreenOn != newHoldScreen) {
9562            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
9563        }
9564        mHoldingScreenOn = newHoldScreen;
9565
9566        final boolean state = mHoldingScreenWakeLock.isHeld();
9567        if (hold != state) {
9568            if (hold) {
9569                mHoldingScreenWakeLock.acquire();
9570                mPolicy.keepScreenOnStartedLw();
9571            } else {
9572                mPolicy.keepScreenOnStoppedLw();
9573                mHoldingScreenWakeLock.release();
9574            }
9575        }
9576    }
9577
9578    @Override
9579    public void requestTraversal() {
9580        synchronized (mWindowMap) {
9581            requestTraversalLocked();
9582        }
9583    }
9584
9585    void requestTraversalLocked() {
9586        if (!mTraversalScheduled) {
9587            mTraversalScheduled = true;
9588            mH.sendEmptyMessage(H.DO_TRAVERSAL);
9589        }
9590    }
9591
9592    /** Note that Locked in this case is on mLayoutToAnim */
9593    void scheduleAnimationLocked() {
9594        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
9595        if (!layoutToAnim.mAnimationScheduled) {
9596            layoutToAnim.mAnimationScheduled = true;
9597            mChoreographer.postCallback(
9598                    Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
9599        }
9600    }
9601
9602    void updateLayoutToAnimationLocked() {
9603        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
9604        synchronized (layoutToAnim) {
9605            // Copy local params to transfer params.
9606            SparseArray<WinAnimatorList> allWinAnimatorLists = layoutToAnim.mWinAnimatorLists;
9607            allWinAnimatorLists.clear();
9608            DisplayContentsIterator iterator = new DisplayContentsIterator();
9609            while (iterator.hasNext()) {
9610                final DisplayContent displayContent = iterator.next();
9611                WinAnimatorList winAnimatorList = new WinAnimatorList();
9612                final WindowList windows = displayContent.getWindowList();
9613                int N = windows.size();
9614                for (int i = 0; i < N; i++) {
9615                    final WindowStateAnimator winAnimator = windows.get(i).mWinAnimator;
9616                    if (winAnimator.mSurface != null) {
9617                        winAnimatorList.add(winAnimator);
9618                    }
9619                }
9620                allWinAnimatorLists.put(displayContent.getDisplayId(), winAnimatorList);
9621            }
9622
9623            layoutToAnim.mWallpaperTarget = mWallpaperTarget;
9624            layoutToAnim.mLowerWallpaperTarget = mLowerWallpaperTarget;
9625            layoutToAnim.mUpperWallpaperTarget = mUpperWallpaperTarget;
9626
9627            final ArrayList<AppWindowAnimParams> paramList = layoutToAnim.mAppWindowAnimParams;
9628            paramList.clear();
9629            int N = mAnimatingAppTokens.size();
9630            for (int i = 0; i < N; i++) {
9631                paramList.add(new AppWindowAnimParams(mAnimatingAppTokens.get(i).mAppAnimator));
9632            }
9633
9634            layoutToAnim.mParamsModified = true;
9635            scheduleAnimationLocked();
9636        }
9637    }
9638
9639    void updateLayoutToAnimWallpaperTokens() {
9640        synchronized(mLayoutToAnim) {
9641            mLayoutToAnim.mWallpaperTokens = new ArrayList<WindowToken>(mWallpaperTokens);
9642            mLayoutToAnim.mChanges |= LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED;
9643        }
9644    }
9645
9646    void setAnimDimParams(int displayId, DimAnimator.Parameters params) {
9647        synchronized (mLayoutToAnim) {
9648            mLayoutToAnim.mDimParams.put(displayId, params);
9649            scheduleAnimationLocked();
9650        }
9651    }
9652
9653    void startDimmingLocked(final WindowStateAnimator winAnimator, final float target,
9654                      final int width, final int height) {
9655        setAnimDimParams(winAnimator.mWin.getDisplayId(),
9656                new DimAnimator.Parameters(winAnimator, width, height, target));
9657    }
9658
9659    void stopDimmingLocked(int displayId) {
9660        setAnimDimParams(displayId, null);
9661    }
9662
9663    private boolean needsLayout() {
9664        DisplayContentsIterator iterator = new DisplayContentsIterator();
9665        while (iterator.hasNext()) {
9666            if (iterator.next().layoutNeeded) {
9667                return true;
9668            }
9669        }
9670        return false;
9671    }
9672
9673    private boolean copyAnimToLayoutParamsLocked() {
9674        boolean doRequest = false;
9675        final WindowAnimator.AnimatorToLayoutParams animToLayout = mAnimator.mAnimToLayout;
9676        synchronized (animToLayout) {
9677            animToLayout.mUpdateQueued = false;
9678            final int bulkUpdateParams = animToLayout.mBulkUpdateParams;
9679            // TODO(cmautner): As the number of bits grows, use masks of bit groups to
9680            //  eliminate unnecessary tests.
9681            if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
9682                mInnerFields.mUpdateRotation = true;
9683                doRequest = true;
9684            }
9685            if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
9686                mInnerFields.mWallpaperMayChange = true;
9687                doRequest = true;
9688            }
9689            if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
9690                mInnerFields.mWallpaperForceHidingChanged = true;
9691                doRequest = true;
9692            }
9693            if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
9694                mInnerFields.mOrientationChangeComplete = false;
9695            } else {
9696                mInnerFields.mOrientationChangeComplete = true;
9697                if (mWindowsFreezingScreen) {
9698                    doRequest = true;
9699                }
9700            }
9701            if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
9702                mTurnOnScreen = true;
9703            }
9704
9705            SparseIntArray pendingLayouts = animToLayout.mPendingLayoutChanges;
9706            final int count = pendingLayouts.size();
9707            if (count > 0) {
9708                doRequest = true;
9709            }
9710            for (int i = 0; i < count; ++i) {
9711                final DisplayContent displayContent =
9712                        getDisplayContentLocked(pendingLayouts.keyAt(i));
9713                displayContent.pendingLayoutChanges |= pendingLayouts.valueAt(i);
9714            }
9715
9716            mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper;
9717        }
9718        return doRequest;
9719    }
9720
9721    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
9722                                           boolean secure) {
9723        final Surface surface = winAnimator.mSurface;
9724        boolean leakedSurface = false;
9725        boolean killedApps = false;
9726
9727        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
9728                winAnimator.mSession.mPid, operation);
9729
9730        if (mForceRemoves == null) {
9731            mForceRemoves = new ArrayList<WindowState>();
9732        }
9733
9734        long callingIdentity = Binder.clearCallingIdentity();
9735        try {
9736            // There was some problem...   first, do a sanity check of the
9737            // window list to make sure we haven't left any dangling surfaces
9738            // around.
9739
9740            AllWindowsIterator iterator = new AllWindowsIterator();
9741            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
9742            while (iterator.hasNext()) {
9743                WindowState ws = iterator.next();
9744                WindowStateAnimator wsa = ws.mWinAnimator;
9745                if (wsa.mSurface != null) {
9746                    if (!mSessions.contains(wsa.mSession)) {
9747                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
9748                                + ws + " surface=" + wsa.mSurface
9749                                + " token=" + ws.mToken
9750                                + " pid=" + ws.mSession.mPid
9751                                + " uid=" + ws.mSession.mUid);
9752                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9753                        wsa.mSurface.destroy();
9754                        wsa.mSurfaceShown = false;
9755                        wsa.mSurface = null;
9756                        ws.mHasSurface = false;
9757                        mForceRemoves.add(ws);
9758                        leakedSurface = true;
9759                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
9760                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
9761                                + ws + " surface=" + wsa.mSurface
9762                                + " token=" + ws.mAppToken);
9763                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9764                        wsa.mSurface.destroy();
9765                        wsa.mSurfaceShown = false;
9766                        wsa.mSurface = null;
9767                        ws.mHasSurface = false;
9768                        leakedSurface = true;
9769                    }
9770                }
9771            }
9772
9773            if (!leakedSurface) {
9774                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
9775                SparseIntArray pidCandidates = new SparseIntArray();
9776                iterator = new AllWindowsIterator();
9777                while (iterator.hasNext()) {
9778                    WindowState ws = iterator.next();
9779                    if (mForceRemoves.contains(ws)) {
9780                        continue;
9781                    }
9782                    WindowStateAnimator wsa = ws.mWinAnimator;
9783                    if (wsa.mSurface != null) {
9784                        pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
9785                    }
9786                }
9787                if (pidCandidates.size() > 0) {
9788                    int[] pids = new int[pidCandidates.size()];
9789                    for (int i=0; i<pids.length; i++) {
9790                        pids[i] = pidCandidates.keyAt(i);
9791                    }
9792                    try {
9793                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
9794                            killedApps = true;
9795                        }
9796                    } catch (RemoteException e) {
9797                    }
9798                }
9799            }
9800
9801            if (leakedSurface || killedApps) {
9802                // We managed to reclaim some memory, so get rid of the trouble
9803                // surface and ask the app to request another one.
9804                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9805                if (surface != null) {
9806                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
9807                            "RECOVER DESTROY", null);
9808                    surface.destroy();
9809                    winAnimator.mSurfaceShown = false;
9810                    winAnimator.mSurface = null;
9811                    winAnimator.mWin.mHasSurface = false;
9812                }
9813
9814                try {
9815                    winAnimator.mWin.mClient.dispatchGetNewSurface();
9816                } catch (RemoteException e) {
9817                }
9818            }
9819        } finally {
9820            Binder.restoreCallingIdentity(callingIdentity);
9821        }
9822
9823        return leakedSurface || killedApps;
9824    }
9825
9826    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9827        WindowState newFocus = computeFocusedWindowLocked();
9828        if (mCurrentFocus != newFocus) {
9829            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
9830            // This check makes sure that we don't already have the focus
9831            // change message pending.
9832            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9833            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9834            if (localLOGV) Slog.v(
9835                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
9836            final WindowState oldFocus = mCurrentFocus;
9837            mCurrentFocus = newFocus;
9838            mAnimator.setCurrentFocus(newFocus);
9839            mLosingFocus.remove(newFocus);
9840            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9841
9842            // TODO(multidisplay): Focused windows on default display only.
9843            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9844
9845            final WindowState imWindow = mInputMethodWindow;
9846            if (newFocus != imWindow && oldFocus != imWindow) {
9847                if (moveInputMethodWindowsIfNeededLocked(
9848                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
9849                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
9850                    displayContent.layoutNeeded = true;
9851                }
9852                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9853                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9854                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9855                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9856                    // Client will do the layout, but we need to assign layers
9857                    // for handleNewWindowLocked() below.
9858                    assignLayersLocked(displayContent.getWindowList());
9859                }
9860            }
9861
9862            if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9863                // The change in focus caused us to need to do a layout.  Okay.
9864                displayContent.layoutNeeded = true;
9865                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9866                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9867                }
9868            }
9869
9870            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9871                // If we defer assigning layers, then the caller is responsible for
9872                // doing this part.
9873                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9874            }
9875
9876            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
9877            return true;
9878        }
9879        return false;
9880    }
9881
9882    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9883        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9884    }
9885
9886    private WindowState computeFocusedWindowLocked() {
9887        if (mAnimator.mUniverseBackground != null
9888                && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) {
9889            return mAnimator.mUniverseBackground.mWin;
9890        }
9891
9892        final int displayCount = mDisplayContents.size();
9893        for (int i = 0; i < displayCount; i++) {
9894            final DisplayContent displayContent = mDisplayContents.valueAt(i);
9895            WindowState win = findFocusedWindowLocked(displayContent);
9896            if (win != null) {
9897                return win;
9898            }
9899        }
9900        return null;
9901    }
9902
9903    private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
9904        int nextAppIndex = mAppTokens.size()-1;
9905        WindowToken nextApp = nextAppIndex >= 0 ? mAppTokens.get(nextAppIndex) : null;
9906
9907        final WindowList windows = displayContent.getWindowList();
9908        for (int i = windows.size() - 1; i >= 0; i--) {
9909            final WindowState win = windows.get(i);
9910
9911            if (localLOGV || DEBUG_FOCUS) Slog.v(
9912                TAG, "Looking for focus: " + i
9913                + " = " + win
9914                + ", flags=" + win.mAttrs.flags
9915                + ", canReceive=" + win.canReceiveKeys());
9916
9917            AppWindowToken thisApp = win.mAppToken;
9918
9919            // If this window's application has been removed, just skip it.
9920            if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
9921                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping app because " + (thisApp.removed
9922                        ? "removed" : "sendingToBottom"));
9923                continue;
9924            }
9925
9926            // If there is a focused app, don't allow focus to go to any
9927            // windows below it.  If this is an application window, step
9928            // through the app tokens until we find its app.
9929            if (thisApp != null && nextApp != null && thisApp != nextApp
9930                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
9931                int origAppIndex = nextAppIndex;
9932                while (nextAppIndex > 0) {
9933                    if (nextApp == mFocusedApp) {
9934                        // Whoops, we are below the focused app...  no focus
9935                        // for you!
9936                        if (localLOGV || DEBUG_FOCUS) Slog.v(
9937                            TAG, "Reached focused app: " + mFocusedApp);
9938                        return null;
9939                    }
9940                    nextAppIndex--;
9941                    nextApp = mAppTokens.get(nextAppIndex);
9942                    if (nextApp == thisApp) {
9943                        break;
9944                    }
9945                }
9946                if (thisApp != nextApp) {
9947                    // Uh oh, the app token doesn't exist!  This shouldn't
9948                    // happen, but if it does we can get totally hosed...
9949                    // so restart at the original app.
9950                    nextAppIndex = origAppIndex;
9951                    nextApp = mAppTokens.get(nextAppIndex);
9952                }
9953            }
9954
9955            // Dispatch to this window if it is wants key events.
9956            if (win.canReceiveKeys()) {
9957                if (DEBUG_FOCUS) Slog.v(
9958                        TAG, "Found focus @ " + i + " = " + win);
9959                return win;
9960            }
9961        }
9962        return null;
9963    }
9964
9965    private void startFreezingDisplayLocked(boolean inTransaction,
9966            int exitAnim, int enterAnim) {
9967        if (mDisplayFrozen) {
9968            return;
9969        }
9970
9971        if (!mDisplayReady || !mPolicy.isScreenOnFully()) {
9972            // No need to freeze the screen before the system is ready or if
9973            // the screen is off.
9974            return;
9975        }
9976
9977        mScreenFrozenLock.acquire();
9978
9979        mDisplayFrozen = true;
9980
9981        mInputMonitor.freezeInputDispatchingLw();
9982
9983        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
9984            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
9985            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
9986            mNextAppTransitionPackage = null;
9987            mNextAppTransitionThumbnail = null;
9988            mAppTransitionReady = true;
9989        }
9990
9991        if (PROFILE_ORIENTATION) {
9992            File file = new File("/data/system/frozen");
9993            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9994        }
9995
9996        if (CUSTOM_SCREEN_ROTATION) {
9997            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9998            final int displayId = displayContent.getDisplayId();
9999            ScreenRotationAnimation screenRotationAnimation =
10000                    mAnimator.getScreenRotationAnimationLocked(displayId);
10001            if (screenRotationAnimation != null) {
10002                screenRotationAnimation.kill();
10003            }
10004
10005            // TODO(multidisplay): rotation on main screen only.
10006            final Display display = displayContent.getDisplay();
10007            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
10008            screenRotationAnimation = new ScreenRotationAnimation(mContext,
10009                    display, mFxSession, inTransaction, displayInfo.logicalWidth,
10010                    displayInfo.logicalHeight, display.getRotation(),
10011                    exitAnim, enterAnim);
10012            mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
10013        }
10014    }
10015
10016    private void stopFreezingDisplayLocked() {
10017        if (!mDisplayFrozen) {
10018            return;
10019        }
10020
10021        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
10022                || mClientFreezingScreen) {
10023            if (DEBUG_ORIENTATION) Slog.d(TAG,
10024                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
10025                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
10026                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
10027                + ", mClientFreezingScreen=" + mClientFreezingScreen);
10028            return;
10029        }
10030
10031        mDisplayFrozen = false;
10032        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
10033        mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
10034        if (PROFILE_ORIENTATION) {
10035            Debug.stopMethodTracing();
10036        }
10037
10038        boolean updateRotation = false;
10039
10040        final DisplayContent displayContent = getDefaultDisplayContentLocked();
10041        final int displayId = displayContent.getDisplayId();
10042        ScreenRotationAnimation screenRotationAnimation =
10043                mAnimator.getScreenRotationAnimationLocked(displayId);
10044        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
10045                && screenRotationAnimation.hasScreenshot()) {
10046            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
10047            // TODO(multidisplay): rotation on main screen only.
10048            DisplayInfo displayInfo = displayContent.getDisplayInfo();
10049            if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
10050                    mTransitionAnimationScale, displayInfo.logicalWidth,
10051                        displayInfo.logicalHeight)) {
10052                updateLayoutToAnimationLocked();
10053            } else {
10054                screenRotationAnimation.kill();
10055                screenRotationAnimation = null;
10056                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
10057                updateRotation = true;
10058            }
10059        } else {
10060            if (screenRotationAnimation != null) {
10061                screenRotationAnimation.kill();
10062                screenRotationAnimation = null;
10063                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
10064            }
10065            updateRotation = true;
10066        }
10067
10068        mInputMonitor.thawInputDispatchingLw();
10069
10070        boolean configChanged;
10071
10072        // While the display is frozen we don't re-compute the orientation
10073        // to avoid inconsistent states.  However, something interesting
10074        // could have actually changed during that time so re-evaluate it
10075        // now to catch that.
10076        configChanged = updateOrientationFromAppTokensLocked(false);
10077
10078        // A little kludge: a lot could have happened while the
10079        // display was frozen, so now that we are coming back we
10080        // do a gc so that any remote references the system
10081        // processes holds on others can be released if they are
10082        // no longer needed.
10083        mH.removeMessages(H.FORCE_GC);
10084        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
10085                2000);
10086
10087        mScreenFrozenLock.release();
10088
10089        if (updateRotation) {
10090            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
10091            configChanged |= updateRotationUncheckedLocked(false);
10092        }
10093
10094        if (configChanged) {
10095            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
10096        }
10097    }
10098
10099    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
10100            DisplayMetrics dm) {
10101        if (index < tokens.length) {
10102            String str = tokens[index];
10103            if (str != null && str.length() > 0) {
10104                try {
10105                    int val = Integer.parseInt(str);
10106                    return val;
10107                } catch (Exception e) {
10108                }
10109            }
10110        }
10111        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
10112            return defDps;
10113        }
10114        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
10115        return val;
10116    }
10117
10118    void createWatermarkInTransaction() {
10119        if (mWatermark != null) {
10120            return;
10121        }
10122
10123        File file = new File("/system/etc/setup.conf");
10124        FileInputStream in = null;
10125        try {
10126            in = new FileInputStream(file);
10127            DataInputStream ind = new DataInputStream(in);
10128            String line = ind.readLine();
10129            if (line != null) {
10130                String[] toks = line.split("%");
10131                if (toks != null && toks.length > 0) {
10132                    mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
10133                            mRealDisplayMetrics, mFxSession, toks);
10134                }
10135            }
10136        } catch (FileNotFoundException e) {
10137        } catch (IOException e) {
10138        } finally {
10139            if (in != null) {
10140                try {
10141                    in.close();
10142                } catch (IOException e) {
10143                }
10144            }
10145        }
10146    }
10147
10148    @Override
10149    public void statusBarVisibilityChanged(int visibility) {
10150        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
10151                != PackageManager.PERMISSION_GRANTED) {
10152            throw new SecurityException("Caller does not hold permission "
10153                    + android.Manifest.permission.STATUS_BAR);
10154        }
10155
10156        synchronized (mWindowMap) {
10157            mLastStatusBarVisibility = visibility;
10158            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
10159            updateStatusBarVisibilityLocked(visibility);
10160        }
10161    }
10162
10163    // TOOD(multidisplay): StatusBar on multiple screens?
10164    void updateStatusBarVisibilityLocked(int visibility) {
10165        mInputManager.setSystemUiVisibility(visibility);
10166        final WindowList windows = getDefaultWindowListLocked();
10167        final int N = windows.size();
10168        for (int i = 0; i < N; i++) {
10169            WindowState ws = windows.get(i);
10170            try {
10171                int curValue = ws.mSystemUiVisibility;
10172                int diff = curValue ^ visibility;
10173                // We are only interested in differences of one of the
10174                // clearable flags...
10175                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
10176                // ...if it has actually been cleared.
10177                diff &= ~visibility;
10178                int newValue = (curValue&~diff) | (visibility&diff);
10179                if (newValue != curValue) {
10180                    ws.mSeq++;
10181                    ws.mSystemUiVisibility = newValue;
10182                }
10183                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
10184                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
10185                            visibility, newValue, diff);
10186                }
10187            } catch (RemoteException e) {
10188                // so sorry
10189            }
10190        }
10191    }
10192
10193    @Override
10194    public void reevaluateStatusBarVisibility() {
10195        synchronized (mWindowMap) {
10196            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
10197            updateStatusBarVisibilityLocked(visibility);
10198            performLayoutAndPlaceSurfacesLocked();
10199        }
10200    }
10201
10202    @Override
10203    public FakeWindow addFakeWindow(Looper looper,
10204            InputEventReceiver.Factory inputEventReceiverFactory,
10205            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
10206            boolean hasFocus, boolean touchFullscreen) {
10207        synchronized (mWindowMap) {
10208            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
10209                    name, windowType,
10210                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
10211            int i=0;
10212            while (i<mFakeWindows.size()) {
10213                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
10214                    break;
10215                }
10216            }
10217            mFakeWindows.add(i, fw);
10218            mInputMonitor.updateInputWindowsLw(true);
10219            return fw;
10220        }
10221    }
10222
10223    boolean removeFakeWindowLocked(FakeWindow window) {
10224        synchronized (mWindowMap) {
10225            if (mFakeWindows.remove(window)) {
10226                mInputMonitor.updateInputWindowsLw(true);
10227                return true;
10228            }
10229            return false;
10230        }
10231    }
10232
10233    // It is assumed that this method is called only by InputMethodManagerService.
10234    public void saveLastInputMethodWindowForTransition() {
10235        synchronized (mWindowMap) {
10236            // TODO(multidisplay): Pass in the displayID.
10237            DisplayContent displayContent = getDefaultDisplayContentLocked();
10238            if (mInputMethodWindow != null) {
10239                mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
10240            }
10241        }
10242    }
10243
10244    @Override
10245    public boolean hasNavigationBar() {
10246        return mPolicy.hasNavigationBar();
10247    }
10248
10249    public void lockNow(Bundle options) {
10250        mPolicy.lockNow(options);
10251    }
10252
10253    void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
10254        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
10255        mPolicy.dump("    ", pw, args);
10256    }
10257
10258    void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
10259        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
10260        if (mTokenMap.size() > 0) {
10261            pw.println("  All tokens:");
10262            Iterator<WindowToken> it = mTokenMap.values().iterator();
10263            while (it.hasNext()) {
10264                WindowToken token = it.next();
10265                pw.print("  Token "); pw.print(token.token);
10266                if (dumpAll) {
10267                    pw.println(':');
10268                    token.dump(pw, "    ");
10269                } else {
10270                    pw.println();
10271                }
10272            }
10273        }
10274        if (mWallpaperTokens.size() > 0) {
10275            pw.println();
10276            pw.println("  Wallpaper tokens:");
10277            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
10278                WindowToken token = mWallpaperTokens.get(i);
10279                pw.print("  Wallpaper #"); pw.print(i);
10280                        pw.print(' '); pw.print(token);
10281                if (dumpAll) {
10282                    pw.println(':');
10283                    token.dump(pw, "    ");
10284                } else {
10285                    pw.println();
10286                }
10287            }
10288        }
10289        if (mAppTokens.size() > 0) {
10290            pw.println();
10291            pw.println("  Application tokens in Z order:");
10292            for (int i=mAppTokens.size()-1; i>=0; i--) {
10293                pw.print("  App #"); pw.print(i); pw.println(": ");
10294                        mAppTokens.get(i).dump(pw, "    ");
10295            }
10296        }
10297        if (mFinishedStarting.size() > 0) {
10298            pw.println();
10299            pw.println("  Finishing start of application tokens:");
10300            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
10301                WindowToken token = mFinishedStarting.get(i);
10302                pw.print("  Finished Starting #"); 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 (mExitingTokens.size() > 0) {
10313            pw.println();
10314            pw.println("  Exiting tokens:");
10315            for (int i=mExitingTokens.size()-1; i>=0; i--) {
10316                WindowToken token = mExitingTokens.get(i);
10317                pw.print("  Exiting #"); pw.print(i);
10318                        pw.print(' '); pw.print(token);
10319                if (dumpAll) {
10320                    pw.println(':');
10321                    token.dump(pw, "    ");
10322                } else {
10323                    pw.println();
10324                }
10325            }
10326        }
10327        if (mExitingAppTokens.size() > 0) {
10328            pw.println();
10329            pw.println("  Exiting application tokens:");
10330            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
10331                WindowToken token = mExitingAppTokens.get(i);
10332                pw.print("  Exiting App #"); pw.print(i);
10333                        pw.print(' '); pw.print(token);
10334                if (dumpAll) {
10335                    pw.println(':');
10336                    token.dump(pw, "    ");
10337                } else {
10338                    pw.println();
10339                }
10340            }
10341        }
10342        if (mAppTransitionRunning && mAnimatingAppTokens.size() > 0) {
10343            pw.println();
10344            pw.println("  Application tokens during animation:");
10345            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
10346                WindowToken token = mAnimatingAppTokens.get(i);
10347                pw.print("  App moving to bottom #"); pw.print(i);
10348                        pw.print(' '); pw.print(token);
10349                if (dumpAll) {
10350                    pw.println(':');
10351                    token.dump(pw, "    ");
10352                } else {
10353                    pw.println();
10354                }
10355            }
10356        }
10357        if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
10358            pw.println();
10359            if (mOpeningApps.size() > 0) {
10360                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
10361            }
10362            if (mClosingApps.size() > 0) {
10363                pw.print("  mClosingApps="); pw.println(mClosingApps);
10364            }
10365        }
10366    }
10367
10368    void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
10369        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
10370        if (mSessions.size() > 0) {
10371            Iterator<Session> it = mSessions.iterator();
10372            while (it.hasNext()) {
10373                Session s = it.next();
10374                pw.print("  Session "); pw.print(s); pw.println(':');
10375                s.dump(pw, "    ");
10376            }
10377        }
10378    }
10379
10380    void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
10381            ArrayList<WindowState> windows) {
10382        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
10383        dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
10384    }
10385
10386    void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
10387            ArrayList<WindowState> windows) {
10388        int j = 0;
10389        final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10390        while (iterator.hasNext()) {
10391            final WindowState w = iterator.next();
10392            if (windows == null || windows.contains(w)) {
10393                pw.print("  Window #"); pw.print(j++); pw.print(' ');
10394                        pw.print(w); pw.println(":");
10395                w.dump(pw, "    ", dumpAll || windows != null);
10396            }
10397        }
10398        if (mInputMethodDialogs.size() > 0) {
10399            pw.println();
10400            pw.println("  Input method dialogs:");
10401            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
10402                WindowState w = mInputMethodDialogs.get(i);
10403                if (windows == null || windows.contains(w)) {
10404                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
10405                }
10406            }
10407        }
10408        if (mPendingRemove.size() > 0) {
10409            pw.println();
10410            pw.println("  Remove pending for:");
10411            for (int i=mPendingRemove.size()-1; i>=0; i--) {
10412                WindowState w = mPendingRemove.get(i);
10413                if (windows == null || windows.contains(w)) {
10414                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
10415                            pw.print(w);
10416                    if (dumpAll) {
10417                        pw.println(":");
10418                        w.dump(pw, "    ", true);
10419                    } else {
10420                        pw.println();
10421                    }
10422                }
10423            }
10424        }
10425        if (mForceRemoves != null && mForceRemoves.size() > 0) {
10426            pw.println();
10427            pw.println("  Windows force removing:");
10428            for (int i=mForceRemoves.size()-1; i>=0; i--) {
10429                WindowState w = mForceRemoves.get(i);
10430                pw.print("  Removing #"); pw.print(i); pw.print(' ');
10431                        pw.print(w);
10432                if (dumpAll) {
10433                    pw.println(":");
10434                    w.dump(pw, "    ", true);
10435                } else {
10436                    pw.println();
10437                }
10438            }
10439        }
10440        if (mDestroySurface.size() > 0) {
10441            pw.println();
10442            pw.println("  Windows waiting to destroy their surface:");
10443            for (int i=mDestroySurface.size()-1; i>=0; i--) {
10444                WindowState w = mDestroySurface.get(i);
10445                if (windows == null || windows.contains(w)) {
10446                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
10447                            pw.print(w);
10448                    if (dumpAll) {
10449                        pw.println(":");
10450                        w.dump(pw, "    ", true);
10451                    } else {
10452                        pw.println();
10453                    }
10454                }
10455            }
10456        }
10457        if (mLosingFocus.size() > 0) {
10458            pw.println();
10459            pw.println("  Windows losing focus:");
10460            for (int i=mLosingFocus.size()-1; i>=0; i--) {
10461                WindowState w = mLosingFocus.get(i);
10462                if (windows == null || windows.contains(w)) {
10463                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
10464                            pw.print(w);
10465                    if (dumpAll) {
10466                        pw.println(":");
10467                        w.dump(pw, "    ", true);
10468                    } else {
10469                        pw.println();
10470                    }
10471                }
10472            }
10473        }
10474        if (mResizingWindows.size() > 0) {
10475            pw.println();
10476            pw.println("  Windows waiting to resize:");
10477            for (int i=mResizingWindows.size()-1; i>=0; i--) {
10478                WindowState w = mResizingWindows.get(i);
10479                if (windows == null || windows.contains(w)) {
10480                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
10481                            pw.print(w);
10482                    if (dumpAll) {
10483                        pw.println(":");
10484                        w.dump(pw, "    ", true);
10485                    } else {
10486                        pw.println();
10487                    }
10488                }
10489            }
10490        }
10491        if (mWaitingForDrawn.size() > 0) {
10492            pw.println();
10493            pw.println("  Clients waiting for these windows to be drawn:");
10494            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
10495                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
10496                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
10497                        pw.print(": "); pw.println(pair.second);
10498            }
10499        }
10500        pw.println("  DisplayContents");
10501        if (mDisplayReady) {
10502            DisplayContentsIterator dCIterator = new DisplayContentsIterator();
10503            while (dCIterator.hasNext()) {
10504                dCIterator.next().dump("    ", pw);
10505            }
10506        } else {
10507            pw.println("  NO DISPLAY");
10508        }
10509        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
10510        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
10511        if (mLastFocus != mCurrentFocus) {
10512            pw.print("  mLastFocus="); pw.println(mLastFocus);
10513        }
10514        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
10515        if (mInputMethodTarget != null) {
10516            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
10517        }
10518        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
10519                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
10520        if (dumpAll) {
10521            pw.print("  mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
10522                    pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
10523                    pw.print(" mScreenRecr="); pw.println(mScreenRect.toShortString());
10524            if (mLastStatusBarVisibility != 0) {
10525                pw.print("  mLastStatusBarVisibility=0x");
10526                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
10527            }
10528            if (mInputMethodWindow != null) {
10529                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
10530            }
10531            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
10532            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
10533                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
10534                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
10535            }
10536            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
10537                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
10538            if (mInputMethodAnimLayerAdjustment != 0 ||
10539                    mWallpaperAnimLayerAdjustment != 0) {
10540                pw.print("  mInputMethodAnimLayerAdjustment=");
10541                        pw.print(mInputMethodAnimLayerAdjustment);
10542                        pw.print("  mWallpaperAnimLayerAdjustment=");
10543                        pw.println(mWallpaperAnimLayerAdjustment);
10544            }
10545            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
10546                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
10547            if (needsLayout()) {
10548                pw.print("  layoutNeeded on displays=");
10549                DisplayContentsIterator dcIterator = new DisplayContentsIterator();
10550                while (dcIterator.hasNext()) {
10551                    final DisplayContent displayContent = dcIterator.next();
10552                    if (displayContent.layoutNeeded) {
10553                        pw.print(displayContent.getDisplayId());
10554                    }
10555                }
10556                pw.println();
10557            }
10558            pw.print("  mTransactionSequence="); pw.println(mTransactionSequence);
10559            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
10560                    pw.print(" windows="); pw.print(mWindowsFreezingScreen);
10561                    pw.print(" client="); pw.print(mClientFreezingScreen);
10562                    pw.print(" apps="); pw.print(mAppsFreezingScreen);
10563                    pw.print(" waitingForConfig="); pw.println(mWaitingForConfig);
10564            pw.print("  mRotation="); pw.print(mRotation);
10565                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
10566            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
10567                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
10568            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
10569            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
10570                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
10571                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
10572            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
10573                    pw.print(" mNextAppTransition=0x");
10574                    pw.print(Integer.toHexString(mNextAppTransition));
10575                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
10576            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
10577                    pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout);
10578            if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) {
10579                pw.print("  mNextAppTransitionType="); pw.println(mNextAppTransitionType);
10580            }
10581            switch (mNextAppTransitionType) {
10582                case ActivityOptions.ANIM_CUSTOM:
10583                    pw.print("  mNextAppTransitionPackage=");
10584                            pw.println(mNextAppTransitionPackage);
10585                    pw.print("  mNextAppTransitionEnter=0x");
10586                            pw.print(Integer.toHexString(mNextAppTransitionEnter));
10587                            pw.print(" mNextAppTransitionExit=0x");
10588                            pw.println(Integer.toHexString(mNextAppTransitionExit));
10589                    break;
10590                case ActivityOptions.ANIM_SCALE_UP:
10591                    pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
10592                            pw.print(" mNextAppTransitionStartY=");
10593                            pw.println(mNextAppTransitionStartY);
10594                    pw.print("  mNextAppTransitionStartWidth=");
10595                            pw.print(mNextAppTransitionStartWidth);
10596                            pw.print(" mNextAppTransitionStartHeight=");
10597                            pw.println(mNextAppTransitionStartHeight);
10598                    break;
10599                case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP:
10600                case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN:
10601                    pw.print("  mNextAppTransitionThumbnail=");
10602                            pw.print(mNextAppTransitionThumbnail);
10603                            pw.print(" mNextAppTransitionStartX=");
10604                            pw.print(mNextAppTransitionStartX);
10605                            pw.print(" mNextAppTransitionStartY=");
10606                            pw.println(mNextAppTransitionStartY);
10607                    pw.print("  mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp);
10608                    break;
10609            }
10610            if (mNextAppTransitionCallback != null) {
10611                pw.print("  mNextAppTransitionCallback=");
10612                        pw.println(mNextAppTransitionCallback);
10613            }
10614            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
10615                    pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
10616            pw.println("  Window Animator:");
10617            mAnimator.dumpLocked(pw, "    ", dumpAll);
10618        }
10619    }
10620
10621    boolean dumpWindows(PrintWriter pw, String name, String[] args,
10622            int opti, boolean dumpAll) {
10623        WindowList windows = new WindowList();
10624        if ("visible".equals(name)) {
10625            synchronized(mWindowMap) {
10626                final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10627                while (iterator.hasNext()) {
10628                    final WindowState w = iterator.next();
10629                    if (w.mWinAnimator.mSurfaceShown) {
10630                        windows.add(w);
10631                    }
10632                }
10633            }
10634        } else {
10635            int objectId = 0;
10636            // See if this is an object ID.
10637            try {
10638                objectId = Integer.parseInt(name, 16);
10639                name = null;
10640            } catch (RuntimeException e) {
10641            }
10642            synchronized(mWindowMap) {
10643                final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10644                while (iterator.hasNext()) {
10645                    final WindowState w = iterator.next();
10646                    if (name != null) {
10647                        if (w.mAttrs.getTitle().toString().contains(name)) {
10648                            windows.add(w);
10649                        }
10650                    } else if (System.identityHashCode(w) == objectId) {
10651                        windows.add(w);
10652                    }
10653                }
10654            }
10655        }
10656
10657        if (windows.size() <= 0) {
10658            return false;
10659        }
10660
10661        synchronized(mWindowMap) {
10662            dumpWindowsLocked(pw, dumpAll, windows);
10663        }
10664        return true;
10665    }
10666
10667    void dumpLastANRLocked(PrintWriter pw) {
10668        pw.println("WINDOW MANAGER LAST ANR (dumpsys window lastanr)");
10669        if (mLastANRState == null) {
10670            pw.println("  <no ANR has occurred since boot>");
10671        } else {
10672            pw.println(mLastANRState);
10673        }
10674    }
10675
10676    /**
10677     * Saves information about the state of the window manager at
10678     * the time an ANR occurred before anything else in the system changes
10679     * in response.
10680     *
10681     * @param appWindowToken The application that ANR'd, may be null.
10682     * @param windowState The window that ANR'd, may be null.
10683     */
10684    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState) {
10685        StringWriter sw = new StringWriter();
10686        PrintWriter pw = new PrintWriter(sw);
10687        pw.println("  ANR time: " + DateFormat.getInstance().format(new Date()));
10688        if (appWindowToken != null) {
10689            pw.println("  Application at fault: " + appWindowToken.stringName);
10690        }
10691        if (windowState != null) {
10692            pw.println("  Window at fault: " + windowState.mAttrs.getTitle());
10693        }
10694        pw.println();
10695        dumpWindowsNoHeaderLocked(pw, true, null);
10696        pw.close();
10697        mLastANRState = sw.toString();
10698    }
10699
10700    @Override
10701    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
10702        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
10703                != PackageManager.PERMISSION_GRANTED) {
10704            pw.println("Permission Denial: can't dump WindowManager from from pid="
10705                    + Binder.getCallingPid()
10706                    + ", uid=" + Binder.getCallingUid());
10707            return;
10708        }
10709
10710        boolean dumpAll = false;
10711
10712        int opti = 0;
10713        while (opti < args.length) {
10714            String opt = args[opti];
10715            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
10716                break;
10717            }
10718            opti++;
10719            if ("-a".equals(opt)) {
10720                dumpAll = true;
10721            } else if ("-h".equals(opt)) {
10722                pw.println("Window manager dump options:");
10723                pw.println("  [-a] [-h] [cmd] ...");
10724                pw.println("  cmd may be one of:");
10725                pw.println("    l[astanr]: last ANR information");
10726                pw.println("    p[policy]: policy state");
10727                pw.println("    s[essions]: active sessions");
10728                pw.println("    t[okens]: token list");
10729                pw.println("    w[indows]: window list");
10730                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
10731                pw.println("    be a partial substring in a window name, a");
10732                pw.println("    Window hex object identifier, or");
10733                pw.println("    \"all\" for all windows, or");
10734                pw.println("    \"visible\" for the visible windows.");
10735                pw.println("  -a: include all available server state.");
10736                return;
10737            } else {
10738                pw.println("Unknown argument: " + opt + "; use -h for help");
10739            }
10740        }
10741
10742        // Is the caller requesting to dump a particular piece of data?
10743        if (opti < args.length) {
10744            String cmd = args[opti];
10745            opti++;
10746            if ("lastanr".equals(cmd) || "l".equals(cmd)) {
10747                synchronized(mWindowMap) {
10748                    dumpLastANRLocked(pw);
10749                }
10750                return;
10751            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
10752                synchronized(mWindowMap) {
10753                    dumpPolicyLocked(pw, args, true);
10754                }
10755                return;
10756            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
10757                synchronized(mWindowMap) {
10758                    dumpSessionsLocked(pw, true);
10759                }
10760                return;
10761            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
10762                synchronized(mWindowMap) {
10763                    dumpTokensLocked(pw, true);
10764                }
10765                return;
10766            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
10767                synchronized(mWindowMap) {
10768                    dumpWindowsLocked(pw, true, null);
10769                }
10770                return;
10771            } else if ("all".equals(cmd) || "a".equals(cmd)) {
10772                synchronized(mWindowMap) {
10773                    dumpWindowsLocked(pw, true, null);
10774                }
10775                return;
10776            } else {
10777                // Dumping a single name?
10778                if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
10779                    pw.println("Bad window command, or no windows match: " + cmd);
10780                    pw.println("Use -h for help.");
10781                }
10782                return;
10783            }
10784        }
10785
10786        synchronized(mWindowMap) {
10787            pw.println();
10788            if (dumpAll) {
10789                pw.println("-------------------------------------------------------------------------------");
10790            }
10791            dumpLastANRLocked(pw);
10792            pw.println();
10793            if (dumpAll) {
10794                pw.println("-------------------------------------------------------------------------------");
10795            }
10796            dumpPolicyLocked(pw, args, dumpAll);
10797            pw.println();
10798            if (dumpAll) {
10799                pw.println("-------------------------------------------------------------------------------");
10800            }
10801            dumpSessionsLocked(pw, dumpAll);
10802            pw.println();
10803            if (dumpAll) {
10804                pw.println("-------------------------------------------------------------------------------");
10805            }
10806            dumpTokensLocked(pw, dumpAll);
10807            pw.println();
10808            if (dumpAll) {
10809                pw.println("-------------------------------------------------------------------------------");
10810            }
10811            dumpWindowsLocked(pw, dumpAll, null);
10812        }
10813    }
10814
10815    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
10816    public void monitor() {
10817        synchronized (mWindowMap) { }
10818    }
10819
10820    public interface OnHardKeyboardStatusChangeListener {
10821        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
10822    }
10823
10824    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
10825        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
10826            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
10827                    Integer.toHexString(pendingLayoutChanges));
10828        }
10829    }
10830
10831    public void createDisplayContentLocked(final Display display) {
10832        if (display == null) {
10833            throw new IllegalArgumentException("getDisplayContent: display must not be null");
10834        }
10835        final DisplayContent displayContent = new DisplayContent(display);
10836        mDisplayContents.put(display.getDisplayId(), displayContent);
10837    }
10838
10839    public DisplayContent getDisplayContentLocked(final int displayId) {
10840        DisplayContent displayContent = mDisplayContents.get(displayId);
10841        if (displayContent == null) {
10842            displayContent = new DisplayContent(mDisplayManager.getDisplay(displayId));
10843            mDisplayContents.put(displayId, displayContent);
10844        }
10845        return displayContent;
10846    }
10847
10848    class DisplayContentsIterator implements Iterator<DisplayContent> {
10849        private int cur;
10850
10851        @Override
10852        public boolean hasNext() {
10853            return cur < mDisplayContents.size();
10854        }
10855
10856        @Override
10857        public DisplayContent next() {
10858            if (hasNext()) {
10859                return mDisplayContents.valueAt(cur++);
10860            }
10861            throw new NoSuchElementException();
10862        }
10863
10864        @Override
10865        public void remove() {
10866            throw new IllegalArgumentException("AllDisplayContentIterator.remove not implemented");
10867        }
10868    }
10869
10870    final static boolean REVERSE_ITERATOR = true;
10871    class AllWindowsIterator implements Iterator<WindowState> {
10872        private DisplayContent mDisplayContent;
10873        private DisplayContentsIterator mDisplayContentsIterator;
10874        private WindowList mWindowList;
10875        private int mWindowListIndex;
10876        private boolean mReverse;
10877
10878        AllWindowsIterator() {
10879            mDisplayContentsIterator = new DisplayContentsIterator();
10880            mDisplayContent = mDisplayContentsIterator.next();
10881            mWindowList = mDisplayContent.getWindowList();
10882        }
10883
10884        AllWindowsIterator(boolean reverse) {
10885            this();
10886            mReverse = reverse;
10887            mWindowListIndex = reverse ? mWindowList.size() - 1 : 0;
10888        }
10889
10890        @Override
10891        public boolean hasNext() {
10892            if (mReverse) {
10893                return mWindowListIndex >= 0;
10894            }
10895            return mWindowListIndex < mWindowList.size();
10896        }
10897
10898        @Override
10899        public WindowState next() {
10900            if (hasNext()) {
10901                WindowState win = mWindowList.get(mWindowListIndex);
10902                if (mReverse) {
10903                    mWindowListIndex--;
10904                    if (mWindowListIndex < 0 && mDisplayContentsIterator.hasNext()) {
10905                        mDisplayContent = mDisplayContentsIterator.next();
10906                        mWindowList = mDisplayContent.getWindowList();
10907                        mWindowListIndex = mWindowList.size() - 1;
10908                    }
10909                } else {
10910                    mWindowListIndex++;
10911                    if (mWindowListIndex >= mWindowList.size()
10912                            && mDisplayContentsIterator.hasNext()) {
10913                        mDisplayContent = mDisplayContentsIterator.next();
10914                        mWindowList = mDisplayContent.getWindowList();
10915                        mWindowListIndex = 0;
10916                    }
10917                }
10918                return win;
10919            }
10920            throw new NoSuchElementException();
10921        }
10922
10923        @Override
10924        public void remove() {
10925            throw new IllegalArgumentException("AllWindowsIterator.remove not implemented");
10926        }
10927    }
10928
10929    public DisplayContent getDefaultDisplayContentLocked() {
10930        return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
10931    }
10932
10933    public WindowList getDefaultWindowListLocked() {
10934        return getDefaultDisplayContentLocked().getWindowList();
10935    }
10936
10937    public DisplayInfo getDefaultDisplayInfoLocked() {
10938        return getDefaultDisplayContentLocked().getDisplayInfo();
10939    }
10940
10941    public WindowList getWindowListLocked(final Display display) {
10942        return getDisplayContentLocked(display.getDisplayId()).getWindowList();
10943    }
10944
10945    @Override
10946    public void onDisplayAdded(int displayId) {
10947        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
10948    }
10949
10950    private void handleDisplayAddedLocked(int displayId) {
10951        createDisplayContentLocked(mDisplayManager.getDisplay(displayId));
10952        displayReady(displayId);
10953    }
10954
10955    @Override
10956    public void onDisplayRemoved(int displayId) {
10957        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
10958    }
10959
10960    private void handleDisplayRemovedLocked(int displayId) {
10961        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10962        mDisplayContents.delete(displayId);
10963        WindowList windows = displayContent.getWindowList();
10964        while (!windows.isEmpty()) {
10965            final WindowState win = windows.get(windows.size() - 1);
10966            removeWindowLocked(win.mSession, win);
10967        }
10968        mAnimator.removeDisplayLocked(displayId);
10969    }
10970
10971    @Override
10972    public void onDisplayChanged(int displayId) {
10973        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
10974    }
10975
10976    private void handleDisplayChangedLocked(int displayId) {
10977        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10978        if (displayContent != null) {
10979            displayContent.updateDisplayInfo();
10980        }
10981    }
10982}
10983