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