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