WindowManagerService.java revision 42bf39edbdad19f51497938d0a3469dd772f19e8
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                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            final AppWindowToken newFocus;
3843            if (token == null) {
3844                if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
3845                newFocus = null;
3846            } else {
3847                newFocus = findAppWindowToken(token);
3848                if (newFocus == null) {
3849                    Slog.w(TAG, "Attempted to set focus to non-existing app token: " + token);
3850                }
3851                if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Set focused app to: " + newFocus
3852                        + " old focus=" + mFocusedApp + " moveFocusNow=" + moveFocusNow);
3853            }
3854
3855            final boolean changed = mFocusedApp != newFocus;
3856            if (changed) {
3857                mFocusedApp = newFocus;
3858                mInputMonitor.setFocusedAppLw(null);
3859            }
3860
3861            if (moveFocusNow && changed) {
3862                final long origId = Binder.clearCallingIdentity();
3863                updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
3864                Binder.restoreCallingIdentity(origId);
3865            }
3866        }
3867    }
3868
3869    @Override
3870    public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
3871        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3872                "prepareAppTransition()")) {
3873            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3874        }
3875
3876        synchronized(mWindowMap) {
3877            if (DEBUG_APP_TRANSITIONS) Slog.v(
3878                    TAG, "Prepare app transition: transit=" + transit
3879                    + " " + mAppTransition
3880                    + " alwaysKeepCurrent=" + alwaysKeepCurrent
3881                    + " Callers=" + Debug.getCallers(3));
3882            if (okToDisplay()) {
3883                if (!mAppTransition.isTransitionSet() || mAppTransition.isTransitionNone()) {
3884                    mAppTransition.setAppTransition(transit);
3885                } else if (!alwaysKeepCurrent) {
3886                    if (transit == AppTransition.TRANSIT_TASK_OPEN
3887                            && mAppTransition.isTransitionEqual(
3888                                    AppTransition.TRANSIT_TASK_CLOSE)) {
3889                        // Opening a new task always supersedes a close for the anim.
3890                        mAppTransition.setAppTransition(transit);
3891                    } else if (transit == AppTransition.TRANSIT_ACTIVITY_OPEN
3892                            && mAppTransition.isTransitionEqual(
3893                                AppTransition.TRANSIT_ACTIVITY_CLOSE)) {
3894                        // Opening a new activity always supersedes a close for the anim.
3895                        mAppTransition.setAppTransition(transit);
3896                    }
3897                }
3898                mAppTransition.prepare();
3899                mStartingIconInTransition = false;
3900                mSkipAppTransitionAnimation = false;
3901                mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
3902                mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, 5000);
3903            }
3904        }
3905    }
3906
3907    @Override
3908    public int getPendingAppTransition() {
3909        return mAppTransition.getAppTransition();
3910    }
3911
3912    @Override
3913    public void overridePendingAppTransition(String packageName,
3914            int enterAnim, int exitAnim, IRemoteCallback startedCallback) {
3915        synchronized(mWindowMap) {
3916            mAppTransition.overridePendingAppTransition(packageName, enterAnim, exitAnim,
3917                    startedCallback);
3918        }
3919    }
3920
3921    @Override
3922    public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
3923            int startHeight) {
3924        synchronized(mWindowMap) {
3925            mAppTransition.overridePendingAppTransitionScaleUp(startX, startY, startWidth,
3926                    startHeight);
3927        }
3928    }
3929
3930    @Override
3931    public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
3932            int startY, IRemoteCallback startedCallback, boolean scaleUp) {
3933        synchronized(mWindowMap) {
3934            mAppTransition.overridePendingAppTransitionThumb(srcThumb, startX, startY,
3935                    startedCallback, scaleUp);
3936        }
3937    }
3938
3939    @Override
3940    public void executeAppTransition() {
3941        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3942                "executeAppTransition()")) {
3943            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3944        }
3945
3946        synchronized(mWindowMap) {
3947            if (DEBUG_APP_TRANSITIONS) {
3948                RuntimeException e = new RuntimeException("here");
3949                e.fillInStackTrace();
3950                Slog.w(TAG, "Execute app transition: " + mAppTransition, e);
3951            }
3952            if (mAppTransition.isTransitionSet()) {
3953                mAppTransition.setReady();
3954                final long origId = Binder.clearCallingIdentity();
3955                performLayoutAndPlaceSurfacesLocked();
3956                Binder.restoreCallingIdentity(origId);
3957            }
3958        }
3959    }
3960
3961    @Override
3962    public void setAppStartingWindow(IBinder token, String pkg,
3963            int theme, CompatibilityInfo compatInfo,
3964            CharSequence nonLocalizedLabel, int labelRes, int icon, int logo,
3965            int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
3966        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3967                "setAppStartingWindow()")) {
3968            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3969        }
3970
3971        synchronized(mWindowMap) {
3972            if (DEBUG_STARTING_WINDOW) Slog.v(
3973                    TAG, "setAppStartingWindow: token=" + token + " pkg=" + pkg
3974                    + " transferFrom=" + transferFrom);
3975
3976            AppWindowToken wtoken = findAppWindowToken(token);
3977            if (wtoken == null) {
3978                Slog.w(TAG, "Attempted to set icon of non-existing app token: " + token);
3979                return;
3980            }
3981
3982            // If the display is frozen, we won't do anything until the
3983            // actual window is displayed so there is no reason to put in
3984            // the starting window.
3985            if (!okToDisplay()) {
3986                return;
3987            }
3988
3989            if (wtoken.startingData != null) {
3990                return;
3991            }
3992
3993            if (transferFrom != null) {
3994                AppWindowToken ttoken = findAppWindowToken(transferFrom);
3995                if (ttoken != null) {
3996                    WindowState startingWindow = ttoken.startingWindow;
3997                    if (startingWindow != null) {
3998                        if (mStartingIconInTransition) {
3999                            // In this case, the starting icon has already
4000                            // been displayed, so start letting windows get
4001                            // shown immediately without any more transitions.
4002                            mSkipAppTransitionAnimation = true;
4003                        }
4004                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
4005                                "Moving existing starting " + startingWindow + " from " + ttoken
4006                                + " to " + wtoken);
4007                        final long origId = Binder.clearCallingIdentity();
4008
4009                        // Transfer the starting window over to the new
4010                        // token.
4011                        wtoken.startingData = ttoken.startingData;
4012                        wtoken.startingView = ttoken.startingView;
4013                        wtoken.startingDisplayed = ttoken.startingDisplayed;
4014                        ttoken.startingDisplayed = false;
4015                        wtoken.startingWindow = startingWindow;
4016                        wtoken.reportedVisible = ttoken.reportedVisible;
4017                        ttoken.startingData = null;
4018                        ttoken.startingView = null;
4019                        ttoken.startingWindow = null;
4020                        ttoken.startingMoved = true;
4021                        startingWindow.mToken = wtoken;
4022                        startingWindow.mRootToken = wtoken;
4023                        startingWindow.mAppToken = wtoken;
4024                        startingWindow.mWinAnimator.mAppAnimator = wtoken.mAppAnimator;
4025
4026                        if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) {
4027                            Slog.v(TAG, "Removing starting window: " + startingWindow);
4028                        }
4029                        removeStartingWindowTimeout(ttoken);
4030                        startingWindow.getWindowList().remove(startingWindow);
4031                        mWindowsChanged = true;
4032                        if (DEBUG_ADD_REMOVE) Slog.v(TAG,
4033                                "Removing starting " + startingWindow + " from " + ttoken);
4034                        ttoken.windows.remove(startingWindow);
4035                        ttoken.allAppWindows.remove(startingWindow);
4036                        addWindowToListInOrderLocked(startingWindow, true);
4037
4038                        // Propagate other interesting state between the
4039                        // tokens.  If the old token is displayed, we should
4040                        // immediately force the new one to be displayed.  If
4041                        // it is animating, we need to move that animation to
4042                        // the new one.
4043                        if (ttoken.allDrawn) {
4044                            wtoken.allDrawn = true;
4045                            wtoken.deferClearAllDrawn = ttoken.deferClearAllDrawn;
4046                        }
4047                        if (ttoken.firstWindowDrawn) {
4048                            wtoken.firstWindowDrawn = true;
4049                        }
4050                        if (!ttoken.hidden) {
4051                            wtoken.hidden = false;
4052                            wtoken.hiddenRequested = false;
4053                            wtoken.willBeHidden = false;
4054                        }
4055                        if (wtoken.clientHidden != ttoken.clientHidden) {
4056                            wtoken.clientHidden = ttoken.clientHidden;
4057                            wtoken.sendAppVisibilityToClients();
4058                        }
4059                        final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator;
4060                        final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator;
4061                        if (tAppAnimator.animation != null) {
4062                            wAppAnimator.animation = tAppAnimator.animation;
4063                            wAppAnimator.animating = tAppAnimator.animating;
4064                            wAppAnimator.animLayerAdjustment = tAppAnimator.animLayerAdjustment;
4065                            tAppAnimator.animation = null;
4066                            tAppAnimator.animLayerAdjustment = 0;
4067                            wAppAnimator.updateLayers();
4068                            tAppAnimator.updateLayers();
4069                        }
4070
4071                        updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4072                                true /*updateInputWindows*/);
4073                        getDefaultDisplayContentLocked().layoutNeeded = true;
4074                        performLayoutAndPlaceSurfacesLocked();
4075                        Binder.restoreCallingIdentity(origId);
4076                        return;
4077                    } else if (ttoken.startingData != null) {
4078                        // The previous app was getting ready to show a
4079                        // starting window, but hasn't yet done so.  Steal it!
4080                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
4081                                "Moving pending starting from " + ttoken
4082                                + " to " + wtoken);
4083                        wtoken.startingData = ttoken.startingData;
4084                        ttoken.startingData = null;
4085                        ttoken.startingMoved = true;
4086                        Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
4087                        // Note: we really want to do sendMessageAtFrontOfQueue() because we
4088                        // want to process the message ASAP, before any other queued
4089                        // messages.
4090                        mH.sendMessageAtFrontOfQueue(m);
4091                        return;
4092                    }
4093                    final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator;
4094                    final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator;
4095                    if (tAppAnimator.thumbnail != null) {
4096                        // The old token is animating with a thumbnail, transfer
4097                        // that to the new token.
4098                        if (wAppAnimator.thumbnail != null) {
4099                            wAppAnimator.thumbnail.destroy();
4100                        }
4101                        wAppAnimator.thumbnail = tAppAnimator.thumbnail;
4102                        wAppAnimator.thumbnailX = tAppAnimator.thumbnailX;
4103                        wAppAnimator.thumbnailY = tAppAnimator.thumbnailY;
4104                        wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
4105                        wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
4106                        tAppAnimator.thumbnail = null;
4107                    }
4108                }
4109            }
4110
4111            // There is no existing starting window, and the caller doesn't
4112            // want us to create one, so that's it!
4113            if (!createIfNeeded) {
4114                return;
4115            }
4116
4117            // If this is a translucent window, then don't
4118            // show a starting window -- the current effect (a full-screen
4119            // opaque starting window that fades away to the real contents
4120            // when it is ready) does not work for this.
4121            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Checking theme of starting window: 0x"
4122                    + Integer.toHexString(theme));
4123            if (theme != 0) {
4124                AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
4125                        com.android.internal.R.styleable.Window, mCurrentUserId);
4126                if (ent == null) {
4127                    // Whoops!  App doesn't exist.  Um.  Okay.  We'll just
4128                    // pretend like we didn't see that.
4129                    return;
4130                }
4131                if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Translucent="
4132                        + ent.array.getBoolean(
4133                                com.android.internal.R.styleable.Window_windowIsTranslucent, false)
4134                        + " Floating="
4135                        + ent.array.getBoolean(
4136                                com.android.internal.R.styleable.Window_windowIsFloating, false)
4137                        + " ShowWallpaper="
4138                        + ent.array.getBoolean(
4139                                com.android.internal.R.styleable.Window_windowShowWallpaper, false));
4140                if (ent.array.getBoolean(
4141                        com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
4142                    return;
4143                }
4144                if (ent.array.getBoolean(
4145                        com.android.internal.R.styleable.Window_windowIsFloating, false)) {
4146                    return;
4147                }
4148                if (ent.array.getBoolean(
4149                        com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
4150                    if (mWallpaperTarget == null) {
4151                        // If this theme is requesting a wallpaper, and the wallpaper
4152                        // is not curently visible, then this effectively serves as
4153                        // an opaque window and our starting window transition animation
4154                        // can still work.  We just need to make sure the starting window
4155                        // is also showing the wallpaper.
4156                        windowFlags |= FLAG_SHOW_WALLPAPER;
4157                    } else {
4158                        return;
4159                    }
4160                }
4161            }
4162
4163            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Creating StartingData");
4164            mStartingIconInTransition = true;
4165            wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
4166                    labelRes, icon, logo, windowFlags);
4167            Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
4168            // Note: we really want to do sendMessageAtFrontOfQueue() because we
4169            // want to process the message ASAP, before any other queued
4170            // messages.
4171            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING");
4172            mH.sendMessageAtFrontOfQueue(m);
4173        }
4174    }
4175
4176    @Override
4177    public void setAppWillBeHidden(IBinder token) {
4178        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4179                "setAppWillBeHidden()")) {
4180            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4181        }
4182
4183        AppWindowToken wtoken;
4184
4185        synchronized(mWindowMap) {
4186            wtoken = findAppWindowToken(token);
4187            if (wtoken == null) {
4188                Slog.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
4189                return;
4190            }
4191            wtoken.willBeHidden = true;
4192        }
4193    }
4194
4195    public void setAppFullscreen(IBinder token, boolean toOpaque) {
4196        AppWindowToken atoken = findAppWindowToken(token);
4197        if (atoken != null) {
4198            atoken.appFullscreen = toOpaque;
4199            // When making translucent, wait until windows below have been drawn.
4200            if (toOpaque) {
4201                // Making opaque so do it now.
4202                setWindowOpaque(token, true);
4203            }
4204            requestTraversal();
4205        }
4206    }
4207
4208    public void setWindowOpaque(IBinder token, boolean isOpaque) {
4209        AppWindowToken wtoken = findAppWindowToken(token);
4210        if (wtoken != null) {
4211            WindowState win = wtoken.findMainWindow();
4212            if (win != null) {
4213                win.mWinAnimator.setOpaque(isOpaque);
4214            }
4215        }
4216    }
4217
4218    boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
4219            boolean visible, int transit, boolean performLayout) {
4220        boolean delayed = false;
4221
4222        if (wtoken.clientHidden == visible) {
4223            wtoken.clientHidden = !visible;
4224            wtoken.sendAppVisibilityToClients();
4225        }
4226
4227        wtoken.willBeHidden = false;
4228        if (wtoken.hidden == visible) {
4229            boolean changed = false;
4230            if (DEBUG_APP_TRANSITIONS) Slog.v(
4231                TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
4232                + " performLayout=" + performLayout);
4233
4234            boolean runningAppAnimation = false;
4235
4236            if (transit != AppTransition.TRANSIT_UNSET) {
4237                if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
4238                    wtoken.mAppAnimator.animation = null;
4239                }
4240                if (applyAnimationLocked(wtoken, lp, transit, visible)) {
4241                    delayed = runningAppAnimation = true;
4242                }
4243                WindowState window = wtoken.findMainWindow();
4244                //TODO (multidisplay): Magnification is supported only for the default display.
4245                if (window != null && mDisplayMagnifier != null
4246                        && window.getDisplayId() == Display.DEFAULT_DISPLAY) {
4247                    mDisplayMagnifier.onAppWindowTransitionLocked(window, transit);
4248                }
4249                changed = true;
4250            }
4251
4252            final int N = wtoken.allAppWindows.size();
4253            for (int i=0; i<N; i++) {
4254                WindowState win = wtoken.allAppWindows.get(i);
4255                if (win == wtoken.startingWindow) {
4256                    continue;
4257                }
4258
4259                //Slog.i(TAG, "Window " + win + ": vis=" + win.isVisible());
4260                //win.dump("  ");
4261                if (visible) {
4262                    if (!win.isVisibleNow()) {
4263                        if (!runningAppAnimation) {
4264                            win.mWinAnimator.applyAnimationLocked(
4265                                    WindowManagerPolicy.TRANSIT_ENTER, true);
4266                            //TODO (multidisplay): Magnification is supported only for the default
4267                            if (mDisplayMagnifier != null
4268                                    && win.getDisplayId() == Display.DEFAULT_DISPLAY) {
4269                                mDisplayMagnifier.onWindowTransitionLocked(win,
4270                                        WindowManagerPolicy.TRANSIT_ENTER);
4271                            }
4272                        }
4273                        changed = true;
4274                        final DisplayContent displayContent = win.getDisplayContent();
4275                        if (displayContent != null) {
4276                            displayContent.layoutNeeded = true;
4277                        }
4278                    }
4279                } else if (win.isVisibleNow()) {
4280                    if (!runningAppAnimation) {
4281                        win.mWinAnimator.applyAnimationLocked(
4282                                WindowManagerPolicy.TRANSIT_EXIT, false);
4283                        //TODO (multidisplay): Magnification is supported only for the default
4284                        if (mDisplayMagnifier != null
4285                                && win.getDisplayId() == Display.DEFAULT_DISPLAY) {
4286                            mDisplayMagnifier.onWindowTransitionLocked(win,
4287                                    WindowManagerPolicy.TRANSIT_EXIT);
4288                        }
4289                    }
4290                    changed = true;
4291                    final DisplayContent displayContent = win.getDisplayContent();
4292                    if (displayContent != null) {
4293                        displayContent.layoutNeeded = true;
4294                    }
4295                }
4296            }
4297
4298            wtoken.hidden = wtoken.hiddenRequested = !visible;
4299            if (!visible) {
4300                unsetAppFreezingScreenLocked(wtoken, true, true);
4301            } else {
4302                // If we are being set visible, and the starting window is
4303                // not yet displayed, then make sure it doesn't get displayed.
4304                WindowState swin = wtoken.startingWindow;
4305                if (swin != null && !swin.isDrawnLw()) {
4306                    swin.mPolicyVisibility = false;
4307                    swin.mPolicyVisibilityAfterAnim = false;
4308                 }
4309            }
4310
4311            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "setTokenVisibilityLocked: " + wtoken
4312                      + ": hidden=" + wtoken.hidden + " hiddenRequested="
4313                      + wtoken.hiddenRequested);
4314
4315            if (changed) {
4316                mInputMonitor.setUpdateInputWindowsNeededLw();
4317                if (performLayout) {
4318                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4319                            false /*updateInputWindows*/);
4320                    performLayoutAndPlaceSurfacesLocked();
4321                }
4322                mInputMonitor.updateInputWindowsLw(false /*force*/);
4323            }
4324        }
4325
4326        if (wtoken.mAppAnimator.animation != null) {
4327            delayed = true;
4328        }
4329
4330        for (int i = wtoken.allAppWindows.size() - 1; i >= 0 && !delayed; i--) {
4331            if (wtoken.allAppWindows.get(i).mWinAnimator.isWindowAnimating()) {
4332                delayed = true;
4333            }
4334        }
4335
4336        return delayed;
4337    }
4338
4339    @Override
4340    public void setAppVisibility(IBinder token, boolean visible) {
4341        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4342                "setAppVisibility()")) {
4343            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4344        }
4345
4346        AppWindowToken wtoken;
4347
4348        synchronized(mWindowMap) {
4349            wtoken = findAppWindowToken(token);
4350            if (wtoken == null) {
4351                Slog.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
4352                return;
4353            }
4354
4355            if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
4356                RuntimeException e = null;
4357                if (!HIDE_STACK_CRAWLS) {
4358                    e = new RuntimeException();
4359                    e.fillInStackTrace();
4360                }
4361                Slog.v(TAG, "setAppVisibility(" + token + ", visible=" + visible
4362                        + "): " + mAppTransition
4363                        + " hidden=" + wtoken.hidden
4364                        + " hiddenRequested=" + wtoken.hiddenRequested, e);
4365            }
4366
4367            // If we are preparing an app transition, then delay changing
4368            // the visibility of this token until we execute that transition.
4369            if (okToDisplay() && mAppTransition.isTransitionSet()) {
4370                wtoken.hiddenRequested = !visible;
4371
4372                if (!wtoken.startingDisplayed) {
4373                    if (DEBUG_APP_TRANSITIONS) Slog.v(
4374                            TAG, "Setting dummy animation on: " + wtoken);
4375                    wtoken.mAppAnimator.setDummyAnimation();
4376                }
4377                mOpeningApps.remove(wtoken);
4378                mClosingApps.remove(wtoken);
4379                wtoken.waitingToShow = wtoken.waitingToHide = false;
4380                wtoken.inPendingTransaction = true;
4381                if (visible) {
4382                    mOpeningApps.add(wtoken);
4383                    wtoken.startingMoved = false;
4384
4385                    // If the token is currently hidden (should be the
4386                    // common case), then we need to set up to wait for
4387                    // its windows to be ready.
4388                    if (wtoken.hidden) {
4389                        wtoken.allDrawn = false;
4390                        wtoken.deferClearAllDrawn = false;
4391                        wtoken.waitingToShow = true;
4392
4393                        if (wtoken.clientHidden) {
4394                            // In the case where we are making an app visible
4395                            // but holding off for a transition, we still need
4396                            // to tell the client to make its windows visible so
4397                            // they get drawn.  Otherwise, we will wait on
4398                            // performing the transition until all windows have
4399                            // been drawn, they never will be, and we are sad.
4400                            wtoken.clientHidden = false;
4401                            wtoken.sendAppVisibilityToClients();
4402                        }
4403                    }
4404                } else {
4405                    mClosingApps.add(wtoken);
4406
4407                    // If the token is currently visible (should be the
4408                    // common case), then set up to wait for it to be hidden.
4409                    if (!wtoken.hidden) {
4410                        wtoken.waitingToHide = true;
4411                    }
4412                }
4413                return;
4414            }
4415
4416            final long origId = Binder.clearCallingIdentity();
4417            setTokenVisibilityLocked(wtoken, null, visible, AppTransition.TRANSIT_UNSET,
4418                    true);
4419            wtoken.updateReportedVisibilityLocked();
4420            Binder.restoreCallingIdentity(origId);
4421        }
4422    }
4423
4424    void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
4425            boolean unfreezeSurfaceNow, boolean force) {
4426        if (wtoken.mAppAnimator.freezingScreen) {
4427            if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + wtoken
4428                    + " force=" + force);
4429            final int N = wtoken.allAppWindows.size();
4430            boolean unfrozeWindows = false;
4431            for (int i=0; i<N; i++) {
4432                WindowState w = wtoken.allAppWindows.get(i);
4433                if (w.mAppFreezing) {
4434                    w.mAppFreezing = false;
4435                    if (w.mHasSurface && !w.mOrientationChanging) {
4436                        if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
4437                        w.mOrientationChanging = true;
4438                        mInnerFields.mOrientationChangeComplete = false;
4439                    }
4440                    w.mLastFreezeDuration = 0;
4441                    unfrozeWindows = true;
4442                    final DisplayContent displayContent = w.getDisplayContent();
4443                    if (displayContent != null) {
4444                        displayContent.layoutNeeded = true;
4445                    }
4446                }
4447            }
4448            if (force || unfrozeWindows) {
4449                if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken);
4450                wtoken.mAppAnimator.freezingScreen = false;
4451                wtoken.mAppAnimator.lastFreezeDuration = (int)(SystemClock.elapsedRealtime()
4452                        - mDisplayFreezeTime);
4453                mAppsFreezingScreen--;
4454                mLastFinishedFreezeSource = wtoken;
4455            }
4456            if (unfreezeSurfaceNow) {
4457                if (unfrozeWindows) {
4458                    performLayoutAndPlaceSurfacesLocked();
4459                }
4460                stopFreezingDisplayLocked();
4461            }
4462        }
4463    }
4464
4465    private void startAppFreezingScreenLocked(AppWindowToken wtoken) {
4466        if (DEBUG_ORIENTATION) {
4467            RuntimeException e = null;
4468            if (!HIDE_STACK_CRAWLS) {
4469                e = new RuntimeException();
4470                e.fillInStackTrace();
4471            }
4472            Slog.i(TAG, "Set freezing of " + wtoken.appToken
4473                    + ": hidden=" + wtoken.hidden + " freezing="
4474                    + wtoken.mAppAnimator.freezingScreen, e);
4475        }
4476        if (!wtoken.hiddenRequested) {
4477            if (!wtoken.mAppAnimator.freezingScreen) {
4478                wtoken.mAppAnimator.freezingScreen = true;
4479                wtoken.mAppAnimator.lastFreezeDuration = 0;
4480                mAppsFreezingScreen++;
4481                if (mAppsFreezingScreen == 1) {
4482                    startFreezingDisplayLocked(false, 0, 0);
4483                    mH.removeMessages(H.APP_FREEZE_TIMEOUT);
4484                    mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 5000);
4485                }
4486            }
4487            final int N = wtoken.allAppWindows.size();
4488            for (int i=0; i<N; i++) {
4489                WindowState w = wtoken.allAppWindows.get(i);
4490                w.mAppFreezing = true;
4491            }
4492        }
4493    }
4494
4495    @Override
4496    public void startAppFreezingScreen(IBinder token, int configChanges) {
4497        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4498                "setAppFreezingScreen()")) {
4499            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4500        }
4501
4502        synchronized(mWindowMap) {
4503            if (configChanges == 0 && okToDisplay()) {
4504                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping set freeze of " + token);
4505                return;
4506            }
4507
4508            AppWindowToken wtoken = findAppWindowToken(token);
4509            if (wtoken == null || wtoken.appToken == null) {
4510                Slog.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
4511                return;
4512            }
4513            final long origId = Binder.clearCallingIdentity();
4514            startAppFreezingScreenLocked(wtoken);
4515            Binder.restoreCallingIdentity(origId);
4516        }
4517    }
4518
4519    @Override
4520    public void stopAppFreezingScreen(IBinder token, boolean force) {
4521        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4522                "setAppFreezingScreen()")) {
4523            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4524        }
4525
4526        synchronized(mWindowMap) {
4527            AppWindowToken wtoken = findAppWindowToken(token);
4528            if (wtoken == null || wtoken.appToken == null) {
4529                return;
4530            }
4531            final long origId = Binder.clearCallingIdentity();
4532            if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + token
4533                    + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
4534            unsetAppFreezingScreenLocked(wtoken, true, force);
4535            Binder.restoreCallingIdentity(origId);
4536        }
4537    }
4538
4539    void removeAppFromTaskLocked(AppWindowToken wtoken) {
4540        final Task task = mTaskIdToTask.get(wtoken.groupId);
4541        if (task != null) {
4542            if (!task.removeAppToken(wtoken)) {
4543                Slog.e(TAG, "removeAppFromTaskLocked: token=" + wtoken + " not found.");
4544            }
4545        }
4546    }
4547
4548    @Override
4549    public void removeAppToken(IBinder token) {
4550        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4551                "removeAppToken()")) {
4552            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4553        }
4554
4555        AppWindowToken wtoken = null;
4556        AppWindowToken startingToken = null;
4557        boolean delayed = false;
4558
4559        final long origId = Binder.clearCallingIdentity();
4560        synchronized(mWindowMap) {
4561            WindowToken basewtoken = mTokenMap.remove(token);
4562            if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
4563                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
4564                delayed = setTokenVisibilityLocked(wtoken, null, false,
4565                        AppTransition.TRANSIT_UNSET, true);
4566                wtoken.inPendingTransaction = false;
4567                mOpeningApps.remove(wtoken);
4568                wtoken.waitingToShow = false;
4569                if (mClosingApps.contains(wtoken)) {
4570                    delayed = true;
4571                } else if (mAppTransition.isTransitionSet()) {
4572                    mClosingApps.add(wtoken);
4573                    wtoken.waitingToHide = true;
4574                    delayed = true;
4575                }
4576                if (DEBUG_APP_TRANSITIONS) Slog.v(
4577                        TAG, "Removing app " + wtoken + " delayed=" + delayed
4578                        + " animation=" + wtoken.mAppAnimator.animation
4579                        + " animating=" + wtoken.mAppAnimator.animating);
4580                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "removeAppToken: "
4581                        + wtoken + " delayed=" + delayed + " Callers=" + Debug.getCallers(4));
4582                final TaskStack stack = mTaskIdToTask.get(wtoken.groupId).mStack;
4583                if (delayed) {
4584                    // set the token aside because it has an active animation to be finished
4585                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
4586                            "removeAppToken make exiting: " + wtoken);
4587                    stack.mExitingAppTokens.add(wtoken);
4588                    wtoken.mDeferRemoval = true;
4589                } else {
4590                    // Make sure there is no animation running on this token,
4591                    // so any windows associated with it will be removed as
4592                    // soon as their animations are complete
4593                    wtoken.mAppAnimator.clearAnimation();
4594                    wtoken.mAppAnimator.animating = false;
4595                    removeAppFromTaskLocked(wtoken);
4596                }
4597
4598                wtoken.removed = true;
4599                if (wtoken.startingData != null) {
4600                    startingToken = wtoken;
4601                }
4602                unsetAppFreezingScreenLocked(wtoken, true, true);
4603                if (mFocusedApp == wtoken) {
4604                    if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "Removing focused app token:" + wtoken);
4605                    mFocusedApp = null;
4606                    updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
4607                    mInputMonitor.setFocusedAppLw(null);
4608                }
4609            } else {
4610                Slog.w(TAG, "Attempted to remove non-existing app token: " + token);
4611            }
4612
4613            if (!delayed && wtoken != null) {
4614                wtoken.updateReportedVisibilityLocked();
4615            }
4616        }
4617        Binder.restoreCallingIdentity(origId);
4618
4619        // Will only remove if startingToken non null.
4620        scheduleRemoveStartingWindow(startingToken);
4621    }
4622
4623    void removeStartingWindowTimeout(AppWindowToken wtoken) {
4624        if (wtoken != null) {
4625            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, Debug.getCallers(1) +
4626                    ": Remove starting window timeout " + wtoken + (wtoken != null ?
4627                    " startingWindow=" + wtoken.startingWindow : ""));
4628            mH.removeMessages(H.REMOVE_STARTING_TIMEOUT, wtoken);
4629        }
4630    }
4631
4632    void scheduleRemoveStartingWindow(AppWindowToken wtoken) {
4633        if (wtoken != null && wtoken.startingWindow != null) {
4634            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, Debug.getCallers(1) +
4635                    ": Schedule remove starting " + wtoken + (wtoken != null ?
4636                    " startingWindow=" + wtoken.startingWindow : ""));
4637            removeStartingWindowTimeout(wtoken);
4638            Message m = mH.obtainMessage(H.REMOVE_STARTING, wtoken);
4639            mH.sendMessage(m);
4640        }
4641    }
4642
4643    private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
4644        WindowList windows = token.windows;
4645        final int NW = windows.size();
4646        if (NW > 0) {
4647            mWindowsChanged = true;
4648        }
4649        for (int i = 0; i < NW; i++) {
4650            WindowState win = windows.get(i);
4651            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
4652            win.getWindowList().remove(win);
4653            int j = win.mChildWindows.size();
4654            while (j > 0) {
4655                j--;
4656                WindowState cwin = win.mChildWindows.get(j);
4657                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
4658                        "Tmp removing child window " + cwin);
4659                cwin.getWindowList().remove(cwin);
4660            }
4661        }
4662        return NW > 0;
4663    }
4664
4665    void dumpAppTokensLocked() {
4666        final int numStacks = mStackIdToStack.size();
4667        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
4668            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
4669            Slog.v(TAG, "  Stack #" + stack.mStackId + " tasks from bottom to top:");
4670            final ArrayList<Task> tasks = stack.getTasks();
4671            final int numTasks = tasks.size();
4672            for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
4673                final Task task = tasks.get(taskNdx);
4674                Slog.v(TAG, "    Task #" + task.taskId + " activities from bottom to top:");
4675                AppTokenList tokens = task.mAppTokens;
4676                final int numTokens = tokens.size();
4677                for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
4678                    Slog.v(TAG, "      activity #" + tokenNdx + ": " + tokens.get(tokenNdx).token);
4679                }
4680            }
4681        }
4682    }
4683
4684    void dumpWindowsLocked() {
4685        final int numDisplays = mDisplayContents.size();
4686        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
4687            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
4688            Slog.v(TAG, " Display #" + displayContent.getDisplayId());
4689            final WindowList windows = displayContent.getWindowList();
4690            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
4691                Slog.v(TAG, "  #" + winNdx + ": " + windows.get(winNdx));
4692            }
4693        }
4694    }
4695
4696    private int findAppWindowInsertionPointLocked(AppWindowToken target) {
4697        final int taskId = target.groupId;
4698        Task targetTask = mTaskIdToTask.get(taskId);
4699        if (targetTask == null) {
4700            Slog.w(TAG, "findAppWindowInsertionPointLocked: no Task for " + target + " taskId="
4701                    + taskId);
4702            return 0;
4703        }
4704        DisplayContent displayContent = targetTask.getDisplayContent();
4705        if (displayContent == null) {
4706            Slog.w(TAG, "findAppWindowInsertionPointLocked: no DisplayContent for " + target);
4707            return 0;
4708        }
4709        final WindowList windows = displayContent.getWindowList();
4710        final int NW = windows.size();
4711
4712        boolean found = false;
4713        final ArrayList<Task> tasks = displayContent.getTasks();
4714        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
4715            final Task task = tasks.get(taskNdx);
4716            if (!found && task.taskId != taskId) {
4717                continue;
4718            }
4719            AppTokenList tokens = task.mAppTokens;
4720            for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
4721                final AppWindowToken wtoken = tokens.get(tokenNdx);
4722                if (!found && wtoken == target) {
4723                    found = true;
4724                }
4725                if (found) {
4726                    // Find the first app token below the new position that has
4727                    // a window displayed.
4728                    if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows in " + wtoken.token);
4729                    if (wtoken.sendingToBottom) {
4730                        if (DEBUG_REORDER) Slog.v(TAG, "Skipping token -- currently sending to bottom");
4731                        continue;
4732                    }
4733                    for (int i = wtoken.windows.size() - 1; i >= 0; --i) {
4734                        WindowState win = wtoken.windows.get(i);
4735                        for (int j = win.mChildWindows.size() - 1; j >= 0; --j) {
4736                            WindowState cwin = win.mChildWindows.get(j);
4737                            if (cwin.mSubLayer >= 0) {
4738                                for (int pos = NW - 1; pos >= 0; pos--) {
4739                                    if (windows.get(pos) == cwin) {
4740                                        if (DEBUG_REORDER) Slog.v(TAG,
4741                                                "Found child win @" + (pos + 1));
4742                                        return pos + 1;
4743                                    }
4744                                }
4745                            }
4746                        }
4747                        for (int pos = NW - 1; pos >= 0; pos--) {
4748                            if (windows.get(pos) == win) {
4749                                if (DEBUG_REORDER) Slog.v(TAG, "Found win @" + (pos + 1));
4750                                return pos + 1;
4751                            }
4752                        }
4753                    }
4754                }
4755            }
4756        }
4757        // Never put an app window underneath wallpaper.
4758        for (int pos = NW - 1; pos >= 0; pos--) {
4759            if (windows.get(pos).mIsWallpaper) {
4760                if (DEBUG_REORDER) Slog.v(TAG, "Found wallpaper @" + pos);
4761                return pos + 1;
4762            }
4763        }
4764        return 0;
4765    }
4766
4767    private final int reAddWindowLocked(int index, WindowState win) {
4768        final WindowList windows = win.getWindowList();
4769        final int NCW = win.mChildWindows.size();
4770        boolean added = false;
4771        for (int j=0; j<NCW; j++) {
4772            WindowState cwin = win.mChildWindows.get(j);
4773            if (!added && cwin.mSubLayer >= 0) {
4774                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding child window at "
4775                        + index + ": " + cwin);
4776                win.mRebuilding = false;
4777                windows.add(index, win);
4778                index++;
4779                added = true;
4780            }
4781            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
4782                    + index + ": " + cwin);
4783            cwin.mRebuilding = false;
4784            windows.add(index, cwin);
4785            index++;
4786        }
4787        if (!added) {
4788            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
4789                    + index + ": " + win);
4790            win.mRebuilding = false;
4791            windows.add(index, win);
4792            index++;
4793        }
4794        mWindowsChanged = true;
4795        return index;
4796    }
4797
4798    private final int reAddAppWindowsLocked(final DisplayContent displayContent, int index,
4799                                            WindowToken token) {
4800        final int NW = token.windows.size();
4801        for (int i=0; i<NW; i++) {
4802            final WindowState win = token.windows.get(i);
4803            final DisplayContent winDisplayContent = win.getDisplayContent();
4804            if (winDisplayContent == displayContent || winDisplayContent == null) {
4805                win.mDisplayContent = displayContent;
4806                index = reAddWindowLocked(index, win);
4807            }
4808        }
4809        return index;
4810    }
4811
4812    void tmpRemoveTaskWindowsLocked(Task task) {
4813        AppTokenList tokens = task.mAppTokens;
4814        for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
4815            tmpRemoveAppWindowsLocked(tokens.get(tokenNdx));
4816        }
4817    }
4818
4819    void moveStackWindowsLocked(DisplayContent displayContent) {
4820        // First remove all of the windows from the list.
4821        final ArrayList<Task> tasks = displayContent.getTasks();
4822        final int numTasks = tasks.size();
4823        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
4824            tmpRemoveTaskWindowsLocked(tasks.get(taskNdx));
4825        }
4826
4827        // And now add them back at the correct place.
4828        // Where to start adding?
4829        for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
4830            AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
4831            int pos = findAppWindowInsertionPointLocked(tokens.get(0));
4832            final int numTokens = tokens.size();
4833            for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
4834                final AppWindowToken wtoken = tokens.get(tokenNdx);
4835                if (wtoken != null) {
4836                    final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
4837                    if (newPos != pos) {
4838                        displayContent.layoutNeeded = true;
4839                    }
4840                    pos = newPos;
4841                }
4842            }
4843        }
4844
4845        if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4846                false /*updateInputWindows*/)) {
4847            assignLayersLocked(displayContent.getWindowList());
4848        }
4849
4850        mInputMonitor.setUpdateInputWindowsNeededLw();
4851        performLayoutAndPlaceSurfacesLocked();
4852        mInputMonitor.updateInputWindowsLw(false /*force*/);
4853
4854        //dump();
4855    }
4856
4857    public void moveTaskToTop(int taskId) {
4858        final long origId = Binder.clearCallingIdentity();
4859        try {
4860            synchronized(mWindowMap) {
4861                Task task = mTaskIdToTask.get(taskId);
4862                if (task == null) {
4863                    // Normal behavior, addAppToken will be called next and task will be created.
4864                    return;
4865                }
4866                final TaskStack stack = task.mStack;
4867                final DisplayContent displayContent = task.getDisplayContent();
4868                displayContent.moveStack(stack, true);
4869                if (displayContent.isDefaultDisplay) {
4870                    final TaskStack homeStack = displayContent.getHomeStack();
4871                    if (homeStack != stack) {
4872                        // When a non-home stack moves to the top, the home stack moves to the
4873                        // bottom.
4874                        displayContent.moveStack(homeStack, false);
4875                    }
4876                }
4877                stack.moveTaskToTop(task);
4878            }
4879        } finally {
4880            Binder.restoreCallingIdentity(origId);
4881        }
4882    }
4883
4884    public void moveTaskToBottom(int taskId) {
4885        final long origId = Binder.clearCallingIdentity();
4886        try {
4887            synchronized(mWindowMap) {
4888                Task task = mTaskIdToTask.get(taskId);
4889                if (task == null) {
4890                    Slog.e(TAG, "moveTaskToBottom: taskId=" + taskId
4891                            + " not found in mTaskIdToTask");
4892                    return;
4893                }
4894                final TaskStack stack = task.mStack;
4895                stack.moveTaskToBottom(task);
4896                moveStackWindowsLocked(stack.getDisplayContent());
4897            }
4898        } finally {
4899            Binder.restoreCallingIdentity(origId);
4900        }
4901    }
4902
4903    /**
4904     * Create a new TaskStack and place it on a DisplayContent.
4905     * @param stackId The unique identifier of the new stack.
4906     * @param displayId The unique identifier of the DisplayContent.
4907     */
4908    public void attachStack(int stackId, int displayId) {
4909        final long origId = Binder.clearCallingIdentity();
4910        try {
4911            synchronized (mWindowMap) {
4912                final DisplayContent displayContent = mDisplayContents.get(displayId);
4913                if (displayContent != null) {
4914                    TaskStack stack = mStackIdToStack.get(stackId);
4915                    if (stack == null) {
4916                        if (DEBUG_STACK) Slog.d(TAG, "attachStack: stackId=" + stackId);
4917                        stack = new TaskStack(this, stackId);
4918                        mStackIdToStack.put(stackId, stack);
4919                    }
4920                    stack.attachDisplayContent(displayContent);
4921                    displayContent.attachStack(stack);
4922                    moveStackWindowsLocked(displayContent);
4923                    final WindowList windows = displayContent.getWindowList();
4924                    for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
4925                        windows.get(winNdx).reportResized();
4926                    }
4927                }
4928            }
4929        } finally {
4930            Binder.restoreCallingIdentity(origId);
4931        }
4932    }
4933
4934    public void detachStack(int stackId) {
4935        synchronized (mWindowMap) {
4936            TaskStack stack = mStackIdToStack.get(stackId);
4937            if (stack != null) {
4938                final DisplayContent displayContent = stack.getDisplayContent();
4939                if (displayContent != null) {
4940                    if (stack.isAnimating()) {
4941                        displayContent.mDeferredActions |= DisplayContent.DEFER_DETACH;
4942                        return;
4943                    }
4944                    displayContent.detachStack(stack);
4945                    stack.detachDisplay();
4946                }
4947            }
4948        }
4949    }
4950
4951    void removeTaskLocked(Task task) {
4952        final int taskId = task.taskId;
4953        final TaskStack stack = task.mStack;
4954        if (stack.isAnimating()) {
4955            if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + taskId);
4956            task.mDeferRemoval = true;
4957            return;
4958        }
4959        if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + taskId);
4960        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
4961        task.mDeferRemoval = false;
4962        task.mStack.removeTask(task);
4963        mTaskIdToTask.delete(task.taskId);
4964    }
4965
4966    public void removeTask(int taskId) {
4967        synchronized (mWindowMap) {
4968            Task task = mTaskIdToTask.get(taskId);
4969            if (task == null) {
4970                if (DEBUG_STACK) Slog.i(TAG, "removeTask: could not find taskId=" + taskId);
4971                return;
4972            }
4973            removeTaskLocked(task);
4974        }
4975    }
4976
4977    public void addTask(int taskId, int stackId, boolean toTop) {
4978        synchronized (mWindowMap) {
4979            if (DEBUG_STACK) Slog.i(TAG, "addTask: adding taskId=" + taskId
4980                    + " to " + (toTop ? "top" : "bottom"));
4981            Task task = mTaskIdToTask.get(taskId);
4982            if (task == null) {
4983                return;
4984            }
4985            TaskStack stack = mStackIdToStack.get(stackId);
4986            stack.addTask(task, toTop);
4987            final DisplayContent displayContent = stack.getDisplayContent();
4988            displayContent.layoutNeeded = true;
4989            performLayoutAndPlaceSurfacesLocked();
4990        }
4991    }
4992
4993    public void resizeStack(int stackId, Rect bounds) {
4994        synchronized (mWindowMap) {
4995            final TaskStack stack = mStackIdToStack.get(stackId);
4996            if (stack == null) {
4997                throw new IllegalArgumentException("resizeStack: stackId " + stackId
4998                        + " not found.");
4999            }
5000            if (stack.setBounds(bounds)) {
5001                stack.resizeWindows();
5002                stack.getDisplayContent().layoutNeeded = true;
5003                performLayoutAndPlaceSurfacesLocked();
5004            }
5005        }
5006    }
5007
5008    public void getStackBounds(int stackId, Rect bounds) {
5009        final TaskStack stack = mStackIdToStack.get(stackId);
5010        if (stack != null) {
5011            stack.getBounds(bounds);
5012            return;
5013        }
5014        bounds.setEmpty();
5015    }
5016
5017    // -------------------------------------------------------------
5018    // Misc IWindowSession methods
5019    // -------------------------------------------------------------
5020
5021    @Override
5022    public void startFreezingScreen(int exitAnim, int enterAnim) {
5023        if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
5024                "startFreezingScreen()")) {
5025            throw new SecurityException("Requires FREEZE_SCREEN permission");
5026        }
5027
5028        synchronized(mWindowMap) {
5029            if (!mClientFreezingScreen) {
5030                mClientFreezingScreen = true;
5031                final long origId = Binder.clearCallingIdentity();
5032                try {
5033                    startFreezingDisplayLocked(false, exitAnim, enterAnim);
5034                    mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
5035                    mH.sendEmptyMessageDelayed(H.CLIENT_FREEZE_TIMEOUT, 5000);
5036                } finally {
5037                    Binder.restoreCallingIdentity(origId);
5038                }
5039            }
5040        }
5041    }
5042
5043    @Override
5044    public void stopFreezingScreen() {
5045        if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
5046                "stopFreezingScreen()")) {
5047            throw new SecurityException("Requires FREEZE_SCREEN permission");
5048        }
5049
5050        synchronized(mWindowMap) {
5051            if (mClientFreezingScreen) {
5052                mClientFreezingScreen = false;
5053                mLastFinishedFreezeSource = "client";
5054                final long origId = Binder.clearCallingIdentity();
5055                try {
5056                    stopFreezingDisplayLocked();
5057                } finally {
5058                    Binder.restoreCallingIdentity(origId);
5059                }
5060            }
5061        }
5062    }
5063
5064    @Override
5065    public void disableKeyguard(IBinder token, String tag) {
5066        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5067            != PackageManager.PERMISSION_GRANTED) {
5068            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5069        }
5070
5071        mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
5072                KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag)));
5073    }
5074
5075    @Override
5076    public void reenableKeyguard(IBinder token) {
5077        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5078            != PackageManager.PERMISSION_GRANTED) {
5079            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5080        }
5081
5082        mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
5083                KeyguardDisableHandler.KEYGUARD_REENABLE, token));
5084    }
5085
5086    /**
5087     * @see android.app.KeyguardManager#exitKeyguardSecurely
5088     */
5089    @Override
5090    public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
5091        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5092            != PackageManager.PERMISSION_GRANTED) {
5093            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5094        }
5095        mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
5096            @Override
5097            public void onKeyguardExitResult(boolean success) {
5098                try {
5099                    callback.onKeyguardExitResult(success);
5100                } catch (RemoteException e) {
5101                    // Client has died, we don't care.
5102                }
5103            }
5104        });
5105    }
5106
5107    @Override
5108    public boolean inKeyguardRestrictedInputMode() {
5109        return mPolicy.inKeyguardRestrictedKeyInputMode();
5110    }
5111
5112    @Override
5113    public boolean isKeyguardLocked() {
5114        return mPolicy.isKeyguardLocked();
5115    }
5116
5117    @Override
5118    public boolean isKeyguardSecure() {
5119        return mPolicy.isKeyguardSecure();
5120    }
5121
5122    @Override
5123    public void dismissKeyguard() {
5124        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5125                != PackageManager.PERMISSION_GRANTED) {
5126            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5127        }
5128        synchronized(mWindowMap) {
5129            mPolicy.dismissKeyguardLw();
5130        }
5131    }
5132
5133    @Override
5134    public void closeSystemDialogs(String reason) {
5135        synchronized(mWindowMap) {
5136            final int numDisplays = mDisplayContents.size();
5137            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
5138                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
5139                final int numWindows = windows.size();
5140                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
5141                    final WindowState w = windows.get(winNdx);
5142                    if (w.mHasSurface) {
5143                        try {
5144                            w.mClient.closeSystemDialogs(reason);
5145                        } catch (RemoteException e) {
5146                        }
5147                    }
5148                }
5149            }
5150        }
5151    }
5152
5153    static float fixScale(float scale) {
5154        if (scale < 0) scale = 0;
5155        else if (scale > 20) scale = 20;
5156        return Math.abs(scale);
5157    }
5158
5159    @Override
5160    public void setAnimationScale(int which, float scale) {
5161        if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
5162                "setAnimationScale()")) {
5163            throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
5164        }
5165
5166        scale = fixScale(scale);
5167        switch (which) {
5168            case 0: mWindowAnimationScale = scale; break;
5169            case 1: mTransitionAnimationScale = scale; break;
5170            case 2: mAnimatorDurationScale = scale; break;
5171        }
5172
5173        // Persist setting
5174        mH.sendEmptyMessage(H.PERSIST_ANIMATION_SCALE);
5175    }
5176
5177    @Override
5178    public void setAnimationScales(float[] scales) {
5179        if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
5180                "setAnimationScale()")) {
5181            throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
5182        }
5183
5184        if (scales != null) {
5185            if (scales.length >= 1) {
5186                mWindowAnimationScale = fixScale(scales[0]);
5187            }
5188            if (scales.length >= 2) {
5189                mTransitionAnimationScale = fixScale(scales[1]);
5190            }
5191            if (scales.length >= 3) {
5192                setAnimatorDurationScale(fixScale(scales[2]));
5193            }
5194        }
5195
5196        // Persist setting
5197        mH.sendEmptyMessage(H.PERSIST_ANIMATION_SCALE);
5198    }
5199
5200    private void setAnimatorDurationScale(float scale) {
5201        mAnimatorDurationScale = scale;
5202        ValueAnimator.setDurationScale(scale);
5203    }
5204
5205    @Override
5206    public float getAnimationScale(int which) {
5207        switch (which) {
5208            case 0: return mWindowAnimationScale;
5209            case 1: return mTransitionAnimationScale;
5210            case 2: return mAnimatorDurationScale;
5211        }
5212        return 0;
5213    }
5214
5215    @Override
5216    public float[] getAnimationScales() {
5217        return new float[] { mWindowAnimationScale, mTransitionAnimationScale,
5218                mAnimatorDurationScale };
5219    }
5220
5221    @Override
5222    public void registerPointerEventListener(PointerEventListener listener) {
5223        mPointerEventDispatcher.registerInputEventListener(listener);
5224    }
5225
5226    @Override
5227    public void unregisterPointerEventListener(PointerEventListener listener) {
5228        mPointerEventDispatcher.unregisterInputEventListener(listener);
5229    }
5230
5231    // Called by window manager policy. Not exposed externally.
5232    @Override
5233    public int getLidState() {
5234        int sw = mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY,
5235                InputManagerService.SW_LID);
5236        if (sw > 0) {
5237            // Switch state: AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL.
5238            return LID_CLOSED;
5239        } else if (sw == 0) {
5240            // Switch state: AKEY_STATE_UP.
5241            return LID_OPEN;
5242        } else {
5243            // Switch state: AKEY_STATE_UNKNOWN.
5244            return LID_ABSENT;
5245        }
5246    }
5247
5248    // Called by window manager policy.  Not exposed externally.
5249    @Override
5250    public void switchKeyboardLayout(int deviceId, int direction) {
5251        mInputManager.switchKeyboardLayout(deviceId, direction);
5252    }
5253
5254    // Called by window manager policy.  Not exposed externally.
5255    @Override
5256    public void shutdown(boolean confirm) {
5257        ShutdownThread.shutdown(mContext, confirm);
5258    }
5259
5260    // Called by window manager policy.  Not exposed externally.
5261    @Override
5262    public void rebootSafeMode(boolean confirm) {
5263        ShutdownThread.rebootSafeMode(mContext, confirm);
5264    }
5265
5266    @Override
5267    public void setInputFilter(IInputFilter filter) {
5268        if (!checkCallingPermission(android.Manifest.permission.FILTER_EVENTS, "setInputFilter()")) {
5269            throw new SecurityException("Requires FILTER_EVENTS permission");
5270        }
5271        mInputManager.setInputFilter(filter);
5272    }
5273
5274    @Override
5275    public void setTouchExplorationEnabled(boolean enabled) {
5276        mPolicy.setTouchExplorationEnabled(enabled);
5277    }
5278
5279    public void setCurrentUser(final int newUserId) {
5280        synchronized (mWindowMap) {
5281            int oldUserId = mCurrentUserId;
5282            mCurrentUserId = newUserId;
5283            mAppTransition.setCurrentUser(newUserId);
5284            mPolicy.setCurrentUserLw(newUserId);
5285
5286            // Hide windows that should not be seen by the new user.
5287            final int numDisplays = mDisplayContents.size();
5288            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
5289                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
5290                displayContent.switchUserStacks(newUserId);
5291                rebuildAppWindowListLocked(displayContent);
5292            }
5293            performLayoutAndPlaceSurfacesLocked();
5294        }
5295    }
5296
5297    public void enableScreenAfterBoot() {
5298        synchronized(mWindowMap) {
5299            if (DEBUG_BOOT) {
5300                RuntimeException here = new RuntimeException("here");
5301                here.fillInStackTrace();
5302                Slog.i(TAG, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled
5303                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5304                        + " mShowingBootMessages=" + mShowingBootMessages
5305                        + " mSystemBooted=" + mSystemBooted, here);
5306            }
5307            if (mSystemBooted) {
5308                return;
5309            }
5310            mSystemBooted = true;
5311            hideBootMessagesLocked();
5312            // If the screen still doesn't come up after 30 seconds, give
5313            // up and turn it on.
5314            mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30*1000);
5315        }
5316
5317        mPolicy.systemBooted();
5318
5319        performEnableScreen();
5320    }
5321
5322    void enableScreenIfNeededLocked() {
5323        if (DEBUG_BOOT) {
5324            RuntimeException here = new RuntimeException("here");
5325            here.fillInStackTrace();
5326            Slog.i(TAG, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled
5327                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5328                    + " mShowingBootMessages=" + mShowingBootMessages
5329                    + " mSystemBooted=" + mSystemBooted, here);
5330        }
5331        if (mDisplayEnabled) {
5332            return;
5333        }
5334        if (!mSystemBooted && !mShowingBootMessages) {
5335            return;
5336        }
5337        mH.sendEmptyMessage(H.ENABLE_SCREEN);
5338    }
5339
5340    public void performBootTimeout() {
5341        synchronized(mWindowMap) {
5342            if (mDisplayEnabled) {
5343                return;
5344            }
5345            Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
5346            mForceDisplayEnabled = true;
5347        }
5348        performEnableScreen();
5349    }
5350
5351    public void performEnableScreen() {
5352        synchronized(mWindowMap) {
5353            if (DEBUG_BOOT) {
5354                RuntimeException here = new RuntimeException("here");
5355                here.fillInStackTrace();
5356                Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
5357                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5358                        + " mShowingBootMessages=" + mShowingBootMessages
5359                        + " mSystemBooted=" + mSystemBooted
5360                        + " mOnlyCore=" + mOnlyCore, here);
5361            }
5362            if (mDisplayEnabled) {
5363                return;
5364            }
5365            if (!mSystemBooted && !mShowingBootMessages) {
5366                return;
5367            }
5368
5369            if (!mForceDisplayEnabled) {
5370                // Don't enable the screen until all existing windows
5371                // have been drawn.
5372                boolean haveBootMsg = false;
5373                boolean haveApp = false;
5374                // if the wallpaper service is disabled on the device, we're never going to have
5375                // wallpaper, don't bother waiting for it
5376                boolean haveWallpaper = false;
5377                boolean wallpaperEnabled = mContext.getResources().getBoolean(
5378                        com.android.internal.R.bool.config_enableWallpaperService)
5379                        && !mOnlyCore;
5380                boolean haveKeyguard = true;
5381                // TODO(multidisplay): Expand to all displays?
5382                final WindowList windows = getDefaultWindowListLocked();
5383                final int N = windows.size();
5384                for (int i=0; i<N; i++) {
5385                    WindowState w = windows.get(i);
5386                    if (w.mAttrs.type == TYPE_KEYGUARD) {
5387                        // Only if there is a keyguard attached to the window manager
5388                        // will we consider ourselves as having a keyguard.  If it
5389                        // isn't attached, we don't know if it wants to be shown or
5390                        // hidden.  If it is attached, we will say we have a keyguard
5391                        // if the window doesn't want to be visible, because in that
5392                        // case it explicitly doesn't want to be shown so we should
5393                        // not delay turning the screen on for it.
5394                        boolean vis = w.mViewVisibility == View.VISIBLE
5395                                && w.mPolicyVisibility;
5396                        haveKeyguard = !vis;
5397                    }
5398                    if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
5399                        return;
5400                    }
5401                    if (w.isDrawnLw()) {
5402                        if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
5403                            haveBootMsg = true;
5404                        } else if (w.mAttrs.type == TYPE_APPLICATION) {
5405                            haveApp = true;
5406                        } else if (w.mAttrs.type == TYPE_WALLPAPER) {
5407                            haveWallpaper = true;
5408                        } else if (w.mAttrs.type == TYPE_KEYGUARD) {
5409                            haveKeyguard = true;
5410                        }
5411                    }
5412                }
5413
5414                if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
5415                    Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
5416                            + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
5417                            + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
5418                            + " haveKeyguard=" + haveKeyguard);
5419                }
5420
5421                // If we are turning on the screen to show the boot message,
5422                // don't do it until the boot message is actually displayed.
5423                if (!mSystemBooted && !haveBootMsg) {
5424                    return;
5425                }
5426
5427                // If we are turning on the screen after the boot is completed
5428                // normally, don't do so until we have the application and
5429                // wallpaper.
5430                if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
5431                        (wallpaperEnabled && !haveWallpaper))) {
5432                    return;
5433                }
5434            }
5435
5436            mDisplayEnabled = true;
5437            if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
5438            if (false) {
5439                StringWriter sw = new StringWriter();
5440                PrintWriter pw = new FastPrintWriter(sw, false, 1024);
5441                this.dump(null, pw, null);
5442                pw.flush();
5443                Slog.i(TAG, sw.toString());
5444            }
5445            try {
5446                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
5447                if (surfaceFlinger != null) {
5448                    //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
5449                    Parcel data = Parcel.obtain();
5450                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
5451                    surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
5452                                            data, null, 0);
5453                    data.recycle();
5454                }
5455            } catch (RemoteException ex) {
5456                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
5457            }
5458
5459            // Enable input dispatch.
5460            mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
5461        }
5462
5463        mPolicy.enableScreenAfterBoot();
5464
5465        // Make sure the last requested orientation has been applied.
5466        updateRotationUnchecked(false, false);
5467    }
5468
5469    public void showBootMessage(final CharSequence msg, final boolean always) {
5470        boolean first = false;
5471        synchronized(mWindowMap) {
5472            if (DEBUG_BOOT) {
5473                RuntimeException here = new RuntimeException("here");
5474                here.fillInStackTrace();
5475                Slog.i(TAG, "showBootMessage: msg=" + msg + " always=" + always
5476                        + " mAllowBootMessages=" + mAllowBootMessages
5477                        + " mShowingBootMessages=" + mShowingBootMessages
5478                        + " mSystemBooted=" + mSystemBooted, here);
5479            }
5480            if (!mAllowBootMessages) {
5481                return;
5482            }
5483            if (!mShowingBootMessages) {
5484                if (!always) {
5485                    return;
5486                }
5487                first = true;
5488            }
5489            if (mSystemBooted) {
5490                return;
5491            }
5492            mShowingBootMessages = true;
5493            mPolicy.showBootMessage(msg, always);
5494        }
5495        if (first) {
5496            performEnableScreen();
5497        }
5498    }
5499
5500    public void hideBootMessagesLocked() {
5501        if (DEBUG_BOOT) {
5502            RuntimeException here = new RuntimeException("here");
5503            here.fillInStackTrace();
5504            Slog.i(TAG, "hideBootMessagesLocked: mDisplayEnabled=" + mDisplayEnabled
5505                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5506                    + " mShowingBootMessages=" + mShowingBootMessages
5507                    + " mSystemBooted=" + mSystemBooted, here);
5508        }
5509        if (mShowingBootMessages) {
5510            mShowingBootMessages = false;
5511            mPolicy.hideBootMessages();
5512        }
5513    }
5514
5515    @Override
5516    public void setInTouchMode(boolean mode) {
5517        synchronized(mWindowMap) {
5518            mInTouchMode = mode;
5519        }
5520    }
5521
5522    // TODO: more accounting of which pid(s) turned it on, keep count,
5523    // only allow disables from pids which have count on, etc.
5524    @Override
5525    public void showStrictModeViolation(boolean on) {
5526        int pid = Binder.getCallingPid();
5527        mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid));
5528    }
5529
5530    private void showStrictModeViolation(int arg, int pid) {
5531        final boolean on = arg != 0;
5532        synchronized(mWindowMap) {
5533            // Ignoring requests to enable the red border from clients
5534            // which aren't on screen.  (e.g. Broadcast Receivers in
5535            // the background..)
5536            if (on) {
5537                boolean isVisible = false;
5538                final int numDisplays = mDisplayContents.size();
5539                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
5540                    final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
5541                    final int numWindows = windows.size();
5542                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
5543                        final WindowState ws = windows.get(winNdx);
5544                        if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
5545                            isVisible = true;
5546                            break;
5547                        }
5548                    }
5549                }
5550                if (!isVisible) {
5551                    return;
5552                }
5553            }
5554
5555            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5556                    ">>> OPEN TRANSACTION showStrictModeViolation");
5557            SurfaceControl.openTransaction();
5558            try {
5559                // TODO(multi-display): support multiple displays
5560                if (mStrictModeFlash == null) {
5561                    mStrictModeFlash = new StrictModeFlash(
5562                            getDefaultDisplayContentLocked().getDisplay(), mFxSession);
5563                }
5564                mStrictModeFlash.setVisibility(on);
5565            } finally {
5566                SurfaceControl.closeTransaction();
5567                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5568                        "<<< CLOSE TRANSACTION showStrictModeViolation");
5569            }
5570        }
5571    }
5572
5573    @Override
5574    public void setStrictModeVisualIndicatorPreference(String value) {
5575        SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
5576    }
5577
5578    /**
5579     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
5580     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
5581     * of the target image.
5582     *
5583     * @param displayId the Display to take a screenshot of.
5584     * @param width the width of the target bitmap
5585     * @param height the height of the target bitmap
5586     * @param force565 if true the returned bitmap will be RGB_565, otherwise it
5587     *                 will be the same config as the surface
5588     */
5589    @Override
5590    public Bitmap screenshotApplications(IBinder appToken, int displayId, int width,
5591            int height, boolean force565) {
5592        if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
5593                "screenshotApplications()")) {
5594            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
5595        }
5596
5597        Bitmap rawss = null;
5598
5599        int maxLayer = 0;
5600        final Rect frame = new Rect();
5601
5602        float scale = 0;
5603        int dw, dh;
5604        int rot = Surface.ROTATION_0;
5605
5606        boolean screenshotReady;
5607        int minLayer;
5608        if (appToken == null) {
5609            screenshotReady = true;
5610            minLayer = 0;
5611        } else {
5612            screenshotReady = false;
5613            minLayer = Integer.MAX_VALUE;
5614        }
5615
5616        int retryCount = 0;
5617        WindowState appWin = null;
5618
5619        do {
5620            if (retryCount++ > 0) {
5621                try {
5622                    Thread.sleep(100);
5623                } catch (InterruptedException e) {
5624                }
5625            }
5626            synchronized(mWindowMap) {
5627                final DisplayContent displayContent = getDisplayContentLocked(displayId);
5628                if (displayContent == null) {
5629                    return null;
5630                }
5631                final DisplayInfo displayInfo = displayContent.getDisplayInfo();
5632                dw = displayInfo.logicalWidth;
5633                dh = displayInfo.logicalHeight;
5634
5635                int aboveAppLayer = mPolicy.windowTypeToLayerLw(TYPE_APPLICATION)
5636                        * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
5637                aboveAppLayer += TYPE_LAYER_MULTIPLIER;
5638
5639                boolean isImeTarget = mInputMethodTarget != null
5640                        && mInputMethodTarget.mAppToken != null
5641                        && mInputMethodTarget.mAppToken.appToken != null
5642                        && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
5643
5644                // Figure out the part of the screen that is actually the app.
5645                boolean including = false;
5646                appWin = null;
5647                final WindowList windows = displayContent.getWindowList();
5648                final Rect stackBounds = new Rect();
5649                for (int i = windows.size() - 1; i >= 0; i--) {
5650                    WindowState ws = windows.get(i);
5651                    if (!ws.mHasSurface) {
5652                        continue;
5653                    }
5654                    if (ws.mLayer >= aboveAppLayer) {
5655                        continue;
5656                    }
5657                    // When we will skip windows: when we are not including
5658                    // ones behind a window we didn't skip, and we are actually
5659                    // taking a screenshot of a specific app.
5660                    if (!including && appToken != null) {
5661                        // Also, we can possibly skip this window if it is not
5662                        // an IME target or the application for the screenshot
5663                        // is not the current IME target.
5664                        if (!ws.mIsImWindow || !isImeTarget) {
5665                            // And finally, this window is of no interest if it
5666                            // is not associated with the screenshot app.
5667                            if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
5668                                continue;
5669                            }
5670                            appWin = ws;
5671                            ws.getStackBounds(stackBounds);
5672                        }
5673                    }
5674
5675                    // We keep on including windows until we go past a full-screen
5676                    // window.
5677                    including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
5678
5679                    final WindowStateAnimator winAnim = ws.mWinAnimator;
5680                    if (maxLayer < winAnim.mSurfaceLayer) {
5681                        maxLayer = winAnim.mSurfaceLayer;
5682                    }
5683                    if (minLayer > winAnim.mSurfaceLayer) {
5684                        minLayer = winAnim.mSurfaceLayer;
5685                    }
5686
5687                    // Don't include wallpaper in bounds calculation
5688                    if (!ws.mIsWallpaper) {
5689                        final Rect wf = ws.mFrame;
5690                        final Rect cr = ws.mContentInsets;
5691                        int left = wf.left + cr.left;
5692                        int top = wf.top + cr.top;
5693                        int right = wf.right - cr.right;
5694                        int bottom = wf.bottom - cr.bottom;
5695                        frame.union(left, top, right, bottom);
5696                        frame.intersect(stackBounds);
5697                    }
5698
5699                    if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
5700                            ws.isDisplayedLw()) {
5701                        screenshotReady = true;
5702                    }
5703                }
5704
5705                if (appToken != null && appWin == null) {
5706                    // Can't find a window to snapshot.
5707                    if (DEBUG_SCREENSHOT) Slog.i(TAG,
5708                            "Screenshot: Couldn't find a surface matching " + appToken);
5709                    return null;
5710                }
5711                if (!screenshotReady) {
5712                    // Delay and hope that window gets drawn.
5713                    if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot: No image ready for " + appToken
5714                            + ", " + appWin + " drawState=" + appWin.mWinAnimator.mDrawState);
5715                    continue;
5716                }
5717
5718                // Constrain frame to the screen size.
5719                frame.intersect(0, 0, dw, dh);
5720
5721                if (frame.isEmpty() || maxLayer == 0) {
5722                    if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot of " + appToken
5723                            + ": returning null frame=" + frame.toShortString() + " maxLayer="
5724                            + maxLayer);
5725                    return null;
5726                }
5727
5728                // The screenshot API does not apply the current screen rotation.
5729                rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
5730                int fw = frame.width();
5731                int fh = frame.height();
5732
5733                // Constrain thumbnail to smaller of screen width or height. Assumes aspect
5734                // of thumbnail is the same as the screen (in landscape) or square.
5735                scale = Math.max(width / (float) fw, height / (float) fh);
5736                /*
5737                float targetWidthScale = width / (float) fw;
5738                float targetHeightScale = height / (float) fh;
5739                if (fw <= fh) {
5740                    scale = targetWidthScale;
5741                    // If aspect of thumbnail is the same as the screen (in landscape),
5742                    // select the slightly larger value so we fill the entire bitmap
5743                    if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
5744                        scale = targetHeightScale;
5745                    }
5746                } else {
5747                    scale = targetHeightScale;
5748                    // If aspect of thumbnail is the same as the screen (in landscape),
5749                    // select the slightly larger value so we fill the entire bitmap
5750                    if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
5751                        scale = targetWidthScale;
5752                    }
5753                }
5754                */
5755
5756                // The screen shot will contain the entire screen.
5757                dw = (int)(dw*scale);
5758                dh = (int)(dh*scale);
5759                if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
5760                    int tmp = dw;
5761                    dw = dh;
5762                    dh = tmp;
5763                    rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
5764                }
5765                if (DEBUG_SCREENSHOT) {
5766                    Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
5767                            + maxLayer + " appToken=" + appToken);
5768                    for (int i = 0; i < windows.size(); i++) {
5769                        WindowState win = windows.get(i);
5770                        Slog.i(TAG, win + ": " + win.mLayer
5771                                + " animLayer=" + win.mWinAnimator.mAnimLayer
5772                                + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
5773                    }
5774                }
5775                rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer);
5776            }
5777        } while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES);
5778        if (retryCount > MAX_SCREENSHOT_RETRIES)  Slog.i(TAG, "Screenshot max retries " +
5779                retryCount + " of " + appToken + " appWin=" + (appWin == null ?
5780                        "null" : (appWin + " drawState=" + appWin.mWinAnimator.mDrawState)));
5781
5782        if (rawss == null) {
5783            Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh
5784                    + ") to layer " + maxLayer);
5785            return null;
5786        }
5787
5788        Bitmap bm = Bitmap.createBitmap(width, height, force565 ? Config.RGB_565 : rawss.getConfig());
5789        frame.scale(scale);
5790        Matrix matrix = new Matrix();
5791        ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
5792        // TODO: Test for RTL vs. LTR and use frame.right-width instead of -frame.left
5793        matrix.postTranslate(-FloatMath.ceil(frame.left), -FloatMath.ceil(frame.top));
5794        Canvas canvas = new Canvas(bm);
5795        canvas.drawColor(0xFF000000);
5796        canvas.drawBitmap(rawss, matrix, null);
5797        canvas.setBitmap(null);
5798
5799        if (DEBUG_SCREENSHOT) {
5800            // TEST IF IT's ALL BLACK
5801            int[] buffer = new int[bm.getWidth() * bm.getHeight()];
5802            bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
5803            boolean allBlack = true;
5804            final int firstColor = buffer[0];
5805            for (int i = 0; i < buffer.length; i++) {
5806                if (buffer[i] != firstColor) {
5807                    allBlack = false;
5808                    break;
5809                }
5810            }
5811            if (allBlack) {
5812                Slog.i(TAG, "Screenshot " + appWin + " was monochrome(" +
5813                        Integer.toHexString(firstColor) + ")! mSurfaceLayer=" +
5814                        (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null") +
5815                        " minLayer=" + minLayer + " maxLayer=" + maxLayer);
5816            }
5817        }
5818
5819        rawss.recycle();
5820        return bm;
5821    }
5822
5823    /**
5824     * Freeze rotation changes.  (Enable "rotation lock".)
5825     * Persists across reboots.
5826     * @param rotation The desired rotation to freeze to, or -1 to use the
5827     * current rotation.
5828     */
5829    @Override
5830    public void freezeRotation(int rotation) {
5831        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5832                "freezeRotation()")) {
5833            throw new SecurityException("Requires SET_ORIENTATION permission");
5834        }
5835        if (rotation < -1 || rotation > Surface.ROTATION_270) {
5836            throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
5837                    + "rotation constant.");
5838        }
5839
5840        if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
5841
5842        long origId = Binder.clearCallingIdentity();
5843        try {
5844            mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
5845                    rotation == -1 ? mRotation : rotation);
5846        } finally {
5847            Binder.restoreCallingIdentity(origId);
5848        }
5849
5850        updateRotationUnchecked(false, false);
5851    }
5852
5853    /**
5854     * Thaw rotation changes.  (Disable "rotation lock".)
5855     * Persists across reboots.
5856     */
5857    @Override
5858    public void thawRotation() {
5859        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5860                "thawRotation()")) {
5861            throw new SecurityException("Requires SET_ORIENTATION permission");
5862        }
5863
5864        if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
5865
5866        long origId = Binder.clearCallingIdentity();
5867        try {
5868            mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE,
5869                    777); // rot not used
5870        } finally {
5871            Binder.restoreCallingIdentity(origId);
5872        }
5873
5874        updateRotationUnchecked(false, false);
5875    }
5876
5877    /**
5878     * Recalculate the current rotation.
5879     *
5880     * Called by the window manager policy whenever the state of the system changes
5881     * such that the current rotation might need to be updated, such as when the
5882     * device is docked or rotated into a new posture.
5883     */
5884    @Override
5885    public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
5886        updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
5887    }
5888
5889    /**
5890     * Temporarily pauses rotation changes until resumed.
5891     *
5892     * This can be used to prevent rotation changes from occurring while the user is
5893     * performing certain operations, such as drag and drop.
5894     *
5895     * This call nests and must be matched by an equal number of calls to
5896     * {@link #resumeRotationLocked}.
5897     */
5898    void pauseRotationLocked() {
5899        mDeferredRotationPauseCount += 1;
5900    }
5901
5902    /**
5903     * Resumes normal rotation changes after being paused.
5904     */
5905    void resumeRotationLocked() {
5906        if (mDeferredRotationPauseCount > 0) {
5907            mDeferredRotationPauseCount -= 1;
5908            if (mDeferredRotationPauseCount == 0) {
5909                boolean changed = updateRotationUncheckedLocked(false);
5910                if (changed) {
5911                    mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
5912                }
5913            }
5914        }
5915    }
5916
5917    public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
5918        if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked("
5919                   + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")");
5920
5921        long origId = Binder.clearCallingIdentity();
5922        boolean changed;
5923        synchronized(mWindowMap) {
5924            changed = updateRotationUncheckedLocked(false);
5925            if (!changed || forceRelayout) {
5926                getDefaultDisplayContentLocked().layoutNeeded = true;
5927                performLayoutAndPlaceSurfacesLocked();
5928            }
5929        }
5930
5931        if (changed || alwaysSendConfiguration) {
5932            sendNewConfiguration();
5933        }
5934
5935        Binder.restoreCallingIdentity(origId);
5936    }
5937
5938    // TODO(multidisplay): Rotate any display?
5939    /**
5940     * Updates the current rotation.
5941     *
5942     * Returns true if the rotation has been changed.  In this case YOU
5943     * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN.
5944     */
5945    public boolean updateRotationUncheckedLocked(boolean inTransaction) {
5946        if (mDeferredRotationPauseCount > 0) {
5947            // Rotation updates have been paused temporarily.  Defer the update until
5948            // updates have been resumed.
5949            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused.");
5950            return false;
5951        }
5952
5953        ScreenRotationAnimation screenRotationAnimation =
5954                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
5955        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
5956            // Rotation updates cannot be performed while the previous rotation change
5957            // animation is still in progress.  Skip this update.  We will try updating
5958            // again after the animation is finished and the display is unfrozen.
5959            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress.");
5960            return false;
5961        }
5962
5963        if (!mDisplayEnabled) {
5964            // No point choosing a rotation if the display is not enabled.
5965            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled.");
5966            return false;
5967        }
5968
5969        // TODO: Implement forced rotation changes.
5970        //       Set mAltOrientation to indicate that the application is receiving
5971        //       an orientation that has different metrics than it expected.
5972        //       eg. Portrait instead of Landscape.
5973
5974        int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);
5975        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
5976                mForcedAppOrientation, rotation);
5977
5978        if (DEBUG_ORIENTATION) {
5979            Slog.v(TAG, "Application requested orientation "
5980                    + mForcedAppOrientation + ", got rotation " + rotation
5981                    + " which has " + (altOrientation ? "incompatible" : "compatible")
5982                    + " metrics");
5983        }
5984
5985        if (mRotation == rotation && mAltOrientation == altOrientation) {
5986            // No change.
5987            return false;
5988        }
5989
5990        if (DEBUG_ORIENTATION) {
5991            Slog.v(TAG,
5992                "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
5993                + " from " + mRotation + (mAltOrientation ? " (alt)" : "")
5994                + ", forceApp=" + mForcedAppOrientation);
5995        }
5996
5997        mRotation = rotation;
5998        mAltOrientation = altOrientation;
5999        mPolicy.setRotationLw(mRotation);
6000
6001        mWindowsFreezingScreen = true;
6002        mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
6003        mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
6004        mWaitingForConfig = true;
6005        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6006        displayContent.layoutNeeded = true;
6007        final int[] anim = new int[2];
6008        if (displayContent.isDimming()) {
6009            anim[0] = anim[1] = 0;
6010        } else {
6011            mPolicy.selectRotationAnimationLw(anim);
6012        }
6013        startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
6014        // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
6015        screenRotationAnimation =
6016                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
6017
6018        // We need to update our screen size information to match the new
6019        // rotation.  Note that this is redundant with the later call to
6020        // sendNewConfiguration() that must be called after this function
6021        // returns...  however we need to do the screen size part of that
6022        // before then so we have the correct size to use when initializing
6023        // the rotation animation for the new rotation.
6024        computeScreenConfigurationLocked(null);
6025
6026        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
6027        if (!inTransaction) {
6028            if (SHOW_TRANSACTIONS) {
6029                Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");
6030            }
6031            SurfaceControl.openTransaction();
6032        }
6033        try {
6034            // NOTE: We disable the rotation in the emulator because
6035            //       it doesn't support hardware OpenGL emulation yet.
6036            if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
6037                    && screenRotationAnimation.hasScreenshot()) {
6038                if (screenRotationAnimation.setRotationInTransaction(
6039                        rotation, mFxSession,
6040                        MAX_ANIMATION_DURATION, mTransitionAnimationScale,
6041                        displayInfo.logicalWidth, displayInfo.logicalHeight)) {
6042                    scheduleAnimationLocked();
6043                }
6044            }
6045
6046            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
6047        } finally {
6048            if (!inTransaction) {
6049                SurfaceControl.closeTransaction();
6050                if (SHOW_LIGHT_TRANSACTIONS) {
6051                    Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");
6052                }
6053            }
6054        }
6055
6056        final WindowList windows = displayContent.getWindowList();
6057        for (int i = windows.size() - 1; i >= 0; i--) {
6058            WindowState w = windows.get(i);
6059            if (w.mHasSurface) {
6060                if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
6061                w.mOrientationChanging = true;
6062                mInnerFields.mOrientationChangeComplete = false;
6063            }
6064            w.mLastFreezeDuration = 0;
6065        }
6066
6067        for (int i=mRotationWatchers.size()-1; i>=0; i--) {
6068            try {
6069                mRotationWatchers.get(i).onRotationChanged(rotation);
6070            } catch (RemoteException e) {
6071            }
6072        }
6073
6074        //TODO (multidisplay): Magnification is supported only for the default display.
6075        if (mDisplayMagnifier != null
6076                && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {
6077            mDisplayMagnifier.onRotationChangedLocked(getDefaultDisplayContentLocked(), rotation);
6078        }
6079
6080        return true;
6081    }
6082
6083    @Override
6084    public int getRotation() {
6085        return mRotation;
6086    }
6087
6088    @Override
6089    public boolean isRotationFrozen() {
6090        return mPolicy.getUserRotationMode() == WindowManagerPolicy.USER_ROTATION_LOCKED;
6091    }
6092
6093    @Override
6094    public int watchRotation(IRotationWatcher watcher) {
6095        final IBinder watcherBinder = watcher.asBinder();
6096        IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
6097            @Override
6098            public void binderDied() {
6099                synchronized (mWindowMap) {
6100                    for (int i=0; i<mRotationWatchers.size(); i++) {
6101                        if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
6102                            IRotationWatcher removed = mRotationWatchers.remove(i);
6103                            if (removed != null) {
6104                                removed.asBinder().unlinkToDeath(this, 0);
6105                            }
6106                            i--;
6107                        }
6108                    }
6109                }
6110            }
6111        };
6112
6113        synchronized (mWindowMap) {
6114            try {
6115                watcher.asBinder().linkToDeath(dr, 0);
6116                mRotationWatchers.add(watcher);
6117            } catch (RemoteException e) {
6118                // Client died, no cleanup needed.
6119            }
6120
6121            return mRotation;
6122        }
6123    }
6124
6125    @Override
6126    public void removeRotationWatcher(IRotationWatcher watcher) {
6127        final IBinder watcherBinder = watcher.asBinder();
6128        synchronized (mWindowMap) {
6129            for (int i=0; i<mRotationWatchers.size(); i++) {
6130                if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
6131                    mRotationWatchers.remove(i);
6132                    i--;
6133                }
6134            }
6135        }
6136    }
6137
6138    /**
6139     * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
6140     * theme attribute) on devices that feature a physical options menu key attempt to position
6141     * their menu panel window along the edge of the screen nearest the physical menu key.
6142     * This lowers the travel distance between invoking the menu panel and selecting
6143     * a menu option.
6144     *
6145     * This method helps control where that menu is placed. Its current implementation makes
6146     * assumptions about the menu key and its relationship to the screen based on whether
6147     * the device's natural orientation is portrait (width < height) or landscape.
6148     *
6149     * The menu key is assumed to be located along the bottom edge of natural-portrait
6150     * devices and along the right edge of natural-landscape devices. If these assumptions
6151     * do not hold for the target device, this method should be changed to reflect that.
6152     *
6153     * @return A {@link Gravity} value for placing the options menu window
6154     */
6155    @Override
6156    public int getPreferredOptionsPanelGravity() {
6157        synchronized (mWindowMap) {
6158            final int rotation = getRotation();
6159
6160            // TODO(multidisplay): Assume that such devices physical keys are on the main screen.
6161            final DisplayContent displayContent = getDefaultDisplayContentLocked();
6162            if (displayContent.mInitialDisplayWidth < displayContent.mInitialDisplayHeight) {
6163                // On devices with a natural orientation of portrait
6164                switch (rotation) {
6165                    default:
6166                    case Surface.ROTATION_0:
6167                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6168                    case Surface.ROTATION_90:
6169                        return Gravity.RIGHT | Gravity.BOTTOM;
6170                    case Surface.ROTATION_180:
6171                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6172                    case Surface.ROTATION_270:
6173                        return Gravity.START | Gravity.BOTTOM;
6174                }
6175            }
6176
6177            // On devices with a natural orientation of landscape
6178            switch (rotation) {
6179                default:
6180                case Surface.ROTATION_0:
6181                    return Gravity.RIGHT | Gravity.BOTTOM;
6182                case Surface.ROTATION_90:
6183                    return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6184                case Surface.ROTATION_180:
6185                    return Gravity.START | Gravity.BOTTOM;
6186                case Surface.ROTATION_270:
6187                    return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6188            }
6189        }
6190    }
6191
6192    /**
6193     * Starts the view server on the specified port.
6194     *
6195     * @param port The port to listener to.
6196     *
6197     * @return True if the server was successfully started, false otherwise.
6198     *
6199     * @see com.android.server.wm.ViewServer
6200     * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
6201     */
6202    @Override
6203    public boolean startViewServer(int port) {
6204        if (isSystemSecure()) {
6205            return false;
6206        }
6207
6208        if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
6209            return false;
6210        }
6211
6212        if (port < 1024) {
6213            return false;
6214        }
6215
6216        if (mViewServer != null) {
6217            if (!mViewServer.isRunning()) {
6218                try {
6219                    return mViewServer.start();
6220                } catch (IOException e) {
6221                    Slog.w(TAG, "View server did not start");
6222                }
6223            }
6224            return false;
6225        }
6226
6227        try {
6228            mViewServer = new ViewServer(this, port);
6229            return mViewServer.start();
6230        } catch (IOException e) {
6231            Slog.w(TAG, "View server did not start");
6232        }
6233        return false;
6234    }
6235
6236    private boolean isSystemSecure() {
6237        return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
6238                "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
6239    }
6240
6241    /**
6242     * Stops the view server if it exists.
6243     *
6244     * @return True if the server stopped, false if it wasn't started or
6245     *         couldn't be stopped.
6246     *
6247     * @see com.android.server.wm.ViewServer
6248     */
6249    @Override
6250    public boolean stopViewServer() {
6251        if (isSystemSecure()) {
6252            return false;
6253        }
6254
6255        if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
6256            return false;
6257        }
6258
6259        if (mViewServer != null) {
6260            return mViewServer.stop();
6261        }
6262        return false;
6263    }
6264
6265    /**
6266     * Indicates whether the view server is running.
6267     *
6268     * @return True if the server is running, false otherwise.
6269     *
6270     * @see com.android.server.wm.ViewServer
6271     */
6272    @Override
6273    public boolean isViewServerRunning() {
6274        if (isSystemSecure()) {
6275            return false;
6276        }
6277
6278        if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
6279            return false;
6280        }
6281
6282        return mViewServer != null && mViewServer.isRunning();
6283    }
6284
6285    /**
6286     * Lists all availble windows in the system. The listing is written in the
6287     * specified Socket's output stream with the following syntax:
6288     * windowHashCodeInHexadecimal windowName
6289     * Each line of the ouput represents a different window.
6290     *
6291     * @param client The remote client to send the listing to.
6292     * @return False if an error occured, true otherwise.
6293     */
6294    boolean viewServerListWindows(Socket client) {
6295        if (isSystemSecure()) {
6296            return false;
6297        }
6298
6299        boolean result = true;
6300
6301        WindowList windows = new WindowList();
6302        synchronized (mWindowMap) {
6303            //noinspection unchecked
6304            final int numDisplays = mDisplayContents.size();
6305            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
6306                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
6307                windows.addAll(displayContent.getWindowList());
6308            }
6309        }
6310
6311        BufferedWriter out = null;
6312
6313        // Any uncaught exception will crash the system process
6314        try {
6315            OutputStream clientStream = client.getOutputStream();
6316            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
6317
6318            final int count = windows.size();
6319            for (int i = 0; i < count; i++) {
6320                final WindowState w = windows.get(i);
6321                out.write(Integer.toHexString(System.identityHashCode(w)));
6322                out.write(' ');
6323                out.append(w.mAttrs.getTitle());
6324                out.write('\n');
6325            }
6326
6327            out.write("DONE.\n");
6328            out.flush();
6329        } catch (Exception e) {
6330            result = false;
6331        } finally {
6332            if (out != null) {
6333                try {
6334                    out.close();
6335                } catch (IOException e) {
6336                    result = false;
6337                }
6338            }
6339        }
6340
6341        return result;
6342    }
6343
6344    // TODO(multidisplay): Extend to multiple displays.
6345    /**
6346     * Returns the focused window in the following format:
6347     * windowHashCodeInHexadecimal windowName
6348     *
6349     * @param client The remote client to send the listing to.
6350     * @return False if an error occurred, true otherwise.
6351     */
6352    boolean viewServerGetFocusedWindow(Socket client) {
6353        if (isSystemSecure()) {
6354            return false;
6355        }
6356
6357        boolean result = true;
6358
6359        WindowState focusedWindow = getFocusedWindow();
6360
6361        BufferedWriter out = null;
6362
6363        // Any uncaught exception will crash the system process
6364        try {
6365            OutputStream clientStream = client.getOutputStream();
6366            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
6367
6368            if(focusedWindow != null) {
6369                out.write(Integer.toHexString(System.identityHashCode(focusedWindow)));
6370                out.write(' ');
6371                out.append(focusedWindow.mAttrs.getTitle());
6372            }
6373            out.write('\n');
6374            out.flush();
6375        } catch (Exception e) {
6376            result = false;
6377        } finally {
6378            if (out != null) {
6379                try {
6380                    out.close();
6381                } catch (IOException e) {
6382                    result = false;
6383                }
6384            }
6385        }
6386
6387        return result;
6388    }
6389
6390    /**
6391     * Sends a command to a target window. The result of the command, if any, will be
6392     * written in the output stream of the specified socket.
6393     *
6394     * The parameters must follow this syntax:
6395     * windowHashcode extra
6396     *
6397     * Where XX is the length in characeters of the windowTitle.
6398     *
6399     * The first parameter is the target window. The window with the specified hashcode
6400     * will be the target. If no target can be found, nothing happens. The extra parameters
6401     * will be delivered to the target window and as parameters to the command itself.
6402     *
6403     * @param client The remote client to sent the result, if any, to.
6404     * @param command The command to execute.
6405     * @param parameters The command parameters.
6406     *
6407     * @return True if the command was successfully delivered, false otherwise. This does
6408     *         not indicate whether the command itself was successful.
6409     */
6410    boolean viewServerWindowCommand(Socket client, String command, String parameters) {
6411        if (isSystemSecure()) {
6412            return false;
6413        }
6414
6415        boolean success = true;
6416        Parcel data = null;
6417        Parcel reply = null;
6418
6419        BufferedWriter out = null;
6420
6421        // Any uncaught exception will crash the system process
6422        try {
6423            // Find the hashcode of the window
6424            int index = parameters.indexOf(' ');
6425            if (index == -1) {
6426                index = parameters.length();
6427            }
6428            final String code = parameters.substring(0, index);
6429            int hashCode = (int) Long.parseLong(code, 16);
6430
6431            // Extract the command's parameter after the window description
6432            if (index < parameters.length()) {
6433                parameters = parameters.substring(index + 1);
6434            } else {
6435                parameters = "";
6436            }
6437
6438            final WindowState window = findWindow(hashCode);
6439            if (window == null) {
6440                return false;
6441            }
6442
6443            data = Parcel.obtain();
6444            data.writeInterfaceToken("android.view.IWindow");
6445            data.writeString(command);
6446            data.writeString(parameters);
6447            data.writeInt(1);
6448            ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
6449
6450            reply = Parcel.obtain();
6451
6452            final IBinder binder = window.mClient.asBinder();
6453            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
6454            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
6455
6456            reply.readException();
6457
6458            if (!client.isOutputShutdown()) {
6459                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
6460                out.write("DONE\n");
6461                out.flush();
6462            }
6463
6464        } catch (Exception e) {
6465            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
6466            success = false;
6467        } finally {
6468            if (data != null) {
6469                data.recycle();
6470            }
6471            if (reply != null) {
6472                reply.recycle();
6473            }
6474            if (out != null) {
6475                try {
6476                    out.close();
6477                } catch (IOException e) {
6478
6479                }
6480            }
6481        }
6482
6483        return success;
6484    }
6485
6486    public void addWindowChangeListener(WindowChangeListener listener) {
6487        synchronized(mWindowMap) {
6488            mWindowChangeListeners.add(listener);
6489        }
6490    }
6491
6492    public void removeWindowChangeListener(WindowChangeListener listener) {
6493        synchronized(mWindowMap) {
6494            mWindowChangeListeners.remove(listener);
6495        }
6496    }
6497
6498    private void notifyWindowsChanged() {
6499        WindowChangeListener[] windowChangeListeners;
6500        synchronized(mWindowMap) {
6501            if(mWindowChangeListeners.isEmpty()) {
6502                return;
6503            }
6504            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6505            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6506        }
6507        int N = windowChangeListeners.length;
6508        for(int i = 0; i < N; i++) {
6509            windowChangeListeners[i].windowsChanged();
6510        }
6511    }
6512
6513    private void notifyFocusChanged() {
6514        WindowChangeListener[] windowChangeListeners;
6515        synchronized(mWindowMap) {
6516            if(mWindowChangeListeners.isEmpty()) {
6517                return;
6518            }
6519            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6520            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6521        }
6522        int N = windowChangeListeners.length;
6523        for(int i = 0; i < N; i++) {
6524            windowChangeListeners[i].focusChanged();
6525        }
6526    }
6527
6528    private WindowState findWindow(int hashCode) {
6529        if (hashCode == -1) {
6530            // TODO(multidisplay): Extend to multiple displays.
6531            return getFocusedWindow();
6532        }
6533
6534        synchronized (mWindowMap) {
6535            final int numDisplays = mDisplayContents.size();
6536            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
6537                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
6538                final int numWindows = windows.size();
6539                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
6540                    final WindowState w = windows.get(winNdx);
6541                    if (System.identityHashCode(w) == hashCode) {
6542                        return w;
6543                    }
6544                }
6545            }
6546        }
6547
6548        return null;
6549    }
6550
6551    /*
6552     * Instruct the Activity Manager to fetch the current configuration and broadcast
6553     * that to config-changed listeners if appropriate.
6554     */
6555    void sendNewConfiguration() {
6556        try {
6557            mActivityManager.updateConfiguration(null);
6558        } catch (RemoteException e) {
6559        }
6560    }
6561
6562    public Configuration computeNewConfiguration() {
6563        synchronized (mWindowMap) {
6564            Configuration config = computeNewConfigurationLocked();
6565            if (config == null && mWaitingForConfig) {
6566                // Nothing changed but we are waiting for something... stop that!
6567                mWaitingForConfig = false;
6568                mLastFinishedFreezeSource = "new-config";
6569                performLayoutAndPlaceSurfacesLocked();
6570            }
6571            return config;
6572        }
6573    }
6574
6575    Configuration computeNewConfigurationLocked() {
6576        Configuration config = new Configuration();
6577        config.fontScale = 0;
6578        if (!computeScreenConfigurationLocked(config)) {
6579            return null;
6580        }
6581        return config;
6582    }
6583
6584    private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) {
6585        // TODO: Multidisplay: for now only use with default display.
6586        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
6587        if (width < displayInfo.smallestNominalAppWidth) {
6588            displayInfo.smallestNominalAppWidth = width;
6589        }
6590        if (width > displayInfo.largestNominalAppWidth) {
6591            displayInfo.largestNominalAppWidth = width;
6592        }
6593        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation);
6594        if (height < displayInfo.smallestNominalAppHeight) {
6595            displayInfo.smallestNominalAppHeight = height;
6596        }
6597        if (height > displayInfo.largestNominalAppHeight) {
6598            displayInfo.largestNominalAppHeight = height;
6599        }
6600    }
6601
6602    private int reduceConfigLayout(int curLayout, int rotation, float density,
6603            int dw, int dh) {
6604        // TODO: Multidisplay: for now only use with default display.
6605        // Get the app screen size at this rotation.
6606        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6607        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6608
6609        // Compute the screen layout size class for this rotation.
6610        int longSize = w;
6611        int shortSize = h;
6612        if (longSize < shortSize) {
6613            int tmp = longSize;
6614            longSize = shortSize;
6615            shortSize = tmp;
6616        }
6617        longSize = (int)(longSize/density);
6618        shortSize = (int)(shortSize/density);
6619        return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
6620    }
6621
6622    private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
6623                  int dw, int dh, float density, Configuration outConfig) {
6624        // TODO: Multidisplay: for now only use with default display.
6625
6626        // We need to determine the smallest width that will occur under normal
6627        // operation.  To this, start with the base screen size and compute the
6628        // width under the different possible rotations.  We need to un-rotate
6629        // the current screen dimensions before doing this.
6630        int unrotDw, unrotDh;
6631        if (rotated) {
6632            unrotDw = dh;
6633            unrotDh = dw;
6634        } else {
6635            unrotDw = dw;
6636            unrotDh = dh;
6637        }
6638        displayInfo.smallestNominalAppWidth = 1<<30;
6639        displayInfo.smallestNominalAppHeight = 1<<30;
6640        displayInfo.largestNominalAppWidth = 0;
6641        displayInfo.largestNominalAppHeight = 0;
6642        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh);
6643        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw);
6644        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh);
6645        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw);
6646        int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
6647        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
6648        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
6649        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
6650        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
6651        outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
6652        outConfig.screenLayout = sl;
6653    }
6654
6655    private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
6656            int dw, int dh) {
6657        // TODO: Multidisplay: for now only use with default display.
6658        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6659        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6660        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
6661        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
6662        if (curSize == 0 || size < curSize) {
6663            curSize = size;
6664        }
6665        return curSize;
6666    }
6667
6668    private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
6669        // TODO: Multidisplay: for now only use with default display.
6670        mTmpDisplayMetrics.setTo(dm);
6671        final DisplayMetrics tmpDm = mTmpDisplayMetrics;
6672        final int unrotDw, unrotDh;
6673        if (rotated) {
6674            unrotDw = dh;
6675            unrotDh = dw;
6676        } else {
6677            unrotDw = dw;
6678            unrotDh = dh;
6679        }
6680        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh);
6681        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw);
6682        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh);
6683        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw);
6684        return sw;
6685    }
6686
6687    boolean computeScreenConfigurationLocked(Configuration config) {
6688        if (!mDisplayReady) {
6689            return false;
6690        }
6691
6692        // TODO(multidisplay): For now, apply Configuration to main screen only.
6693        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6694
6695        // Use the effective "visual" dimensions based on current rotation
6696        final boolean rotated = (mRotation == Surface.ROTATION_90
6697                || mRotation == Surface.ROTATION_270);
6698        final int realdw = rotated ?
6699                displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
6700        final int realdh = rotated ?
6701                displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
6702        int dw = realdw;
6703        int dh = realdh;
6704
6705        if (mAltOrientation) {
6706            if (realdw > realdh) {
6707                // Turn landscape into portrait.
6708                int maxw = (int)(realdh/1.3f);
6709                if (maxw < realdw) {
6710                    dw = maxw;
6711                }
6712            } else {
6713                // Turn portrait into landscape.
6714                int maxh = (int)(realdw/1.3f);
6715                if (maxh < realdh) {
6716                    dh = maxh;
6717                }
6718            }
6719        }
6720
6721        if (config != null) {
6722            config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
6723                    Configuration.ORIENTATION_LANDSCAPE;
6724        }
6725
6726        // Update application display metrics.
6727        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
6728        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
6729        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
6730        synchronized(displayContent.mDisplaySizeLock) {
6731            displayInfo.rotation = mRotation;
6732            displayInfo.logicalWidth = dw;
6733            displayInfo.logicalHeight = dh;
6734            displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
6735            displayInfo.appWidth = appWidth;
6736            displayInfo.appHeight = appHeight;
6737            displayInfo.getLogicalMetrics(mRealDisplayMetrics,
6738                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
6739            displayInfo.getAppMetrics(mDisplayMetrics);
6740            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
6741                    displayContent.getDisplayId(), displayInfo);
6742        }
6743        if (false) {
6744            Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);
6745        }
6746
6747        final DisplayMetrics dm = mDisplayMetrics;
6748        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
6749                mCompatDisplayMetrics);
6750
6751        if (config != null) {
6752            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
6753                    / dm.density);
6754            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
6755                    / dm.density);
6756            computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);
6757
6758            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
6759            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
6760            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
6761            config.densityDpi = displayContent.mBaseDisplayDensity;
6762
6763            // Update the configuration based on available input devices, lid switch,
6764            // and platform configuration.
6765            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6766            config.keyboard = Configuration.KEYBOARD_NOKEYS;
6767            config.navigation = Configuration.NAVIGATION_NONAV;
6768
6769            int keyboardPresence = 0;
6770            int navigationPresence = 0;
6771            final InputDevice[] devices = mInputManager.getInputDevices();
6772            final int len = devices.length;
6773            for (int i = 0; i < len; i++) {
6774                InputDevice device = devices[i];
6775                if (!device.isVirtual()) {
6776                    final int sources = device.getSources();
6777                    final int presenceFlag = device.isExternal() ?
6778                            WindowManagerPolicy.PRESENCE_EXTERNAL :
6779                                    WindowManagerPolicy.PRESENCE_INTERNAL;
6780
6781                    if (mIsTouchDevice) {
6782                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
6783                                InputDevice.SOURCE_TOUCHSCREEN) {
6784                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
6785                        }
6786                    } else {
6787                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6788                    }
6789
6790                    if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
6791                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
6792                        navigationPresence |= presenceFlag;
6793                    } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
6794                            && config.navigation == Configuration.NAVIGATION_NONAV) {
6795                        config.navigation = Configuration.NAVIGATION_DPAD;
6796                        navigationPresence |= presenceFlag;
6797                    }
6798
6799                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
6800                        config.keyboard = Configuration.KEYBOARD_QWERTY;
6801                        keyboardPresence |= presenceFlag;
6802                    }
6803                }
6804            }
6805
6806            // Determine whether a hard keyboard is available and enabled.
6807            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6808            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6809                mHardKeyboardAvailable = hardKeyboardAvailable;
6810                mHardKeyboardEnabled = hardKeyboardAvailable;
6811                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6812                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6813            }
6814            if (!mHardKeyboardEnabled) {
6815                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6816            }
6817
6818            // Let the policy update hidden states.
6819            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6820            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6821            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6822            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
6823        }
6824
6825        return true;
6826    }
6827
6828    public boolean isHardKeyboardAvailable() {
6829        synchronized (mWindowMap) {
6830            return mHardKeyboardAvailable;
6831        }
6832    }
6833
6834    public boolean isHardKeyboardEnabled() {
6835        synchronized (mWindowMap) {
6836            return mHardKeyboardEnabled;
6837        }
6838    }
6839
6840    public void setHardKeyboardEnabled(boolean enabled) {
6841        synchronized (mWindowMap) {
6842            if (mHardKeyboardEnabled != enabled) {
6843                mHardKeyboardEnabled = enabled;
6844                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6845            }
6846        }
6847    }
6848
6849    public void setOnHardKeyboardStatusChangeListener(
6850            OnHardKeyboardStatusChangeListener listener) {
6851        synchronized (mWindowMap) {
6852            mHardKeyboardStatusChangeListener = listener;
6853        }
6854    }
6855
6856    void notifyHardKeyboardStatusChange() {
6857        final boolean available, enabled;
6858        final OnHardKeyboardStatusChangeListener listener;
6859        synchronized (mWindowMap) {
6860            listener = mHardKeyboardStatusChangeListener;
6861            available = mHardKeyboardAvailable;
6862            enabled = mHardKeyboardEnabled;
6863        }
6864        if (listener != null) {
6865            listener.onHardKeyboardStatusChange(available, enabled);
6866        }
6867    }
6868
6869    // -------------------------------------------------------------
6870    // Drag and drop
6871    // -------------------------------------------------------------
6872
6873    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
6874            int flags, int width, int height, Surface outSurface) {
6875        if (DEBUG_DRAG) {
6876            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
6877                    + " flags=" + Integer.toHexString(flags) + " win=" + window
6878                    + " asbinder=" + window.asBinder());
6879        }
6880
6881        final int callerPid = Binder.getCallingPid();
6882        final long origId = Binder.clearCallingIdentity();
6883        IBinder token = null;
6884
6885        try {
6886            synchronized (mWindowMap) {
6887                try {
6888                    if (mDragState == null) {
6889                        // TODO(multi-display): support other displays
6890                        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6891                        final Display display = displayContent.getDisplay();
6892                        SurfaceControl surface = new SurfaceControl(session, "drag surface",
6893                                width, height, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
6894                        surface.setLayerStack(display.getLayerStack());
6895                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
6896                                + surface + ": CREATE");
6897                        outSurface.copyFrom(surface);
6898                        final IBinder winBinder = window.asBinder();
6899                        token = new Binder();
6900                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
6901                        token = mDragState.mToken = new Binder();
6902
6903                        // 5 second timeout for this window to actually begin the drag
6904                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
6905                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
6906                        mH.sendMessageDelayed(msg, 5000);
6907                    } else {
6908                        Slog.w(TAG, "Drag already in progress");
6909                    }
6910                } catch (OutOfResourcesException e) {
6911                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
6912                    if (mDragState != null) {
6913                        mDragState.reset();
6914                        mDragState = null;
6915                    }
6916                }
6917            }
6918        } finally {
6919            Binder.restoreCallingIdentity(origId);
6920        }
6921
6922        return token;
6923    }
6924
6925    // -------------------------------------------------------------
6926    // Input Events and Focus Management
6927    // -------------------------------------------------------------
6928
6929    final InputMonitor mInputMonitor = new InputMonitor(this);
6930    private boolean mEventDispatchingEnabled;
6931
6932    @Override
6933    public void pauseKeyDispatching(IBinder _token) {
6934        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6935                "pauseKeyDispatching()")) {
6936            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6937        }
6938
6939        synchronized (mWindowMap) {
6940            WindowToken token = mTokenMap.get(_token);
6941            if (token != null) {
6942                mInputMonitor.pauseDispatchingLw(token);
6943            }
6944        }
6945    }
6946
6947    @Override
6948    public void resumeKeyDispatching(IBinder _token) {
6949        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6950                "resumeKeyDispatching()")) {
6951            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6952        }
6953
6954        synchronized (mWindowMap) {
6955            WindowToken token = mTokenMap.get(_token);
6956            if (token != null) {
6957                mInputMonitor.resumeDispatchingLw(token);
6958            }
6959        }
6960    }
6961
6962    @Override
6963    public void setEventDispatching(boolean enabled) {
6964        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6965                "setEventDispatching()")) {
6966            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6967        }
6968
6969        synchronized (mWindowMap) {
6970            mEventDispatchingEnabled = enabled;
6971            if (mDisplayEnabled) {
6972                mInputMonitor.setEventDispatchingLw(enabled);
6973            }
6974            sendScreenStatusToClientsLocked();
6975        }
6976    }
6977
6978    @Override
6979    public IBinder getFocusedWindowToken() {
6980        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
6981                "getFocusedWindowToken()")) {
6982            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
6983        }
6984        synchronized (mWindowMap) {
6985            WindowState windowState = getFocusedWindowLocked();
6986            if (windowState != null) {
6987                return windowState.mClient.asBinder();
6988            }
6989            return null;
6990        }
6991    }
6992
6993    private WindowState getFocusedWindow() {
6994        synchronized (mWindowMap) {
6995            return getFocusedWindowLocked();
6996        }
6997    }
6998
6999    private WindowState getFocusedWindowLocked() {
7000        return mCurrentFocus;
7001    }
7002
7003    public boolean detectSafeMode() {
7004        if (!mInputMonitor.waitForInputDevicesReady(
7005                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
7006            Slog.w(TAG, "Devices still not ready after waiting "
7007                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
7008                   + " milliseconds before attempting to detect safe mode.");
7009        }
7010
7011        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
7012                KeyEvent.KEYCODE_MENU);
7013        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
7014        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
7015                KeyEvent.KEYCODE_DPAD_CENTER);
7016        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
7017                InputManagerService.BTN_MOUSE);
7018        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
7019                KeyEvent.KEYCODE_VOLUME_DOWN);
7020        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
7021                || volumeDownState > 0;
7022        try {
7023            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
7024                mSafeMode = true;
7025                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
7026            }
7027        } catch (IllegalArgumentException e) {
7028        }
7029        if (mSafeMode) {
7030            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
7031                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
7032        } else {
7033            Log.i(TAG, "SAFE MODE not enabled");
7034        }
7035        mPolicy.setSafeMode(mSafeMode);
7036        return mSafeMode;
7037    }
7038
7039    public void displayReady() {
7040        displayReady(Display.DEFAULT_DISPLAY);
7041
7042        synchronized(mWindowMap) {
7043            final DisplayContent displayContent = getDefaultDisplayContentLocked();
7044            readForcedDisplaySizeAndDensityLocked(displayContent);
7045            mDisplayReady = true;
7046        }
7047
7048        try {
7049            mActivityManager.updateConfiguration(null);
7050        } catch (RemoteException e) {
7051        }
7052
7053        synchronized(mWindowMap) {
7054            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
7055                    PackageManager.FEATURE_TOUCHSCREEN);
7056            configureDisplayPolicyLocked(getDefaultDisplayContentLocked());
7057        }
7058
7059        try {
7060            mActivityManager.updateConfiguration(null);
7061        } catch (RemoteException e) {
7062        }
7063    }
7064
7065    private void displayReady(int displayId) {
7066        synchronized(mWindowMap) {
7067            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7068            if (displayContent != null) {
7069                mAnimator.addDisplayLocked(displayId);
7070                synchronized(displayContent.mDisplaySizeLock) {
7071                    // Bootstrap the default logical display from the display manager.
7072                    final DisplayInfo displayInfo = displayContent.getDisplayInfo();
7073                    DisplayInfo newDisplayInfo = mDisplayManagerInternal.getDisplayInfo(displayId);
7074                    if (newDisplayInfo != null) {
7075                        displayInfo.copyFrom(newDisplayInfo);
7076                    }
7077                    displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
7078                    displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
7079                    displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
7080                    displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
7081                    displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
7082                    displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
7083                    displayContent.mBaseDisplayRect.set(0, 0,
7084                            displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight);
7085                }
7086            }
7087        }
7088    }
7089
7090    public void systemReady() {
7091        mPolicy.systemReady();
7092    }
7093
7094    // TODO(multidisplay): Call isScreenOn for each display.
7095    private void sendScreenStatusToClientsLocked() {
7096        final boolean on = mPowerManager.isScreenOn();
7097        final int numDisplays = mDisplayContents.size();
7098        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
7099            final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
7100            final int numWindows = windows.size();
7101            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
7102                try {
7103                    windows.get(winNdx).mClient.dispatchScreenState(on);
7104                } catch (RemoteException e) {
7105                    // Ignored
7106                }
7107            }
7108        }
7109    }
7110
7111    // -------------------------------------------------------------
7112    // Async Handler
7113    // -------------------------------------------------------------
7114
7115    final class H extends Handler {
7116        public static final int REPORT_FOCUS_CHANGE = 2;
7117        public static final int REPORT_LOSING_FOCUS = 3;
7118        public static final int DO_TRAVERSAL = 4;
7119        public static final int ADD_STARTING = 5;
7120        public static final int REMOVE_STARTING = 6;
7121        public static final int FINISHED_STARTING = 7;
7122        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
7123        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
7124        public static final int WINDOW_FREEZE_TIMEOUT = 11;
7125
7126        public static final int APP_TRANSITION_TIMEOUT = 13;
7127        public static final int PERSIST_ANIMATION_SCALE = 14;
7128        public static final int FORCE_GC = 15;
7129        public static final int ENABLE_SCREEN = 16;
7130        public static final int APP_FREEZE_TIMEOUT = 17;
7131        public static final int SEND_NEW_CONFIGURATION = 18;
7132        public static final int REPORT_WINDOWS_CHANGE = 19;
7133        public static final int DRAG_START_TIMEOUT = 20;
7134        public static final int DRAG_END_TIMEOUT = 21;
7135        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
7136        public static final int BOOT_TIMEOUT = 23;
7137        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
7138        public static final int SHOW_STRICT_MODE_VIOLATION = 25;
7139        public static final int DO_ANIMATION_CALLBACK = 26;
7140
7141        public static final int DO_DISPLAY_ADDED = 27;
7142        public static final int DO_DISPLAY_REMOVED = 28;
7143        public static final int DO_DISPLAY_CHANGED = 29;
7144
7145        public static final int CLIENT_FREEZE_TIMEOUT = 30;
7146        public static final int TAP_OUTSIDE_STACK = 31;
7147        public static final int NOTIFY_ACTIVITY_DRAWN = 32;
7148
7149        public static final int REMOVE_STARTING_TIMEOUT = 33;
7150
7151        @Override
7152        public void handleMessage(Message msg) {
7153            if (DEBUG_WINDOW_TRACE) {
7154                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
7155            }
7156            switch (msg.what) {
7157                case REPORT_FOCUS_CHANGE: {
7158                    WindowState lastFocus;
7159                    WindowState newFocus;
7160
7161                    synchronized(mWindowMap) {
7162                        lastFocus = mLastFocus;
7163                        newFocus = mCurrentFocus;
7164                        if (lastFocus == newFocus) {
7165                            // Focus is not changing, so nothing to do.
7166                            return;
7167                        }
7168                        mLastFocus = newFocus;
7169                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Focus moving from " + lastFocus +
7170                                " to " + newFocus);
7171                        if (newFocus != null && lastFocus != null
7172                                && !newFocus.isDisplayedLw()) {
7173                            //Slog.i(TAG, "Delaying loss of focus...");
7174                            mLosingFocus.add(lastFocus);
7175                            lastFocus = null;
7176                        }
7177                    }
7178
7179                    //System.out.println("Changing focus from " + lastFocus
7180                    //                   + " to " + newFocus);
7181                    if (newFocus != null) {
7182                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Gaining focus: " + newFocus);
7183                        newFocus.reportFocusChangedSerialized(true, mInTouchMode);
7184                        notifyFocusChanged();
7185                    }
7186
7187                    if (lastFocus != null) {
7188                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing focus: " + lastFocus);
7189                        lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
7190                    }
7191                } break;
7192
7193                case REPORT_LOSING_FOCUS: {
7194                    ArrayList<WindowState> losers;
7195
7196                    synchronized(mWindowMap) {
7197                        losers = mLosingFocus;
7198                        mLosingFocus = new ArrayList<WindowState>();
7199                    }
7200
7201                    final int N = losers.size();
7202                    for (int i=0; i<N; i++) {
7203                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing delayed focus: " +
7204                                losers.get(i));
7205                        losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
7206                    }
7207                } break;
7208
7209                case DO_TRAVERSAL: {
7210                    synchronized(mWindowMap) {
7211                        mTraversalScheduled = false;
7212                        performLayoutAndPlaceSurfacesLocked();
7213                    }
7214                } break;
7215
7216                case ADD_STARTING: {
7217                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7218                    final StartingData sd = wtoken.startingData;
7219
7220                    if (sd == null) {
7221                        // Animation has been canceled... do nothing.
7222                        return;
7223                    }
7224
7225                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
7226                            + wtoken + ": pkg=" + sd.pkg);
7227
7228                    View view = null;
7229                    try {
7230                        view = mPolicy.addStartingWindow(
7231                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
7232                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo, sd.windowFlags);
7233                    } catch (Exception e) {
7234                        Slog.w(TAG, "Exception when adding starting window", e);
7235                    }
7236
7237                    if (view != null) {
7238                        boolean abort = false;
7239
7240                        synchronized(mWindowMap) {
7241                            if (wtoken.removed || wtoken.startingData == null) {
7242                                // If the window was successfully added, then
7243                                // we need to remove it.
7244                                if (wtoken.startingWindow != null) {
7245                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7246                                            "Aborted starting " + wtoken
7247                                            + ": removed=" + wtoken.removed
7248                                            + " startingData=" + wtoken.startingData);
7249                                    removeStartingWindowTimeout(wtoken);
7250                                    wtoken.startingWindow = null;
7251                                    wtoken.startingData = null;
7252                                    abort = true;
7253                                }
7254                            } else {
7255                                wtoken.startingView = view;
7256                            }
7257                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
7258                                    "Added starting " + wtoken
7259                                    + ": startingWindow="
7260                                    + wtoken.startingWindow + " startingView="
7261                                    + wtoken.startingView);
7262                        }
7263
7264                        if (abort) {
7265                            try {
7266                                mPolicy.removeStartingWindow(wtoken.token, view);
7267                            } catch (Exception e) {
7268                                Slog.w(TAG, "Exception when removing starting window", e);
7269                            }
7270                        }
7271                    }
7272                } break;
7273
7274                case REMOVE_STARTING_TIMEOUT: {
7275                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7276                    Slog.e(TAG, "Starting window " + wtoken + " timed out");
7277                    // Fall through.
7278                }
7279                case REMOVE_STARTING: {
7280                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7281                    IBinder token = null;
7282                    View view = null;
7283                    synchronized (mWindowMap) {
7284                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
7285                                + wtoken + ": startingWindow="
7286                                + wtoken.startingWindow + " startingView="
7287                                + wtoken.startingView);
7288                        if (wtoken.startingWindow != null) {
7289                            view = wtoken.startingView;
7290                            token = wtoken.token;
7291                            wtoken.startingData = null;
7292                            wtoken.startingView = null;
7293                            wtoken.startingWindow = null;
7294                            wtoken.startingDisplayed = false;
7295                        }
7296                    }
7297                    if (view != null) {
7298                        try {
7299                            mPolicy.removeStartingWindow(token, view);
7300                        } catch (Exception e) {
7301                            Slog.w(TAG, "Exception when removing starting window", e);
7302                        }
7303                    }
7304                } break;
7305
7306                case FINISHED_STARTING: {
7307                    IBinder token = null;
7308                    View view = null;
7309                    while (true) {
7310                        synchronized (mWindowMap) {
7311                            final int N = mFinishedStarting.size();
7312                            if (N <= 0) {
7313                                break;
7314                            }
7315                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7316
7317                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7318                                    "Finished starting " + wtoken
7319                                    + ": startingWindow=" + wtoken.startingWindow
7320                                    + " startingView=" + wtoken.startingView);
7321
7322                            if (wtoken.startingWindow == null) {
7323                                continue;
7324                            }
7325
7326                            view = wtoken.startingView;
7327                            token = wtoken.token;
7328                            wtoken.startingData = null;
7329                            wtoken.startingView = null;
7330                            wtoken.startingWindow = null;
7331                            wtoken.startingDisplayed = false;
7332                        }
7333
7334                        try {
7335                            mPolicy.removeStartingWindow(token, view);
7336                        } catch (Exception e) {
7337                            Slog.w(TAG, "Exception when removing starting window", e);
7338                        }
7339                    }
7340                } break;
7341
7342                case REPORT_APPLICATION_TOKEN_DRAWN: {
7343                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7344
7345                    try {
7346                        if (DEBUG_VISIBILITY) Slog.v(
7347                                TAG, "Reporting drawn in " + wtoken);
7348                        wtoken.appToken.windowsDrawn();
7349                    } catch (RemoteException ex) {
7350                    }
7351                } break;
7352
7353                case REPORT_APPLICATION_TOKEN_WINDOWS: {
7354                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7355
7356                    boolean nowVisible = msg.arg1 != 0;
7357                    boolean nowGone = msg.arg2 != 0;
7358
7359                    try {
7360                        if (DEBUG_VISIBILITY) Slog.v(
7361                                TAG, "Reporting visible in " + wtoken
7362                                + " visible=" + nowVisible
7363                                + " gone=" + nowGone);
7364                        if (nowVisible) {
7365                            wtoken.appToken.windowsVisible();
7366                        } else {
7367                            wtoken.appToken.windowsGone();
7368                        }
7369                    } catch (RemoteException ex) {
7370                    }
7371                } break;
7372
7373                case WINDOW_FREEZE_TIMEOUT: {
7374                    // TODO(multidisplay): Can non-default displays rotate?
7375                    synchronized (mWindowMap) {
7376                        Slog.w(TAG, "Window freeze timeout expired.");
7377                        final WindowList windows = getDefaultWindowListLocked();
7378                        int i = windows.size();
7379                        while (i > 0) {
7380                            i--;
7381                            WindowState w = windows.get(i);
7382                            if (w.mOrientationChanging) {
7383                                w.mOrientationChanging = false;
7384                                w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
7385                                        - mDisplayFreezeTime);
7386                                Slog.w(TAG, "Force clearing orientation change: " + w);
7387                            }
7388                        }
7389                        performLayoutAndPlaceSurfacesLocked();
7390                    }
7391                    break;
7392                }
7393
7394                case APP_TRANSITION_TIMEOUT: {
7395                    synchronized (mWindowMap) {
7396                        if (mAppTransition.isTransitionSet()) {
7397                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** APP TRANSITION TIMEOUT");
7398                            mAppTransition.setTimeout();
7399                            performLayoutAndPlaceSurfacesLocked();
7400                        }
7401                    }
7402                    break;
7403                }
7404
7405                case PERSIST_ANIMATION_SCALE: {
7406                    Settings.Global.putFloat(mContext.getContentResolver(),
7407                            Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7408                    Settings.Global.putFloat(mContext.getContentResolver(),
7409                            Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7410                    Settings.Global.putFloat(mContext.getContentResolver(),
7411                            Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
7412                    break;
7413                }
7414
7415                case FORCE_GC: {
7416                    synchronized (mWindowMap) {
7417                        // Since we're holding both mWindowMap and mAnimator we don't need to
7418                        // hold mAnimator.mLayoutToAnim.
7419                        if (mAnimator.mAnimating || mAnimationScheduled) {
7420                            // If we are animating, don't do the gc now but
7421                            // delay a bit so we don't interrupt the animation.
7422                            sendEmptyMessageDelayed(H.FORCE_GC, 2000);
7423                            return;
7424                        }
7425                        // If we are currently rotating the display, it will
7426                        // schedule a new message when done.
7427                        if (mDisplayFrozen) {
7428                            return;
7429                        }
7430                    }
7431                    Runtime.getRuntime().gc();
7432                    break;
7433                }
7434
7435                case ENABLE_SCREEN: {
7436                    performEnableScreen();
7437                    break;
7438                }
7439
7440                case APP_FREEZE_TIMEOUT: {
7441                    synchronized (mWindowMap) {
7442                        Slog.w(TAG, "App freeze timeout expired.");
7443                        final int numStacks = mStackIdToStack.size();
7444                        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
7445                            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
7446                            final ArrayList<Task> tasks = stack.getTasks();
7447                            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
7448                                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
7449                                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
7450                                    AppWindowToken tok = tokens.get(tokenNdx);
7451                                    if (tok.mAppAnimator.freezingScreen) {
7452                                        Slog.w(TAG, "Force clearing freeze: " + tok);
7453                                        unsetAppFreezingScreenLocked(tok, true, true);
7454                                    }
7455                                }
7456                            }
7457                        }
7458                    }
7459                    break;
7460                }
7461
7462                case CLIENT_FREEZE_TIMEOUT: {
7463                    synchronized (mWindowMap) {
7464                        if (mClientFreezingScreen) {
7465                            mClientFreezingScreen = false;
7466                            mLastFinishedFreezeSource = "client-timeout";
7467                            stopFreezingDisplayLocked();
7468                        }
7469                    }
7470                    break;
7471                }
7472
7473                case SEND_NEW_CONFIGURATION: {
7474                    removeMessages(SEND_NEW_CONFIGURATION);
7475                    sendNewConfiguration();
7476                    break;
7477                }
7478
7479                case REPORT_WINDOWS_CHANGE: {
7480                    if (mWindowsChanged) {
7481                        synchronized (mWindowMap) {
7482                            mWindowsChanged = false;
7483                        }
7484                        notifyWindowsChanged();
7485                    }
7486                    break;
7487                }
7488
7489                case DRAG_START_TIMEOUT: {
7490                    IBinder win = (IBinder)msg.obj;
7491                    if (DEBUG_DRAG) {
7492                        Slog.w(TAG, "Timeout starting drag by win " + win);
7493                    }
7494                    synchronized (mWindowMap) {
7495                        // !!! TODO: ANR the app that has failed to start the drag in time
7496                        if (mDragState != null) {
7497                            mDragState.unregister();
7498                            mInputMonitor.updateInputWindowsLw(true /*force*/);
7499                            mDragState.reset();
7500                            mDragState = null;
7501                        }
7502                    }
7503                    break;
7504                }
7505
7506                case DRAG_END_TIMEOUT: {
7507                    IBinder win = (IBinder)msg.obj;
7508                    if (DEBUG_DRAG) {
7509                        Slog.w(TAG, "Timeout ending drag to win " + win);
7510                    }
7511                    synchronized (mWindowMap) {
7512                        // !!! TODO: ANR the drag-receiving app
7513                        if (mDragState != null) {
7514                            mDragState.mDragResult = false;
7515                            mDragState.endDragLw();
7516                        }
7517                    }
7518                    break;
7519                }
7520
7521                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
7522                    notifyHardKeyboardStatusChange();
7523                    break;
7524                }
7525
7526                case BOOT_TIMEOUT: {
7527                    performBootTimeout();
7528                    break;
7529                }
7530
7531                case WAITING_FOR_DRAWN_TIMEOUT: {
7532                    Pair<WindowState, IRemoteCallback> pair;
7533                    synchronized (mWindowMap) {
7534                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
7535                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
7536                        if (!mWaitingForDrawn.remove(pair)) {
7537                            return;
7538                        }
7539                    }
7540                    try {
7541                        pair.second.sendResult(null);
7542                    } catch (RemoteException e) {
7543                    }
7544                    break;
7545                }
7546
7547                case SHOW_STRICT_MODE_VIOLATION: {
7548                    showStrictModeViolation(msg.arg1, msg.arg2);
7549                    break;
7550                }
7551
7552                case DO_ANIMATION_CALLBACK: {
7553                    try {
7554                        ((IRemoteCallback)msg.obj).sendResult(null);
7555                    } catch (RemoteException e) {
7556                    }
7557                    break;
7558                }
7559
7560                case DO_DISPLAY_ADDED:
7561                    handleDisplayAdded(msg.arg1);
7562                    break;
7563
7564                case DO_DISPLAY_REMOVED:
7565                    synchronized (mWindowMap) {
7566                        handleDisplayRemovedLocked(msg.arg1);
7567                    }
7568                    break;
7569
7570                case DO_DISPLAY_CHANGED:
7571                    synchronized (mWindowMap) {
7572                        handleDisplayChangedLocked(msg.arg1);
7573                    }
7574                    break;
7575
7576                case TAP_OUTSIDE_STACK: {
7577                    int stackId;
7578                    synchronized (mWindowMap) {
7579                        stackId = ((DisplayContent)msg.obj).stackIdFromPoint(msg.arg1, msg.arg2);
7580                    }
7581                    if (stackId >= 0) {
7582                        try {
7583                            mActivityManager.setFocusedStack(stackId);
7584                        } catch (RemoteException e) {
7585                        }
7586                    }
7587                }
7588                break;
7589                case NOTIFY_ACTIVITY_DRAWN:
7590                    try {
7591                        mActivityManager.notifyActivityDrawn((IBinder) msg.obj);
7592                    } catch (RemoteException e) {
7593                    }
7594                    break;
7595            }
7596            if (DEBUG_WINDOW_TRACE) {
7597                Slog.v(TAG, "handleMessage: exit");
7598            }
7599        }
7600    }
7601
7602    // -------------------------------------------------------------
7603    // IWindowManager API
7604    // -------------------------------------------------------------
7605
7606    @Override
7607    public IWindowSession openSession(IInputMethodClient client,
7608            IInputContext inputContext) {
7609        if (client == null) throw new IllegalArgumentException("null client");
7610        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7611        Session session = new Session(this, client, inputContext);
7612        return session;
7613    }
7614
7615    @Override
7616    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7617        synchronized (mWindowMap) {
7618            // The focus for the client is the window immediately below
7619            // where we would place the input method window.
7620            int idx = findDesiredInputMethodWindowIndexLocked(false);
7621            if (idx > 0) {
7622                // TODO(multidisplay): IMEs are only supported on the default display.
7623                WindowState imFocus = getDefaultWindowListLocked().get(idx-1);
7624                if (DEBUG_INPUT_METHOD) {
7625                    Slog.i(TAG, "Desired input method target: " + imFocus);
7626                    Slog.i(TAG, "Current focus: " + mCurrentFocus);
7627                    Slog.i(TAG, "Last focus: " + mLastFocus);
7628                }
7629                if (imFocus != null) {
7630                    // This may be a starting window, in which case we still want
7631                    // to count it as okay.
7632                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
7633                            && imFocus.mAppToken != null) {
7634                        // The client has definitely started, so it really should
7635                        // have a window in this app token.  Let's look for it.
7636                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
7637                            WindowState w = imFocus.mAppToken.windows.get(i);
7638                            if (w != imFocus) {
7639                                Log.i(TAG, "Switching to real app window: " + w);
7640                                imFocus = w;
7641                                break;
7642                            }
7643                        }
7644                    }
7645                    if (DEBUG_INPUT_METHOD) {
7646                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
7647                        if (imFocus.mSession.mClient != null) {
7648                            Slog.i(TAG, "IM target client binder: "
7649                                    + imFocus.mSession.mClient.asBinder());
7650                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
7651                        }
7652                    }
7653                    if (imFocus.mSession.mClient != null &&
7654                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7655                        return true;
7656                    }
7657                }
7658            }
7659
7660            // Okay, how about this...  what is the current focus?
7661            // It seems in some cases we may not have moved the IM
7662            // target window, such as when it was in a pop-up window,
7663            // so let's also look at the current focus.  (An example:
7664            // go to Gmail, start searching so the keyboard goes up,
7665            // press home.  Sometimes the IME won't go down.)
7666            // Would be nice to fix this more correctly, but it's
7667            // way at the end of a release, and this should be good enough.
7668            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
7669                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7670                return true;
7671            }
7672        }
7673        return false;
7674    }
7675
7676    @Override
7677    public void getInitialDisplaySize(int displayId, Point size) {
7678        synchronized (mWindowMap) {
7679            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7680            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
7681                synchronized(displayContent.mDisplaySizeLock) {
7682                    size.x = displayContent.mInitialDisplayWidth;
7683                    size.y = displayContent.mInitialDisplayHeight;
7684                }
7685            }
7686        }
7687    }
7688
7689    @Override
7690    public void getBaseDisplaySize(int displayId, Point size) {
7691        synchronized (mWindowMap) {
7692            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7693            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
7694                synchronized(displayContent.mDisplaySizeLock) {
7695                    size.x = displayContent.mBaseDisplayWidth;
7696                    size.y = displayContent.mBaseDisplayHeight;
7697                }
7698            }
7699        }
7700    }
7701
7702    @Override
7703    public void setForcedDisplaySize(int displayId, int width, int height) {
7704        if (mContext.checkCallingOrSelfPermission(
7705                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7706                PackageManager.PERMISSION_GRANTED) {
7707            throw new SecurityException("Must hold permission " +
7708                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7709        }
7710        if (displayId != Display.DEFAULT_DISPLAY) {
7711            throw new IllegalArgumentException("Can only set the default display");
7712        }
7713        final long ident = Binder.clearCallingIdentity();
7714        try {
7715            synchronized(mWindowMap) {
7716                // Set some sort of reasonable bounds on the size of the display that we
7717                // will try to emulate.
7718                final int MIN_WIDTH = 200;
7719                final int MIN_HEIGHT = 200;
7720                final int MAX_SCALE = 2;
7721                final DisplayContent displayContent = getDisplayContentLocked(displayId);
7722                if (displayContent != null) {
7723                    width = Math.min(Math.max(width, MIN_WIDTH),
7724                            displayContent.mInitialDisplayWidth * MAX_SCALE);
7725                    height = Math.min(Math.max(height, MIN_HEIGHT),
7726                            displayContent.mInitialDisplayHeight * MAX_SCALE);
7727                    setForcedDisplaySizeLocked(displayContent, width, height);
7728                    Settings.Global.putString(mContext.getContentResolver(),
7729                            Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
7730                }
7731            }
7732        } finally {
7733            Binder.restoreCallingIdentity(ident);
7734        }
7735    }
7736
7737    private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) {
7738        String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
7739                Settings.Global.DISPLAY_SIZE_FORCED);
7740        if (sizeStr == null || sizeStr.length() == 0) {
7741            sizeStr = SystemProperties.get(SIZE_OVERRIDE, null);
7742        }
7743        if (sizeStr != null && sizeStr.length() > 0) {
7744            final int pos = sizeStr.indexOf(',');
7745            if (pos > 0 && sizeStr.lastIndexOf(',') == pos) {
7746                int width, height;
7747                try {
7748                    width = Integer.parseInt(sizeStr.substring(0, pos));
7749                    height = Integer.parseInt(sizeStr.substring(pos+1));
7750                    synchronized(displayContent.mDisplaySizeLock) {
7751                        if (displayContent.mBaseDisplayWidth != width
7752                                || displayContent.mBaseDisplayHeight != height) {
7753                            Slog.i(TAG, "FORCED DISPLAY SIZE: " + width + "x" + height);
7754                            displayContent.mBaseDisplayWidth = width;
7755                            displayContent.mBaseDisplayHeight = height;
7756                        }
7757                    }
7758                } catch (NumberFormatException ex) {
7759                }
7760            }
7761        }
7762        String densityStr = Settings.Global.getString(mContext.getContentResolver(),
7763                Settings.Global.DISPLAY_DENSITY_FORCED);
7764        if (densityStr == null || densityStr.length() == 0) {
7765            densityStr = SystemProperties.get(DENSITY_OVERRIDE, null);
7766        }
7767        if (densityStr != null && densityStr.length() > 0) {
7768            int density;
7769            try {
7770                density = Integer.parseInt(densityStr);
7771                synchronized(displayContent.mDisplaySizeLock) {
7772                    if (displayContent.mBaseDisplayDensity != density) {
7773                        Slog.i(TAG, "FORCED DISPLAY DENSITY: " + density);
7774                        displayContent.mBaseDisplayDensity = density;
7775                    }
7776                }
7777            } catch (NumberFormatException ex) {
7778            }
7779        }
7780    }
7781
7782    // displayContent must not be null
7783    private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
7784        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7785
7786        synchronized(displayContent.mDisplaySizeLock) {
7787            displayContent.mBaseDisplayWidth = width;
7788            displayContent.mBaseDisplayHeight = height;
7789        }
7790        reconfigureDisplayLocked(displayContent);
7791    }
7792
7793    @Override
7794    public void clearForcedDisplaySize(int displayId) {
7795        if (mContext.checkCallingOrSelfPermission(
7796                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7797                PackageManager.PERMISSION_GRANTED) {
7798            throw new SecurityException("Must hold permission " +
7799                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7800        }
7801        if (displayId != Display.DEFAULT_DISPLAY) {
7802            throw new IllegalArgumentException("Can only set the default display");
7803        }
7804        final long ident = Binder.clearCallingIdentity();
7805        try {
7806            synchronized(mWindowMap) {
7807                final DisplayContent displayContent = getDisplayContentLocked(displayId);
7808                if (displayContent != null) {
7809                    setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
7810                            displayContent.mInitialDisplayHeight);
7811                    Settings.Global.putString(mContext.getContentResolver(),
7812                            Settings.Global.DISPLAY_SIZE_FORCED, "");
7813                }
7814            }
7815        } finally {
7816            Binder.restoreCallingIdentity(ident);
7817        }
7818    }
7819
7820    @Override
7821    public int getInitialDisplayDensity(int displayId) {
7822        synchronized (mWindowMap) {
7823            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7824            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
7825                synchronized(displayContent.mDisplaySizeLock) {
7826                    return displayContent.mInitialDisplayDensity;
7827                }
7828            }
7829        }
7830        return -1;
7831    }
7832
7833    @Override
7834    public int getBaseDisplayDensity(int displayId) {
7835        synchronized (mWindowMap) {
7836            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7837            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
7838                synchronized(displayContent.mDisplaySizeLock) {
7839                    return displayContent.mBaseDisplayDensity;
7840                }
7841            }
7842        }
7843        return -1;
7844    }
7845
7846    @Override
7847    public void setForcedDisplayDensity(int displayId, int density) {
7848        if (mContext.checkCallingOrSelfPermission(
7849                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7850                PackageManager.PERMISSION_GRANTED) {
7851            throw new SecurityException("Must hold permission " +
7852                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7853        }
7854        if (displayId != Display.DEFAULT_DISPLAY) {
7855            throw new IllegalArgumentException("Can only set the default display");
7856        }
7857        final long ident = Binder.clearCallingIdentity();
7858        try {
7859            synchronized(mWindowMap) {
7860                final DisplayContent displayContent = getDisplayContentLocked(displayId);
7861                if (displayContent != null) {
7862                    setForcedDisplayDensityLocked(displayContent, density);
7863                    Settings.Global.putString(mContext.getContentResolver(),
7864                            Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
7865                }
7866            }
7867        } finally {
7868            Binder.restoreCallingIdentity(ident);
7869        }
7870    }
7871
7872    // displayContent must not be null
7873    private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) {
7874        Slog.i(TAG, "Using new display density: " + density);
7875
7876        synchronized(displayContent.mDisplaySizeLock) {
7877            displayContent.mBaseDisplayDensity = density;
7878        }
7879        reconfigureDisplayLocked(displayContent);
7880    }
7881
7882    @Override
7883    public void clearForcedDisplayDensity(int displayId) {
7884        if (mContext.checkCallingOrSelfPermission(
7885                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7886                PackageManager.PERMISSION_GRANTED) {
7887            throw new SecurityException("Must hold permission " +
7888                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7889        }
7890        if (displayId != Display.DEFAULT_DISPLAY) {
7891            throw new IllegalArgumentException("Can only set the default display");
7892        }
7893        final long ident = Binder.clearCallingIdentity();
7894        try {
7895            synchronized(mWindowMap) {
7896                final DisplayContent displayContent = getDisplayContentLocked(displayId);
7897                if (displayContent != null) {
7898                    setForcedDisplayDensityLocked(displayContent,
7899                            displayContent.mInitialDisplayDensity);
7900                    Settings.Global.putString(mContext.getContentResolver(),
7901                            Settings.Global.DISPLAY_DENSITY_FORCED, "");
7902                }
7903            }
7904        } finally {
7905            Binder.restoreCallingIdentity(ident);
7906        }
7907    }
7908
7909    // displayContent must not be null
7910    private void reconfigureDisplayLocked(DisplayContent displayContent) {
7911        // TODO: Multidisplay: for now only use with default display.
7912        configureDisplayPolicyLocked(displayContent);
7913        displayContent.layoutNeeded = true;
7914
7915        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7916        mTempConfiguration.setToDefaults();
7917        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7918        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7919            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7920                configChanged = true;
7921            }
7922        }
7923
7924        if (configChanged) {
7925            mWaitingForConfig = true;
7926            startFreezingDisplayLocked(false, 0, 0);
7927            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7928        }
7929
7930        performLayoutAndPlaceSurfacesLocked();
7931    }
7932
7933    private void configureDisplayPolicyLocked(DisplayContent displayContent) {
7934        mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
7935                displayContent.mBaseDisplayWidth,
7936                displayContent.mBaseDisplayHeight,
7937                displayContent.mBaseDisplayDensity);
7938
7939        DisplayInfo displayInfo = displayContent.getDisplayInfo();
7940        mPolicy.setDisplayOverscan(displayContent.getDisplay(),
7941                displayInfo.overscanLeft, displayInfo.overscanTop,
7942                displayInfo.overscanRight, displayInfo.overscanBottom);
7943    }
7944
7945    @Override
7946    public void setOverscan(int displayId, int left, int top, int right, int bottom) {
7947        if (mContext.checkCallingOrSelfPermission(
7948                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7949                PackageManager.PERMISSION_GRANTED) {
7950            throw new SecurityException("Must hold permission " +
7951                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7952        }
7953        final long ident = Binder.clearCallingIdentity();
7954        try {
7955            synchronized(mWindowMap) {
7956                DisplayContent displayContent = getDisplayContentLocked(displayId);
7957                if (displayContent != null) {
7958                    setOverscanLocked(displayContent, left, top, right, bottom);
7959                }
7960            }
7961        } finally {
7962            Binder.restoreCallingIdentity(ident);
7963        }
7964    }
7965
7966    private void setOverscanLocked(DisplayContent displayContent,
7967            int left, int top, int right, int bottom) {
7968        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
7969        synchronized (displayContent.mDisplaySizeLock) {
7970            displayInfo.overscanLeft = left;
7971            displayInfo.overscanTop = top;
7972            displayInfo.overscanRight = right;
7973            displayInfo.overscanBottom = bottom;
7974        }
7975
7976        mDisplaySettings.setOverscanLocked(displayInfo.name, left, top, right, bottom);
7977        mDisplaySettings.writeSettingsLocked();
7978
7979        reconfigureDisplayLocked(displayContent);
7980    }
7981
7982    // -------------------------------------------------------------
7983    // Internals
7984    // -------------------------------------------------------------
7985
7986    final WindowState windowForClientLocked(Session session, IWindow client,
7987            boolean throwOnError) {
7988        return windowForClientLocked(session, client.asBinder(), throwOnError);
7989    }
7990
7991    final WindowState windowForClientLocked(Session session, IBinder client,
7992            boolean throwOnError) {
7993        WindowState win = mWindowMap.get(client);
7994        if (localLOGV) Slog.v(
7995            TAG, "Looking up client " + client + ": " + win);
7996        if (win == null) {
7997            RuntimeException ex = new IllegalArgumentException(
7998                    "Requested window " + client + " does not exist");
7999            if (throwOnError) {
8000                throw ex;
8001            }
8002            Slog.w(TAG, "Failed looking up window", ex);
8003            return null;
8004        }
8005        if (session != null && win.mSession != session) {
8006            RuntimeException ex = new IllegalArgumentException(
8007                    "Requested window " + client + " is in session " +
8008                    win.mSession + ", not " + session);
8009            if (throwOnError) {
8010                throw ex;
8011            }
8012            Slog.w(TAG, "Failed looking up window", ex);
8013            return null;
8014        }
8015
8016        return win;
8017    }
8018
8019    final void rebuildAppWindowListLocked() {
8020        rebuildAppWindowListLocked(getDefaultDisplayContentLocked());
8021    }
8022
8023    private void rebuildAppWindowListLocked(final DisplayContent displayContent) {
8024        final WindowList windows = displayContent.getWindowList();
8025        int NW = windows.size();
8026        int i;
8027        int lastBelow = -1;
8028        int numRemoved = 0;
8029
8030        if (mRebuildTmp.length < NW) {
8031            mRebuildTmp = new WindowState[NW+10];
8032        }
8033
8034        // First remove all existing app windows.
8035        i=0;
8036        while (i < NW) {
8037            WindowState w = windows.get(i);
8038            if (w.mAppToken != null) {
8039                WindowState win = windows.remove(i);
8040                win.mRebuilding = true;
8041                mRebuildTmp[numRemoved] = win;
8042                mWindowsChanged = true;
8043                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Rebuild removing window: " + win);
8044                NW--;
8045                numRemoved++;
8046                continue;
8047            } else if (lastBelow == i-1) {
8048                if (w.mAttrs.type == TYPE_WALLPAPER || w.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
8049                    lastBelow = i;
8050                }
8051            }
8052            i++;
8053        }
8054
8055        // Keep whatever windows were below the app windows still below,
8056        // by skipping them.
8057        lastBelow++;
8058        i = lastBelow;
8059
8060        // First add all of the exiting app tokens...  these are no longer
8061        // in the main app list, but still have windows shown.  We put them
8062        // in the back because now that the animation is over we no longer
8063        // will care about them.
8064        final ArrayList<TaskStack> stacks = displayContent.getStacks();
8065        final int numStacks = stacks.size();
8066        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
8067            AppTokenList exitingAppTokens = stacks.get(stackNdx).mExitingAppTokens;
8068            int NT = exitingAppTokens.size();
8069            for (int j = 0; j < NT; j++) {
8070                i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
8071            }
8072        }
8073
8074        // And add in the still active app tokens in Z order.
8075        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
8076            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
8077            final int numTasks = tasks.size();
8078            for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
8079                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
8080                final int numTokens = tokens.size();
8081                for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
8082                    final AppWindowToken wtoken = tokens.get(tokenNdx);
8083                    if (wtoken.mDeferRemoval) {
8084                        continue;
8085                    }
8086                    i = reAddAppWindowsLocked(displayContent, i, wtoken);
8087                }
8088            }
8089        }
8090
8091        i -= lastBelow;
8092        if (i != numRemoved) {
8093            Slog.w(TAG, "On display=" + displayContent.getDisplayId() + " Rebuild removed " +
8094                    numRemoved + " windows but added " + i,
8095                    new RuntimeException("here").fillInStackTrace());
8096            for (i=0; i<numRemoved; i++) {
8097                WindowState ws = mRebuildTmp[i];
8098                if (ws.mRebuilding) {
8099                    StringWriter sw = new StringWriter();
8100                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
8101                    ws.dump(pw, "", true);
8102                    pw.flush();
8103                    Slog.w(TAG, "This window was lost: " + ws);
8104                    Slog.w(TAG, sw.toString());
8105                    ws.mWinAnimator.destroySurfaceLocked();
8106                }
8107            }
8108            Slog.w(TAG, "Current app token list:");
8109            dumpAppTokensLocked();
8110            Slog.w(TAG, "Final window list:");
8111            dumpWindowsLocked();
8112        }
8113    }
8114
8115    private final void assignLayersLocked(WindowList windows) {
8116        int N = windows.size();
8117        int curBaseLayer = 0;
8118        int curLayer = 0;
8119        int i;
8120
8121        if (DEBUG_LAYERS) Slog.v(TAG, "Assigning layers based on windows=" + windows,
8122                new RuntimeException("here").fillInStackTrace());
8123
8124        boolean anyLayerChanged = false;
8125
8126        for (i=0; i<N; i++) {
8127            final WindowState w = windows.get(i);
8128            final WindowStateAnimator winAnimator = w.mWinAnimator;
8129            boolean layerChanged = false;
8130            int oldLayer = w.mLayer;
8131            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
8132                    || (i > 0 && w.mIsWallpaper)) {
8133                curLayer += WINDOW_LAYER_MULTIPLIER;
8134                w.mLayer = curLayer;
8135            } else {
8136                curBaseLayer = curLayer = w.mBaseLayer;
8137                w.mLayer = curLayer;
8138            }
8139            if (w.mLayer != oldLayer) {
8140                layerChanged = true;
8141                anyLayerChanged = true;
8142            }
8143            final AppWindowToken wtoken = w.mAppToken;
8144            oldLayer = winAnimator.mAnimLayer;
8145            if (w.mTargetAppToken != null) {
8146                winAnimator.mAnimLayer =
8147                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
8148            } else if (wtoken != null) {
8149                winAnimator.mAnimLayer =
8150                        w.mLayer + wtoken.mAppAnimator.animLayerAdjustment;
8151            } else {
8152                winAnimator.mAnimLayer = w.mLayer;
8153            }
8154            if (w.mIsImWindow) {
8155                winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
8156            } else if (w.mIsWallpaper) {
8157                winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
8158            }
8159            if (winAnimator.mAnimLayer != oldLayer) {
8160                layerChanged = true;
8161                anyLayerChanged = true;
8162            }
8163            if (layerChanged && w.getStack().isDimming(winAnimator)) {
8164                // Force an animation pass just to update the mDimLayer layer.
8165                scheduleAnimationLocked();
8166            }
8167            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
8168                    + "mBase=" + w.mBaseLayer
8169                    + " mLayer=" + w.mLayer
8170                    + (wtoken == null ?
8171                            "" : " mAppLayer=" + wtoken.mAppAnimator.animLayerAdjustment)
8172                    + " =mAnimLayer=" + winAnimator.mAnimLayer);
8173            //System.out.println(
8174            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
8175        }
8176
8177        //TODO (multidisplay): Magnification is supported only for the default display.
8178        if (mDisplayMagnifier != null && anyLayerChanged
8179                && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
8180            mDisplayMagnifier.onWindowLayersChangedLocked();
8181        }
8182    }
8183
8184    private final void performLayoutAndPlaceSurfacesLocked() {
8185        int loopCount = 6;
8186        do {
8187            mTraversalScheduled = false;
8188            performLayoutAndPlaceSurfacesLockedLoop();
8189            mH.removeMessages(H.DO_TRAVERSAL);
8190            loopCount--;
8191        } while (mTraversalScheduled && loopCount > 0);
8192        mInnerFields.mWallpaperActionPending = false;
8193    }
8194
8195    private boolean mInLayout = false;
8196    private final void performLayoutAndPlaceSurfacesLockedLoop() {
8197        if (mInLayout) {
8198            if (DEBUG) {
8199                throw new RuntimeException("Recursive call!");
8200            }
8201            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
8202                    + Debug.getCallers(3));
8203            return;
8204        }
8205
8206        if (mWaitingForConfig) {
8207            // Our configuration has changed (most likely rotation), but we
8208            // don't yet have the complete configuration to report to
8209            // applications.  Don't do any window layout until we have it.
8210            return;
8211        }
8212
8213        if (!mDisplayReady) {
8214            // Not yet initialized, nothing to do.
8215            return;
8216        }
8217
8218        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
8219        mInLayout = true;
8220        boolean recoveringMemory = false;
8221
8222        try {
8223            if (mForceRemoves != null) {
8224                recoveringMemory = true;
8225                // Wait a little bit for things to settle down, and off we go.
8226                for (int i=0; i<mForceRemoves.size(); i++) {
8227                    WindowState ws = mForceRemoves.get(i);
8228                    Slog.i(TAG, "Force removing: " + ws);
8229                    removeWindowInnerLocked(ws.mSession, ws);
8230                }
8231                mForceRemoves = null;
8232                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
8233                Object tmp = new Object();
8234                synchronized (tmp) {
8235                    try {
8236                        tmp.wait(250);
8237                    } catch (InterruptedException e) {
8238                    }
8239                }
8240            }
8241        } catch (RuntimeException e) {
8242            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
8243        }
8244
8245        try {
8246            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
8247
8248            mInLayout = false;
8249
8250            if (needsLayout()) {
8251                if (++mLayoutRepeatCount < 6) {
8252                    requestTraversalLocked();
8253                } else {
8254                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
8255                    mLayoutRepeatCount = 0;
8256                }
8257            } else {
8258                mLayoutRepeatCount = 0;
8259            }
8260
8261            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
8262                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
8263                mH.sendEmptyMessage(H.REPORT_WINDOWS_CHANGE);
8264            }
8265        } catch (RuntimeException e) {
8266            mInLayout = false;
8267            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
8268        }
8269
8270        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
8271    }
8272
8273    private final void performLayoutLockedInner(final DisplayContent displayContent,
8274                                    boolean initial, boolean updateInputWindows) {
8275        if (!displayContent.layoutNeeded) {
8276            return;
8277        }
8278        displayContent.layoutNeeded = false;
8279        WindowList windows = displayContent.getWindowList();
8280        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
8281
8282        DisplayInfo displayInfo = displayContent.getDisplayInfo();
8283        final int dw = displayInfo.logicalWidth;
8284        final int dh = displayInfo.logicalHeight;
8285
8286        final int NFW = mFakeWindows.size();
8287        for (int i=0; i<NFW; i++) {
8288            mFakeWindows.get(i).layout(dw, dh);
8289        }
8290
8291        final int N = windows.size();
8292        int i;
8293
8294        if (DEBUG_LAYOUT) {
8295            Slog.v(TAG, "-------------------------------------");
8296            Slog.v(TAG, "performLayout: needed="
8297                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
8298        }
8299
8300        WindowStateAnimator universeBackground = null;
8301
8302        mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
8303        if (isDefaultDisplay) {
8304            // Not needed on non-default displays.
8305            mSystemDecorLayer = mPolicy.getSystemDecorLayerLw();
8306            mScreenRect.set(0, 0, dw, dh);
8307        }
8308
8309        mPolicy.getContentRectLw(mTmpContentRect);
8310        displayContent.resize(mTmpContentRect);
8311
8312        int seq = mLayoutSeq+1;
8313        if (seq < 0) seq = 0;
8314        mLayoutSeq = seq;
8315
8316        boolean behindDream = false;
8317
8318        // First perform layout of any root windows (not attached
8319        // to another window).
8320        int topAttached = -1;
8321        for (i = N-1; i >= 0; i--) {
8322            final WindowState win = windows.get(i);
8323
8324            // Don't do layout of a window if it is not visible, or
8325            // soon won't be visible, to avoid wasting time and funky
8326            // changes while a window is animating away.
8327            final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
8328                    || win.isGoneForLayoutLw();
8329
8330            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
8331                Slog.v(TAG, "1ST PASS " + win
8332                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
8333                        + " mLayoutAttached=" + win.mLayoutAttached
8334                        + " screen changed=" + win.isConfigChanged());
8335                final AppWindowToken atoken = win.mAppToken;
8336                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
8337                        + win.mViewVisibility + " mRelayoutCalled="
8338                        + win.mRelayoutCalled + " hidden="
8339                        + win.mRootToken.hidden + " hiddenRequested="
8340                        + (atoken != null && atoken.hiddenRequested)
8341                        + " mAttachedHidden=" + win.mAttachedHidden);
8342                else Slog.v(TAG, "  VIS: mViewVisibility="
8343                        + win.mViewVisibility + " mRelayoutCalled="
8344                        + win.mRelayoutCalled + " hidden="
8345                        + win.mRootToken.hidden + " hiddenRequested="
8346                        + (atoken != null && atoken.hiddenRequested)
8347                        + " mAttachedHidden=" + win.mAttachedHidden);
8348            }
8349
8350            // If this view is GONE, then skip it -- keep the current
8351            // frame, and let the caller know so they can ignore it
8352            // if they want.  (We do the normal layout for INVISIBLE
8353            // windows, since that means "perform layout as normal,
8354            // just don't display").
8355            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
8356                    || ((win.isConfigChanged() || win.setInsetsChanged()) &&
8357                            (win.mAttrs.type == TYPE_KEYGUARD ||
8358                            win.mAppToken != null && win.mAppToken.layoutConfigChanges))
8359                    || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
8360                if (!win.mLayoutAttached) {
8361                    if (initial) {
8362                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8363                        win.mContentChanged = false;
8364                    }
8365                    if (win.mAttrs.type == TYPE_DREAM) {
8366                        // Don't layout windows behind a dream, so that if it
8367                        // does stuff like hide the status bar we won't get a
8368                        // bad transition when it goes away.
8369                        behindDream = true;
8370                    }
8371                    win.mLayoutNeeded = false;
8372                    win.prelayout();
8373                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
8374                    win.mLayoutSeq = seq;
8375                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8376                            + win.mFrame + " mContainingFrame="
8377                            + win.mContainingFrame + " mDisplayFrame="
8378                            + win.mDisplayFrame);
8379                } else {
8380                    if (topAttached < 0) topAttached = i;
8381                }
8382            }
8383            if (win.mViewVisibility == View.VISIBLE
8384                    && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND
8385                    && universeBackground == null) {
8386                universeBackground = win.mWinAnimator;
8387            }
8388        }
8389
8390        if (mAnimator.mUniverseBackground  != universeBackground) {
8391            mFocusMayChange = true;
8392            mAnimator.mUniverseBackground = universeBackground;
8393        }
8394
8395        boolean attachedBehindDream = false;
8396
8397        // Now perform layout of attached windows, which usually
8398        // depend on the position of the window they are attached to.
8399        // XXX does not deal with windows that are attached to windows
8400        // that are themselves attached.
8401        for (i = topAttached; i >= 0; i--) {
8402            final WindowState win = windows.get(i);
8403
8404            if (win.mLayoutAttached) {
8405                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
8406                        + " mHaveFrame=" + win.mHaveFrame
8407                        + " mViewVisibility=" + win.mViewVisibility
8408                        + " mRelayoutCalled=" + win.mRelayoutCalled);
8409                // If this view is GONE, then skip it -- keep the current
8410                // frame, and let the caller know so they can ignore it
8411                // if they want.  (We do the normal layout for INVISIBLE
8412                // windows, since that means "perform layout as normal,
8413                // just don't display").
8414                if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
8415                    continue;
8416                }
8417                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
8418                        || !win.mHaveFrame || win.mLayoutNeeded) {
8419                    if (initial) {
8420                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8421                        win.mContentChanged = false;
8422                    }
8423                    win.mLayoutNeeded = false;
8424                    win.prelayout();
8425                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
8426                    win.mLayoutSeq = seq;
8427                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8428                            + win.mFrame + " mContainingFrame="
8429                            + win.mContainingFrame + " mDisplayFrame="
8430                            + win.mDisplayFrame);
8431                }
8432            } else if (win.mAttrs.type == TYPE_DREAM) {
8433                // Don't layout windows behind a dream, so that if it
8434                // does stuff like hide the status bar we won't get a
8435                // bad transition when it goes away.
8436                attachedBehindDream = behindDream;
8437            }
8438        }
8439
8440        // Window frames may have changed.  Tell the input dispatcher about it.
8441        mInputMonitor.setUpdateInputWindowsNeededLw();
8442        if (updateInputWindows) {
8443            mInputMonitor.updateInputWindowsLw(false /*force*/);
8444        }
8445
8446        mPolicy.finishLayoutLw();
8447    }
8448
8449    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
8450        // If the screen is currently frozen or off, then keep
8451        // it frozen/off until this window draws at its new
8452        // orientation.
8453        if (!okToDisplay()) {
8454            if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w);
8455            w.mOrientationChanging = true;
8456            w.mLastFreezeDuration = 0;
8457            mInnerFields.mOrientationChangeComplete = false;
8458            if (!mWindowsFreezingScreen) {
8459                mWindowsFreezingScreen = true;
8460                // XXX should probably keep timeout from
8461                // when we first froze the display.
8462                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8463                mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT,
8464                        WINDOW_FREEZE_TIMEOUT_DURATION);
8465            }
8466        }
8467    }
8468
8469    /**
8470     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8471     * @param windows List of windows on default display.
8472     * @return bitmap indicating if another pass through layout must be made.
8473     */
8474    public int handleAppTransitionReadyLocked(WindowList windows) {
8475        int changes = 0;
8476        int i;
8477        int NN = mOpeningApps.size();
8478        boolean goodToGo = true;
8479        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8480                "Checking " + NN + " opening apps (frozen="
8481                + mDisplayFrozen + " timeout="
8482                + mAppTransition.isTimeout() + ")...");
8483        if (!mDisplayFrozen && !mAppTransition.isTimeout()) {
8484            // If the display isn't frozen, wait to do anything until
8485            // all of the apps are ready.  Otherwise just go because
8486            // we'll unfreeze the display when everyone is ready.
8487            for (i=0; i<NN && goodToGo; i++) {
8488                AppWindowToken wtoken = mOpeningApps.get(i);
8489                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8490                        "Check opening app=" + wtoken + ": allDrawn="
8491                        + wtoken.allDrawn + " startingDisplayed="
8492                        + wtoken.startingDisplayed + " startingMoved="
8493                        + wtoken.startingMoved);
8494                if (!wtoken.allDrawn && !wtoken.startingDisplayed
8495                        && !wtoken.startingMoved) {
8496                    goodToGo = false;
8497                }
8498            }
8499        }
8500        if (goodToGo) {
8501            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
8502            int transit = mAppTransition.getAppTransition();
8503            if (mSkipAppTransitionAnimation) {
8504                transit = AppTransition.TRANSIT_UNSET;
8505            }
8506            mAppTransition.goodToGo();
8507            mStartingIconInTransition = false;
8508            mSkipAppTransitionAnimation = false;
8509
8510            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8511
8512            rebuildAppWindowListLocked();
8513
8514            // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
8515            WindowState oldWallpaper =
8516                    mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
8517                        && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
8518                    ? null : mWallpaperTarget;
8519
8520            mInnerFields.mWallpaperMayChange = false;
8521
8522            // The top-most window will supply the layout params,
8523            // and we will determine it below.
8524            LayoutParams animLp = null;
8525            int bestAnimLayer = -1;
8526            boolean fullscreenAnim = false;
8527
8528            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8529                    "New wallpaper target=" + mWallpaperTarget
8530                    + ", oldWallpaper=" + oldWallpaper
8531                    + ", lower target=" + mLowerWallpaperTarget
8532                    + ", upper target=" + mUpperWallpaperTarget);
8533
8534            boolean openingAppHasWallpaper = false;
8535            boolean closingAppHasWallpaper = false;
8536            final AppWindowToken lowerWallpaperAppToken;
8537            final AppWindowToken upperWallpaperAppToken;
8538            if (mLowerWallpaperTarget == null) {
8539                lowerWallpaperAppToken = upperWallpaperAppToken = null;
8540            } else {
8541                lowerWallpaperAppToken = mLowerWallpaperTarget.mAppToken;
8542                upperWallpaperAppToken = mUpperWallpaperTarget.mAppToken;
8543            }
8544
8545            // Do a first pass through the tokens for two
8546            // things:
8547            // (1) Determine if both the closing and opening
8548            // app token sets are wallpaper targets, in which
8549            // case special animations are needed
8550            // (since the wallpaper needs to stay static
8551            // behind them).
8552            // (2) Find the layout params of the top-most
8553            // application window in the tokens, which is
8554            // what will control the animation theme.
8555            final int NC = mClosingApps.size();
8556            NN = NC + mOpeningApps.size();
8557            for (i=0; i<NN; i++) {
8558                final AppWindowToken wtoken;
8559                if (i < NC) {
8560                    wtoken = mClosingApps.get(i);
8561                    if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
8562                        closingAppHasWallpaper = true;
8563                    }
8564                } else {
8565                    wtoken = mOpeningApps.get(i - NC);
8566                    if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
8567                        openingAppHasWallpaper = true;
8568                    }
8569                }
8570
8571                if (wtoken.appFullscreen) {
8572                    WindowState ws = wtoken.findMainWindow();
8573                    if (ws != null) {
8574                        animLp = ws.mAttrs;
8575                        bestAnimLayer = ws.mLayer;
8576                        fullscreenAnim = true;
8577                    }
8578                } else if (!fullscreenAnim) {
8579                    WindowState ws = wtoken.findMainWindow();
8580                    if (ws != null) {
8581                        if (ws.mLayer > bestAnimLayer) {
8582                            animLp = ws.mAttrs;
8583                            bestAnimLayer = ws.mLayer;
8584                        }
8585                    }
8586                }
8587            }
8588
8589            mAnimateWallpaperWithTarget = false;
8590            if (closingAppHasWallpaper && openingAppHasWallpaper) {
8591                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
8592                switch (transit) {
8593                    case AppTransition.TRANSIT_ACTIVITY_OPEN:
8594                    case AppTransition.TRANSIT_TASK_OPEN:
8595                    case AppTransition.TRANSIT_TASK_TO_FRONT:
8596                        transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
8597                        break;
8598                    case AppTransition.TRANSIT_ACTIVITY_CLOSE:
8599                    case AppTransition.TRANSIT_TASK_CLOSE:
8600                    case AppTransition.TRANSIT_TASK_TO_BACK:
8601                        transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
8602                        break;
8603                }
8604                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit: " + transit);
8605            } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
8606                    && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
8607                // We are transitioning from an activity with
8608                // a wallpaper to one without.
8609                transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
8610                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8611                        "New transit away from wallpaper: " + transit);
8612            } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
8613                // We are transitioning from an activity without
8614                // a wallpaper to now showing the wallpaper
8615                transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
8616                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8617                        "New transit into wallpaper: " + transit);
8618            } else {
8619                mAnimateWallpaperWithTarget = true;
8620            }
8621
8622            // If all closing windows are obscured, then there is
8623            // no need to do an animation.  This is the case, for
8624            // example, when this transition is being done behind
8625            // the lock screen.
8626            if (!mPolicy.allowAppAnimationsLw()) {
8627                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8628                        "Animations disallowed by keyguard or dream.");
8629                animLp = null;
8630            }
8631
8632            AppWindowToken topOpeningApp = null;
8633            int topOpeningLayer = 0;
8634
8635            NN = mOpeningApps.size();
8636            for (i=0; i<NN; i++) {
8637                AppWindowToken wtoken = mOpeningApps.get(i);
8638                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
8639                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
8640                appAnimator.clearThumbnail();
8641                wtoken.inPendingTransaction = false;
8642                appAnimator.animation = null;
8643                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
8644                wtoken.updateReportedVisibilityLocked();
8645                wtoken.waitingToShow = false;
8646
8647                appAnimator.mAllAppWinAnimators.clear();
8648                final int N = wtoken.allAppWindows.size();
8649                for (int j = 0; j < N; j++) {
8650                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
8651                }
8652                mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
8653
8654                if (animLp != null) {
8655                    int layer = -1;
8656                    for (int j=0; j<wtoken.windows.size(); j++) {
8657                        WindowState win = wtoken.windows.get(j);
8658                        if (win.mWinAnimator.mAnimLayer > layer) {
8659                            layer = win.mWinAnimator.mAnimLayer;
8660                        }
8661                    }
8662                    if (topOpeningApp == null || layer > topOpeningLayer) {
8663                        topOpeningApp = wtoken;
8664                        topOpeningLayer = layer;
8665                    }
8666                }
8667            }
8668            NN = mClosingApps.size();
8669            for (i=0; i<NN; i++) {
8670                AppWindowToken wtoken = mClosingApps.get(i);
8671                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
8672                wtoken.mAppAnimator.clearThumbnail();
8673                wtoken.inPendingTransaction = false;
8674                wtoken.mAppAnimator.animation = null;
8675                setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
8676                wtoken.updateReportedVisibilityLocked();
8677                wtoken.waitingToHide = false;
8678                // Force the allDrawn flag, because we want to start
8679                // this guy's animations regardless of whether it's
8680                // gotten drawn.
8681                wtoken.allDrawn = true;
8682                wtoken.deferClearAllDrawn = false;
8683            }
8684
8685            AppWindowAnimator appAnimator =
8686                    topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
8687            Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
8688            if (nextAppTransitionThumbnail != null && appAnimator != null
8689                    && appAnimator.animation != null) {
8690                // This thumbnail animation is very special, we need to have
8691                // an extra surface with the thumbnail included with the animation.
8692                Rect dirty = new Rect(0, 0, nextAppTransitionThumbnail.getWidth(),
8693                        nextAppTransitionThumbnail.getHeight());
8694                try {
8695                    // TODO(multi-display): support other displays
8696                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
8697                    final Display display = displayContent.getDisplay();
8698                    SurfaceControl surfaceControl = new SurfaceControl(mFxSession,
8699                            "thumbnail anim",
8700                            dirty.width(), dirty.height(),
8701                            PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
8702                    surfaceControl.setLayerStack(display.getLayerStack());
8703                    appAnimator.thumbnail = surfaceControl;
8704                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");
8705                    Surface drawSurface = new Surface();
8706                    drawSurface.copyFrom(surfaceControl);
8707                    Canvas c = drawSurface.lockCanvas(dirty);
8708                    c.drawBitmap(nextAppTransitionThumbnail, 0, 0, null);
8709                    drawSurface.unlockCanvasAndPost(c);
8710                    drawSurface.release();
8711                    appAnimator.thumbnailLayer = topOpeningLayer;
8712                    DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
8713                    Animation anim = mAppTransition.createThumbnailAnimationLocked(
8714                            transit, true, true, displayInfo.appWidth, displayInfo.appHeight);
8715                    appAnimator.thumbnailAnimation = anim;
8716                    anim.restrictDuration(MAX_ANIMATION_DURATION);
8717                    anim.scaleCurrentDuration(mTransitionAnimationScale);
8718                    Point p = new Point();
8719                    mAppTransition.getStartingPoint(p);
8720                    appAnimator.thumbnailX = p.x;
8721                    appAnimator.thumbnailY = p.y;
8722                } catch (OutOfResourcesException e) {
8723                    Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" + dirty.width()
8724                            + " h=" + dirty.height(), e);
8725                    appAnimator.clearThumbnail();
8726                }
8727            }
8728
8729            mAppTransition.postAnimationCallback();
8730            mAppTransition.clear();
8731
8732            mOpeningApps.clear();
8733            mClosingApps.clear();
8734
8735            // This has changed the visibility of windows, so perform
8736            // a new layout to get them all up-to-date.
8737            changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
8738                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8739            getDefaultDisplayContentLocked().layoutNeeded = true;
8740
8741            // TODO(multidisplay): IMEs are only supported on the default display.
8742            if (windows == getDefaultWindowListLocked()
8743                    && !moveInputMethodWindowsIfNeededLocked(true)) {
8744                assignLayersLocked(windows);
8745            }
8746            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, false /*updateInputWindows*/);
8747            mFocusMayChange = false;
8748        }
8749
8750        return changes;
8751    }
8752
8753    /**
8754     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8755     * @return bitmap indicating if another pass through layout must be made.
8756     */
8757    private int handleAnimatingStoppedAndTransitionLocked() {
8758        int changes = 0;
8759
8760        mAppTransition.setIdle();
8761        // Restore window app tokens to the ActivityManager views
8762        ArrayList<TaskStack> stacks = getDefaultDisplayContentLocked().getStacks();
8763        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
8764            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
8765            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
8766                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
8767                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
8768                    tokens.get(tokenNdx).sendingToBottom = false;
8769                }
8770            }
8771        }
8772        rebuildAppWindowListLocked();
8773
8774        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8775        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
8776                "Wallpaper layer changed: assigning layers + relayout");
8777        moveInputMethodWindowsIfNeededLocked(true);
8778        mInnerFields.mWallpaperMayChange = true;
8779        // Since the window list has been rebuilt, focus might
8780        // have to be recomputed since the actual order of windows
8781        // might have changed again.
8782        mFocusMayChange = true;
8783
8784        return changes;
8785    }
8786
8787    private void updateResizingWindows(final WindowState w) {
8788        final WindowStateAnimator winAnimator = w.mWinAnimator;
8789        if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
8790            w.setInsetsChanged();
8791            boolean configChanged = w.isConfigChanged();
8792            if (DEBUG_CONFIGURATION && configChanged) {
8793                Slog.v(TAG, "Win " + w + " config changed: "
8794                        + mCurConfiguration);
8795            }
8796            if (localLOGV) Slog.v(TAG, "Resizing " + w
8797                    + ": configChanged=" + configChanged
8798                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8799            w.mLastFrame.set(w.mFrame);
8800            if (w.mContentInsetsChanged
8801                    || w.mVisibleInsetsChanged
8802                    || winAnimator.mSurfaceResized
8803                    || configChanged) {
8804                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8805                    Slog.v(TAG, "Resize reasons for w=" + w + ": "
8806                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8807                            + " " + w.mContentInsets.toShortString()
8808                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8809                            + " " + w.mVisibleInsets.toShortString()
8810                            + " surfaceResized=" + winAnimator.mSurfaceResized
8811                            + " configChanged=" + configChanged);
8812                }
8813
8814                w.mLastOverscanInsets.set(w.mOverscanInsets);
8815                w.mLastContentInsets.set(w.mContentInsets);
8816                w.mLastVisibleInsets.set(w.mVisibleInsets);
8817                makeWindowFreezingScreenIfNeededLocked(w);
8818                // If the orientation is changing, then we need to
8819                // hold off on unfreezing the display until this
8820                // window has been redrawn; to do that, we need
8821                // to go through the process of getting informed
8822                // by the application when it has finished drawing.
8823                if (w.mOrientationChanging) {
8824                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
8825                            "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
8826                            + w + ", surface " + winAnimator.mSurfaceControl);
8827                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8828                    if (w.mAppToken != null) {
8829                        w.mAppToken.allDrawn = false;
8830                        w.mAppToken.deferClearAllDrawn = false;
8831                    }
8832                }
8833                if (!mResizingWindows.contains(w)) {
8834                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8835                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8836                            + "x" + winAnimator.mSurfaceH);
8837                    mResizingWindows.add(w);
8838                }
8839            } else if (w.mOrientationChanging) {
8840                if (w.isDrawnLw()) {
8841                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8842                            "Orientation not waiting for draw in "
8843                            + w + ", surface " + winAnimator.mSurfaceControl);
8844                    w.mOrientationChanging = false;
8845                    w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
8846                            - mDisplayFreezeTime);
8847                }
8848            }
8849        }
8850    }
8851
8852    /**
8853     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8854     *
8855     * @param w WindowState this method is applied to.
8856     * @param currentTime The time which animations use for calculating transitions.
8857     * @param innerDw Width of app window.
8858     * @param innerDh Height of app window.
8859     */
8860    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8861                                         final int innerDw, final int innerDh) {
8862        final WindowManager.LayoutParams attrs = w.mAttrs;
8863        final int attrFlags = attrs.flags;
8864        final boolean canBeSeen = w.isDisplayedLw();
8865        final boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8866
8867        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8868            // This window completely covers everything behind it,
8869            // so we want to leave all of them as undimmed (for
8870            // performance reasons).
8871            mInnerFields.mObscured = true;
8872        }
8873
8874        if (w.mHasSurface) {
8875            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8876                mInnerFields.mHoldScreen = w.mSession;
8877            }
8878            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8879                    && mInnerFields.mScreenBrightness < 0) {
8880                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8881            }
8882            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8883                    && mInnerFields.mButtonBrightness < 0) {
8884                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8885            }
8886            if (!mInnerFields.mSyswin && w.mAttrs.userActivityTimeout >= 0
8887                    && mInnerFields.mUserActivityTimeout < 0) {
8888                mInnerFields.mUserActivityTimeout = w.mAttrs.userActivityTimeout;
8889            }
8890
8891            final int type = attrs.type;
8892            if (canBeSeen
8893                    && (type == TYPE_SYSTEM_DIALOG
8894                     || type == TYPE_RECENTS_OVERLAY
8895                     || type == TYPE_KEYGUARD
8896                     || type == TYPE_SYSTEM_ERROR)) {
8897                mInnerFields.mSyswin = true;
8898            }
8899
8900            if (canBeSeen) {
8901                // This function assumes that the contents of the default display are
8902                // processed first before secondary displays.
8903                final DisplayContent displayContent = w.getDisplayContent();
8904                if (displayContent != null && displayContent.isDefaultDisplay) {
8905                    // While a dream or keyguard is showing, obscure ordinary application
8906                    // content on secondary displays (by forcibly enabling mirroring unless
8907                    // there is other content we want to show) but still allow opaque
8908                    // keyguard dialogs to be shown.
8909                    if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
8910                        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
8911                    }
8912                    mInnerFields.mDisplayHasContent = true;
8913                } else if (displayContent != null &&
8914                        (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
8915                        || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG))) {
8916                    // Allow full screen keyguard presentation dialogs to be seen.
8917                    mInnerFields.mDisplayHasContent = true;
8918                }
8919            }
8920        }
8921    }
8922
8923    private void handleFlagDimBehind(WindowState w) {
8924        final WindowManager.LayoutParams attrs = w.mAttrs;
8925        if ((attrs.flags & FLAG_DIM_BEHIND) != 0
8926                && w.isDisplayedLw()
8927                && !w.mExiting) {
8928            final WindowStateAnimator winAnimator = w.mWinAnimator;
8929            final TaskStack stack = w.getStack();
8930            stack.setDimmingTag();
8931            if (!stack.isDimming(winAnimator)) {
8932                if (localLOGV) Slog.v(TAG, "Win " + w + " start dimming.");
8933                stack.startDimmingIfNeeded(winAnimator);
8934            }
8935        }
8936    }
8937
8938    private void updateAllDrawnLocked(DisplayContent displayContent) {
8939        // See if any windows have been drawn, so they (and others
8940        // associated with them) can now be shown.
8941        ArrayList<TaskStack> stacks = displayContent.getStacks();
8942        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
8943            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
8944            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
8945                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
8946                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
8947                    final AppWindowToken wtoken = tokens.get(tokenNdx);
8948                    if (!wtoken.allDrawn) {
8949                        int numInteresting = wtoken.numInterestingWindows;
8950                        if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8951                            if (DEBUG_VISIBILITY) Slog.v(TAG,
8952                                    "allDrawn: " + wtoken
8953                                    + " interesting=" + numInteresting
8954                                    + " drawn=" + wtoken.numDrawnWindows);
8955                            wtoken.allDrawn = true;
8956                            mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
8957                        }
8958                    }
8959                }
8960            }
8961        }
8962    }
8963
8964    // "Something has changed!  Let's make it correct now."
8965    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
8966        if (DEBUG_WINDOW_TRACE) {
8967            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8968                    + Debug.getCallers(3));
8969        }
8970
8971        final long currentTime = SystemClock.uptimeMillis();
8972
8973        int i;
8974
8975        if (mFocusMayChange) {
8976            mFocusMayChange = false;
8977            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8978                    false /*updateInputWindows*/);
8979        }
8980
8981        // Initialize state of exiting tokens.
8982        final int numDisplays = mDisplayContents.size();
8983        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
8984            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
8985            for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
8986                displayContent.mExitingTokens.get(i).hasVisible = false;
8987            }
8988        }
8989
8990        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
8991            // Initialize state of exiting applications.
8992            final AppTokenList exitingAppTokens =
8993                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
8994            for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
8995                exitingAppTokens.get(tokenNdx).hasVisible = false;
8996            }
8997        }
8998
8999        mInnerFields.mHoldScreen = null;
9000        mInnerFields.mScreenBrightness = -1;
9001        mInnerFields.mButtonBrightness = -1;
9002        mInnerFields.mUserActivityTimeout = -1;
9003        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = false;
9004
9005        mTransactionSequence++;
9006
9007        final DisplayContent defaultDisplay = getDefaultDisplayContentLocked();
9008        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
9009        final int defaultDw = defaultInfo.logicalWidth;
9010        final int defaultDh = defaultInfo.logicalHeight;
9011
9012        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
9013                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
9014        SurfaceControl.openTransaction();
9015        try {
9016
9017            if (mWatermark != null) {
9018                mWatermark.positionSurface(defaultDw, defaultDh);
9019            }
9020            if (mStrictModeFlash != null) {
9021                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
9022            }
9023
9024            boolean focusDisplayed = false;
9025
9026            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9027                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
9028                boolean updateAllDrawn = false;
9029                WindowList windows = displayContent.getWindowList();
9030                DisplayInfo displayInfo = displayContent.getDisplayInfo();
9031                final int displayId = displayContent.getDisplayId();
9032                final int dw = displayInfo.logicalWidth;
9033                final int dh = displayInfo.logicalHeight;
9034                final int innerDw = displayInfo.appWidth;
9035                final int innerDh = displayInfo.appHeight;
9036                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
9037
9038                // Reset for each display.
9039                mInnerFields.mDisplayHasContent = false;
9040
9041                int repeats = 0;
9042                do {
9043                    repeats++;
9044                    if (repeats > 6) {
9045                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
9046                        displayContent.layoutNeeded = false;
9047                        break;
9048                    }
9049
9050                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
9051                        displayContent.pendingLayoutChanges);
9052
9053                    if ((displayContent.pendingLayoutChanges &
9054                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
9055                            (adjustWallpaperWindowsLocked() &
9056                                    ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
9057                        assignLayersLocked(windows);
9058                        displayContent.layoutNeeded = true;
9059                    }
9060
9061                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
9062                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
9063                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
9064                        if (updateOrientationFromAppTokensLocked(true)) {
9065                            displayContent.layoutNeeded = true;
9066                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9067                        }
9068                    }
9069
9070                    if ((displayContent.pendingLayoutChanges
9071                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9072                        displayContent.layoutNeeded = true;
9073                    }
9074
9075                    // FIRST LOOP: Perform a layout, if needed.
9076                    if (repeats < 4) {
9077                        performLayoutLockedInner(displayContent, repeats == 1,
9078                                false /*updateInputWindows*/);
9079                    } else {
9080                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
9081                    }
9082
9083                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
9084                    // it is animating.
9085                    displayContent.pendingLayoutChanges = 0;
9086
9087                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
9088                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
9089
9090                    if (isDefaultDisplay) {
9091                        mPolicy.beginPostLayoutPolicyLw(dw, dh);
9092                        for (i = windows.size() - 1; i >= 0; i--) {
9093                            WindowState w = windows.get(i);
9094                            if (w.mHasSurface) {
9095                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
9096                            }
9097                        }
9098                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
9099                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
9100                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
9101                    }
9102                } while (displayContent.pendingLayoutChanges != 0);
9103
9104                mInnerFields.mObscured = false;
9105                mInnerFields.mSyswin = false;
9106                displayContent.resetDimming();
9107
9108                // Only used if default window
9109                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
9110
9111                final int N = windows.size();
9112                for (i=N-1; i>=0; i--) {
9113                    WindowState w = windows.get(i);
9114                    final TaskStack stack = w.getStack();
9115                    if (stack == null) {
9116                        continue;
9117                    }
9118
9119                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
9120
9121                    // Update effect.
9122                    w.mObscured = mInnerFields.mObscured;
9123                    if (!mInnerFields.mObscured) {
9124                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
9125                    }
9126
9127                    if (!stack.testDimmingTag()) {
9128                        handleFlagDimBehind(w);
9129                    }
9130
9131                    if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
9132                            && w.isVisibleLw()) {
9133                        // This is the wallpaper target and its obscured state
9134                        // changed... make sure the current wallaper's visibility
9135                        // has been updated accordingly.
9136                        updateWallpaperVisibilityLocked();
9137                    }
9138
9139                    final WindowStateAnimator winAnimator = w.mWinAnimator;
9140
9141                    // If the window has moved due to its containing
9142                    // content frame changing, then we'd like to animate
9143                    // it.
9144                    if (w.mHasSurface && w.shouldAnimateMove()) {
9145                        // Frame has moved, containing content frame
9146                        // has also moved, and we're not currently animating...
9147                        // let's do something.
9148                        Animation a = AnimationUtils.loadAnimation(mContext,
9149                                com.android.internal.R.anim.window_move_from_decor);
9150                        winAnimator.setAnimation(a);
9151                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
9152                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
9153                        try {
9154                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
9155                        } catch (RemoteException e) {
9156                        }
9157                    }
9158
9159                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
9160                    w.mContentChanged = false;
9161
9162                    // Moved from updateWindowsAndWallpaperLocked().
9163                    if (w.mHasSurface) {
9164                        // Take care of the window being ready to display.
9165                        final boolean committed =
9166                                winAnimator.commitFinishDrawingLocked(currentTime);
9167                        if (isDefaultDisplay && committed) {
9168                            if (w.mAttrs.type == TYPE_DREAM) {
9169                                // HACK: When a dream is shown, it may at that
9170                                // point hide the lock screen.  So we need to
9171                                // redo the layout to let the phone window manager
9172                                // make this happen.
9173                                displayContent.pendingLayoutChanges |=
9174                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9175                                if (DEBUG_LAYOUT_REPEATS) {
9176                                    debugLayoutRepeats(
9177                                        "dream and commitFinishDrawingLocked true",
9178                                        displayContent.pendingLayoutChanges);
9179                                }
9180                            }
9181                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
9182                                if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
9183                                        "First draw done in potential wallpaper target " + w);
9184                                mInnerFields.mWallpaperMayChange = true;
9185                                displayContent.pendingLayoutChanges |=
9186                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9187                                if (DEBUG_LAYOUT_REPEATS) {
9188                                    debugLayoutRepeats(
9189                                        "wallpaper and commitFinishDrawingLocked true",
9190                                        displayContent.pendingLayoutChanges);
9191                                }
9192                            }
9193                        }
9194
9195                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
9196
9197                        final AppWindowToken atoken = w.mAppToken;
9198                        if (DEBUG_STARTING_WINDOW && atoken != null
9199                                && w == atoken.startingWindow) {
9200                            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
9201                                + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
9202                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
9203                        }
9204                        if (atoken != null
9205                                && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
9206                            if (atoken.lastTransactionSequence != mTransactionSequence) {
9207                                atoken.lastTransactionSequence = mTransactionSequence;
9208                                atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
9209                                atoken.startingDisplayed = false;
9210                            }
9211                            if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
9212                                    && !w.mExiting && !w.mDestroying) {
9213                                if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
9214                                    Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
9215                                            + ", isAnimating=" + winAnimator.isAnimating());
9216                                    if (!w.isDrawnLw()) {
9217                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceControl
9218                                                + " pv=" + w.mPolicyVisibility
9219                                                + " mDrawState=" + winAnimator.mDrawState
9220                                                + " ah=" + w.mAttachedHidden
9221                                                + " th=" + atoken.hiddenRequested
9222                                                + " a=" + winAnimator.mAnimating);
9223                                    }
9224                                }
9225                                if (w != atoken.startingWindow) {
9226                                    if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
9227                                        atoken.numInterestingWindows++;
9228                                        if (w.isDrawnLw()) {
9229                                            atoken.numDrawnWindows++;
9230                                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
9231                                                    "tokenMayBeDrawn: " + atoken
9232                                                    + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
9233                                                    + " mAppFreezing=" + w.mAppFreezing);
9234                                            updateAllDrawn = true;
9235                                        }
9236                                    }
9237                                } else if (w.isDrawnLw()) {
9238                                    atoken.startingDisplayed = true;
9239                                }
9240                            }
9241                        }
9242                    }
9243
9244                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
9245                            && w.isDisplayedLw()) {
9246                        focusDisplayed = true;
9247                    }
9248
9249                    updateResizingWindows(w);
9250                }
9251
9252                mDisplayManagerInternal.setDisplayHasContent(displayId,
9253                        mInnerFields.mDisplayHasContent,
9254                        true /* inTraversal, must call performTraversalInTrans... below */);
9255
9256                getDisplayContentLocked(displayId).stopDimmingIfNeeded();
9257
9258                if (updateAllDrawn) {
9259                    updateAllDrawnLocked(displayContent);
9260                }
9261            }
9262
9263            if (focusDisplayed) {
9264                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
9265            }
9266
9267            // Give the display manager a chance to adjust properties
9268            // like display rotation if it needs to.
9269            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
9270
9271        } catch (RuntimeException e) {
9272            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
9273        } finally {
9274            SurfaceControl.closeTransaction();
9275            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
9276                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
9277        }
9278
9279        final WindowList defaultWindows = defaultDisplay.getWindowList();
9280
9281        // If we are ready to perform an app transition, check through
9282        // all of the app tokens to be shown and see if they are ready
9283        // to go.
9284        if (mAppTransition.isReady()) {
9285            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
9286            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
9287                    defaultDisplay.pendingLayoutChanges);
9288        }
9289
9290        if (!mAnimator.mAnimating && mAppTransition.isRunning()) {
9291            // We have finished the animation of an app transition.  To do
9292            // this, we have delayed a lot of operations like showing and
9293            // hiding apps, moving apps in Z-order, etc.  The app token list
9294            // reflects the correct Z-order, but the window list may now
9295            // be out of sync with it.  So here we will just rebuild the
9296            // entire app window list.  Fun!
9297            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
9298            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
9299                defaultDisplay.pendingLayoutChanges);
9300        }
9301
9302        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
9303                && !mAppTransition.isReady()) {
9304            // At this point, there was a window with a wallpaper that
9305            // was force hiding other windows behind it, but now it
9306            // is going away.  This may be simple -- just animate
9307            // away the wallpaper and its window -- or it may be
9308            // hard -- the wallpaper now needs to be shown behind
9309            // something that was hidden.
9310            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9311            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
9312                defaultDisplay.pendingLayoutChanges);
9313        }
9314        mInnerFields.mWallpaperForceHidingChanged = false;
9315
9316        if (mInnerFields.mWallpaperMayChange) {
9317            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change!  Adjusting");
9318            defaultDisplay.pendingLayoutChanges |=
9319                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9320            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
9321                    defaultDisplay.pendingLayoutChanges);
9322        }
9323
9324        if (mFocusMayChange) {
9325            mFocusMayChange = false;
9326            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
9327                    false /*updateInputWindows*/)) {
9328                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
9329            }
9330        }
9331
9332        if (needsLayout()) {
9333            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9334            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
9335                    defaultDisplay.pendingLayoutChanges);
9336        }
9337
9338        for (i = mResizingWindows.size() - 1; i >= 0; i--) {
9339            WindowState win = mResizingWindows.get(i);
9340            if (win.mAppFreezing) {
9341                // Don't remove this window until rotation has completed.
9342                continue;
9343            }
9344            win.reportResized();
9345            mResizingWindows.remove(i);
9346        }
9347
9348        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
9349                "With display frozen, orientationChangeComplete="
9350                + mInnerFields.mOrientationChangeComplete);
9351        if (mInnerFields.mOrientationChangeComplete) {
9352            if (mWindowsFreezingScreen) {
9353                mWindowsFreezingScreen = false;
9354                mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
9355                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
9356            }
9357            stopFreezingDisplayLocked();
9358        }
9359
9360        // Destroy the surface of any windows that are no longer visible.
9361        boolean wallpaperDestroyed = false;
9362        i = mDestroySurface.size();
9363        if (i > 0) {
9364            do {
9365                i--;
9366                WindowState win = mDestroySurface.get(i);
9367                win.mDestroying = false;
9368                if (mInputMethodWindow == win) {
9369                    mInputMethodWindow = null;
9370                }
9371                if (win == mWallpaperTarget) {
9372                    wallpaperDestroyed = true;
9373                }
9374                win.mWinAnimator.destroySurfaceLocked();
9375            } while (i > 0);
9376            mDestroySurface.clear();
9377        }
9378
9379        // Time to remove any exiting tokens?
9380        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9381            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
9382            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
9383            for (i = exitingTokens.size() - 1; i >= 0; i--) {
9384                WindowToken token = exitingTokens.get(i);
9385                if (!token.hasVisible) {
9386                    exitingTokens.remove(i);
9387                    if (token.windowType == TYPE_WALLPAPER) {
9388                        mWallpaperTokens.remove(token);
9389                    }
9390                }
9391            }
9392        }
9393
9394        // Time to remove any exiting applications?
9395        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
9396            // Initialize state of exiting applications.
9397            final AppTokenList exitingAppTokens =
9398                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
9399            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
9400                AppWindowToken token = exitingAppTokens.get(i);
9401                if (!token.hasVisible && !mClosingApps.contains(token)) {
9402                    // Make sure there is no animation running on this token,
9403                    // so any windows associated with it will be removed as
9404                    // soon as their animations are complete
9405                    token.mAppAnimator.clearAnimation();
9406                    token.mAppAnimator.animating = false;
9407                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
9408                            "performLayout: App token exiting now removed" + token);
9409                    removeAppFromTaskLocked(token);
9410                    exitingAppTokens.remove(i);
9411                }
9412            }
9413        }
9414
9415        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
9416            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
9417                try {
9418                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
9419                } catch (RemoteException e) {
9420                }
9421            }
9422            mRelayoutWhileAnimating.clear();
9423        }
9424
9425        if (wallpaperDestroyed) {
9426            defaultDisplay.pendingLayoutChanges |=
9427                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9428            defaultDisplay.layoutNeeded = true;
9429        }
9430
9431        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9432            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
9433            if (displayContent.pendingLayoutChanges != 0) {
9434                displayContent.layoutNeeded = true;
9435            }
9436        }
9437
9438        // Finally update all input windows now that the window changes have stabilized.
9439        mInputMonitor.updateInputWindowsLw(true /*force*/);
9440
9441        setHoldScreenLocked(mInnerFields.mHoldScreen);
9442        if (!mDisplayFrozen) {
9443            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
9444                mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
9445            } else {
9446                mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
9447                        toBrightnessOverride(mInnerFields.mScreenBrightness));
9448            }
9449            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
9450                mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
9451            } else {
9452                mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
9453                        toBrightnessOverride(mInnerFields.mButtonBrightness));
9454            }
9455            mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
9456                    mInnerFields.mUserActivityTimeout);
9457        }
9458
9459        if (mTurnOnScreen) {
9460            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
9461            mPowerManager.wakeUp(SystemClock.uptimeMillis());
9462            mTurnOnScreen = false;
9463        }
9464
9465        if (mInnerFields.mUpdateRotation) {
9466            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9467            if (updateRotationUncheckedLocked(false)) {
9468                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9469            } else {
9470                mInnerFields.mUpdateRotation = false;
9471            }
9472        }
9473
9474        if (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded
9475                && !mInnerFields.mUpdateRotation) {
9476            checkDrawnWindowsLocked();
9477        }
9478
9479        final int N = mPendingRemove.size();
9480        if (N > 0) {
9481            if (mPendingRemoveTmp.length < N) {
9482                mPendingRemoveTmp = new WindowState[N+10];
9483            }
9484            mPendingRemove.toArray(mPendingRemoveTmp);
9485            mPendingRemove.clear();
9486            DisplayContentList displayList = new DisplayContentList();
9487            for (i = 0; i < N; i++) {
9488                WindowState w = mPendingRemoveTmp[i];
9489                removeWindowInnerLocked(w.mSession, w);
9490                final DisplayContent displayContent = w.getDisplayContent();
9491                if (displayContent != null && !displayList.contains(displayContent)) {
9492                    displayList.add(displayContent);
9493                }
9494            }
9495
9496            for (DisplayContent displayContent : displayList) {
9497                assignLayersLocked(displayContent.getWindowList());
9498                displayContent.layoutNeeded = true;
9499            }
9500        }
9501
9502        // Remove all deferred Stacks, tasks, and activities.
9503        for (int stackNdx = mPendingStacksRemove.size() - 1; stackNdx >= 0; --stackNdx) {
9504            mPendingStacksRemove.removeAt(stackNdx).checkForDeferredActions();
9505        }
9506
9507        setFocusedStackFrame();
9508
9509        // Check to see if we are now in a state where the screen should
9510        // be enabled, because the window obscured flags have changed.
9511        enableScreenIfNeededLocked();
9512
9513        scheduleAnimationLocked();
9514
9515        if (DEBUG_WINDOW_TRACE) {
9516            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
9517                    + mAnimator.mAnimating);
9518        }
9519    }
9520
9521    private int toBrightnessOverride(float value) {
9522        return (int)(value * PowerManager.BRIGHTNESS_ON);
9523    }
9524
9525    void checkDrawnWindowsLocked() {
9526        if (mWaitingForDrawn.size() > 0) {
9527            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
9528                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
9529                WindowState win = pair.first;
9530                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
9531                //        + win.mRemoved + " visible=" + win.isVisibleLw()
9532                //        + " shown=" + win.mSurfaceShown);
9533                if (win.mRemoved) {
9534                    // Window has been removed; no draw will now happen, so stop waiting.
9535                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
9536                    try {
9537                        pair.second.sendResult(null);
9538                    } catch (RemoteException e) {
9539                    }
9540                    mWaitingForDrawn.remove(pair);
9541                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9542                } else if (win.mWinAnimator.mSurfaceShown) {
9543                    // Window is now drawn (and shown).
9544                    try {
9545                        pair.second.sendResult(null);
9546                    } catch (RemoteException e) {
9547                    }
9548                    mWaitingForDrawn.remove(pair);
9549                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9550                }
9551            }
9552        }
9553    }
9554
9555    @Override
9556    public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
9557        if (token != null && callback != null) {
9558            synchronized (mWindowMap) {
9559                WindowState win = windowForClientLocked(null, token, true);
9560                if (win != null) {
9561                    Pair<WindowState, IRemoteCallback> pair =
9562                            new Pair<WindowState, IRemoteCallback>(win, callback);
9563                    Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9564                    mH.sendMessageDelayed(m, 2000);
9565                    mWaitingForDrawn.add(pair);
9566                    checkDrawnWindowsLocked();
9567                    return true;
9568                }
9569                Slog.i(TAG, "waitForWindowDrawn: win null");
9570            }
9571        }
9572        return false;
9573    }
9574
9575    void setHoldScreenLocked(final Session newHoldScreen) {
9576        final boolean hold = newHoldScreen != null;
9577
9578        if (hold && mHoldingScreenOn != newHoldScreen) {
9579            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
9580        }
9581        mHoldingScreenOn = newHoldScreen;
9582
9583        final boolean state = mHoldingScreenWakeLock.isHeld();
9584        if (hold != state) {
9585            if (hold) {
9586                mHoldingScreenWakeLock.acquire();
9587                mPolicy.keepScreenOnStartedLw();
9588            } else {
9589                mPolicy.keepScreenOnStoppedLw();
9590                mHoldingScreenWakeLock.release();
9591            }
9592        }
9593    }
9594
9595    void requestTraversal() {
9596        synchronized (mWindowMap) {
9597            requestTraversalLocked();
9598        }
9599    }
9600
9601    void requestTraversalLocked() {
9602        if (!mTraversalScheduled) {
9603            mTraversalScheduled = true;
9604            mH.sendEmptyMessage(H.DO_TRAVERSAL);
9605        }
9606    }
9607
9608    /** Note that Locked in this case is on mLayoutToAnim */
9609    void scheduleAnimationLocked() {
9610        if (!mAnimationScheduled) {
9611            mAnimationScheduled = true;
9612            mChoreographer.postCallback(
9613                    Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
9614        }
9615    }
9616
9617    private boolean needsLayout() {
9618        final int numDisplays = mDisplayContents.size();
9619        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9620            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
9621            if (displayContent.layoutNeeded) {
9622                return true;
9623            }
9624        }
9625        return false;
9626    }
9627
9628    boolean copyAnimToLayoutParamsLocked() {
9629        boolean doRequest = false;
9630
9631        final int bulkUpdateParams = mAnimator.mBulkUpdateParams;
9632        if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
9633            mInnerFields.mUpdateRotation = true;
9634            doRequest = true;
9635        }
9636        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
9637            mInnerFields.mWallpaperMayChange = true;
9638            doRequest = true;
9639        }
9640        if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
9641            mInnerFields.mWallpaperForceHidingChanged = true;
9642            doRequest = true;
9643        }
9644        if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
9645            mInnerFields.mOrientationChangeComplete = false;
9646        } else {
9647            mInnerFields.mOrientationChangeComplete = true;
9648            mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
9649            if (mWindowsFreezingScreen) {
9650                doRequest = true;
9651            }
9652        }
9653        if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
9654            mTurnOnScreen = true;
9655        }
9656        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_ACTION_PENDING) != 0) {
9657            mInnerFields.mWallpaperActionPending = true;
9658        }
9659
9660        return doRequest;
9661    }
9662
9663    /** If a window that has an animation specifying a colored background and the current wallpaper
9664     * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to
9665     * suddenly disappear. */
9666    int adjustAnimationBackground(WindowStateAnimator winAnimator) {
9667        WindowList windows = winAnimator.mWin.getWindowList();
9668        for (int i = windows.size() - 1; i >= 0; --i) {
9669            WindowState testWin = windows.get(i);
9670            if (testWin.mIsWallpaper && testWin.isVisibleNow()) {
9671                return testWin.mWinAnimator.mAnimLayer;
9672            }
9673        }
9674        return winAnimator.mAnimLayer;
9675    }
9676
9677    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
9678                                           boolean secure) {
9679        final SurfaceControl surface = winAnimator.mSurfaceControl;
9680        boolean leakedSurface = false;
9681        boolean killedApps = false;
9682
9683        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
9684                winAnimator.mSession.mPid, operation);
9685
9686        if (mForceRemoves == null) {
9687            mForceRemoves = new ArrayList<WindowState>();
9688        }
9689
9690        long callingIdentity = Binder.clearCallingIdentity();
9691        try {
9692            // There was some problem...   first, do a sanity check of the
9693            // window list to make sure we haven't left any dangling surfaces
9694            // around.
9695
9696            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
9697            final int numDisplays = mDisplayContents.size();
9698            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9699                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
9700                final int numWindows = windows.size();
9701                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
9702                    final WindowState ws = windows.get(winNdx);
9703                    WindowStateAnimator wsa = ws.mWinAnimator;
9704                    if (wsa.mSurfaceControl != null) {
9705                        if (!mSessions.contains(wsa.mSession)) {
9706                            Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
9707                                    + ws + " surface=" + wsa.mSurfaceControl
9708                                    + " token=" + ws.mToken
9709                                    + " pid=" + ws.mSession.mPid
9710                                    + " uid=" + ws.mSession.mUid);
9711                            if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9712                            wsa.mSurfaceControl.destroy();
9713                            wsa.mSurfaceShown = false;
9714                            wsa.mSurfaceControl = null;
9715                            ws.mHasSurface = false;
9716                            mForceRemoves.add(ws);
9717                            leakedSurface = true;
9718                        } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
9719                            Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
9720                                    + ws + " surface=" + wsa.mSurfaceControl
9721                                    + " token=" + ws.mAppToken);
9722                            if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9723                            wsa.mSurfaceControl.destroy();
9724                            wsa.mSurfaceShown = false;
9725                            wsa.mSurfaceControl = null;
9726                            ws.mHasSurface = false;
9727                            leakedSurface = true;
9728                        }
9729                    }
9730                }
9731            }
9732
9733            if (!leakedSurface) {
9734                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
9735                SparseIntArray pidCandidates = new SparseIntArray();
9736                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9737                    final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
9738                    final int numWindows = windows.size();
9739                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
9740                        final WindowState ws = windows.get(winNdx);
9741                        if (mForceRemoves.contains(ws)) {
9742                            continue;
9743                        }
9744                        WindowStateAnimator wsa = ws.mWinAnimator;
9745                        if (wsa.mSurfaceControl != null) {
9746                            pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
9747                        }
9748                    }
9749                    if (pidCandidates.size() > 0) {
9750                        int[] pids = new int[pidCandidates.size()];
9751                        for (int i=0; i<pids.length; i++) {
9752                            pids[i] = pidCandidates.keyAt(i);
9753                        }
9754                        try {
9755                            if (mActivityManager.killPids(pids, "Free memory", secure)) {
9756                                killedApps = true;
9757                            }
9758                        } catch (RemoteException e) {
9759                        }
9760                    }
9761                }
9762            }
9763
9764            if (leakedSurface || killedApps) {
9765                // We managed to reclaim some memory, so get rid of the trouble
9766                // surface and ask the app to request another one.
9767                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9768                if (surface != null) {
9769                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
9770                            "RECOVER DESTROY", null);
9771                    surface.destroy();
9772                    winAnimator.mSurfaceShown = false;
9773                    winAnimator.mSurfaceControl = null;
9774                    winAnimator.mWin.mHasSurface = false;
9775                    scheduleRemoveStartingWindow(winAnimator.mWin.mAppToken);
9776                }
9777
9778                try {
9779                    winAnimator.mWin.mClient.dispatchGetNewSurface();
9780                } catch (RemoteException e) {
9781                }
9782            }
9783        } finally {
9784            Binder.restoreCallingIdentity(callingIdentity);
9785        }
9786
9787        return leakedSurface || killedApps;
9788    }
9789
9790    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9791        WindowState newFocus = computeFocusedWindowLocked();
9792        if (mCurrentFocus != newFocus) {
9793            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
9794            // This check makes sure that we don't already have the focus
9795            // change message pending.
9796            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9797            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9798            // TODO(multidisplay): Focused windows on default display only.
9799            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9800            final boolean imWindowChanged = moveInputMethodWindowsIfNeededLocked(
9801                    mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
9802                            && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES);
9803            if (imWindowChanged) {
9804                displayContent.layoutNeeded = true;
9805                newFocus = computeFocusedWindowLocked();
9806            }
9807
9808            if (DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(TAG, "Changing focus from " +
9809                    mCurrentFocus + " to " + newFocus + " Callers=" + Debug.getCallers(4));
9810            final WindowState oldFocus = mCurrentFocus;
9811            mCurrentFocus = newFocus;
9812            mLosingFocus.remove(newFocus);
9813            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9814
9815            if (imWindowChanged && oldFocus != mInputMethodWindow) {
9816                // Focus of the input method window changed. Perform layout if needed.
9817                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9818                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9819                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9820                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9821                    // Client will do the layout, but we need to assign layers
9822                    // for handleNewWindowLocked() below.
9823                    assignLayersLocked(displayContent.getWindowList());
9824                }
9825            }
9826
9827            if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9828                // The change in focus caused us to need to do a layout.  Okay.
9829                displayContent.layoutNeeded = true;
9830                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9831                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9832                }
9833            }
9834
9835            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9836                // If we defer assigning layers, then the caller is responsible for
9837                // doing this part.
9838                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9839            }
9840
9841            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
9842            return true;
9843        }
9844        return false;
9845    }
9846
9847    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9848        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9849    }
9850
9851    private WindowState computeFocusedWindowLocked() {
9852        if (mAnimator.mUniverseBackground != null
9853                && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) {
9854            return mAnimator.mUniverseBackground.mWin;
9855        }
9856
9857        final int displayCount = mDisplayContents.size();
9858        for (int i = 0; i < displayCount; i++) {
9859            final DisplayContent displayContent = mDisplayContents.valueAt(i);
9860            WindowState win = findFocusedWindowLocked(displayContent);
9861            if (win != null) {
9862                return win;
9863            }
9864        }
9865        return null;
9866    }
9867
9868    private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
9869        final WindowList windows = displayContent.getWindowList();
9870        for (int i = windows.size() - 1; i >= 0; i--) {
9871            final WindowState win = windows.get(i);
9872
9873            if (localLOGV || DEBUG_FOCUS) Slog.v(
9874                TAG, "Looking for focus: " + i
9875                + " = " + win
9876                + ", flags=" + win.mAttrs.flags
9877                + ", canReceive=" + win.canReceiveKeys());
9878
9879            AppWindowToken wtoken = win.mAppToken;
9880
9881            // If this window's application has been removed, just skip it.
9882            if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) {
9883                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping " + wtoken + " because "
9884                        + (wtoken.removed ? "removed" : "sendingToBottom"));
9885                continue;
9886            }
9887
9888            if (!win.canReceiveKeys()) {
9889                continue;
9890            }
9891
9892            // Descend through all of the app tokens and find the first that either matches
9893            // win.mAppToken (return win) or mFocusedApp (return null).
9894            if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING &&
9895                    mFocusedApp != null) {
9896                ArrayList<Task> tasks = displayContent.getTasks();
9897                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
9898                    AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
9899                    int tokenNdx = tokens.size() - 1;
9900                    for ( ; tokenNdx >= 0; --tokenNdx) {
9901                        final AppWindowToken token = tokens.get(tokenNdx);
9902                        if (wtoken == token) {
9903                            break;
9904                        }
9905                        if (mFocusedApp == token) {
9906                            // Whoops, we are below the focused app...  no focus for you!
9907                            if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG,
9908                                    "findFocusedWindow: Reached focused app=" + mFocusedApp);
9909                            return null;
9910                        }
9911                    }
9912                    if (tokenNdx >= 0) {
9913                        // Early exit from loop, must have found the matching token.
9914                        break;
9915                    }
9916                }
9917            }
9918
9919            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "findFocusedWindow: Found new focus @ " + i +
9920                        " = " + win);
9921            return win;
9922        }
9923
9924        if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "findFocusedWindow: No focusable windows.");
9925        return null;
9926    }
9927
9928    private void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
9929        if (mDisplayFrozen) {
9930            return;
9931        }
9932
9933        if (!mDisplayReady || !mPolicy.isScreenOnFully()) {
9934            // No need to freeze the screen before the system is ready or if
9935            // the screen is off.
9936            return;
9937        }
9938
9939        mScreenFrozenLock.acquire();
9940
9941        mDisplayFrozen = true;
9942        mDisplayFreezeTime = SystemClock.elapsedRealtime();
9943        mLastFinishedFreezeSource = null;
9944
9945        mInputMonitor.freezeInputDispatchingLw();
9946
9947        // Clear the last input window -- that is just used for
9948        // clean transitions between IMEs, and if we are freezing
9949        // the screen then the whole world is changing behind the scenes.
9950        mPolicy.setLastInputMethodWindowLw(null, null);
9951
9952        if (mAppTransition.isTransitionSet()) {
9953            mAppTransition.freeze();
9954        }
9955
9956        if (PROFILE_ORIENTATION) {
9957            File file = new File("/data/system/frozen");
9958            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9959        }
9960
9961        if (CUSTOM_SCREEN_ROTATION) {
9962            mExitAnimId = exitAnim;
9963            mEnterAnimId = enterAnim;
9964            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9965            final int displayId = displayContent.getDisplayId();
9966            ScreenRotationAnimation screenRotationAnimation =
9967                    mAnimator.getScreenRotationAnimationLocked(displayId);
9968            if (screenRotationAnimation != null) {
9969                screenRotationAnimation.kill();
9970            }
9971
9972            // TODO(multidisplay): rotation on main screen only.
9973            displayContent.updateDisplayInfo();
9974            screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
9975                    mFxSession, inTransaction, mPolicy.isDefaultOrientationForced());
9976            mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9977        }
9978    }
9979
9980    private void stopFreezingDisplayLocked() {
9981        if (!mDisplayFrozen) {
9982            return;
9983        }
9984
9985        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
9986                || mClientFreezingScreen) {
9987            if (DEBUG_ORIENTATION) Slog.d(TAG,
9988                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
9989                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
9990                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
9991                + ", mClientFreezingScreen=" + mClientFreezingScreen);
9992            return;
9993        }
9994
9995        mDisplayFrozen = false;
9996        mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
9997        StringBuilder sb = new StringBuilder(128);
9998        sb.append("Screen frozen for ");
9999        TimeUtils.formatDuration(mLastDisplayFreezeDuration, sb);
10000        if (mLastFinishedFreezeSource != null) {
10001            sb.append(" due to ");
10002            sb.append(mLastFinishedFreezeSource);
10003        }
10004        Slog.i(TAG, sb.toString());
10005        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
10006        mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
10007        if (PROFILE_ORIENTATION) {
10008            Debug.stopMethodTracing();
10009        }
10010
10011        boolean updateRotation = false;
10012
10013        final DisplayContent displayContent = getDefaultDisplayContentLocked();
10014        final int displayId = displayContent.getDisplayId();
10015        ScreenRotationAnimation screenRotationAnimation =
10016                mAnimator.getScreenRotationAnimationLocked(displayId);
10017        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
10018                && screenRotationAnimation.hasScreenshot()) {
10019            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
10020            // TODO(multidisplay): rotation on main screen only.
10021            DisplayInfo displayInfo = displayContent.getDisplayInfo();
10022            // Get rotation animation again, with new top window
10023            boolean isDimming = displayContent.isDimming();
10024            if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
10025                mExitAnimId = mEnterAnimId = 0;
10026            }
10027            if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
10028                    mTransitionAnimationScale, displayInfo.logicalWidth,
10029                        displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
10030                scheduleAnimationLocked();
10031            } else {
10032                screenRotationAnimation.kill();
10033                screenRotationAnimation = null;
10034                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
10035                updateRotation = true;
10036            }
10037        } else {
10038            if (screenRotationAnimation != null) {
10039                screenRotationAnimation.kill();
10040                screenRotationAnimation = null;
10041                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
10042            }
10043            updateRotation = true;
10044        }
10045
10046        mInputMonitor.thawInputDispatchingLw();
10047
10048        boolean configChanged;
10049
10050        // While the display is frozen we don't re-compute the orientation
10051        // to avoid inconsistent states.  However, something interesting
10052        // could have actually changed during that time so re-evaluate it
10053        // now to catch that.
10054        configChanged = updateOrientationFromAppTokensLocked(false);
10055
10056        // A little kludge: a lot could have happened while the
10057        // display was frozen, so now that we are coming back we
10058        // do a gc so that any remote references the system
10059        // processes holds on others can be released if they are
10060        // no longer needed.
10061        mH.removeMessages(H.FORCE_GC);
10062        mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);
10063
10064        mScreenFrozenLock.release();
10065
10066        if (updateRotation) {
10067            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
10068            configChanged |= updateRotationUncheckedLocked(false);
10069        }
10070
10071        if (configChanged) {
10072            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
10073        }
10074    }
10075
10076    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
10077            DisplayMetrics dm) {
10078        if (index < tokens.length) {
10079            String str = tokens[index];
10080            if (str != null && str.length() > 0) {
10081                try {
10082                    int val = Integer.parseInt(str);
10083                    return val;
10084                } catch (Exception e) {
10085                }
10086            }
10087        }
10088        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
10089            return defDps;
10090        }
10091        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
10092        return val;
10093    }
10094
10095    void createWatermarkInTransaction() {
10096        if (mWatermark != null) {
10097            return;
10098        }
10099
10100        File file = new File("/system/etc/setup.conf");
10101        FileInputStream in = null;
10102        DataInputStream ind = null;
10103        try {
10104            in = new FileInputStream(file);
10105            ind = new DataInputStream(in);
10106            String line = ind.readLine();
10107            if (line != null) {
10108                String[] toks = line.split("%");
10109                if (toks != null && toks.length > 0) {
10110                    mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
10111                            mRealDisplayMetrics, mFxSession, toks);
10112                }
10113            }
10114        } catch (FileNotFoundException e) {
10115        } catch (IOException e) {
10116        } finally {
10117            if (ind != null) {
10118                try {
10119                    ind.close();
10120                } catch (IOException e) {
10121                }
10122            } else if (in != null) {
10123                try {
10124                    in.close();
10125                } catch (IOException e) {
10126                }
10127            }
10128        }
10129    }
10130
10131    @Override
10132    public void statusBarVisibilityChanged(int visibility) {
10133        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
10134                != PackageManager.PERMISSION_GRANTED) {
10135            throw new SecurityException("Caller does not hold permission "
10136                    + android.Manifest.permission.STATUS_BAR);
10137        }
10138
10139        synchronized (mWindowMap) {
10140            mLastStatusBarVisibility = visibility;
10141            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
10142            updateStatusBarVisibilityLocked(visibility);
10143        }
10144    }
10145
10146    // TOOD(multidisplay): StatusBar on multiple screens?
10147    void updateStatusBarVisibilityLocked(int visibility) {
10148        mInputManager.setSystemUiVisibility(visibility);
10149        final WindowList windows = getDefaultWindowListLocked();
10150        final int N = windows.size();
10151        for (int i = 0; i < N; i++) {
10152            WindowState ws = windows.get(i);
10153            try {
10154                int curValue = ws.mSystemUiVisibility;
10155                int diff = curValue ^ visibility;
10156                // We are only interested in differences of one of the
10157                // clearable flags...
10158                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
10159                // ...if it has actually been cleared.
10160                diff &= ~visibility;
10161                int newValue = (curValue&~diff) | (visibility&diff);
10162                if (newValue != curValue) {
10163                    ws.mSeq++;
10164                    ws.mSystemUiVisibility = newValue;
10165                }
10166                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
10167                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
10168                            visibility, newValue, diff);
10169                }
10170            } catch (RemoteException e) {
10171                // so sorry
10172            }
10173        }
10174    }
10175
10176    @Override
10177    public void reevaluateStatusBarVisibility() {
10178        synchronized (mWindowMap) {
10179            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
10180            updateStatusBarVisibilityLocked(visibility);
10181            performLayoutAndPlaceSurfacesLocked();
10182        }
10183    }
10184
10185    @Override
10186    public FakeWindow addFakeWindow(Looper looper,
10187            InputEventReceiver.Factory inputEventReceiverFactory,
10188            String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags,
10189            boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) {
10190        synchronized (mWindowMap) {
10191            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
10192                    name, windowType,
10193                    layoutParamsFlags, layoutParamsPrivateFlags, canReceiveKeys,
10194                    hasFocus, touchFullscreen);
10195            int i=0;
10196            while (i<mFakeWindows.size()) {
10197                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
10198                    break;
10199                }
10200            }
10201            mFakeWindows.add(i, fw);
10202            mInputMonitor.updateInputWindowsLw(true);
10203            return fw;
10204        }
10205    }
10206
10207    boolean removeFakeWindowLocked(FakeWindow window) {
10208        synchronized (mWindowMap) {
10209            if (mFakeWindows.remove(window)) {
10210                mInputMonitor.updateInputWindowsLw(true);
10211                return true;
10212            }
10213            return false;
10214        }
10215    }
10216
10217    // It is assumed that this method is called only by InputMethodManagerService.
10218    public void saveLastInputMethodWindowForTransition() {
10219        synchronized (mWindowMap) {
10220            // TODO(multidisplay): Pass in the displayID.
10221            DisplayContent displayContent = getDefaultDisplayContentLocked();
10222            if (mInputMethodWindow != null) {
10223                mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
10224            }
10225        }
10226    }
10227
10228    @Override
10229    public boolean hasNavigationBar() {
10230        return mPolicy.hasNavigationBar();
10231    }
10232
10233    @Override
10234    public void lockNow(Bundle options) {
10235        mPolicy.lockNow(options);
10236    }
10237
10238    @Override
10239    public boolean isSafeModeEnabled() {
10240        return mSafeMode;
10241    }
10242
10243    void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
10244        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
10245        mPolicy.dump("    ", pw, args);
10246    }
10247
10248    void dumpAnimatorLocked(PrintWriter pw, String[] args, boolean dumpAll) {
10249        pw.println("WINDOW MANAGER ANIMATOR STATE (dumpsys window animator)");
10250        mAnimator.dumpLocked(pw, "    ", dumpAll);
10251    }
10252
10253    void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
10254        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
10255        if (mTokenMap.size() > 0) {
10256            pw.println("  All tokens:");
10257            Iterator<WindowToken> it = mTokenMap.values().iterator();
10258            while (it.hasNext()) {
10259                WindowToken token = it.next();
10260                pw.print("  "); pw.print(token);
10261                if (dumpAll) {
10262                    pw.println(':');
10263                    token.dump(pw, "    ");
10264                } else {
10265                    pw.println();
10266                }
10267            }
10268        }
10269        if (mWallpaperTokens.size() > 0) {
10270            pw.println();
10271            pw.println("  Wallpaper tokens:");
10272            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
10273                WindowToken token = mWallpaperTokens.get(i);
10274                pw.print("  Wallpaper #"); pw.print(i);
10275                        pw.print(' '); pw.print(token);
10276                if (dumpAll) {
10277                    pw.println(':');
10278                    token.dump(pw, "    ");
10279                } else {
10280                    pw.println();
10281                }
10282            }
10283        }
10284        if (mFinishedStarting.size() > 0) {
10285            pw.println();
10286            pw.println("  Finishing start of application tokens:");
10287            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
10288                WindowToken token = mFinishedStarting.get(i);
10289                pw.print("  Finished Starting #"); pw.print(i);
10290                        pw.print(' '); pw.print(token);
10291                if (dumpAll) {
10292                    pw.println(':');
10293                    token.dump(pw, "    ");
10294                } else {
10295                    pw.println();
10296                }
10297            }
10298        }
10299        if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
10300            pw.println();
10301            if (mOpeningApps.size() > 0) {
10302                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
10303            }
10304            if (mClosingApps.size() > 0) {
10305                pw.print("  mClosingApps="); pw.println(mClosingApps);
10306            }
10307        }
10308    }
10309
10310    void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
10311        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
10312        if (mSessions.size() > 0) {
10313            Iterator<Session> it = mSessions.iterator();
10314            while (it.hasNext()) {
10315                Session s = it.next();
10316                pw.print("  Session "); pw.print(s); pw.println(':');
10317                s.dump(pw, "    ");
10318            }
10319        }
10320    }
10321
10322    void dumpDisplayContentsLocked(PrintWriter pw, boolean dumpAll) {
10323        pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)");
10324        if (mDisplayReady) {
10325            final int numDisplays = mDisplayContents.size();
10326            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10327                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
10328                displayContent.dump("  ", pw);
10329            }
10330        } else {
10331            pw.println("  NO DISPLAY");
10332        }
10333    }
10334
10335    void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
10336            ArrayList<WindowState> windows) {
10337        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
10338        dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
10339    }
10340
10341    void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
10342            ArrayList<WindowState> windows) {
10343        final int numDisplays = mDisplayContents.size();
10344        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10345            final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
10346            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10347                final WindowState w = windowList.get(winNdx);
10348                if (windows == null || windows.contains(w)) {
10349                    pw.print("  Window #"); pw.print(winNdx); pw.print(' ');
10350                            pw.print(w); pw.println(":");
10351                    w.dump(pw, "    ", dumpAll || windows != null);
10352                }
10353            }
10354        }
10355        if (mInputMethodDialogs.size() > 0) {
10356            pw.println();
10357            pw.println("  Input method dialogs:");
10358            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
10359                WindowState w = mInputMethodDialogs.get(i);
10360                if (windows == null || windows.contains(w)) {
10361                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
10362                }
10363            }
10364        }
10365        if (mPendingRemove.size() > 0) {
10366            pw.println();
10367            pw.println("  Remove pending for:");
10368            for (int i=mPendingRemove.size()-1; i>=0; i--) {
10369                WindowState w = mPendingRemove.get(i);
10370                if (windows == null || windows.contains(w)) {
10371                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
10372                            pw.print(w);
10373                    if (dumpAll) {
10374                        pw.println(":");
10375                        w.dump(pw, "    ", true);
10376                    } else {
10377                        pw.println();
10378                    }
10379                }
10380            }
10381        }
10382        if (mForceRemoves != null && mForceRemoves.size() > 0) {
10383            pw.println();
10384            pw.println("  Windows force removing:");
10385            for (int i=mForceRemoves.size()-1; i>=0; i--) {
10386                WindowState w = mForceRemoves.get(i);
10387                pw.print("  Removing #"); pw.print(i); pw.print(' ');
10388                        pw.print(w);
10389                if (dumpAll) {
10390                    pw.println(":");
10391                    w.dump(pw, "    ", true);
10392                } else {
10393                    pw.println();
10394                }
10395            }
10396        }
10397        if (mDestroySurface.size() > 0) {
10398            pw.println();
10399            pw.println("  Windows waiting to destroy their surface:");
10400            for (int i=mDestroySurface.size()-1; i>=0; i--) {
10401                WindowState w = mDestroySurface.get(i);
10402                if (windows == null || windows.contains(w)) {
10403                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
10404                            pw.print(w);
10405                    if (dumpAll) {
10406                        pw.println(":");
10407                        w.dump(pw, "    ", true);
10408                    } else {
10409                        pw.println();
10410                    }
10411                }
10412            }
10413        }
10414        if (mLosingFocus.size() > 0) {
10415            pw.println();
10416            pw.println("  Windows losing focus:");
10417            for (int i=mLosingFocus.size()-1; i>=0; i--) {
10418                WindowState w = mLosingFocus.get(i);
10419                if (windows == null || windows.contains(w)) {
10420                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
10421                            pw.print(w);
10422                    if (dumpAll) {
10423                        pw.println(":");
10424                        w.dump(pw, "    ", true);
10425                    } else {
10426                        pw.println();
10427                    }
10428                }
10429            }
10430        }
10431        if (mResizingWindows.size() > 0) {
10432            pw.println();
10433            pw.println("  Windows waiting to resize:");
10434            for (int i=mResizingWindows.size()-1; i>=0; i--) {
10435                WindowState w = mResizingWindows.get(i);
10436                if (windows == null || windows.contains(w)) {
10437                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
10438                            pw.print(w);
10439                    if (dumpAll) {
10440                        pw.println(":");
10441                        w.dump(pw, "    ", true);
10442                    } else {
10443                        pw.println();
10444                    }
10445                }
10446            }
10447        }
10448        if (mWaitingForDrawn.size() > 0) {
10449            pw.println();
10450            pw.println("  Clients waiting for these windows to be drawn:");
10451            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
10452                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
10453                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
10454                        pw.print(": "); pw.println(pair.second);
10455            }
10456        }
10457        pw.println();
10458        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
10459        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
10460        if (mLastFocus != mCurrentFocus) {
10461            pw.print("  mLastFocus="); pw.println(mLastFocus);
10462        }
10463        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
10464        if (mInputMethodTarget != null) {
10465            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
10466        }
10467        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
10468                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
10469        pw.print("  mLastDisplayFreezeDuration=");
10470                TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
10471                if ( mLastFinishedFreezeSource != null) {
10472                    pw.print(" due to ");
10473                    pw.print(mLastFinishedFreezeSource);
10474                }
10475                pw.println();
10476        if (dumpAll) {
10477            pw.print("  mSystemDecorLayer="); pw.print(mSystemDecorLayer);
10478                    pw.print(" mScreenRect="); pw.println(mScreenRect.toShortString());
10479            if (mLastStatusBarVisibility != 0) {
10480                pw.print("  mLastStatusBarVisibility=0x");
10481                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
10482            }
10483            if (mInputMethodWindow != null) {
10484                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
10485            }
10486            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
10487            if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
10488                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
10489                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
10490            }
10491            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
10492                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
10493            if (mInputMethodAnimLayerAdjustment != 0 ||
10494                    mWallpaperAnimLayerAdjustment != 0) {
10495                pw.print("  mInputMethodAnimLayerAdjustment=");
10496                        pw.print(mInputMethodAnimLayerAdjustment);
10497                        pw.print("  mWallpaperAnimLayerAdjustment=");
10498                        pw.println(mWallpaperAnimLayerAdjustment);
10499            }
10500            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
10501                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
10502            if (needsLayout()) {
10503                pw.print("  layoutNeeded on displays=");
10504                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10505                    final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
10506                    if (displayContent.layoutNeeded) {
10507                        pw.print(displayContent.getDisplayId());
10508                    }
10509                }
10510                pw.println();
10511            }
10512            pw.print("  mTransactionSequence="); pw.println(mTransactionSequence);
10513            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
10514                    pw.print(" windows="); pw.print(mWindowsFreezingScreen);
10515                    pw.print(" client="); pw.print(mClientFreezingScreen);
10516                    pw.print(" apps="); pw.print(mAppsFreezingScreen);
10517                    pw.print(" waitingForConfig="); pw.println(mWaitingForConfig);
10518            pw.print("  mRotation="); pw.print(mRotation);
10519                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
10520            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
10521                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
10522            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
10523            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
10524                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
10525                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
10526            pw.print("  mTraversalScheduled="); pw.println(mTraversalScheduled);
10527            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
10528                    pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
10529            pw.println("  mLayoutToAnim:");
10530            mAppTransition.dump(pw);
10531        }
10532    }
10533
10534    boolean dumpWindows(PrintWriter pw, String name, String[] args,
10535            int opti, boolean dumpAll) {
10536        WindowList windows = new WindowList();
10537        if ("visible".equals(name)) {
10538            synchronized(mWindowMap) {
10539                final int numDisplays = mDisplayContents.size();
10540                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10541                    final WindowList windowList =
10542                            mDisplayContents.valueAt(displayNdx).getWindowList();
10543                    for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10544                        final WindowState w = windowList.get(winNdx);
10545                        if (w.mWinAnimator.mSurfaceShown) {
10546                            windows.add(w);
10547                        }
10548                    }
10549                }
10550            }
10551        } else {
10552            int objectId = 0;
10553            // See if this is an object ID.
10554            try {
10555                objectId = Integer.parseInt(name, 16);
10556                name = null;
10557            } catch (RuntimeException e) {
10558            }
10559            synchronized(mWindowMap) {
10560                final int numDisplays = mDisplayContents.size();
10561                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10562                    final WindowList windowList =
10563                            mDisplayContents.valueAt(displayNdx).getWindowList();
10564                    for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10565                        final WindowState w = windowList.get(winNdx);
10566                        if (name != null) {
10567                            if (w.mAttrs.getTitle().toString().contains(name)) {
10568                                windows.add(w);
10569                            }
10570                        } else if (System.identityHashCode(w) == objectId) {
10571                            windows.add(w);
10572                        }
10573                    }
10574                }
10575            }
10576        }
10577
10578        if (windows.size() <= 0) {
10579            return false;
10580        }
10581
10582        synchronized(mWindowMap) {
10583            dumpWindowsLocked(pw, dumpAll, windows);
10584        }
10585        return true;
10586    }
10587
10588    void dumpLastANRLocked(PrintWriter pw) {
10589        pw.println("WINDOW MANAGER LAST ANR (dumpsys window lastanr)");
10590        if (mLastANRState == null) {
10591            pw.println("  <no ANR has occurred since boot>");
10592        } else {
10593            pw.println(mLastANRState);
10594        }
10595    }
10596
10597    /**
10598     * Saves information about the state of the window manager at
10599     * the time an ANR occurred before anything else in the system changes
10600     * in response.
10601     *
10602     * @param appWindowToken The application that ANR'd, may be null.
10603     * @param windowState The window that ANR'd, may be null.
10604     * @param reason The reason for the ANR, may be null.
10605     */
10606    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState,
10607            String reason) {
10608        StringWriter sw = new StringWriter();
10609        PrintWriter pw = new FastPrintWriter(sw, false, 1024);
10610        pw.println("  ANR time: " + DateFormat.getInstance().format(new Date()));
10611        if (appWindowToken != null) {
10612            pw.println("  Application at fault: " + appWindowToken.stringName);
10613        }
10614        if (windowState != null) {
10615            pw.println("  Window at fault: " + windowState.mAttrs.getTitle());
10616        }
10617        if (reason != null) {
10618            pw.println("  Reason: " + reason);
10619        }
10620        pw.println();
10621        dumpWindowsNoHeaderLocked(pw, true, null);
10622        pw.close();
10623        mLastANRState = sw.toString();
10624    }
10625
10626    @Override
10627    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
10628        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
10629                != PackageManager.PERMISSION_GRANTED) {
10630            pw.println("Permission Denial: can't dump WindowManager from from pid="
10631                    + Binder.getCallingPid()
10632                    + ", uid=" + Binder.getCallingUid());
10633            return;
10634        }
10635
10636        boolean dumpAll = false;
10637
10638        int opti = 0;
10639        while (opti < args.length) {
10640            String opt = args[opti];
10641            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
10642                break;
10643            }
10644            opti++;
10645            if ("-a".equals(opt)) {
10646                dumpAll = true;
10647            } else if ("-h".equals(opt)) {
10648                pw.println("Window manager dump options:");
10649                pw.println("  [-a] [-h] [cmd] ...");
10650                pw.println("  cmd may be one of:");
10651                pw.println("    l[astanr]: last ANR information");
10652                pw.println("    p[policy]: policy state");
10653                pw.println("    a[animator]: animator state");
10654                pw.println("    s[essions]: active sessions");
10655                pw.println("    d[isplays]: active display contents");
10656                pw.println("    t[okens]: token list");
10657                pw.println("    w[indows]: window list");
10658                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
10659                pw.println("    be a partial substring in a window name, a");
10660                pw.println("    Window hex object identifier, or");
10661                pw.println("    \"all\" for all windows, or");
10662                pw.println("    \"visible\" for the visible windows.");
10663                pw.println("  -a: include all available server state.");
10664                return;
10665            } else {
10666                pw.println("Unknown argument: " + opt + "; use -h for help");
10667            }
10668        }
10669
10670        // Is the caller requesting to dump a particular piece of data?
10671        if (opti < args.length) {
10672            String cmd = args[opti];
10673            opti++;
10674            if ("lastanr".equals(cmd) || "l".equals(cmd)) {
10675                synchronized(mWindowMap) {
10676                    dumpLastANRLocked(pw);
10677                }
10678                return;
10679            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
10680                synchronized(mWindowMap) {
10681                    dumpPolicyLocked(pw, args, true);
10682                }
10683                return;
10684            } else if ("animator".equals(cmd) || "a".equals(cmd)) {
10685                synchronized(mWindowMap) {
10686                    dumpAnimatorLocked(pw, args, true);
10687                }
10688                return;
10689            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
10690                synchronized(mWindowMap) {
10691                    dumpSessionsLocked(pw, true);
10692                }
10693                return;
10694            } else if ("displays".equals(cmd) || "d".equals(cmd)) {
10695                synchronized(mWindowMap) {
10696                    dumpDisplayContentsLocked(pw, true);
10697                }
10698                return;
10699            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
10700                synchronized(mWindowMap) {
10701                    dumpTokensLocked(pw, true);
10702                }
10703                return;
10704            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
10705                synchronized(mWindowMap) {
10706                    dumpWindowsLocked(pw, true, null);
10707                }
10708                return;
10709            } else if ("all".equals(cmd) || "a".equals(cmd)) {
10710                synchronized(mWindowMap) {
10711                    dumpWindowsLocked(pw, true, null);
10712                }
10713                return;
10714            } else {
10715                // Dumping a single name?
10716                if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
10717                    pw.println("Bad window command, or no windows match: " + cmd);
10718                    pw.println("Use -h for help.");
10719                }
10720                return;
10721            }
10722        }
10723
10724        synchronized(mWindowMap) {
10725            pw.println();
10726            if (dumpAll) {
10727                pw.println("-------------------------------------------------------------------------------");
10728            }
10729            dumpLastANRLocked(pw);
10730            pw.println();
10731            if (dumpAll) {
10732                pw.println("-------------------------------------------------------------------------------");
10733            }
10734            dumpPolicyLocked(pw, args, dumpAll);
10735            pw.println();
10736            if (dumpAll) {
10737                pw.println("-------------------------------------------------------------------------------");
10738            }
10739            dumpAnimatorLocked(pw, args, dumpAll);
10740            pw.println();
10741            if (dumpAll) {
10742                pw.println("-------------------------------------------------------------------------------");
10743            }
10744            dumpSessionsLocked(pw, dumpAll);
10745            pw.println();
10746            if (dumpAll) {
10747                pw.println("-------------------------------------------------------------------------------");
10748            }
10749            dumpDisplayContentsLocked(pw, dumpAll);
10750            pw.println();
10751            if (dumpAll) {
10752                pw.println("-------------------------------------------------------------------------------");
10753            }
10754            dumpTokensLocked(pw, dumpAll);
10755            pw.println();
10756            if (dumpAll) {
10757                pw.println("-------------------------------------------------------------------------------");
10758            }
10759            dumpWindowsLocked(pw, dumpAll, null);
10760        }
10761    }
10762
10763    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
10764    @Override
10765    public void monitor() {
10766        synchronized (mWindowMap) { }
10767    }
10768
10769    public interface OnHardKeyboardStatusChangeListener {
10770        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
10771    }
10772
10773    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
10774        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
10775            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
10776                    Integer.toHexString(pendingLayoutChanges));
10777        }
10778    }
10779
10780    private DisplayContent newDisplayContentLocked(final Display display) {
10781        DisplayContent displayContent = new DisplayContent(display, this);
10782        final int displayId = display.getDisplayId();
10783        mDisplayContents.put(displayId, displayContent);
10784
10785        DisplayInfo displayInfo = displayContent.getDisplayInfo();
10786        final Rect rect = new Rect();
10787        mDisplaySettings.getOverscanLocked(displayInfo.name, rect);
10788        synchronized (displayContent.mDisplaySizeLock) {
10789            displayInfo.overscanLeft = rect.left;
10790            displayInfo.overscanTop = rect.top;
10791            displayInfo.overscanRight = rect.right;
10792            displayInfo.overscanBottom = rect.bottom;
10793            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
10794                    displayId, displayInfo);
10795        }
10796        configureDisplayPolicyLocked(displayContent);
10797
10798        // TODO: Create an input channel for each display with touch capability.
10799        if (displayId == Display.DEFAULT_DISPLAY) {
10800            displayContent.mTapDetector = new StackTapPointerEventListener(this, displayContent);
10801            registerPointerEventListener(displayContent.mTapDetector);
10802        }
10803
10804        return displayContent;
10805    }
10806
10807    public void createDisplayContentLocked(final Display display) {
10808        if (display == null) {
10809            throw new IllegalArgumentException("getDisplayContent: display must not be null");
10810        }
10811        getDisplayContentLocked(display.getDisplayId());
10812    }
10813
10814    /**
10815     * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
10816     * there is a Display for the displayId.
10817     * @param displayId The display the caller is interested in.
10818     * @return The DisplayContent associated with displayId or null if there is no Display for it.
10819     */
10820    public DisplayContent getDisplayContentLocked(final int displayId) {
10821        DisplayContent displayContent = mDisplayContents.get(displayId);
10822        if (displayContent == null) {
10823            final Display display = mDisplayManager.getDisplay(displayId);
10824            if (display != null) {
10825                displayContent = newDisplayContentLocked(display);
10826            }
10827        }
10828        return displayContent;
10829    }
10830
10831    // There is an inherent assumption that this will never return null.
10832    public DisplayContent getDefaultDisplayContentLocked() {
10833        return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
10834    }
10835
10836    public WindowList getDefaultWindowListLocked() {
10837        return getDefaultDisplayContentLocked().getWindowList();
10838    }
10839
10840    public DisplayInfo getDefaultDisplayInfoLocked() {
10841        return getDefaultDisplayContentLocked().getDisplayInfo();
10842    }
10843
10844    /**
10845     * Return the list of WindowStates associated on the passed display.
10846     * @param display The screen to return windows from.
10847     * @return The list of WindowStates on the screen, or null if the there is no screen.
10848     */
10849    public WindowList getWindowListLocked(final Display display) {
10850        return getWindowListLocked(display.getDisplayId());
10851    }
10852
10853    /**
10854     * Return the list of WindowStates associated on the passed display.
10855     * @param displayId The screen to return windows from.
10856     * @return The list of WindowStates on the screen, or null if the there is no screen.
10857     */
10858    public WindowList getWindowListLocked(final int displayId) {
10859        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10860        return displayContent != null ? displayContent.getWindowList() : null;
10861    }
10862
10863    public void onDisplayAdded(int displayId) {
10864        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
10865    }
10866
10867    public void handleDisplayAdded(int displayId) {
10868        synchronized (mWindowMap) {
10869            final Display display = mDisplayManager.getDisplay(displayId);
10870            if (display != null) {
10871                createDisplayContentLocked(display);
10872                displayReady(displayId);
10873            }
10874        }
10875    }
10876
10877    public void onDisplayRemoved(int displayId) {
10878        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
10879    }
10880
10881    private void handleDisplayRemovedLocked(int displayId) {
10882        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10883        if (displayContent != null) {
10884            if ((displayContent.mDeferredActions & DisplayContent.DEFER_DETACH) != 0) {
10885                displayContent.mDeferredActions |= DisplayContent.DEFER_REMOVAL;
10886                return;
10887            }
10888            mDisplayContents.delete(displayId);
10889            displayContent.close();
10890            if (displayId == Display.DEFAULT_DISPLAY) {
10891                unregisterPointerEventListener(displayContent.mTapDetector);
10892            }
10893        }
10894        mAnimator.removeDisplayLocked(displayId);
10895    }
10896
10897    public void onDisplayChanged(int displayId) {
10898        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
10899    }
10900
10901    private void handleDisplayChangedLocked(int displayId) {
10902        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10903        if (displayContent != null) {
10904            displayContent.updateDisplayInfo();
10905        }
10906    }
10907
10908    @Override
10909    public Object getWindowManagerLock() {
10910        return mWindowMap;
10911    }
10912
10913    private final class LocalService extends WindowManagerInternal {
10914        @Override
10915        public void requestTraversalFromDisplayManager() {
10916            requestTraversal();
10917        }
10918    }
10919}
10920