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