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