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