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