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