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