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