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