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