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