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