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