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