WindowManagerService.java revision 5962b12bedc4a1d0354816c1cd6b06ba04f6d807
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        // First perform layout of any root windows (not attached
8243        // to another window).
8244        int topAttached = -1;
8245        for (i = N-1; i >= 0; i--) {
8246            final WindowState win = windows.get(i);
8247
8248            // Don't do layout of a window if it is not visible, or
8249            // soon won't be visible, to avoid wasting time and funky
8250            // changes while a window is animating away.
8251            final boolean gone = win.isGoneForLayoutLw();
8252
8253            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
8254                Slog.v(TAG, "1ST PASS " + win
8255                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
8256                        + " mLayoutAttached=" + win.mLayoutAttached
8257                        + " screen changed=" + win.isConfigDiff(ActivityInfo.CONFIG_SCREEN_SIZE));
8258                final AppWindowToken atoken = win.mAppToken;
8259                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
8260                        + win.mViewVisibility + " mRelayoutCalled="
8261                        + win.mRelayoutCalled + " hidden="
8262                        + win.mRootToken.hidden + " hiddenRequested="
8263                        + (atoken != null && atoken.hiddenRequested)
8264                        + " mAttachedHidden=" + win.mAttachedHidden);
8265                else Slog.v(TAG, "  VIS: mViewVisibility="
8266                        + win.mViewVisibility + " mRelayoutCalled="
8267                        + win.mRelayoutCalled + " hidden="
8268                        + win.mRootToken.hidden + " hiddenRequested="
8269                        + (atoken != null && atoken.hiddenRequested)
8270                        + " mAttachedHidden=" + win.mAttachedHidden);
8271            }
8272
8273            // If this view is GONE, then skip it -- keep the current
8274            // frame, and let the caller know so they can ignore it
8275            // if they want.  (We do the normal layout for INVISIBLE
8276            // windows, since that means "perform layout as normal,
8277            // just don't display").
8278            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
8279                    || win.isConfigDiff(ActivityInfo.CONFIG_SCREEN_SIZE)
8280                    || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
8281                if (!win.mLayoutAttached) {
8282                    if (initial) {
8283                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8284                        win.mContentChanged = false;
8285                    }
8286                    win.mLayoutNeeded = false;
8287                    win.prelayout();
8288                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
8289                    win.mLayoutSeq = seq;
8290                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8291                            + win.mFrame + " mContainingFrame="
8292                            + win.mContainingFrame + " mDisplayFrame="
8293                            + win.mDisplayFrame);
8294                } else {
8295                    if (topAttached < 0) topAttached = i;
8296                }
8297            }
8298            if (win.mViewVisibility == View.VISIBLE
8299                    && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND
8300                    && universeBackground == null) {
8301                universeBackground = win.mWinAnimator;
8302            }
8303        }
8304
8305        if (mAnimator.mUniverseBackground  != universeBackground) {
8306            mFocusMayChange = true;
8307            mAnimator.mUniverseBackground = universeBackground;
8308        }
8309
8310        // Now perform layout of attached windows, which usually
8311        // depend on the position of the window they are attached to.
8312        // XXX does not deal with windows that are attached to windows
8313        // that are themselves attached.
8314        for (i = topAttached; i >= 0; i--) {
8315            final WindowState win = windows.get(i);
8316
8317            if (win.mLayoutAttached) {
8318                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
8319                        + " mHaveFrame=" + win.mHaveFrame
8320                        + " mViewVisibility=" + win.mViewVisibility
8321                        + " mRelayoutCalled=" + win.mRelayoutCalled);
8322                // If this view is GONE, then skip it -- keep the current
8323                // frame, and let the caller know so they can ignore it
8324                // if they want.  (We do the normal layout for INVISIBLE
8325                // windows, since that means "perform layout as normal,
8326                // just don't display").
8327                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
8328                        || !win.mHaveFrame || win.mLayoutNeeded) {
8329                    if (initial) {
8330                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8331                        win.mContentChanged = false;
8332                    }
8333                    win.mLayoutNeeded = false;
8334                    win.prelayout();
8335                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
8336                    win.mLayoutSeq = seq;
8337                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8338                            + win.mFrame + " mContainingFrame="
8339                            + win.mContainingFrame + " mDisplayFrame="
8340                            + win.mDisplayFrame);
8341                }
8342            }
8343        }
8344
8345        // Window frames may have changed.  Tell the input dispatcher about it.
8346        mInputMonitor.setUpdateInputWindowsNeededLw();
8347        if (updateInputWindows) {
8348            mInputMonitor.updateInputWindowsLw(false /*force*/);
8349        }
8350
8351        mPolicy.finishLayoutLw();
8352    }
8353
8354    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
8355        // If the screen is currently frozen or off, then keep
8356        // it frozen/off until this window draws at its new
8357        // orientation.
8358        if (!okToDisplay()) {
8359            if (DEBUG_ORIENTATION) Slog.v(TAG,
8360                    "Changing surface while display frozen: " + w);
8361            w.mOrientationChanging = true;
8362            mInnerFields.mOrientationChangeComplete = false;
8363            if (!mWindowsFreezingScreen) {
8364                mWindowsFreezingScreen = true;
8365                // XXX should probably keep timeout from
8366                // when we first froze the display.
8367                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8368                mH.sendMessageDelayed(mH.obtainMessage(
8369                        H.WINDOW_FREEZE_TIMEOUT), 2000);
8370            }
8371        }
8372    }
8373
8374    /**
8375     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8376     * @param windows List of windows on default display.
8377     * @return bitmap indicating if another pass through layout must be made.
8378     */
8379    public int handleAppTransitionReadyLocked(WindowList windows) {
8380        int changes = 0;
8381        int i;
8382        int NN = mOpeningApps.size();
8383        boolean goodToGo = true;
8384        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8385                "Checking " + NN + " opening apps (frozen="
8386                + mDisplayFrozen + " timeout="
8387                + mAppTransitionTimeout + ")...");
8388        if (!mDisplayFrozen && !mAppTransitionTimeout) {
8389            // If the display isn't frozen, wait to do anything until
8390            // all of the apps are ready.  Otherwise just go because
8391            // we'll unfreeze the display when everyone is ready.
8392            for (i=0; i<NN && goodToGo; i++) {
8393                AppWindowToken wtoken = mOpeningApps.get(i);
8394                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8395                        "Check opening app=" + wtoken + ": allDrawn="
8396                        + wtoken.allDrawn + " startingDisplayed="
8397                        + wtoken.startingDisplayed + " startingMoved="
8398                        + wtoken.startingMoved);
8399                if (!wtoken.allDrawn && !wtoken.startingDisplayed
8400                        && !wtoken.startingMoved) {
8401                    goodToGo = false;
8402                }
8403            }
8404        }
8405        if (goodToGo) {
8406            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
8407            int transit = mNextAppTransition;
8408            if (mSkipAppTransitionAnimation) {
8409                transit = WindowManagerPolicy.TRANSIT_UNSET;
8410            }
8411            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
8412            mAppTransitionReady = false;
8413            mAppTransitionRunning = true;
8414            mAppTransitionTimeout = false;
8415            mStartingIconInTransition = false;
8416            mSkipAppTransitionAnimation = false;
8417
8418            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8419
8420            rebuildAppWindowListLocked();
8421
8422            // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
8423            WindowState oldWallpaper =
8424                    mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
8425                        && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
8426                    ? null : mWallpaperTarget;
8427
8428            adjustWallpaperWindowsLocked();
8429            mInnerFields.mWallpaperMayChange = false;
8430
8431            // The top-most window will supply the layout params,
8432            // and we will determine it below.
8433            LayoutParams animLp = null;
8434            int bestAnimLayer = -1;
8435            boolean fullscreenAnim = false;
8436
8437            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8438                    "New wallpaper target=" + mWallpaperTarget
8439                    + ", oldWallpaper=" + oldWallpaper
8440                    + ", lower target=" + mLowerWallpaperTarget
8441                    + ", upper target=" + mUpperWallpaperTarget);
8442            int foundWallpapers = 0;
8443            // Do a first pass through the tokens for two
8444            // things:
8445            // (1) Determine if both the closing and opening
8446            // app token sets are wallpaper targets, in which
8447            // case special animations are needed
8448            // (since the wallpaper needs to stay static
8449            // behind them).
8450            // (2) Find the layout params of the top-most
8451            // application window in the tokens, which is
8452            // what will control the animation theme.
8453            final int NC = mClosingApps.size();
8454            NN = NC + mOpeningApps.size();
8455            for (i=0; i<NN; i++) {
8456                AppWindowToken wtoken;
8457                int mode;
8458                if (i < NC) {
8459                    wtoken = mClosingApps.get(i);
8460                    mode = 1;
8461                } else {
8462                    wtoken = mOpeningApps.get(i-NC);
8463                    mode = 2;
8464                }
8465                if (mLowerWallpaperTarget != null) {
8466                    if (mLowerWallpaperTarget.mAppToken == wtoken
8467                            || mUpperWallpaperTarget.mAppToken == wtoken) {
8468                        foundWallpapers |= mode;
8469                    }
8470                }
8471                if (wtoken.appFullscreen) {
8472                    WindowState ws = wtoken.findMainWindow();
8473                    if (ws != null) {
8474                        animLp = ws.mAttrs;
8475                        bestAnimLayer = ws.mLayer;
8476                        fullscreenAnim = true;
8477                    }
8478                } else if (!fullscreenAnim) {
8479                    WindowState ws = wtoken.findMainWindow();
8480                    if (ws != null) {
8481                        if (ws.mLayer > bestAnimLayer) {
8482                            animLp = ws.mAttrs;
8483                            bestAnimLayer = ws.mLayer;
8484                        }
8485                    }
8486                }
8487            }
8488
8489            if (foundWallpapers == 3) {
8490                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8491                        "Wallpaper animation!");
8492                switch (transit) {
8493                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
8494                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
8495                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
8496                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
8497                        break;
8498                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
8499                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
8500                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
8501                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
8502                        break;
8503                }
8504                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8505                        "New transit: " + transit);
8506            } else if ((oldWallpaper != null) && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
8507                // We are transitioning from an activity with
8508                // a wallpaper to one without.
8509                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
8510                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8511                        "New transit away from wallpaper: " + transit);
8512            } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
8513                // We are transitioning from an activity without
8514                // a wallpaper to now showing the wallpaper
8515                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
8516                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8517                        "New transit into wallpaper: " + transit);
8518            }
8519
8520            // If all closing windows are obscured, then there is
8521            // no need to do an animation.  This is the case, for
8522            // example, when this transition is being done behind
8523            // the lock screen.
8524            if (!mPolicy.allowAppAnimationsLw()) {
8525                animLp = null;
8526            }
8527
8528            AppWindowToken topOpeningApp = null;
8529            int topOpeningLayer = 0;
8530
8531            NN = mOpeningApps.size();
8532            for (i=0; i<NN; i++) {
8533                AppWindowToken wtoken = mOpeningApps.get(i);
8534                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
8535                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
8536                appAnimator.clearThumbnail();
8537                wtoken.reportedVisible = false;
8538                wtoken.inPendingTransaction = false;
8539                appAnimator.animation = null;
8540                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
8541                wtoken.updateReportedVisibilityLocked();
8542                wtoken.waitingToShow = false;
8543
8544                appAnimator.mAllAppWinAnimators.clear();
8545                final int N = wtoken.allAppWindows.size();
8546                for (int j = 0; j < N; j++) {
8547                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
8548                }
8549                mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
8550
8551                if (animLp != null) {
8552                    int layer = -1;
8553                    for (int j=0; j<wtoken.windows.size(); j++) {
8554                        WindowState win = wtoken.windows.get(j);
8555                        if (win.mWinAnimator.mAnimLayer > layer) {
8556                            layer = win.mWinAnimator.mAnimLayer;
8557                        }
8558                    }
8559                    if (topOpeningApp == null || layer > topOpeningLayer) {
8560                        topOpeningApp = wtoken;
8561                        topOpeningLayer = layer;
8562                    }
8563                }
8564            }
8565            NN = mClosingApps.size();
8566            for (i=0; i<NN; i++) {
8567                AppWindowToken wtoken = mClosingApps.get(i);
8568                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8569                        "Now closing app " + wtoken);
8570                wtoken.mAppAnimator.clearThumbnail();
8571                wtoken.inPendingTransaction = false;
8572                wtoken.mAppAnimator.animation = null;
8573                setTokenVisibilityLocked(wtoken, animLp, false,
8574                        transit, false);
8575                wtoken.updateReportedVisibilityLocked();
8576                wtoken.waitingToHide = false;
8577                // Force the allDrawn flag, because we want to start
8578                // this guy's animations regardless of whether it's
8579                // gotten drawn.
8580                wtoken.allDrawn = true;
8581            }
8582
8583            if (mNextAppTransitionThumbnail != null && topOpeningApp != null
8584                    && topOpeningApp.mAppAnimator.animation != null) {
8585                // This thumbnail animation is very special, we need to have
8586                // an extra surface with the thumbnail included with the animation.
8587                Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
8588                        mNextAppTransitionThumbnail.getHeight());
8589                try {
8590                    // TODO(multi-display): support other displays
8591                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
8592                    final Display display = displayContent.getDisplay();
8593                    Surface surface = new Surface(mFxSession,
8594                            "thumbnail anim",
8595                            dirty.width(), dirty.height(),
8596                            PixelFormat.TRANSLUCENT, Surface.HIDDEN);
8597                    surface.setLayerStack(display.getLayerStack());
8598                    topOpeningApp.mAppAnimator.thumbnail = surface;
8599                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
8600                            + surface + ": CREATE");
8601                    Surface drawSurface = new Surface();
8602                    drawSurface.copyFrom(surface);
8603                    Canvas c = drawSurface.lockCanvas(dirty);
8604                    c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
8605                    drawSurface.unlockCanvasAndPost(c);
8606                    drawSurface.release();
8607                    topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
8608                    Animation anim = createThumbnailAnimationLocked(
8609                            transit, true, true, mNextAppTransitionScaleUp);
8610                    topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
8611                    anim.restrictDuration(MAX_ANIMATION_DURATION);
8612                    anim.scaleCurrentDuration(mTransitionAnimationScale);
8613                    topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX;
8614                    topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY;
8615                } catch (Surface.OutOfResourcesException e) {
8616                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
8617                            + " h=" + dirty.height(), e);
8618                    topOpeningApp.mAppAnimator.clearThumbnail();
8619                }
8620            }
8621
8622            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
8623            mNextAppTransitionPackage = null;
8624            mNextAppTransitionThumbnail = null;
8625            scheduleAnimationCallback(mNextAppTransitionCallback);
8626            mNextAppTransitionCallback = null;
8627
8628            mOpeningApps.clear();
8629            mClosingApps.clear();
8630
8631            // This has changed the visibility of windows, so perform
8632            // a new layout to get them all up-to-date.
8633            changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
8634                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8635            getDefaultDisplayContentLocked().layoutNeeded = true;
8636
8637            // TODO(multidisplay): IMEs are only supported on the default display.
8638            if (windows == getDefaultWindowListLocked()
8639                    && !moveInputMethodWindowsIfNeededLocked(true)) {
8640                assignLayersLocked(windows);
8641            }
8642            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, false /*updateInputWindows*/);
8643            mFocusMayChange = false;
8644        }
8645
8646        return changes;
8647    }
8648
8649    /**
8650     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8651     * @return bitmap indicating if another pass through layout must be made.
8652     */
8653    private int handleAnimatingStoppedAndTransitionLocked() {
8654        int changes = 0;
8655
8656        mAppTransitionRunning = false;
8657        // Restore window app tokens to the ActivityManager views
8658        for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) {
8659            mAnimatingAppTokens.get(i).sendingToBottom = false;
8660        }
8661        mAnimatingAppTokens.clear();
8662        mAnimatingAppTokens.addAll(mAppTokens);
8663        rebuildAppWindowListLocked();
8664
8665        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8666        mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
8667        moveInputMethodWindowsIfNeededLocked(true);
8668        mInnerFields.mWallpaperMayChange = true;
8669        // Since the window list has been rebuilt, focus might
8670        // have to be recomputed since the actual order of windows
8671        // might have changed again.
8672        mFocusMayChange = true;
8673
8674        return changes;
8675    }
8676
8677    /**
8678     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8679     *
8680     * @return bitmap indicating if another pass through layout must be made.
8681     */
8682    private int animateAwayWallpaperLocked() {
8683        int changes = 0;
8684        WindowState oldWallpaper = mWallpaperTarget;
8685        if (mLowerWallpaperTarget != null
8686                && mLowerWallpaperTarget.mAppToken != null) {
8687            if (DEBUG_WALLPAPER) Slog.v(TAG,
8688                    "wallpaperForceHiding changed with lower="
8689                    + mLowerWallpaperTarget);
8690            if (DEBUG_WALLPAPER) Slog.v(TAG,
8691                    "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
8692                    " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
8693            if (mLowerWallpaperTarget.mAppToken.hidden) {
8694                // The lower target has become hidden before we
8695                // actually started the animation...  let's completely
8696                // re-evaluate everything.
8697                mLowerWallpaperTarget = mUpperWallpaperTarget = null;
8698                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8699            }
8700        }
8701        mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8702        if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
8703                + " NEW: " + mWallpaperTarget
8704                + " LOWER: " + mLowerWallpaperTarget);
8705        return changes;
8706    }
8707
8708    private void updateResizingWindows(final WindowState w) {
8709        final WindowStateAnimator winAnimator = w.mWinAnimator;
8710        if (w.mHasSurface && !w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
8711            w.mContentInsetsChanged |=
8712                    !w.mLastContentInsets.equals(w.mContentInsets);
8713            w.mVisibleInsetsChanged |=
8714                    !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8715            boolean configChanged = w.isConfigChanged();
8716            if (DEBUG_CONFIGURATION && configChanged) {
8717                Slog.v(TAG, "Win " + w + " config changed: "
8718                        + mCurConfiguration);
8719            }
8720            if (localLOGV) Slog.v(TAG, "Resizing " + w
8721                    + ": configChanged=" + configChanged
8722                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8723            w.mLastFrame.set(w.mFrame);
8724            if (w.mContentInsetsChanged
8725                    || w.mVisibleInsetsChanged
8726                    || winAnimator.mSurfaceResized
8727                    || configChanged) {
8728                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8729                    Slog.v(TAG, "Resize reasons: "
8730                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8731                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8732                            + " surfaceResized=" + winAnimator.mSurfaceResized
8733                            + " configChanged=" + configChanged);
8734                }
8735
8736                w.mLastContentInsets.set(w.mContentInsets);
8737                w.mLastVisibleInsets.set(w.mVisibleInsets);
8738                makeWindowFreezingScreenIfNeededLocked(w);
8739                // If the orientation is changing, then we need to
8740                // hold off on unfreezing the display until this
8741                // window has been redrawn; to do that, we need
8742                // to go through the process of getting informed
8743                // by the application when it has finished drawing.
8744                if (w.mOrientationChanging) {
8745                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
8746                            "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
8747                            + w + ", surface " + winAnimator.mSurface);
8748                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8749                    if (w.mAppToken != null) {
8750                        w.mAppToken.allDrawn = false;
8751                    }
8752                }
8753                if (!mResizingWindows.contains(w)) {
8754                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8755                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8756                            + "x" + winAnimator.mSurfaceH);
8757                    mResizingWindows.add(w);
8758                }
8759            } else if (w.mOrientationChanging) {
8760                if (w.isDrawnLw()) {
8761                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8762                            "Orientation not waiting for draw in "
8763                            + w + ", surface " + winAnimator.mSurface);
8764                    w.mOrientationChanging = false;
8765                }
8766            }
8767        }
8768    }
8769
8770    /**
8771     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8772     *
8773     * @param w WindowState this method is applied to.
8774     * @param currentTime The time which animations use for calculating transitions.
8775     * @param innerDw Width of app window.
8776     * @param innerDh Height of app window.
8777     */
8778    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8779                                         final int innerDw, final int innerDh) {
8780        final WindowManager.LayoutParams attrs = w.mAttrs;
8781        final int attrFlags = attrs.flags;
8782        final boolean canBeSeen = w.isDisplayedLw();
8783
8784        if (w.mHasSurface) {
8785            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8786                mInnerFields.mHoldScreen = w.mSession;
8787            }
8788            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8789                    && mInnerFields.mScreenBrightness < 0) {
8790                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8791            }
8792            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8793                    && mInnerFields.mButtonBrightness < 0) {
8794                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8795            }
8796            if (!mInnerFields.mSyswin && w.mAttrs.userActivityTimeout >= 0
8797                    && mInnerFields.mUserActivityTimeout < 0) {
8798                mInnerFields.mUserActivityTimeout = w.mAttrs.userActivityTimeout;
8799            }
8800
8801            final int type = attrs.type;
8802            if (canBeSeen
8803                    && (type == TYPE_SYSTEM_DIALOG
8804                     || type == TYPE_RECENTS_OVERLAY
8805                     || type == TYPE_KEYGUARD
8806                     || type == TYPE_SYSTEM_ERROR)) {
8807                mInnerFields.mSyswin = true;
8808            }
8809
8810            if (canBeSeen) {
8811                if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
8812                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_MIRROR;
8813                } else if (mInnerFields.mDisplayHasContent
8814                        == LayoutFields.DISPLAY_CONTENT_UNKNOWN) {
8815                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNIQUE;
8816                }
8817            }
8818        }
8819
8820        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8821        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8822            // This window completely covers everything behind it,
8823            // so we want to leave all of them as undimmed (for
8824            // performance reasons).
8825            mInnerFields.mObscured = true;
8826        } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0
8827                && !(w.mAppToken != null && w.mAppToken.hiddenRequested)
8828                && !w.mExiting) {
8829            if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured);
8830            if (!mInnerFields.mDimming) {
8831                //Slog.i(TAG, "DIM BEHIND: " + w);
8832                mInnerFields.mDimming = true;
8833                final WindowStateAnimator winAnimator = w.mWinAnimator;
8834                if (!mAnimator.isDimmingLocked(winAnimator)) {
8835                    final int width, height;
8836                    if (attrs.type == TYPE_BOOT_PROGRESS) {
8837                        final DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo();
8838                        width = displayInfo.logicalWidth;
8839                        height = displayInfo.logicalHeight;
8840                    } else {
8841                        width = innerDw;
8842                        height = innerDh;
8843                    }
8844                    startDimmingLocked(
8845                        winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount, width, height);
8846                }
8847            }
8848        }
8849    }
8850
8851    private void updateAllDrawnLocked() {
8852        // See if any windows have been drawn, so they (and others
8853        // associated with them) can now be shown.
8854        final ArrayList<AppWindowToken> appTokens = mAnimatingAppTokens;
8855        final int NT = appTokens.size();
8856        for (int i=0; i<NT; i++) {
8857            AppWindowToken wtoken = appTokens.get(i);
8858            if (!wtoken.allDrawn) {
8859                int numInteresting = wtoken.numInterestingWindows;
8860                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8861                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
8862                            "allDrawn: " + wtoken
8863                            + " interesting=" + numInteresting
8864                            + " drawn=" + wtoken.numDrawnWindows);
8865                    wtoken.allDrawn = true;
8866                }
8867            }
8868        }
8869    }
8870
8871    // "Something has changed!  Let's make it correct now."
8872    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
8873        if (DEBUG_WINDOW_TRACE) {
8874            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8875                    + Debug.getCallers(3));
8876        }
8877
8878        final long currentTime = SystemClock.uptimeMillis();
8879
8880        int i;
8881
8882        if (mFocusMayChange) {
8883            mFocusMayChange = false;
8884            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8885                    false /*updateInputWindows*/);
8886        }
8887
8888        // Initialize state of exiting tokens.
8889        for (i=mExitingTokens.size()-1; i>=0; i--) {
8890            mExitingTokens.get(i).hasVisible = false;
8891        }
8892
8893        // Initialize state of exiting applications.
8894        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8895            mExitingAppTokens.get(i).hasVisible = false;
8896        }
8897
8898        mInnerFields.mHoldScreen = null;
8899        mInnerFields.mScreenBrightness = -1;
8900        mInnerFields.mButtonBrightness = -1;
8901        mInnerFields.mUserActivityTimeout = -1;
8902        mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
8903
8904        mTransactionSequence++;
8905
8906        final DisplayContent defaultDisplay = getDefaultDisplayContentLocked();
8907        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
8908        final int defaultDw = defaultInfo.logicalWidth;
8909        final int defaultDh = defaultInfo.logicalHeight;
8910
8911        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8912                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8913        Surface.openTransaction();
8914        try {
8915
8916            if (mWatermark != null) {
8917                mWatermark.positionSurface(defaultDw, defaultDh);
8918            }
8919            if (mStrictModeFlash != null) {
8920                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
8921            }
8922
8923            boolean focusDisplayed = false;
8924            boolean updateAllDrawn = false;
8925
8926            DisplayContentsIterator iterator = new DisplayContentsIterator();
8927            while (iterator.hasNext()) {
8928                final DisplayContent displayContent = iterator.next();
8929                WindowList windows = displayContent.getWindowList();
8930                DisplayInfo displayInfo = displayContent.getDisplayInfo();
8931                final int displayId = displayContent.getDisplayId();
8932                final int dw = displayInfo.logicalWidth;
8933                final int dh = displayInfo.logicalHeight;
8934                final int innerDw = displayInfo.appWidth;
8935                final int innerDh = displayInfo.appHeight;
8936                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
8937
8938                // Reset for each display unless we are forcing mirroring.
8939                if (mInnerFields.mDisplayHasContent != LayoutFields.DISPLAY_CONTENT_MIRROR) {
8940                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
8941                }
8942
8943                int repeats = 0;
8944                do {
8945                    repeats++;
8946                    if (repeats > 6) {
8947                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
8948                        displayContent.layoutNeeded = false;
8949                        break;
8950                    }
8951
8952                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
8953                        displayContent.pendingLayoutChanges);
8954
8955                    if (isDefaultDisplay && ((displayContent.pendingLayoutChanges
8956                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0)
8957                            && ((adjustWallpaperWindowsLocked()
8958                                    & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0)) {
8959                        assignLayersLocked(windows);
8960                        displayContent.layoutNeeded = true;
8961                    }
8962
8963                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
8964                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
8965                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
8966                        if (updateOrientationFromAppTokensLocked(true)) {
8967                            displayContent.layoutNeeded = true;
8968                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8969                        }
8970                    }
8971
8972                    if ((displayContent.pendingLayoutChanges
8973                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8974                        displayContent.layoutNeeded = true;
8975                    }
8976
8977                    // FIRST LOOP: Perform a layout, if needed.
8978                    if (repeats < 4) {
8979                        performLayoutLockedInner(displayContent, repeats == 1,
8980                                false /*updateInputWindows*/);
8981                    } else {
8982                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
8983                    }
8984
8985                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
8986                    // it is animating.
8987                    displayContent.pendingLayoutChanges = 0;
8988
8989                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
8990                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
8991
8992                    if (isDefaultDisplay) {
8993                        mPolicy.beginPostLayoutPolicyLw(dw, dh);
8994                        for (i = windows.size() - 1; i >= 0; i--) {
8995                            WindowState w = windows.get(i);
8996                            if (w.mHasSurface) {
8997                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
8998                            }
8999                        }
9000                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
9001                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
9002                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
9003                    }
9004                } while (displayContent.pendingLayoutChanges != 0);
9005
9006                mInnerFields.mObscured = false;
9007                mInnerFields.mDimming = false;
9008                mInnerFields.mSyswin = false;
9009
9010                // Only used if default window
9011                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
9012
9013                final int N = windows.size();
9014                for (i=N-1; i>=0; i--) {
9015                    WindowState w = windows.get(i);
9016
9017                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
9018
9019                    // Update effect.
9020                    w.mObscured = mInnerFields.mObscured;
9021                    if (!mInnerFields.mObscured) {
9022                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
9023                    }
9024
9025                    if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
9026                            && w.isVisibleLw()) {
9027                        // This is the wallpaper target and its obscured state
9028                        // changed... make sure the current wallaper's visibility
9029                        // has been updated accordingly.
9030                        updateWallpaperVisibilityLocked();
9031                    }
9032
9033                    final WindowStateAnimator winAnimator = w.mWinAnimator;
9034
9035                    // If the window has moved due to its containing
9036                    // content frame changing, then we'd like to animate
9037                    // it.
9038                    if (w.mHasSurface && w.shouldAnimateMove()) {
9039                        // Frame has moved, containing content frame
9040                        // has also moved, and we're not currently animating...
9041                        // let's do something.
9042                        Animation a = AnimationUtils.loadAnimation(mContext,
9043                                com.android.internal.R.anim.window_move_from_decor);
9044                        winAnimator.setAnimation(a);
9045                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
9046                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
9047                        try {
9048                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
9049                        } catch (RemoteException e) {
9050                        }
9051                    }
9052
9053                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
9054                    w.mContentChanged = false;
9055
9056                    // Moved from updateWindowsAndWallpaperLocked().
9057                    if (w.mHasSurface) {
9058                        // Take care of the window being ready to display.
9059                        final boolean committed =
9060                                winAnimator.commitFinishDrawingLocked(currentTime);
9061                        if (isDefaultDisplay && committed) {
9062                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
9063                                if (DEBUG_WALLPAPER) Slog.v(TAG,
9064                                        "First draw done in potential wallpaper target " + w);
9065                                mInnerFields.mWallpaperMayChange = true;
9066                                displayContent.pendingLayoutChanges |=
9067                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9068                                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
9069                                    debugLayoutRepeats(
9070                                        "wallpaper and commitFinishDrawingLocked true",
9071                                        displayContent.pendingLayoutChanges);
9072                                }
9073                            }
9074                        }
9075
9076                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
9077
9078                        final AppWindowToken atoken = w.mAppToken;
9079                        if (DEBUG_STARTING_WINDOW && atoken != null
9080                                && w == atoken.startingWindow) {
9081                            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
9082                                + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
9083                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
9084                        }
9085                        if (atoken != null
9086                                && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
9087                            if (atoken.lastTransactionSequence != mTransactionSequence) {
9088                                atoken.lastTransactionSequence = mTransactionSequence;
9089                                atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
9090                                atoken.startingDisplayed = false;
9091                            }
9092                            if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
9093                                    && !w.mExiting && !w.mDestroying) {
9094                                if (WindowManagerService.DEBUG_VISIBILITY ||
9095                                        WindowManagerService.DEBUG_ORIENTATION) {
9096                                    Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
9097                                            + ", isAnimating=" + winAnimator.isAnimating());
9098                                    if (!w.isDrawnLw()) {
9099                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
9100                                                + " pv=" + w.mPolicyVisibility
9101                                                + " mDrawState=" + winAnimator.mDrawState
9102                                                + " ah=" + w.mAttachedHidden
9103                                                + " th=" + atoken.hiddenRequested
9104                                                + " a=" + winAnimator.mAnimating);
9105                                    }
9106                                }
9107                                if (w != atoken.startingWindow) {
9108                                    if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
9109                                        atoken.numInterestingWindows++;
9110                                        if (w.isDrawnLw()) {
9111                                            atoken.numDrawnWindows++;
9112                                            if (WindowManagerService.DEBUG_VISIBILITY ||
9113                                                    WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
9114                                                    "tokenMayBeDrawn: " + atoken
9115                                                    + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
9116                                                    + " mAppFreezing=" + w.mAppFreezing);
9117                                            updateAllDrawn = true;
9118                                        }
9119                                    }
9120                                } else if (w.isDrawnLw()) {
9121                                    atoken.startingDisplayed = true;
9122                                }
9123                            }
9124                        }
9125                    }
9126
9127                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
9128                            && w.isDisplayedLw()) {
9129                        focusDisplayed = true;
9130                    }
9131
9132                    updateResizingWindows(w);
9133                }
9134
9135                final boolean hasUniqueContent;
9136                switch (mInnerFields.mDisplayHasContent) {
9137                    case LayoutFields.DISPLAY_CONTENT_MIRROR:
9138                        hasUniqueContent = isDefaultDisplay;
9139                        break;
9140                    case LayoutFields.DISPLAY_CONTENT_UNIQUE:
9141                        hasUniqueContent = true;
9142                        break;
9143                    case LayoutFields.DISPLAY_CONTENT_UNKNOWN:
9144                    default:
9145                        hasUniqueContent = false;
9146                        break;
9147                }
9148                mDisplayManagerService.setDisplayHasContent(displayId, hasUniqueContent,
9149                        true /* inTraversal, must call performTraversalInTrans... below */);
9150
9151                if (!mInnerFields.mDimming && mAnimator.isDimmingLocked(displayId)) {
9152                    stopDimmingLocked(displayId);
9153                }
9154            }
9155
9156            if (updateAllDrawn) {
9157                updateAllDrawnLocked();
9158            }
9159
9160            if (focusDisplayed) {
9161                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
9162            }
9163
9164            // Give the display manager a chance to adjust properties
9165            // like display rotation if it needs to.
9166            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
9167
9168        } catch (RuntimeException e) {
9169            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
9170        } finally {
9171            Surface.closeTransaction();
9172        }
9173
9174        final WindowList defaultWindows = defaultDisplay.getWindowList();
9175
9176        // If we are ready to perform an app transition, check through
9177        // all of the app tokens to be shown and see if they are ready
9178        // to go.
9179        if (mAppTransitionReady) {
9180            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
9181            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
9182                defaultDisplay.pendingLayoutChanges);
9183        }
9184
9185        mInnerFields.mAdjResult = 0;
9186
9187        if (!mAnimator.mAnimating && mAppTransitionRunning) {
9188            // We have finished the animation of an app transition.  To do
9189            // this, we have delayed a lot of operations like showing and
9190            // hiding apps, moving apps in Z-order, etc.  The app token list
9191            // reflects the correct Z-order, but the window list may now
9192            // be out of sync with it.  So here we will just rebuild the
9193            // entire app window list.  Fun!
9194            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
9195            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
9196                defaultDisplay.pendingLayoutChanges);
9197        }
9198
9199        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
9200                && !mAppTransitionReady) {
9201            // At this point, there was a window with a wallpaper that
9202            // was force hiding other windows behind it, but now it
9203            // is going away.  This may be simple -- just animate
9204            // away the wallpaper and its window -- or it may be
9205            // hard -- the wallpaper now needs to be shown behind
9206            // something that was hidden.
9207            defaultDisplay.pendingLayoutChanges |= animateAwayWallpaperLocked();
9208            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
9209                defaultDisplay.pendingLayoutChanges);
9210        }
9211        mInnerFields.mWallpaperForceHidingChanged = false;
9212
9213        if (mInnerFields.mWallpaperMayChange) {
9214            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
9215                    "Wallpaper may change!  Adjusting");
9216            mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
9217        }
9218
9219        if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
9220            if (DEBUG_WALLPAPER) Slog.v(TAG,
9221                    "Wallpaper layer changed: assigning layers + relayout");
9222            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9223            assignLayersLocked(defaultWindows);
9224        } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
9225            if (DEBUG_WALLPAPER) Slog.v(TAG,
9226                    "Wallpaper visibility changed: relayout");
9227            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9228        }
9229
9230        if (mFocusMayChange) {
9231            mFocusMayChange = false;
9232            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
9233                    false /*updateInputWindows*/)) {
9234                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
9235                mInnerFields.mAdjResult = 0;
9236            }
9237        }
9238
9239        if (needsLayout()) {
9240            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9241            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
9242                    defaultDisplay.pendingLayoutChanges);
9243        }
9244
9245        if (!mResizingWindows.isEmpty()) {
9246            for (i = mResizingWindows.size() - 1; i >= 0; i--) {
9247                WindowState win = mResizingWindows.get(i);
9248                final WindowStateAnimator winAnimator = win.mWinAnimator;
9249                try {
9250                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
9251                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
9252                    int diff = 0;
9253                    boolean configChanged = win.isConfigChanged();
9254                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION
9255                            // TODO: Remove once b/7094175 is fixed
9256                            || ((String)win.mAttrs.getTitle()).contains("Keyguard"))
9257                            && configChanged) {
9258                        Slog.i(TAG, "Sending new config to window " + win + ": "
9259                                + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
9260                                + " / " + mCurConfiguration + " / 0x"
9261                                + Integer.toHexString(diff));
9262                    }
9263                    win.mConfiguration = mCurConfiguration;
9264                    if (DEBUG_ORIENTATION &&
9265                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
9266                            TAG, "Resizing " + win + " WITH DRAW PENDING");
9267                    win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
9268                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
9269                            configChanged ? win.mConfiguration : null);
9270                    win.mContentInsetsChanged = false;
9271                    win.mVisibleInsetsChanged = false;
9272                    winAnimator.mSurfaceResized = false;
9273                } catch (RemoteException e) {
9274                    win.mOrientationChanging = false;
9275                }
9276            }
9277            mResizingWindows.clear();
9278        }
9279
9280        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
9281                "With display frozen, orientationChangeComplete="
9282                + mInnerFields.mOrientationChangeComplete);
9283        if (mInnerFields.mOrientationChangeComplete) {
9284            if (mWindowsFreezingScreen) {
9285                mWindowsFreezingScreen = false;
9286                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
9287            }
9288            stopFreezingDisplayLocked();
9289        }
9290
9291        // Destroy the surface of any windows that are no longer visible.
9292        boolean wallpaperDestroyed = false;
9293        i = mDestroySurface.size();
9294        if (i > 0) {
9295            do {
9296                i--;
9297                WindowState win = mDestroySurface.get(i);
9298                win.mDestroying = false;
9299                if (mInputMethodWindow == win) {
9300                    mInputMethodWindow = null;
9301                }
9302                if (win == mWallpaperTarget) {
9303                    wallpaperDestroyed = true;
9304                }
9305                win.mWinAnimator.destroySurfaceLocked();
9306            } while (i > 0);
9307            mDestroySurface.clear();
9308        }
9309
9310        // Time to remove any exiting tokens?
9311        for (i=mExitingTokens.size()-1; i>=0; i--) {
9312            WindowToken token = mExitingTokens.get(i);
9313            if (!token.hasVisible) {
9314                mExitingTokens.remove(i);
9315                if (token.windowType == TYPE_WALLPAPER) {
9316                    mWallpaperTokens.remove(token);
9317                    updateLayoutToAnimWallpaperTokens();
9318                }
9319            }
9320        }
9321
9322        // Time to remove any exiting applications?
9323        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
9324            AppWindowToken token = mExitingAppTokens.get(i);
9325            if (!token.hasVisible && !mClosingApps.contains(token)) {
9326                // Make sure there is no animation running on this token,
9327                // so any windows associated with it will be removed as
9328                // soon as their animations are complete
9329                token.mAppAnimator.clearAnimation();
9330                token.mAppAnimator.animating = false;
9331                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
9332                        "performLayout: App token exiting now removed" + token);
9333                mAppTokens.remove(token);
9334                mAnimatingAppTokens.remove(token);
9335                mExitingAppTokens.remove(i);
9336            }
9337        }
9338
9339        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
9340            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
9341                try {
9342                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
9343                } catch (RemoteException e) {
9344                }
9345            }
9346            mRelayoutWhileAnimating.clear();
9347        }
9348
9349        if (wallpaperDestroyed && (adjustWallpaperWindowsLocked() != 0)) {
9350            getDefaultDisplayContentLocked().layoutNeeded = true;
9351        }
9352
9353        DisplayContentsIterator iterator = new DisplayContentsIterator();
9354        while (iterator.hasNext()) {
9355            DisplayContent displayContent = iterator.next();
9356            if (displayContent.pendingLayoutChanges != 0) {
9357                displayContent.layoutNeeded = true;
9358            }
9359        }
9360
9361        // Finally update all input windows now that the window changes have stabilized.
9362        mInputMonitor.updateInputWindowsLw(true /*force*/);
9363
9364        setHoldScreenLocked(mInnerFields.mHoldScreen);
9365        if (!mDisplayFrozen) {
9366            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
9367                mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
9368            } else {
9369                mPowerManager.setScreenBrightnessOverrideFromWindowManager(
9370                        toBrightnessOverride(mInnerFields.mScreenBrightness));
9371            }
9372            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
9373                mPowerManager.setButtonBrightnessOverrideFromWindowManager(-1);
9374            } else {
9375                mPowerManager.setButtonBrightnessOverrideFromWindowManager(
9376                        toBrightnessOverride(mInnerFields.mButtonBrightness));
9377            }
9378            mPowerManager.setUserActivityTimeoutOverrideFromWindowManager(
9379                    mInnerFields.mUserActivityTimeout);
9380        }
9381
9382        if (mTurnOnScreen) {
9383            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
9384            mPowerManager.wakeUp(SystemClock.uptimeMillis());
9385            mTurnOnScreen = false;
9386        }
9387
9388        if (mInnerFields.mUpdateRotation) {
9389            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9390            if (updateRotationUncheckedLocked(false)) {
9391                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9392            } else {
9393                mInnerFields.mUpdateRotation = false;
9394            }
9395        }
9396
9397        if (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded
9398                && !mInnerFields.mUpdateRotation) {
9399            checkDrawnWindowsLocked();
9400        }
9401
9402        final int N = mPendingRemove.size();
9403        if (N > 0) {
9404            if (mPendingRemoveTmp.length < N) {
9405                mPendingRemoveTmp = new WindowState[N+10];
9406            }
9407            mPendingRemove.toArray(mPendingRemoveTmp);
9408            mPendingRemove.clear();
9409            DisplayContentList displayList = new DisplayContentList();
9410            for (i = 0; i < N; i++) {
9411                WindowState w = mPendingRemoveTmp[i];
9412                removeWindowInnerLocked(w.mSession, w);
9413                if (!displayList.contains(w.mDisplayContent)) {
9414                    displayList.add(w.mDisplayContent);
9415                }
9416            }
9417
9418            for (DisplayContent displayContent : displayList) {
9419                assignLayersLocked(displayContent.getWindowList());
9420                displayContent.layoutNeeded = true;
9421            }
9422        }
9423
9424        // Check to see if we are now in a state where the screen should
9425        // be enabled, because the window obscured flags have changed.
9426        enableScreenIfNeededLocked();
9427
9428        updateLayoutToAnimationLocked();
9429
9430        if (DEBUG_WINDOW_TRACE) {
9431            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
9432                    + mAnimator.mAnimating);
9433        }
9434    }
9435
9436    private int toBrightnessOverride(float value) {
9437        return (int)(value * PowerManager.BRIGHTNESS_ON);
9438    }
9439
9440    void checkDrawnWindowsLocked() {
9441        if (mWaitingForDrawn.size() > 0) {
9442            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
9443                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
9444                WindowState win = pair.first;
9445                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
9446                //        + win.mRemoved + " visible=" + win.isVisibleLw()
9447                //        + " shown=" + win.mSurfaceShown);
9448                if (win.mRemoved || !win.isVisibleLw()) {
9449                    // Window has been removed or made invisible; no draw
9450                    // will now happen, so stop waiting.
9451                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
9452                    try {
9453                        pair.second.sendResult(null);
9454                    } catch (RemoteException e) {
9455                    }
9456                    mWaitingForDrawn.remove(pair);
9457                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9458                } else if (win.mWinAnimator.mSurfaceShown) {
9459                    // Window is now drawn (and shown).
9460                    try {
9461                        pair.second.sendResult(null);
9462                    } catch (RemoteException e) {
9463                    }
9464                    mWaitingForDrawn.remove(pair);
9465                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9466                }
9467            }
9468        }
9469    }
9470
9471    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
9472        synchronized (mWindowMap) {
9473            WindowState win = windowForClientLocked(null, token, true);
9474            if (win != null) {
9475                Pair<WindowState, IRemoteCallback> pair =
9476                        new Pair<WindowState, IRemoteCallback>(win, callback);
9477                Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9478                mH.sendMessageDelayed(m, 2000);
9479                mWaitingForDrawn.add(pair);
9480                checkDrawnWindowsLocked();
9481            }
9482        }
9483    }
9484
9485    void setHoldScreenLocked(final Session newHoldScreen) {
9486        final boolean hold = newHoldScreen != null;
9487
9488        if (hold && mHoldingScreenOn != newHoldScreen) {
9489            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
9490        }
9491        mHoldingScreenOn = newHoldScreen;
9492
9493        final boolean state = mHoldingScreenWakeLock.isHeld();
9494        if (hold != state) {
9495            if (hold) {
9496                mPolicy.screenOnStartedLw();
9497                mHoldingScreenWakeLock.acquire();
9498            } else {
9499                mPolicy.screenOnStoppedLw();
9500                mHoldingScreenWakeLock.release();
9501            }
9502        }
9503    }
9504
9505    @Override
9506    public void requestTraversal() {
9507        synchronized (mWindowMap) {
9508            requestTraversalLocked();
9509        }
9510    }
9511
9512    void requestTraversalLocked() {
9513        if (!mTraversalScheduled) {
9514            mTraversalScheduled = true;
9515            mH.sendEmptyMessage(H.DO_TRAVERSAL);
9516        }
9517    }
9518
9519    /** Note that Locked in this case is on mLayoutToAnim */
9520    void scheduleAnimationLocked() {
9521        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
9522        if (!layoutToAnim.mAnimationScheduled) {
9523            layoutToAnim.mAnimationScheduled = true;
9524            mChoreographer.postCallback(
9525                    Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
9526        }
9527    }
9528
9529    void updateLayoutToAnimationLocked() {
9530        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
9531        synchronized (layoutToAnim) {
9532            // Copy local params to transfer params.
9533            SparseArray<WinAnimatorList> allWinAnimatorLists = layoutToAnim.mWinAnimatorLists;
9534            allWinAnimatorLists.clear();
9535            DisplayContentsIterator iterator = new DisplayContentsIterator();
9536            while (iterator.hasNext()) {
9537                final DisplayContent displayContent = iterator.next();
9538                WinAnimatorList winAnimatorList = new WinAnimatorList();
9539                final WindowList windows = displayContent.getWindowList();
9540                int N = windows.size();
9541                for (int i = 0; i < N; i++) {
9542                    final WindowStateAnimator winAnimator = windows.get(i).mWinAnimator;
9543                    if (winAnimator.mSurface != null) {
9544                        winAnimatorList.add(winAnimator);
9545                    }
9546                }
9547                allWinAnimatorLists.put(displayContent.getDisplayId(), winAnimatorList);
9548            }
9549
9550            layoutToAnim.mWallpaperTarget = mWallpaperTarget;
9551            layoutToAnim.mLowerWallpaperTarget = mLowerWallpaperTarget;
9552            layoutToAnim.mUpperWallpaperTarget = mUpperWallpaperTarget;
9553
9554            final ArrayList<AppWindowAnimParams> paramList = layoutToAnim.mAppWindowAnimParams;
9555            paramList.clear();
9556            int N = mAnimatingAppTokens.size();
9557            for (int i = 0; i < N; i++) {
9558                paramList.add(new AppWindowAnimParams(mAnimatingAppTokens.get(i).mAppAnimator));
9559            }
9560
9561            layoutToAnim.mParamsModified = true;
9562            scheduleAnimationLocked();
9563        }
9564    }
9565
9566    void updateLayoutToAnimWallpaperTokens() {
9567        synchronized(mLayoutToAnim) {
9568            mLayoutToAnim.mWallpaperTokens = new ArrayList<WindowToken>(mWallpaperTokens);
9569            mLayoutToAnim.mChanges |= LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED;
9570        }
9571    }
9572
9573    void setAnimDimParams(int displayId, DimAnimator.Parameters params) {
9574        synchronized (mLayoutToAnim) {
9575            mLayoutToAnim.mDimParams.put(displayId, params);
9576            scheduleAnimationLocked();
9577        }
9578    }
9579
9580    void startDimmingLocked(final WindowStateAnimator winAnimator, final float target,
9581                      final int width, final int height) {
9582        setAnimDimParams(winAnimator.mWin.getDisplayId(),
9583                new DimAnimator.Parameters(winAnimator, width, height, target));
9584    }
9585
9586    void stopDimmingLocked(int displayId) {
9587        setAnimDimParams(displayId, null);
9588    }
9589
9590    private boolean needsLayout() {
9591        DisplayContentsIterator iterator = new DisplayContentsIterator();
9592        while (iterator.hasNext()) {
9593            if (iterator.next().layoutNeeded) {
9594                return true;
9595            }
9596        }
9597        return false;
9598    }
9599
9600    private boolean copyAnimToLayoutParamsLocked() {
9601        boolean doRequest = false;
9602        final WindowAnimator.AnimatorToLayoutParams animToLayout = mAnimator.mAnimToLayout;
9603        synchronized (animToLayout) {
9604            animToLayout.mUpdateQueued = false;
9605            final int bulkUpdateParams = animToLayout.mBulkUpdateParams;
9606            // TODO(cmautner): As the number of bits grows, use masks of bit groups to
9607            //  eliminate unnecessary tests.
9608            if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
9609                mInnerFields.mUpdateRotation = true;
9610                doRequest = true;
9611            }
9612            if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
9613                mInnerFields.mWallpaperMayChange = true;
9614                doRequest = true;
9615            }
9616            if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
9617                mInnerFields.mWallpaperForceHidingChanged = true;
9618                doRequest = true;
9619            }
9620            if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
9621                mInnerFields.mOrientationChangeComplete = false;
9622            } else {
9623                mInnerFields.mOrientationChangeComplete = true;
9624                if (mWindowsFreezingScreen) {
9625                    doRequest = true;
9626                }
9627            }
9628            if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
9629                mTurnOnScreen = true;
9630            }
9631
9632            SparseIntArray pendingLayouts = animToLayout.mPendingLayoutChanges;
9633            final int count = pendingLayouts.size();
9634            if (count > 0) {
9635                doRequest = true;
9636            }
9637            for (int i = 0; i < count; ++i) {
9638                final DisplayContent displayContent =
9639                        getDisplayContentLocked(pendingLayouts.keyAt(i));
9640                displayContent.pendingLayoutChanges |= pendingLayouts.valueAt(i);
9641            }
9642
9643            mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper;
9644        }
9645        return doRequest;
9646    }
9647
9648    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
9649                                           boolean secure) {
9650        final Surface surface = winAnimator.mSurface;
9651        boolean leakedSurface = false;
9652        boolean killedApps = false;
9653
9654        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
9655                winAnimator.mSession.mPid, operation);
9656
9657        if (mForceRemoves == null) {
9658            mForceRemoves = new ArrayList<WindowState>();
9659        }
9660
9661        long callingIdentity = Binder.clearCallingIdentity();
9662        try {
9663            // There was some problem...   first, do a sanity check of the
9664            // window list to make sure we haven't left any dangling surfaces
9665            // around.
9666
9667            AllWindowsIterator iterator = new AllWindowsIterator();
9668            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
9669            while (iterator.hasNext()) {
9670                WindowState ws = iterator.next();
9671                WindowStateAnimator wsa = ws.mWinAnimator;
9672                if (wsa.mSurface != null) {
9673                    if (!mSessions.contains(wsa.mSession)) {
9674                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
9675                                + ws + " surface=" + wsa.mSurface
9676                                + " token=" + ws.mToken
9677                                + " pid=" + ws.mSession.mPid
9678                                + " uid=" + ws.mSession.mUid);
9679                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9680                        wsa.mSurface.destroy();
9681                        wsa.mSurfaceShown = false;
9682                        wsa.mSurface = null;
9683                        ws.mHasSurface = false;
9684                        mForceRemoves.add(ws);
9685                        leakedSurface = true;
9686                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
9687                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
9688                                + ws + " surface=" + wsa.mSurface
9689                                + " token=" + ws.mAppToken);
9690                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9691                        wsa.mSurface.destroy();
9692                        wsa.mSurfaceShown = false;
9693                        wsa.mSurface = null;
9694                        ws.mHasSurface = false;
9695                        leakedSurface = true;
9696                    }
9697                }
9698            }
9699
9700            if (!leakedSurface) {
9701                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
9702                SparseIntArray pidCandidates = new SparseIntArray();
9703                iterator = new AllWindowsIterator();
9704                while (iterator.hasNext()) {
9705                    WindowState ws = iterator.next();
9706                    if (mForceRemoves.contains(ws)) {
9707                        continue;
9708                    }
9709                    WindowStateAnimator wsa = ws.mWinAnimator;
9710                    if (wsa.mSurface != null) {
9711                        pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
9712                    }
9713                }
9714                if (pidCandidates.size() > 0) {
9715                    int[] pids = new int[pidCandidates.size()];
9716                    for (int i=0; i<pids.length; i++) {
9717                        pids[i] = pidCandidates.keyAt(i);
9718                    }
9719                    try {
9720                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
9721                            killedApps = true;
9722                        }
9723                    } catch (RemoteException e) {
9724                    }
9725                }
9726            }
9727
9728            if (leakedSurface || killedApps) {
9729                // We managed to reclaim some memory, so get rid of the trouble
9730                // surface and ask the app to request another one.
9731                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9732                if (surface != null) {
9733                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
9734                            "RECOVER DESTROY", null);
9735                    surface.destroy();
9736                    winAnimator.mSurfaceShown = false;
9737                    winAnimator.mSurface = null;
9738                    winAnimator.mWin.mHasSurface = false;
9739                }
9740
9741                try {
9742                    winAnimator.mWin.mClient.dispatchGetNewSurface();
9743                } catch (RemoteException e) {
9744                }
9745            }
9746        } finally {
9747            Binder.restoreCallingIdentity(callingIdentity);
9748        }
9749
9750        return leakedSurface || killedApps;
9751    }
9752
9753    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9754        WindowState newFocus = computeFocusedWindowLocked();
9755        if (mCurrentFocus != newFocus) {
9756            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
9757            // This check makes sure that we don't already have the focus
9758            // change message pending.
9759            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9760            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9761            if (localLOGV) Slog.v(
9762                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
9763            final WindowState oldFocus = mCurrentFocus;
9764            mCurrentFocus = newFocus;
9765            mAnimator.setCurrentFocus(newFocus);
9766            mLosingFocus.remove(newFocus);
9767            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9768
9769            // TODO(multidisplay): Focused windows on default display only.
9770            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9771
9772            final WindowState imWindow = mInputMethodWindow;
9773            if (newFocus != imWindow && oldFocus != imWindow) {
9774                if (moveInputMethodWindowsIfNeededLocked(
9775                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
9776                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
9777                    displayContent.layoutNeeded = true;
9778                }
9779                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9780                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9781                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9782                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9783                    // Client will do the layout, but we need to assign layers
9784                    // for handleNewWindowLocked() below.
9785                    assignLayersLocked(displayContent.getWindowList());
9786                }
9787            }
9788
9789            if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9790                // The change in focus caused us to need to do a layout.  Okay.
9791                displayContent.layoutNeeded = true;
9792                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9793                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9794                }
9795            }
9796
9797            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9798                // If we defer assigning layers, then the caller is responsible for
9799                // doing this part.
9800                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9801            }
9802
9803            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
9804            return true;
9805        }
9806        return false;
9807    }
9808
9809    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9810        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9811    }
9812
9813    private WindowState computeFocusedWindowLocked() {
9814        if (mAnimator.mUniverseBackground != null
9815                && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) {
9816            return mAnimator.mUniverseBackground.mWin;
9817        }
9818
9819        final int displayCount = mDisplayContents.size();
9820        for (int i = 0; i < displayCount; i++) {
9821            final DisplayContent displayContent = mDisplayContents.valueAt(i);
9822            WindowState win = findFocusedWindowLocked(displayContent);
9823            if (win != null) {
9824                return win;
9825            }
9826        }
9827        return null;
9828    }
9829
9830    private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
9831        int nextAppIndex = mAppTokens.size()-1;
9832        WindowToken nextApp = nextAppIndex >= 0 ? mAppTokens.get(nextAppIndex) : null;
9833
9834        final WindowList windows = displayContent.getWindowList();
9835        for (int i = windows.size() - 1; i >= 0; i--) {
9836            final WindowState win = windows.get(i);
9837
9838            if (localLOGV || DEBUG_FOCUS) Slog.v(
9839                TAG, "Looking for focus: " + i
9840                + " = " + win
9841                + ", flags=" + win.mAttrs.flags
9842                + ", canReceive=" + win.canReceiveKeys());
9843
9844            AppWindowToken thisApp = win.mAppToken;
9845
9846            // If this window's application has been removed, just skip it.
9847            if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
9848                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping app because " + (thisApp.removed
9849                        ? "removed" : "sendingToBottom"));
9850                continue;
9851            }
9852
9853            // If there is a focused app, don't allow focus to go to any
9854            // windows below it.  If this is an application window, step
9855            // through the app tokens until we find its app.
9856            if (thisApp != null && nextApp != null && thisApp != nextApp
9857                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
9858                int origAppIndex = nextAppIndex;
9859                while (nextAppIndex > 0) {
9860                    if (nextApp == mFocusedApp) {
9861                        // Whoops, we are below the focused app...  no focus
9862                        // for you!
9863                        if (localLOGV || DEBUG_FOCUS) Slog.v(
9864                            TAG, "Reached focused app: " + mFocusedApp);
9865                        return null;
9866                    }
9867                    nextAppIndex--;
9868                    nextApp = mAppTokens.get(nextAppIndex);
9869                    if (nextApp == thisApp) {
9870                        break;
9871                    }
9872                }
9873                if (thisApp != nextApp) {
9874                    // Uh oh, the app token doesn't exist!  This shouldn't
9875                    // happen, but if it does we can get totally hosed...
9876                    // so restart at the original app.
9877                    nextAppIndex = origAppIndex;
9878                    nextApp = mAppTokens.get(nextAppIndex);
9879                }
9880            }
9881
9882            // Dispatch to this window if it is wants key events.
9883            if (win.canReceiveKeys()) {
9884                if (DEBUG_FOCUS) Slog.v(
9885                        TAG, "Found focus @ " + i + " = " + win);
9886                return win;
9887            }
9888        }
9889        return null;
9890    }
9891
9892    private void startFreezingDisplayLocked(boolean inTransaction,
9893            int exitAnim, int enterAnim) {
9894        if (mDisplayFrozen) {
9895            return;
9896        }
9897
9898        if (!mDisplayReady || !mPolicy.isScreenOnFully()) {
9899            // No need to freeze the screen before the system is ready or if
9900            // the screen is off.
9901            return;
9902        }
9903
9904        mScreenFrozenLock.acquire();
9905
9906        mDisplayFrozen = true;
9907
9908        mInputMonitor.freezeInputDispatchingLw();
9909
9910        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
9911            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
9912            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
9913            mNextAppTransitionPackage = null;
9914            mNextAppTransitionThumbnail = null;
9915            mAppTransitionReady = true;
9916        }
9917
9918        if (PROFILE_ORIENTATION) {
9919            File file = new File("/data/system/frozen");
9920            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9921        }
9922
9923        if (CUSTOM_SCREEN_ROTATION) {
9924            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9925            final int displayId = displayContent.getDisplayId();
9926            ScreenRotationAnimation screenRotationAnimation =
9927                    mAnimator.getScreenRotationAnimationLocked(displayId);
9928            if (screenRotationAnimation != null) {
9929                screenRotationAnimation.kill();
9930            }
9931
9932            // TODO(multidisplay): rotation on main screen only.
9933            final Display display = displayContent.getDisplay();
9934            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
9935            screenRotationAnimation = new ScreenRotationAnimation(mContext,
9936                    display, mFxSession, inTransaction, displayInfo.logicalWidth,
9937                    displayInfo.logicalHeight, display.getRotation(),
9938                    exitAnim, enterAnim);
9939            mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9940        }
9941    }
9942
9943    private void stopFreezingDisplayLocked() {
9944        if (!mDisplayFrozen) {
9945            return;
9946        }
9947
9948        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
9949                || mClientFreezingScreen) {
9950            if (DEBUG_ORIENTATION) Slog.d(TAG,
9951                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
9952                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
9953                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
9954                + ", mClientFreezingScreen=" + mClientFreezingScreen);
9955            return;
9956        }
9957
9958        mDisplayFrozen = false;
9959        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9960        mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
9961        if (PROFILE_ORIENTATION) {
9962            Debug.stopMethodTracing();
9963        }
9964
9965        boolean updateRotation = false;
9966
9967        final DisplayContent displayContent = getDefaultDisplayContentLocked();
9968        final int displayId = displayContent.getDisplayId();
9969        ScreenRotationAnimation screenRotationAnimation =
9970                mAnimator.getScreenRotationAnimationLocked(displayId);
9971        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
9972                && screenRotationAnimation.hasScreenshot()) {
9973            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
9974            // TODO(multidisplay): rotation on main screen only.
9975            DisplayInfo displayInfo = displayContent.getDisplayInfo();
9976            if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9977                    mTransitionAnimationScale, displayInfo.logicalWidth,
9978                        displayInfo.logicalHeight)) {
9979                updateLayoutToAnimationLocked();
9980            } else {
9981                screenRotationAnimation.kill();
9982                screenRotationAnimation = null;
9983                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9984                updateRotation = true;
9985            }
9986        } else {
9987            if (screenRotationAnimation != null) {
9988                screenRotationAnimation.kill();
9989                screenRotationAnimation = null;
9990                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9991            }
9992            updateRotation = true;
9993        }
9994
9995        mInputMonitor.thawInputDispatchingLw();
9996
9997        boolean configChanged;
9998
9999        // While the display is frozen we don't re-compute the orientation
10000        // to avoid inconsistent states.  However, something interesting
10001        // could have actually changed during that time so re-evaluate it
10002        // now to catch that.
10003        configChanged = updateOrientationFromAppTokensLocked(false);
10004
10005        // A little kludge: a lot could have happened while the
10006        // display was frozen, so now that we are coming back we
10007        // do a gc so that any remote references the system
10008        // processes holds on others can be released if they are
10009        // no longer needed.
10010        mH.removeMessages(H.FORCE_GC);
10011        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
10012                2000);
10013
10014        mScreenFrozenLock.release();
10015
10016        if (updateRotation) {
10017            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
10018            configChanged |= updateRotationUncheckedLocked(false);
10019        }
10020
10021        if (configChanged) {
10022            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
10023        }
10024    }
10025
10026    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
10027            DisplayMetrics dm) {
10028        if (index < tokens.length) {
10029            String str = tokens[index];
10030            if (str != null && str.length() > 0) {
10031                try {
10032                    int val = Integer.parseInt(str);
10033                    return val;
10034                } catch (Exception e) {
10035                }
10036            }
10037        }
10038        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
10039            return defDps;
10040        }
10041        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
10042        return val;
10043    }
10044
10045    void createWatermarkInTransaction() {
10046        if (mWatermark != null) {
10047            return;
10048        }
10049
10050        File file = new File("/system/etc/setup.conf");
10051        FileInputStream in = null;
10052        try {
10053            in = new FileInputStream(file);
10054            DataInputStream ind = new DataInputStream(in);
10055            String line = ind.readLine();
10056            if (line != null) {
10057                String[] toks = line.split("%");
10058                if (toks != null && toks.length > 0) {
10059                    mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
10060                            mRealDisplayMetrics, mFxSession, toks);
10061                }
10062            }
10063        } catch (FileNotFoundException e) {
10064        } catch (IOException e) {
10065        } finally {
10066            if (in != null) {
10067                try {
10068                    in.close();
10069                } catch (IOException e) {
10070                }
10071            }
10072        }
10073    }
10074
10075    @Override
10076    public void statusBarVisibilityChanged(int visibility) {
10077        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
10078                != PackageManager.PERMISSION_GRANTED) {
10079            throw new SecurityException("Caller does not hold permission "
10080                    + android.Manifest.permission.STATUS_BAR);
10081        }
10082
10083        synchronized (mWindowMap) {
10084            mLastStatusBarVisibility = visibility;
10085            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
10086            updateStatusBarVisibilityLocked(visibility);
10087        }
10088    }
10089
10090    // TOOD(multidisplay): StatusBar on multiple screens?
10091    void updateStatusBarVisibilityLocked(int visibility) {
10092        mInputManager.setSystemUiVisibility(visibility);
10093        final WindowList windows = getDefaultWindowListLocked();
10094        final int N = windows.size();
10095        for (int i = 0; i < N; i++) {
10096            WindowState ws = windows.get(i);
10097            try {
10098                int curValue = ws.mSystemUiVisibility;
10099                int diff = curValue ^ visibility;
10100                // We are only interested in differences of one of the
10101                // clearable flags...
10102                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
10103                // ...if it has actually been cleared.
10104                diff &= ~visibility;
10105                int newValue = (curValue&~diff) | (visibility&diff);
10106                if (newValue != curValue) {
10107                    ws.mSeq++;
10108                    ws.mSystemUiVisibility = newValue;
10109                }
10110                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
10111                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
10112                            visibility, newValue, diff);
10113                }
10114            } catch (RemoteException e) {
10115                // so sorry
10116            }
10117        }
10118    }
10119
10120    @Override
10121    public void reevaluateStatusBarVisibility() {
10122        synchronized (mWindowMap) {
10123            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
10124            updateStatusBarVisibilityLocked(visibility);
10125            performLayoutAndPlaceSurfacesLocked();
10126        }
10127    }
10128
10129    @Override
10130    public FakeWindow addFakeWindow(Looper looper,
10131            InputEventReceiver.Factory inputEventReceiverFactory,
10132            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
10133            boolean hasFocus, boolean touchFullscreen) {
10134        synchronized (mWindowMap) {
10135            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
10136                    name, windowType,
10137                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
10138            int i=0;
10139            while (i<mFakeWindows.size()) {
10140                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
10141                    break;
10142                }
10143            }
10144            mFakeWindows.add(i, fw);
10145            mInputMonitor.updateInputWindowsLw(true);
10146            return fw;
10147        }
10148    }
10149
10150    boolean removeFakeWindowLocked(FakeWindow window) {
10151        synchronized (mWindowMap) {
10152            if (mFakeWindows.remove(window)) {
10153                mInputMonitor.updateInputWindowsLw(true);
10154                return true;
10155            }
10156            return false;
10157        }
10158    }
10159
10160    // It is assumed that this method is called only by InputMethodManagerService.
10161    public void saveLastInputMethodWindowForTransition() {
10162        synchronized (mWindowMap) {
10163            // TODO(multidisplay): Pass in the displayID.
10164            DisplayContent displayContent = getDefaultDisplayContentLocked();
10165            if (mInputMethodWindow != null) {
10166                mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
10167            }
10168        }
10169    }
10170
10171    @Override
10172    public boolean hasNavigationBar() {
10173        return mPolicy.hasNavigationBar();
10174    }
10175
10176    public void lockNow() {
10177        mPolicy.lockNow();
10178    }
10179
10180    void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
10181        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
10182        mPolicy.dump("    ", pw, args);
10183    }
10184
10185    void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
10186        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
10187        if (mTokenMap.size() > 0) {
10188            pw.println("  All tokens:");
10189            Iterator<WindowToken> it = mTokenMap.values().iterator();
10190            while (it.hasNext()) {
10191                WindowToken token = it.next();
10192                pw.print("  Token "); pw.print(token.token);
10193                if (dumpAll) {
10194                    pw.println(':');
10195                    token.dump(pw, "    ");
10196                } else {
10197                    pw.println();
10198                }
10199            }
10200        }
10201        if (mWallpaperTokens.size() > 0) {
10202            pw.println();
10203            pw.println("  Wallpaper tokens:");
10204            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
10205                WindowToken token = mWallpaperTokens.get(i);
10206                pw.print("  Wallpaper #"); pw.print(i);
10207                        pw.print(' '); pw.print(token);
10208                if (dumpAll) {
10209                    pw.println(':');
10210                    token.dump(pw, "    ");
10211                } else {
10212                    pw.println();
10213                }
10214            }
10215        }
10216        if (mAppTokens.size() > 0) {
10217            pw.println();
10218            pw.println("  Application tokens in Z order:");
10219            for (int i=mAppTokens.size()-1; i>=0; i--) {
10220                pw.print("  App #"); pw.print(i); pw.println(": ");
10221                        mAppTokens.get(i).dump(pw, "    ");
10222            }
10223        }
10224        if (mFinishedStarting.size() > 0) {
10225            pw.println();
10226            pw.println("  Finishing start of application tokens:");
10227            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
10228                WindowToken token = mFinishedStarting.get(i);
10229                pw.print("  Finished Starting #"); 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 (mExitingTokens.size() > 0) {
10240            pw.println();
10241            pw.println("  Exiting tokens:");
10242            for (int i=mExitingTokens.size()-1; i>=0; i--) {
10243                WindowToken token = mExitingTokens.get(i);
10244                pw.print("  Exiting #"); pw.print(i);
10245                        pw.print(' '); pw.print(token);
10246                if (dumpAll) {
10247                    pw.println(':');
10248                    token.dump(pw, "    ");
10249                } else {
10250                    pw.println();
10251                }
10252            }
10253        }
10254        if (mExitingAppTokens.size() > 0) {
10255            pw.println();
10256            pw.println("  Exiting application tokens:");
10257            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
10258                WindowToken token = mExitingAppTokens.get(i);
10259                pw.print("  Exiting App #"); pw.print(i);
10260                        pw.print(' '); pw.print(token);
10261                if (dumpAll) {
10262                    pw.println(':');
10263                    token.dump(pw, "    ");
10264                } else {
10265                    pw.println();
10266                }
10267            }
10268        }
10269        if (mAppTransitionRunning && mAnimatingAppTokens.size() > 0) {
10270            pw.println();
10271            pw.println("  Application tokens during animation:");
10272            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
10273                WindowToken token = mAnimatingAppTokens.get(i);
10274                pw.print("  App moving to bottom #"); pw.print(i);
10275                        pw.print(' '); pw.print(token);
10276                if (dumpAll) {
10277                    pw.println(':');
10278                    token.dump(pw, "    ");
10279                } else {
10280                    pw.println();
10281                }
10282            }
10283        }
10284        if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
10285            pw.println();
10286            if (mOpeningApps.size() > 0) {
10287                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
10288            }
10289            if (mClosingApps.size() > 0) {
10290                pw.print("  mClosingApps="); pw.println(mClosingApps);
10291            }
10292        }
10293    }
10294
10295    void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
10296        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
10297        if (mSessions.size() > 0) {
10298            Iterator<Session> it = mSessions.iterator();
10299            while (it.hasNext()) {
10300                Session s = it.next();
10301                pw.print("  Session "); pw.print(s); pw.println(':');
10302                s.dump(pw, "    ");
10303            }
10304        }
10305    }
10306
10307    void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
10308            ArrayList<WindowState> windows) {
10309        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
10310        dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
10311    }
10312
10313    void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
10314            ArrayList<WindowState> windows) {
10315        int j = 0;
10316        final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10317        while (iterator.hasNext()) {
10318            final WindowState w = iterator.next();
10319            if (windows == null || windows.contains(w)) {
10320                pw.print("  Window #"); pw.print(j++); pw.print(' ');
10321                        pw.print(w); pw.println(":");
10322                w.dump(pw, "    ", dumpAll || windows != null);
10323            }
10324        }
10325        if (mInputMethodDialogs.size() > 0) {
10326            pw.println();
10327            pw.println("  Input method dialogs:");
10328            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
10329                WindowState w = mInputMethodDialogs.get(i);
10330                if (windows == null || windows.contains(w)) {
10331                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
10332                }
10333            }
10334        }
10335        if (mPendingRemove.size() > 0) {
10336            pw.println();
10337            pw.println("  Remove pending for:");
10338            for (int i=mPendingRemove.size()-1; i>=0; i--) {
10339                WindowState w = mPendingRemove.get(i);
10340                if (windows == null || windows.contains(w)) {
10341                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
10342                            pw.print(w);
10343                    if (dumpAll) {
10344                        pw.println(":");
10345                        w.dump(pw, "    ", true);
10346                    } else {
10347                        pw.println();
10348                    }
10349                }
10350            }
10351        }
10352        if (mForceRemoves != null && mForceRemoves.size() > 0) {
10353            pw.println();
10354            pw.println("  Windows force removing:");
10355            for (int i=mForceRemoves.size()-1; i>=0; i--) {
10356                WindowState w = mForceRemoves.get(i);
10357                pw.print("  Removing #"); pw.print(i); pw.print(' ');
10358                        pw.print(w);
10359                if (dumpAll) {
10360                    pw.println(":");
10361                    w.dump(pw, "    ", true);
10362                } else {
10363                    pw.println();
10364                }
10365            }
10366        }
10367        if (mDestroySurface.size() > 0) {
10368            pw.println();
10369            pw.println("  Windows waiting to destroy their surface:");
10370            for (int i=mDestroySurface.size()-1; i>=0; i--) {
10371                WindowState w = mDestroySurface.get(i);
10372                if (windows == null || windows.contains(w)) {
10373                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
10374                            pw.print(w);
10375                    if (dumpAll) {
10376                        pw.println(":");
10377                        w.dump(pw, "    ", true);
10378                    } else {
10379                        pw.println();
10380                    }
10381                }
10382            }
10383        }
10384        if (mLosingFocus.size() > 0) {
10385            pw.println();
10386            pw.println("  Windows losing focus:");
10387            for (int i=mLosingFocus.size()-1; i>=0; i--) {
10388                WindowState w = mLosingFocus.get(i);
10389                if (windows == null || windows.contains(w)) {
10390                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
10391                            pw.print(w);
10392                    if (dumpAll) {
10393                        pw.println(":");
10394                        w.dump(pw, "    ", true);
10395                    } else {
10396                        pw.println();
10397                    }
10398                }
10399            }
10400        }
10401        if (mResizingWindows.size() > 0) {
10402            pw.println();
10403            pw.println("  Windows waiting to resize:");
10404            for (int i=mResizingWindows.size()-1; i>=0; i--) {
10405                WindowState w = mResizingWindows.get(i);
10406                if (windows == null || windows.contains(w)) {
10407                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
10408                            pw.print(w);
10409                    if (dumpAll) {
10410                        pw.println(":");
10411                        w.dump(pw, "    ", true);
10412                    } else {
10413                        pw.println();
10414                    }
10415                }
10416            }
10417        }
10418        if (mWaitingForDrawn.size() > 0) {
10419            pw.println();
10420            pw.println("  Clients waiting for these windows to be drawn:");
10421            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
10422                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
10423                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
10424                        pw.print(": "); pw.println(pair.second);
10425            }
10426        }
10427        pw.println("  DisplayContents");
10428        if (mDisplayReady) {
10429            DisplayContentsIterator dCIterator = new DisplayContentsIterator();
10430            while (dCIterator.hasNext()) {
10431                dCIterator.next().dump("    ", pw);
10432            }
10433        } else {
10434            pw.println("  NO DISPLAY");
10435        }
10436        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
10437        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
10438        if (mLastFocus != mCurrentFocus) {
10439            pw.print("  mLastFocus="); pw.println(mLastFocus);
10440        }
10441        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
10442        if (mInputMethodTarget != null) {
10443            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
10444        }
10445        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
10446                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
10447        if (dumpAll) {
10448            pw.print("  mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
10449                    pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
10450                    pw.print(" mScreenRecr="); pw.println(mScreenRect.toShortString());
10451            if (mLastStatusBarVisibility != 0) {
10452                pw.print("  mLastStatusBarVisibility=0x");
10453                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
10454            }
10455            if (mInputMethodWindow != null) {
10456                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
10457            }
10458            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
10459            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
10460                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
10461                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
10462            }
10463            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
10464                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
10465            if (mInputMethodAnimLayerAdjustment != 0 ||
10466                    mWallpaperAnimLayerAdjustment != 0) {
10467                pw.print("  mInputMethodAnimLayerAdjustment=");
10468                        pw.print(mInputMethodAnimLayerAdjustment);
10469                        pw.print("  mWallpaperAnimLayerAdjustment=");
10470                        pw.println(mWallpaperAnimLayerAdjustment);
10471            }
10472            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
10473                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
10474            if (needsLayout()) {
10475                pw.print("  layoutNeeded on displays=");
10476                DisplayContentsIterator dcIterator = new DisplayContentsIterator();
10477                while (dcIterator.hasNext()) {
10478                    final DisplayContent displayContent = dcIterator.next();
10479                    if (displayContent.layoutNeeded) {
10480                        pw.print(displayContent.getDisplayId());
10481                    }
10482                }
10483                pw.println();
10484            }
10485            pw.print("  mTransactionSequence="); pw.println(mTransactionSequence);
10486            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
10487                    pw.print(" windows="); pw.print(mWindowsFreezingScreen);
10488                    pw.print(" client="); pw.print(mClientFreezingScreen);
10489                    pw.print(" apps="); pw.print(mAppsFreezingScreen);
10490                    pw.print(" waitingForConfig="); pw.println(mWaitingForConfig);
10491            pw.print("  mRotation="); pw.print(mRotation);
10492                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
10493            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
10494                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
10495            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
10496            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
10497                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
10498                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
10499            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
10500                    pw.print(" mNextAppTransition=0x");
10501                    pw.print(Integer.toHexString(mNextAppTransition));
10502                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
10503            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
10504                    pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout);
10505            if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) {
10506                pw.print("  mNextAppTransitionType="); pw.println(mNextAppTransitionType);
10507            }
10508            switch (mNextAppTransitionType) {
10509                case ActivityOptions.ANIM_CUSTOM:
10510                    pw.print("  mNextAppTransitionPackage=");
10511                            pw.println(mNextAppTransitionPackage);
10512                    pw.print("  mNextAppTransitionEnter=0x");
10513                            pw.print(Integer.toHexString(mNextAppTransitionEnter));
10514                            pw.print(" mNextAppTransitionExit=0x");
10515                            pw.println(Integer.toHexString(mNextAppTransitionExit));
10516                    break;
10517                case ActivityOptions.ANIM_SCALE_UP:
10518                    pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
10519                            pw.print(" mNextAppTransitionStartY=");
10520                            pw.println(mNextAppTransitionStartY);
10521                    pw.print("  mNextAppTransitionStartWidth=");
10522                            pw.print(mNextAppTransitionStartWidth);
10523                            pw.print(" mNextAppTransitionStartHeight=");
10524                            pw.println(mNextAppTransitionStartHeight);
10525                    break;
10526                case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP:
10527                case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN:
10528                    pw.print("  mNextAppTransitionThumbnail=");
10529                            pw.print(mNextAppTransitionThumbnail);
10530                            pw.print(" mNextAppTransitionStartX=");
10531                            pw.print(mNextAppTransitionStartX);
10532                            pw.print(" mNextAppTransitionStartY=");
10533                            pw.println(mNextAppTransitionStartY);
10534                    pw.print("  mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp);
10535                    break;
10536            }
10537            if (mNextAppTransitionCallback != null) {
10538                pw.print("  mNextAppTransitionCallback=");
10539                        pw.println(mNextAppTransitionCallback);
10540            }
10541            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
10542                    pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
10543            pw.println("  Window Animator:");
10544            mAnimator.dumpLocked(pw, "    ", dumpAll);
10545        }
10546    }
10547
10548    boolean dumpWindows(PrintWriter pw, String name, String[] args,
10549            int opti, boolean dumpAll) {
10550        WindowList windows = new WindowList();
10551        if ("visible".equals(name)) {
10552            synchronized(mWindowMap) {
10553                final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10554                while (iterator.hasNext()) {
10555                    final WindowState w = iterator.next();
10556                    if (w.mWinAnimator.mSurfaceShown) {
10557                        windows.add(w);
10558                    }
10559                }
10560            }
10561        } else {
10562            int objectId = 0;
10563            // See if this is an object ID.
10564            try {
10565                objectId = Integer.parseInt(name, 16);
10566                name = null;
10567            } catch (RuntimeException e) {
10568            }
10569            synchronized(mWindowMap) {
10570                final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10571                while (iterator.hasNext()) {
10572                    final WindowState w = iterator.next();
10573                    if (name != null) {
10574                        if (w.mAttrs.getTitle().toString().contains(name)) {
10575                            windows.add(w);
10576                        }
10577                    } else if (System.identityHashCode(w) == objectId) {
10578                        windows.add(w);
10579                    }
10580                }
10581            }
10582        }
10583
10584        if (windows.size() <= 0) {
10585            return false;
10586        }
10587
10588        synchronized(mWindowMap) {
10589            dumpWindowsLocked(pw, dumpAll, windows);
10590        }
10591        return true;
10592    }
10593
10594    void dumpLastANRLocked(PrintWriter pw) {
10595        pw.println("WINDOW MANAGER LAST ANR (dumpsys window lastanr)");
10596        if (mLastANRState == null) {
10597            pw.println("  <no ANR has occurred since boot>");
10598        } else {
10599            pw.println(mLastANRState);
10600        }
10601    }
10602
10603    /**
10604     * Saves information about the state of the window manager at
10605     * the time an ANR occurred before anything else in the system changes
10606     * in response.
10607     *
10608     * @param appWindowToken The application that ANR'd, may be null.
10609     * @param windowState The window that ANR'd, may be null.
10610     */
10611    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState) {
10612        StringWriter sw = new StringWriter();
10613        PrintWriter pw = new PrintWriter(sw);
10614        pw.println("  ANR time: " + DateFormat.getInstance().format(new Date()));
10615        if (appWindowToken != null) {
10616            pw.println("  Application at fault: " + appWindowToken.stringName);
10617        }
10618        if (windowState != null) {
10619            pw.println("  Window at fault: " + windowState.mAttrs.getTitle());
10620        }
10621        pw.println();
10622        dumpWindowsNoHeaderLocked(pw, true, null);
10623        pw.close();
10624        mLastANRState = sw.toString();
10625    }
10626
10627    @Override
10628    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
10629        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
10630                != PackageManager.PERMISSION_GRANTED) {
10631            pw.println("Permission Denial: can't dump WindowManager from from pid="
10632                    + Binder.getCallingPid()
10633                    + ", uid=" + Binder.getCallingUid());
10634            return;
10635        }
10636
10637        boolean dumpAll = false;
10638
10639        int opti = 0;
10640        while (opti < args.length) {
10641            String opt = args[opti];
10642            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
10643                break;
10644            }
10645            opti++;
10646            if ("-a".equals(opt)) {
10647                dumpAll = true;
10648            } else if ("-h".equals(opt)) {
10649                pw.println("Window manager dump options:");
10650                pw.println("  [-a] [-h] [cmd] ...");
10651                pw.println("  cmd may be one of:");
10652                pw.println("    l[astanr]: last ANR information");
10653                pw.println("    p[policy]: policy state");
10654                pw.println("    s[essions]: active sessions");
10655                pw.println("    t[okens]: token list");
10656                pw.println("    w[indows]: window list");
10657                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
10658                pw.println("    be a partial substring in a window name, a");
10659                pw.println("    Window hex object identifier, or");
10660                pw.println("    \"all\" for all windows, or");
10661                pw.println("    \"visible\" for the visible windows.");
10662                pw.println("  -a: include all available server state.");
10663                return;
10664            } else {
10665                pw.println("Unknown argument: " + opt + "; use -h for help");
10666            }
10667        }
10668
10669        // Is the caller requesting to dump a particular piece of data?
10670        if (opti < args.length) {
10671            String cmd = args[opti];
10672            opti++;
10673            if ("lastanr".equals(cmd) || "l".equals(cmd)) {
10674                synchronized(mWindowMap) {
10675                    dumpLastANRLocked(pw);
10676                }
10677                return;
10678            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
10679                synchronized(mWindowMap) {
10680                    dumpPolicyLocked(pw, args, true);
10681                }
10682                return;
10683            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
10684                synchronized(mWindowMap) {
10685                    dumpSessionsLocked(pw, true);
10686                }
10687                return;
10688            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
10689                synchronized(mWindowMap) {
10690                    dumpTokensLocked(pw, true);
10691                }
10692                return;
10693            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
10694                synchronized(mWindowMap) {
10695                    dumpWindowsLocked(pw, true, null);
10696                }
10697                return;
10698            } else if ("all".equals(cmd) || "a".equals(cmd)) {
10699                synchronized(mWindowMap) {
10700                    dumpWindowsLocked(pw, true, null);
10701                }
10702                return;
10703            } else {
10704                // Dumping a single name?
10705                if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
10706                    pw.println("Bad window command, or no windows match: " + cmd);
10707                    pw.println("Use -h for help.");
10708                }
10709                return;
10710            }
10711        }
10712
10713        synchronized(mWindowMap) {
10714            pw.println();
10715            if (dumpAll) {
10716                pw.println("-------------------------------------------------------------------------------");
10717            }
10718            dumpLastANRLocked(pw);
10719            pw.println();
10720            if (dumpAll) {
10721                pw.println("-------------------------------------------------------------------------------");
10722            }
10723            dumpPolicyLocked(pw, args, dumpAll);
10724            pw.println();
10725            if (dumpAll) {
10726                pw.println("-------------------------------------------------------------------------------");
10727            }
10728            dumpSessionsLocked(pw, dumpAll);
10729            pw.println();
10730            if (dumpAll) {
10731                pw.println("-------------------------------------------------------------------------------");
10732            }
10733            dumpTokensLocked(pw, dumpAll);
10734            pw.println();
10735            if (dumpAll) {
10736                pw.println("-------------------------------------------------------------------------------");
10737            }
10738            dumpWindowsLocked(pw, dumpAll, null);
10739        }
10740    }
10741
10742    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
10743    public void monitor() {
10744        synchronized (mWindowMap) { }
10745    }
10746
10747    public interface OnHardKeyboardStatusChangeListener {
10748        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
10749    }
10750
10751    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
10752        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
10753            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
10754                    Integer.toHexString(pendingLayoutChanges));
10755        }
10756    }
10757
10758    public void createDisplayContentLocked(final Display display) {
10759        if (display == null) {
10760            throw new IllegalArgumentException("getDisplayContent: display must not be null");
10761        }
10762        final DisplayContent displayContent = new DisplayContent(display);
10763        mDisplayContents.put(display.getDisplayId(), displayContent);
10764    }
10765
10766    public DisplayContent getDisplayContentLocked(final int displayId) {
10767        DisplayContent displayContent = mDisplayContents.get(displayId);
10768        if (displayContent == null) {
10769            displayContent = new DisplayContent(mDisplayManager.getDisplay(displayId));
10770            mDisplayContents.put(displayId, displayContent);
10771        }
10772        return displayContent;
10773    }
10774
10775    class DisplayContentsIterator implements Iterator<DisplayContent> {
10776        private int cur;
10777
10778        @Override
10779        public boolean hasNext() {
10780            return cur < mDisplayContents.size();
10781        }
10782
10783        @Override
10784        public DisplayContent next() {
10785            if (hasNext()) {
10786                return mDisplayContents.valueAt(cur++);
10787            }
10788            throw new NoSuchElementException();
10789        }
10790
10791        @Override
10792        public void remove() {
10793            throw new IllegalArgumentException("AllDisplayContentIterator.remove not implemented");
10794        }
10795    }
10796
10797    final static boolean REVERSE_ITERATOR = true;
10798    class AllWindowsIterator implements Iterator<WindowState> {
10799        private DisplayContent mDisplayContent;
10800        private DisplayContentsIterator mDisplayContentsIterator;
10801        private WindowList mWindowList;
10802        private int mWindowListIndex;
10803        private boolean mReverse;
10804
10805        AllWindowsIterator() {
10806            mDisplayContentsIterator = new DisplayContentsIterator();
10807            mDisplayContent = mDisplayContentsIterator.next();
10808            mWindowList = mDisplayContent.getWindowList();
10809        }
10810
10811        AllWindowsIterator(boolean reverse) {
10812            this();
10813            mReverse = reverse;
10814            mWindowListIndex = reverse ? mWindowList.size() - 1 : 0;
10815        }
10816
10817        @Override
10818        public boolean hasNext() {
10819            if (mReverse) {
10820                return mWindowListIndex >= 0;
10821            }
10822            return mWindowListIndex < mWindowList.size();
10823        }
10824
10825        @Override
10826        public WindowState next() {
10827            if (hasNext()) {
10828                WindowState win = mWindowList.get(mWindowListIndex);
10829                if (mReverse) {
10830                    mWindowListIndex--;
10831                    if (mWindowListIndex < 0 && mDisplayContentsIterator.hasNext()) {
10832                        mDisplayContent = mDisplayContentsIterator.next();
10833                        mWindowList = mDisplayContent.getWindowList();
10834                        mWindowListIndex = mWindowList.size() - 1;
10835                    }
10836                } else {
10837                    mWindowListIndex++;
10838                    if (mWindowListIndex >= mWindowList.size()
10839                            && mDisplayContentsIterator.hasNext()) {
10840                        mDisplayContent = mDisplayContentsIterator.next();
10841                        mWindowList = mDisplayContent.getWindowList();
10842                        mWindowListIndex = 0;
10843                    }
10844                }
10845                return win;
10846            }
10847            throw new NoSuchElementException();
10848        }
10849
10850        @Override
10851        public void remove() {
10852            throw new IllegalArgumentException("AllWindowsIterator.remove not implemented");
10853        }
10854    }
10855
10856    public DisplayContent getDefaultDisplayContentLocked() {
10857        return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
10858    }
10859
10860    public WindowList getDefaultWindowListLocked() {
10861        return getDefaultDisplayContentLocked().getWindowList();
10862    }
10863
10864    public DisplayInfo getDefaultDisplayInfoLocked() {
10865        return getDefaultDisplayContentLocked().getDisplayInfo();
10866    }
10867
10868    public WindowList getWindowListLocked(final Display display) {
10869        return getDisplayContentLocked(display.getDisplayId()).getWindowList();
10870    }
10871
10872    @Override
10873    public void onDisplayAdded(int displayId) {
10874        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
10875    }
10876
10877    private void handleDisplayAddedLocked(int displayId) {
10878        createDisplayContentLocked(mDisplayManager.getDisplay(displayId));
10879        displayReady(displayId);
10880    }
10881
10882    @Override
10883    public void onDisplayRemoved(int displayId) {
10884        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
10885    }
10886
10887    private void handleDisplayRemovedLocked(int displayId) {
10888        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10889        mDisplayContents.delete(displayId);
10890        WindowList windows = displayContent.getWindowList();
10891        while (!windows.isEmpty()) {
10892            final WindowState win = windows.get(windows.size() - 1);
10893            removeWindowLocked(win.mSession, win);
10894        }
10895        mAnimator.removeDisplayLocked(displayId);
10896    }
10897
10898    @Override
10899    public void onDisplayChanged(int displayId) {
10900        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
10901    }
10902
10903    private void handleDisplayChangedLocked(int displayId) {
10904        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10905        if (displayContent != null) {
10906            displayContent.updateDisplayInfo();
10907        }
10908    }
10909}
10910