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