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