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