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