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