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