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