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