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