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