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