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