WindowManagerService.java revision 3aa7fcac1c46353c2f147d978d9eb2f2748def4a
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 hidden and not 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                    + " at " + addPos);
3549            mAppTokens.add(addPos, wtoken);
3550            addAppTokenToAnimating(addPos, wtoken);
3551            mTokenMap.put(token.asBinder(), wtoken);
3552
3553            // Application tokens start out hidden.
3554            wtoken.hidden = true;
3555            wtoken.hiddenRequested = true;
3556
3557            //dump();
3558        }
3559    }
3560
3561    public void setAppGroupId(IBinder token, int groupId) {
3562        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3563                "setAppStartingIcon()")) {
3564            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3565        }
3566
3567        synchronized(mWindowMap) {
3568            AppWindowToken wtoken = findAppWindowToken(token);
3569            if (wtoken == null) {
3570                Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
3571                return;
3572            }
3573            wtoken.groupId = groupId;
3574        }
3575    }
3576
3577    public int getOrientationFromWindowsLocked() {
3578        if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
3579            // If the display is frozen, some activities may be in the middle
3580            // of restarting, and thus have removed their old window.  If the
3581            // window has the flag to hide the lock screen, then the lock screen
3582            // can re-appear and inflict its own orientation on us.  Keep the
3583            // orientation stable until this all settles down.
3584            return mLastWindowForcedOrientation;
3585        }
3586
3587        int pos = mWindows.size() - 1;
3588        while (pos >= 0) {
3589            WindowState wtoken = mWindows.get(pos);
3590            pos--;
3591            if (wtoken.mAppToken != null) {
3592                // We hit an application window. so the orientation will be determined by the
3593                // app window. No point in continuing further.
3594                return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
3595            }
3596            if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) {
3597                continue;
3598            }
3599            int req = wtoken.mAttrs.screenOrientation;
3600            if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
3601                    (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
3602                continue;
3603            } else {
3604                return (mLastWindowForcedOrientation=req);
3605            }
3606        }
3607        return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
3608    }
3609
3610    public int getOrientationFromAppTokensLocked() {
3611        int curGroup = 0;
3612        int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3613        boolean findingBehind = false;
3614        boolean haveGroup = false;
3615        boolean lastFullscreen = false;
3616        for (int pos = mAppTokens.size() - 1; pos >= 0; pos--) {
3617            AppWindowToken wtoken = mAppTokens.get(pos);
3618
3619            if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + wtoken);
3620
3621            // if we're about to tear down this window and not seek for
3622            // the behind activity, don't use it for orientation
3623            if (!findingBehind
3624                    && (!wtoken.hidden && wtoken.hiddenRequested)) {
3625                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + wtoken
3626                        + " -- going to hide");
3627                continue;
3628            }
3629
3630            if (haveGroup == true && curGroup != wtoken.groupId) {
3631                // If we have hit a new application group, and the bottom
3632                // of the previous group didn't explicitly say to use
3633                // the orientation behind it, and the last app was
3634                // full screen, then we'll stick with the
3635                // user's orientation.
3636                if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
3637                        && lastFullscreen) {
3638                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken
3639                            + " -- end of group, return " + lastOrientation);
3640                    return lastOrientation;
3641                }
3642            }
3643
3644            // We ignore any hidden applications on the top.
3645            if (wtoken.hiddenRequested || wtoken.willBeHidden) {
3646                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + wtoken
3647                        + " -- hidden on top");
3648                continue;
3649            }
3650
3651            if (!haveGroup) {
3652                haveGroup = true;
3653                curGroup = wtoken.groupId;
3654                lastOrientation = wtoken.requestedOrientation;
3655            }
3656
3657            int or = wtoken.requestedOrientation;
3658            // If this application is fullscreen, and didn't explicitly say
3659            // to use the orientation behind it, then just take whatever
3660            // orientation it has and ignores whatever is under it.
3661            lastFullscreen = wtoken.appFullscreen;
3662            if (lastFullscreen
3663                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
3664                if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken
3665                        + " -- full screen, return " + or);
3666                return or;
3667            }
3668            // If this application has requested an explicit orientation,
3669            // then use it.
3670            if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
3671                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
3672                if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + wtoken
3673                        + " -- explicitly set, return " + or);
3674                return or;
3675            }
3676            findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
3677        }
3678        if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation");
3679        return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3680    }
3681
3682    public Configuration updateOrientationFromAppTokens(
3683            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
3684        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3685                "updateOrientationFromAppTokens()")) {
3686            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3687        }
3688
3689        Configuration config = null;
3690        long ident = Binder.clearCallingIdentity();
3691
3692        synchronized(mWindowMap) {
3693            config = updateOrientationFromAppTokensLocked(currentConfig,
3694                    freezeThisOneIfNeeded);
3695        }
3696
3697        Binder.restoreCallingIdentity(ident);
3698        return config;
3699    }
3700
3701    private Configuration updateOrientationFromAppTokensLocked(
3702            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
3703        Configuration config = null;
3704
3705        if (updateOrientationFromAppTokensLocked(false)) {
3706            if (freezeThisOneIfNeeded != null) {
3707                AppWindowToken wtoken = findAppWindowToken(
3708                        freezeThisOneIfNeeded);
3709                if (wtoken != null) {
3710                    startAppFreezingScreenLocked(wtoken,
3711                            ActivityInfo.CONFIG_ORIENTATION);
3712                }
3713            }
3714            config = computeNewConfigurationLocked();
3715
3716        } else if (currentConfig != null) {
3717            // No obvious action we need to take, but if our current
3718            // state mismatches the activity manager's, update it,
3719            // disregarding font scale, which should remain set to
3720            // the value of the previous configuration.
3721            mTempConfiguration.setToDefaults();
3722            mTempConfiguration.fontScale = currentConfig.fontScale;
3723            if (computeScreenConfigurationLocked(mTempConfiguration)) {
3724                if (currentConfig.diff(mTempConfiguration) != 0) {
3725                    mWaitingForConfig = true;
3726                    mLayoutNeeded = true;
3727                    startFreezingDisplayLocked(false);
3728                    config = new Configuration(mTempConfiguration);
3729                }
3730            }
3731        }
3732
3733        return config;
3734    }
3735
3736    /*
3737     * Determine the new desired orientation of the display, returning
3738     * a non-null new Configuration if it has changed from the current
3739     * orientation.  IF TRUE IS RETURNED SOMEONE MUST CALL
3740     * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE
3741     * SCREEN.  This will typically be done for you if you call
3742     * sendNewConfiguration().
3743     *
3744     * The orientation is computed from non-application windows first. If none of
3745     * the non-application windows specify orientation, the orientation is computed from
3746     * application tokens.
3747     * @see android.view.IWindowManager#updateOrientationFromAppTokens(
3748     * android.os.IBinder)
3749     */
3750    boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
3751        long ident = Binder.clearCallingIdentity();
3752        try {
3753            int req = computeForcedAppOrientationLocked();
3754
3755            if (req != mForcedAppOrientation) {
3756                mForcedAppOrientation = req;
3757                //send a message to Policy indicating orientation change to take
3758                //action like disabling/enabling sensors etc.,
3759                mPolicy.setCurrentOrientationLw(req);
3760                if (updateRotationUncheckedLocked(inTransaction)) {
3761                    // changed
3762                    return true;
3763                }
3764            }
3765
3766            return false;
3767        } finally {
3768            Binder.restoreCallingIdentity(ident);
3769        }
3770    }
3771
3772    int computeForcedAppOrientationLocked() {
3773        int req = getOrientationFromWindowsLocked();
3774        if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
3775            req = getOrientationFromAppTokensLocked();
3776        }
3777        return req;
3778    }
3779
3780    public void setNewConfiguration(Configuration config) {
3781        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3782                "setNewConfiguration()")) {
3783            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3784        }
3785
3786        synchronized(mWindowMap) {
3787            mCurConfiguration = new Configuration(config);
3788            mWaitingForConfig = false;
3789            performLayoutAndPlaceSurfacesLocked();
3790        }
3791    }
3792
3793    public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
3794        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3795                "setAppOrientation()")) {
3796            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3797        }
3798
3799        synchronized(mWindowMap) {
3800            AppWindowToken wtoken = findAppWindowToken(token.asBinder());
3801            if (wtoken == null) {
3802                Slog.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
3803                return;
3804            }
3805
3806            wtoken.requestedOrientation = requestedOrientation;
3807        }
3808    }
3809
3810    public int getAppOrientation(IApplicationToken token) {
3811        synchronized(mWindowMap) {
3812            AppWindowToken wtoken = findAppWindowToken(token.asBinder());
3813            if (wtoken == null) {
3814                return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3815            }
3816
3817            return wtoken.requestedOrientation;
3818        }
3819    }
3820
3821    public void setFocusedApp(IBinder token, boolean moveFocusNow) {
3822        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3823                "setFocusedApp()")) {
3824            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3825        }
3826
3827        synchronized(mWindowMap) {
3828            boolean changed = false;
3829            if (token == null) {
3830                if (DEBUG_FOCUS) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
3831                changed = mFocusedApp != null;
3832                mFocusedApp = null;
3833                if (changed) {
3834                    mInputMonitor.setFocusedAppLw(null);
3835                }
3836            } else {
3837                AppWindowToken newFocus = findAppWindowToken(token);
3838                if (newFocus == null) {
3839                    Slog.w(TAG, "Attempted to set focus to non-existing app token: " + token);
3840                    return;
3841                }
3842                changed = mFocusedApp != newFocus;
3843                mFocusedApp = newFocus;
3844                if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp);
3845                if (changed) {
3846                    mInputMonitor.setFocusedAppLw(newFocus);
3847                }
3848            }
3849
3850            if (moveFocusNow && changed) {
3851                final long origId = Binder.clearCallingIdentity();
3852                updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
3853                Binder.restoreCallingIdentity(origId);
3854            }
3855        }
3856    }
3857
3858    public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
3859        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3860                "prepareAppTransition()")) {
3861            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3862        }
3863
3864        synchronized(mWindowMap) {
3865            if (DEBUG_APP_TRANSITIONS) Slog.v(
3866                    TAG, "Prepare app transition: transit=" + transit
3867                    + " mNextAppTransition=" + mNextAppTransition
3868                    + " alwaysKeepCurrent=" + alwaysKeepCurrent
3869                    + " Callers=" + Debug.getCallers(3));
3870            if (okToDisplay()) {
3871                if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
3872                        || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
3873                    mNextAppTransition = transit;
3874                } else if (!alwaysKeepCurrent) {
3875                    if (transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
3876                            && mNextAppTransition == WindowManagerPolicy.TRANSIT_TASK_CLOSE) {
3877                        // Opening a new task always supersedes a close for the anim.
3878                        mNextAppTransition = transit;
3879                    } else if (transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
3880                            && mNextAppTransition == WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE) {
3881                        // Opening a new activity always supersedes a close for the anim.
3882                        mNextAppTransition = transit;
3883                    }
3884                }
3885                mAppTransitionReady = false;
3886                mAppTransitionTimeout = false;
3887                mStartingIconInTransition = false;
3888                mSkipAppTransitionAnimation = false;
3889                mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
3890                mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT),
3891                        5000);
3892            }
3893        }
3894    }
3895
3896    public int getPendingAppTransition() {
3897        return mNextAppTransition;
3898    }
3899
3900    public void overridePendingAppTransition(String packageName,
3901            int enterAnim, int exitAnim) {
3902        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
3903            mNextAppTransitionType = ActivityOptions.ANIM_CUSTOM;
3904            mNextAppTransitionPackage = packageName;
3905            mNextAppTransitionThumbnail = null;
3906            mNextAppTransitionEnter = enterAnim;
3907            mNextAppTransitionExit = exitAnim;
3908        }
3909    }
3910
3911    public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
3912            int startHeight) {
3913        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
3914            mNextAppTransitionType = ActivityOptions.ANIM_SCALE_UP;
3915            mNextAppTransitionPackage = null;
3916            mNextAppTransitionThumbnail = null;
3917            mNextAppTransitionStartX = startX;
3918            mNextAppTransitionStartY = startY;
3919            mNextAppTransitionStartWidth = startWidth;
3920            mNextAppTransitionStartHeight = startHeight;
3921        }
3922    }
3923
3924    public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
3925            int startY, IRemoteCallback startedCallback, boolean delayed) {
3926        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
3927            mNextAppTransitionType =
3928                    delayed ? ActivityOptions.ANIM_THUMBNAIL_DELAYED : ActivityOptions.ANIM_THUMBNAIL;
3929            mNextAppTransitionPackage = null;
3930            mNextAppTransitionThumbnail = srcThumb;
3931            mNextAppTransitionDelayed = delayed;
3932            mNextAppTransitionStartX = startX;
3933            mNextAppTransitionStartY = startY;
3934            mNextAppTransitionCallback = startedCallback;
3935        }
3936    }
3937
3938    private void cancelWindowAnimations(final AppWindowToken wtoken) {
3939        for (int i = wtoken.windows.size() - 1; i >= 0; i--) {
3940            final WindowStateAnimator winAnimator = wtoken.windows.get(i).mWinAnimator;
3941            if (winAnimator.isAnimating()) {
3942                winAnimator.clearAnimation();
3943            }
3944        }
3945    }
3946
3947    public void executeAppTransition() {
3948        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3949                "executeAppTransition()")) {
3950            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3951        }
3952
3953        synchronized(mWindowMap) {
3954            if (DEBUG_APP_TRANSITIONS) {
3955                RuntimeException e = new RuntimeException("here");
3956                e.fillInStackTrace();
3957                Slog.w(TAG, "Execute app transition: mNextAppTransition="
3958                        + mNextAppTransition, e);
3959            }
3960            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
3961                mAppTransitionReady = true;
3962                for (int i = mOpeningApps.size() - 1; i >= 0; i--) {
3963                    cancelWindowAnimations(mOpeningApps.get(i));
3964                }
3965                for (int i = mClosingApps.size() - 1; i >= 0; i--) {
3966                    cancelWindowAnimations(mClosingApps.get(i));
3967                }
3968                final long origId = Binder.clearCallingIdentity();
3969                performLayoutAndPlaceSurfacesLocked();
3970                Binder.restoreCallingIdentity(origId);
3971            }
3972        }
3973    }
3974
3975    public void setAppStartingWindow(IBinder token, String pkg,
3976            int theme, CompatibilityInfo compatInfo,
3977            CharSequence nonLocalizedLabel, int labelRes, int icon,
3978            int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
3979        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3980                "setAppStartingIcon()")) {
3981            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3982        }
3983
3984        synchronized(mWindowMap) {
3985            if (DEBUG_STARTING_WINDOW) Slog.v(
3986                    TAG, "setAppStartingIcon: token=" + token + " pkg=" + pkg
3987                    + " transferFrom=" + transferFrom);
3988
3989            AppWindowToken wtoken = findAppWindowToken(token);
3990            if (wtoken == null) {
3991                Slog.w(TAG, "Attempted to set icon of non-existing app token: " + token);
3992                return;
3993            }
3994
3995            // If the display is frozen, we won't do anything until the
3996            // actual window is displayed so there is no reason to put in
3997            // the starting window.
3998            if (!okToDisplay()) {
3999                return;
4000            }
4001
4002            if (wtoken.startingData != null) {
4003                return;
4004            }
4005
4006            if (transferFrom != null) {
4007                AppWindowToken ttoken = findAppWindowToken(transferFrom);
4008                if (ttoken != null) {
4009                    WindowState startingWindow = ttoken.startingWindow;
4010                    if (startingWindow != null) {
4011                        if (mStartingIconInTransition) {
4012                            // In this case, the starting icon has already
4013                            // been displayed, so start letting windows get
4014                            // shown immediately without any more transitions.
4015                            mSkipAppTransitionAnimation = true;
4016                        }
4017                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
4018                                "Moving existing starting from " + ttoken
4019                                + " to " + wtoken);
4020                        final long origId = Binder.clearCallingIdentity();
4021
4022                        // Transfer the starting window over to the new
4023                        // token.
4024                        wtoken.startingData = ttoken.startingData;
4025                        wtoken.startingView = ttoken.startingView;
4026                        wtoken.startingWindow = startingWindow;
4027                        ttoken.startingData = null;
4028                        ttoken.startingView = null;
4029                        ttoken.startingWindow = null;
4030                        ttoken.startingMoved = true;
4031                        startingWindow.mToken = wtoken;
4032                        startingWindow.mRootToken = wtoken;
4033                        startingWindow.mAppToken = wtoken;
4034                        if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
4035                                "Removing starting window: " + startingWindow);
4036                        mWindows.remove(startingWindow);
4037                        mWindowsChanged = true;
4038                        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing starting " + startingWindow
4039                                + " from " + ttoken);
4040                        ttoken.windows.remove(startingWindow);
4041                        ttoken.allAppWindows.remove(startingWindow);
4042                        addWindowToListInOrderLocked(startingWindow, true);
4043
4044                        // Propagate other interesting state between the
4045                        // tokens.  If the old token is displayed, we should
4046                        // immediately force the new one to be displayed.  If
4047                        // it is animating, we need to move that animation to
4048                        // the new one.
4049                        if (ttoken.allDrawn) {
4050                            wtoken.allDrawn = true;
4051                        }
4052                        if (ttoken.firstWindowDrawn) {
4053                            wtoken.firstWindowDrawn = true;
4054                        }
4055                        if (!ttoken.hidden) {
4056                            wtoken.hidden = false;
4057                            wtoken.hiddenRequested = false;
4058                            wtoken.willBeHidden = false;
4059                        }
4060                        if (wtoken.clientHidden != ttoken.clientHidden) {
4061                            wtoken.clientHidden = ttoken.clientHidden;
4062                            wtoken.sendAppVisibilityToClients();
4063                        }
4064                        final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator;
4065                        final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator;
4066                        if (tAppAnimator.animation != null) {
4067                            wAppAnimator.animation = tAppAnimator.animation;
4068                            wAppAnimator.animating = tAppAnimator.animating;
4069                            wAppAnimator.animLayerAdjustment = tAppAnimator.animLayerAdjustment;
4070                            tAppAnimator.animation = null;
4071                            tAppAnimator.animLayerAdjustment = 0;
4072                            wAppAnimator.updateLayers();
4073                            tAppAnimator.updateLayers();
4074                        }
4075
4076                        updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4077                                true /*updateInputWindows*/);
4078                        mLayoutNeeded = true;
4079                        performLayoutAndPlaceSurfacesLocked();
4080                        Binder.restoreCallingIdentity(origId);
4081                        return;
4082                    } else if (ttoken.startingData != null) {
4083                        // The previous app was getting ready to show a
4084                        // starting window, but hasn't yet done so.  Steal it!
4085                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
4086                                "Moving pending starting from " + ttoken
4087                                + " to " + wtoken);
4088                        wtoken.startingData = ttoken.startingData;
4089                        ttoken.startingData = null;
4090                        ttoken.startingMoved = true;
4091                        Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
4092                        // Note: we really want to do sendMessageAtFrontOfQueue() because we
4093                        // want to process the message ASAP, before any other queued
4094                        // messages.
4095                        mH.sendMessageAtFrontOfQueue(m);
4096                        return;
4097                    }
4098                    final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator;
4099                    final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator;
4100                    if (tAppAnimator.thumbnail != null) {
4101                        // The old token is animating with a thumbnail, transfer
4102                        // that to the new token.
4103                        if (wAppAnimator.thumbnail != null) {
4104                            wAppAnimator.thumbnail.destroy();
4105                        }
4106                        wAppAnimator.thumbnail = tAppAnimator.thumbnail;
4107                        wAppAnimator.thumbnailX = tAppAnimator.thumbnailX;
4108                        wAppAnimator.thumbnailY = tAppAnimator.thumbnailY;
4109                        wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
4110                        wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
4111                        tAppAnimator.thumbnail = null;
4112                    }
4113                }
4114            }
4115
4116            // There is no existing starting window, and the caller doesn't
4117            // want us to create one, so that's it!
4118            if (!createIfNeeded) {
4119                return;
4120            }
4121
4122            // If this is a translucent window, then don't
4123            // show a starting window -- the current effect (a full-screen
4124            // opaque starting window that fades away to the real contents
4125            // when it is ready) does not work for this.
4126            if (theme != 0) {
4127                AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
4128                        com.android.internal.R.styleable.Window);
4129                if (ent.array.getBoolean(
4130                        com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
4131                    return;
4132                }
4133                if (ent.array.getBoolean(
4134                        com.android.internal.R.styleable.Window_windowIsFloating, false)) {
4135                    return;
4136                }
4137                if (ent.array.getBoolean(
4138                        com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
4139                    if (mWallpaperTarget == null) {
4140                        // If this theme is requesting a wallpaper, and the wallpaper
4141                        // is not curently visible, then this effectively serves as
4142                        // an opaque window and our starting window transition animation
4143                        // can still work.  We just need to make sure the starting window
4144                        // is also showing the wallpaper.
4145                        windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
4146                    } else {
4147                        return;
4148                    }
4149                }
4150            }
4151
4152            mStartingIconInTransition = true;
4153            wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
4154                    labelRes, icon, windowFlags);
4155            Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
4156            // Note: we really want to do sendMessageAtFrontOfQueue() because we
4157            // want to process the message ASAP, before any other queued
4158            // messages.
4159            mH.sendMessageAtFrontOfQueue(m);
4160        }
4161    }
4162
4163    public void setAppWillBeHidden(IBinder token) {
4164        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4165                "setAppWillBeHidden()")) {
4166            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4167        }
4168
4169        AppWindowToken wtoken;
4170
4171        synchronized(mWindowMap) {
4172            wtoken = findAppWindowToken(token);
4173            if (wtoken == null) {
4174                Slog.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
4175                return;
4176            }
4177            wtoken.willBeHidden = true;
4178        }
4179    }
4180
4181    boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
4182            boolean visible, int transit, boolean performLayout) {
4183        boolean delayed = false;
4184
4185        if (wtoken.clientHidden == visible) {
4186            wtoken.clientHidden = !visible;
4187            wtoken.sendAppVisibilityToClients();
4188        }
4189
4190        wtoken.willBeHidden = false;
4191        if (wtoken.hidden == visible) {
4192            boolean changed = false;
4193            if (DEBUG_APP_TRANSITIONS) Slog.v(
4194                TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
4195                + " performLayout=" + performLayout);
4196
4197            boolean runningAppAnimation = false;
4198
4199            if (transit != WindowManagerPolicy.TRANSIT_UNSET) {
4200                if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
4201                    wtoken.mAppAnimator.animation = null;
4202                }
4203                if (applyAnimationLocked(wtoken, lp, transit, visible)) {
4204                    delayed = runningAppAnimation = true;
4205                }
4206                changed = true;
4207            }
4208
4209            final int N = wtoken.allAppWindows.size();
4210            for (int i=0; i<N; i++) {
4211                WindowState win = wtoken.allAppWindows.get(i);
4212                if (win == wtoken.startingWindow) {
4213                    continue;
4214                }
4215
4216                //Slog.i(TAG, "Window " + win + ": vis=" + win.isVisible());
4217                //win.dump("  ");
4218                if (visible) {
4219                    if (!win.isVisibleNow()) {
4220                        if (!runningAppAnimation) {
4221                            win.mWinAnimator.applyAnimationLocked(
4222                                    WindowManagerPolicy.TRANSIT_ENTER, true);
4223                        }
4224                        changed = true;
4225                    }
4226                } else if (win.isVisibleNow()) {
4227                    if (!runningAppAnimation) {
4228                        win.mWinAnimator.applyAnimationLocked(
4229                                WindowManagerPolicy.TRANSIT_EXIT, false);
4230                    }
4231                    changed = true;
4232                }
4233            }
4234
4235            wtoken.hidden = wtoken.hiddenRequested = !visible;
4236            if (!visible) {
4237                unsetAppFreezingScreenLocked(wtoken, true, true);
4238            } else {
4239                // If we are being set visible, and the starting window is
4240                // not yet displayed, then make sure it doesn't get displayed.
4241                WindowState swin = wtoken.startingWindow;
4242                if (swin != null && !swin.isDrawnLw()) {
4243                    swin.mPolicyVisibility = false;
4244                    swin.mPolicyVisibilityAfterAnim = false;
4245                 }
4246            }
4247
4248            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "setTokenVisibilityLocked: " + wtoken
4249                      + ": hidden=" + wtoken.hidden + " hiddenRequested="
4250                      + wtoken.hiddenRequested);
4251
4252            if (changed) {
4253                mLayoutNeeded = true;
4254                mInputMonitor.setUpdateInputWindowsNeededLw();
4255                if (performLayout) {
4256                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4257                            false /*updateInputWindows*/);
4258                    performLayoutAndPlaceSurfacesLocked();
4259                }
4260                mInputMonitor.updateInputWindowsLw(false /*force*/);
4261            }
4262        }
4263
4264        if (wtoken.mAppAnimator.animation != null) {
4265            delayed = true;
4266        }
4267
4268        for (int i = wtoken.allAppWindows.size() - 1; i >= 0 && !delayed; i--) {
4269            if (wtoken.allAppWindows.get(i).mWinAnimator.isWindowAnimating()) {
4270                delayed = true;
4271            }
4272        }
4273
4274        return delayed;
4275    }
4276
4277    public void setAppVisibility(IBinder token, boolean visible) {
4278        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4279                "setAppVisibility()")) {
4280            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4281        }
4282
4283        AppWindowToken wtoken;
4284
4285        synchronized(mWindowMap) {
4286            wtoken = findAppWindowToken(token);
4287            if (wtoken == null) {
4288                Slog.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
4289                return;
4290            }
4291
4292            if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
4293                RuntimeException e = null;
4294                if (!HIDE_STACK_CRAWLS) {
4295                    e = new RuntimeException();
4296                    e.fillInStackTrace();
4297                }
4298                Slog.v(TAG, "setAppVisibility(" + token + ", visible=" + visible
4299                        + "): mNextAppTransition=" + mNextAppTransition
4300                        + " hidden=" + wtoken.hidden
4301                        + " hiddenRequested=" + wtoken.hiddenRequested, e);
4302            }
4303
4304            // If we are preparing an app transition, then delay changing
4305            // the visibility of this token until we execute that transition.
4306            if (okToDisplay() && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4307                // Already in requested state, don't do anything more.
4308                if (wtoken.hiddenRequested != visible) {
4309                    return;
4310                }
4311                wtoken.hiddenRequested = !visible;
4312
4313                if (DEBUG_APP_TRANSITIONS) Slog.v(
4314                        TAG, "Setting dummy animation on: " + wtoken);
4315                cancelWindowAnimations(wtoken);
4316                wtoken.mAppAnimator.setDummyAnimation();
4317                mOpeningApps.remove(wtoken);
4318                mClosingApps.remove(wtoken);
4319                wtoken.waitingToShow = wtoken.waitingToHide = false;
4320                wtoken.inPendingTransaction = true;
4321                if (visible) {
4322                    mOpeningApps.add(wtoken);
4323                    wtoken.startingDisplayed = false;
4324                    wtoken.startingMoved = false;
4325
4326                    // If the token is currently hidden (should be the
4327                    // common case), then we need to set up to wait for
4328                    // its windows to be ready.
4329                    if (wtoken.hidden) {
4330                        wtoken.allDrawn = false;
4331                        wtoken.waitingToShow = true;
4332
4333                        if (wtoken.clientHidden) {
4334                            // In the case where we are making an app visible
4335                            // but holding off for a transition, we still need
4336                            // to tell the client to make its windows visible so
4337                            // they get drawn.  Otherwise, we will wait on
4338                            // performing the transition until all windows have
4339                            // been drawn, they never will be, and we are sad.
4340                            wtoken.clientHidden = false;
4341                            wtoken.sendAppVisibilityToClients();
4342                        }
4343                    }
4344                } else {
4345                    mClosingApps.add(wtoken);
4346
4347                    // If the token is currently visible (should be the
4348                    // common case), then set up to wait for it to be hidden.
4349                    if (!wtoken.hidden) {
4350                        wtoken.waitingToHide = true;
4351                    }
4352                }
4353                return;
4354            }
4355
4356            final long origId = Binder.clearCallingIdentity();
4357            setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET,
4358                    true);
4359            wtoken.updateReportedVisibilityLocked();
4360            Binder.restoreCallingIdentity(origId);
4361        }
4362    }
4363
4364    void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
4365            boolean unfreezeSurfaceNow, boolean force) {
4366        if (wtoken.mAppAnimator.freezingScreen) {
4367            if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + wtoken
4368                    + " force=" + force);
4369            final int N = wtoken.allAppWindows.size();
4370            boolean unfrozeWindows = false;
4371            for (int i=0; i<N; i++) {
4372                WindowState w = wtoken.allAppWindows.get(i);
4373                if (w.mAppFreezing) {
4374                    w.mAppFreezing = false;
4375                    if (w.mHasSurface && !w.mOrientationChanging) {
4376                        if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
4377                        w.mOrientationChanging = true;
4378                        mInnerFields.mOrientationChangeComplete = false;
4379                    }
4380                    unfrozeWindows = true;
4381                }
4382            }
4383            if (force || unfrozeWindows) {
4384                if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken);
4385                wtoken.mAppAnimator.freezingScreen = false;
4386                mAppsFreezingScreen--;
4387            }
4388            if (unfreezeSurfaceNow) {
4389                if (unfrozeWindows) {
4390                    mLayoutNeeded = true;
4391                    performLayoutAndPlaceSurfacesLocked();
4392                }
4393                stopFreezingDisplayLocked();
4394            }
4395        }
4396    }
4397
4398    public void startAppFreezingScreenLocked(AppWindowToken wtoken,
4399            int configChanges) {
4400        if (DEBUG_ORIENTATION) {
4401            RuntimeException e = null;
4402            if (!HIDE_STACK_CRAWLS) {
4403                e = new RuntimeException();
4404                e.fillInStackTrace();
4405            }
4406            Slog.i(TAG, "Set freezing of " + wtoken.appToken
4407                    + ": hidden=" + wtoken.hidden + " freezing="
4408                    + wtoken.mAppAnimator.freezingScreen, e);
4409        }
4410        if (!wtoken.hiddenRequested) {
4411            if (!wtoken.mAppAnimator.freezingScreen) {
4412                wtoken.mAppAnimator.freezingScreen = true;
4413                mAppsFreezingScreen++;
4414                if (mAppsFreezingScreen == 1) {
4415                    startFreezingDisplayLocked(false);
4416                    mH.removeMessages(H.APP_FREEZE_TIMEOUT);
4417                    mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT),
4418                            5000);
4419                }
4420            }
4421            final int N = wtoken.allAppWindows.size();
4422            for (int i=0; i<N; i++) {
4423                WindowState w = wtoken.allAppWindows.get(i);
4424                w.mAppFreezing = true;
4425            }
4426        }
4427    }
4428
4429    public void startAppFreezingScreen(IBinder token, int configChanges) {
4430        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4431                "setAppFreezingScreen()")) {
4432            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4433        }
4434
4435        synchronized(mWindowMap) {
4436            if (configChanges == 0 && okToDisplay()) {
4437                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping set freeze of " + token);
4438                return;
4439            }
4440
4441            AppWindowToken wtoken = findAppWindowToken(token);
4442            if (wtoken == null || wtoken.appToken == null) {
4443                Slog.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
4444                return;
4445            }
4446            final long origId = Binder.clearCallingIdentity();
4447            startAppFreezingScreenLocked(wtoken, configChanges);
4448            Binder.restoreCallingIdentity(origId);
4449        }
4450    }
4451
4452    public void stopAppFreezingScreen(IBinder token, boolean force) {
4453        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4454                "setAppFreezingScreen()")) {
4455            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4456        }
4457
4458        synchronized(mWindowMap) {
4459            AppWindowToken wtoken = findAppWindowToken(token);
4460            if (wtoken == null || wtoken.appToken == null) {
4461                return;
4462            }
4463            final long origId = Binder.clearCallingIdentity();
4464            if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + token
4465                    + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
4466            unsetAppFreezingScreenLocked(wtoken, true, force);
4467            Binder.restoreCallingIdentity(origId);
4468        }
4469    }
4470
4471    public void removeAppToken(IBinder token) {
4472        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4473                "removeAppToken()")) {
4474            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4475        }
4476
4477        AppWindowToken wtoken = null;
4478        AppWindowToken startingToken = null;
4479        boolean delayed = false;
4480
4481        final long origId = Binder.clearCallingIdentity();
4482        synchronized(mWindowMap) {
4483            WindowToken basewtoken = mTokenMap.remove(token);
4484            if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
4485                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
4486                delayed = setTokenVisibilityLocked(wtoken, null, false,
4487                        WindowManagerPolicy.TRANSIT_UNSET, true);
4488                wtoken.inPendingTransaction = false;
4489                mOpeningApps.remove(wtoken);
4490                wtoken.waitingToShow = false;
4491                if (mClosingApps.contains(wtoken)) {
4492                    delayed = true;
4493                } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4494                    mClosingApps.add(wtoken);
4495                    wtoken.waitingToHide = true;
4496                    delayed = true;
4497                }
4498                if (DEBUG_APP_TRANSITIONS) Slog.v(
4499                        TAG, "Removing app " + wtoken + " delayed=" + delayed
4500                        + " animation=" + wtoken.mAppAnimator.animation
4501                        + " animating=" + wtoken.mAppAnimator.animating);
4502                if (delayed) {
4503                    // set the token aside because it has an active animation to be finished
4504                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
4505                            "removeAppToken make exiting: " + wtoken);
4506                    mExitingAppTokens.add(wtoken);
4507                } else {
4508                    // Make sure there is no animation running on this token,
4509                    // so any windows associated with it will be removed as
4510                    // soon as their animations are complete
4511                    wtoken.mAppAnimator.clearAnimation();
4512                    wtoken.mAppAnimator.animating = false;
4513                }
4514                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
4515                        "removeAppToken: " + wtoken);
4516                mAppTokens.remove(wtoken);
4517                mAnimatingAppTokens.remove(wtoken);
4518                wtoken.removed = true;
4519                if (wtoken.startingData != null) {
4520                    startingToken = wtoken;
4521                }
4522                unsetAppFreezingScreenLocked(wtoken, true, true);
4523                if (mFocusedApp == wtoken) {
4524                    if (DEBUG_FOCUS) Slog.v(TAG, "Removing focused app token:" + wtoken);
4525                    mFocusedApp = null;
4526                    updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
4527                    mInputMonitor.setFocusedAppLw(null);
4528                }
4529            } else {
4530                Slog.w(TAG, "Attempted to remove non-existing app token: " + token);
4531            }
4532
4533            if (!delayed && wtoken != null) {
4534                wtoken.updateReportedVisibilityLocked();
4535            }
4536        }
4537        Binder.restoreCallingIdentity(origId);
4538
4539        if (startingToken != null) {
4540            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Schedule remove starting "
4541                    + startingToken + ": app token removed");
4542            Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
4543            mH.sendMessage(m);
4544        }
4545    }
4546
4547    private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
4548        final int NW = token.windows.size();
4549        if (NW > 0) {
4550            mWindowsChanged = true;
4551        }
4552        for (int i=0; i<NW; i++) {
4553            WindowState win = token.windows.get(i);
4554            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
4555            mWindows.remove(win);
4556            int j = win.mChildWindows.size();
4557            while (j > 0) {
4558                j--;
4559                WindowState cwin = win.mChildWindows.get(j);
4560                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
4561                        "Tmp removing child window " + cwin);
4562                mWindows.remove(cwin);
4563            }
4564        }
4565        return NW > 0;
4566    }
4567
4568    void dumpAppTokensLocked() {
4569        for (int i=mAppTokens.size()-1; i>=0; i--) {
4570            Slog.v(TAG, "  #" + i + ": " + mAppTokens.get(i).token);
4571        }
4572    }
4573
4574    void dumpAnimatingAppTokensLocked() {
4575        for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
4576            Slog.v(TAG, "  #" + i + ": " + mAnimatingAppTokens.get(i).token);
4577        }
4578    }
4579
4580    void dumpWindowsLocked() {
4581        for (int i=mWindows.size()-1; i>=0; i--) {
4582            Slog.v(TAG, "  #" + i + ": " + mWindows.get(i));
4583        }
4584    }
4585
4586    private int findWindowOffsetLocked(int tokenPos) {
4587        final int NW = mWindows.size();
4588
4589        if (tokenPos >= mAnimatingAppTokens.size()) {
4590            int i = NW;
4591            while (i > 0) {
4592                i--;
4593                WindowState win = mWindows.get(i);
4594                if (win.getAppToken() != null) {
4595                    return i+1;
4596                }
4597            }
4598        }
4599
4600        while (tokenPos > 0) {
4601            // Find the first app token below the new position that has
4602            // a window displayed.
4603            final AppWindowToken wtoken = mAnimatingAppTokens.get(tokenPos-1);
4604            if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ "
4605                    + tokenPos + " -- " + wtoken.token);
4606            if (wtoken.sendingToBottom) {
4607                if (DEBUG_REORDER) Slog.v(TAG,
4608                        "Skipping token -- currently sending to bottom");
4609                tokenPos--;
4610                continue;
4611            }
4612            int i = wtoken.windows.size();
4613            while (i > 0) {
4614                i--;
4615                WindowState win = wtoken.windows.get(i);
4616                int j = win.mChildWindows.size();
4617                while (j > 0) {
4618                    j--;
4619                    WindowState cwin = win.mChildWindows.get(j);
4620                    if (cwin.mSubLayer >= 0) {
4621                        for (int pos=NW-1; pos>=0; pos--) {
4622                            if (mWindows.get(pos) == cwin) {
4623                                if (DEBUG_REORDER) Slog.v(TAG,
4624                                        "Found child win @" + (pos+1));
4625                                return pos+1;
4626                            }
4627                        }
4628                    }
4629                }
4630                for (int pos=NW-1; pos>=0; pos--) {
4631                    if (mWindows.get(pos) == win) {
4632                        if (DEBUG_REORDER) Slog.v(TAG, "Found win @" + (pos+1));
4633                        return pos+1;
4634                    }
4635                }
4636            }
4637            tokenPos--;
4638        }
4639
4640        return 0;
4641    }
4642
4643    private final int reAddWindowLocked(int index, WindowState win) {
4644        final int NCW = win.mChildWindows.size();
4645        boolean added = false;
4646        for (int j=0; j<NCW; j++) {
4647            WindowState cwin = win.mChildWindows.get(j);
4648            if (!added && cwin.mSubLayer >= 0) {
4649                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding child window at "
4650                        + index + ": " + cwin);
4651                win.mRebuilding = false;
4652                mWindows.add(index, win);
4653                index++;
4654                added = true;
4655            }
4656            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
4657                    + index + ": " + cwin);
4658            cwin.mRebuilding = false;
4659            mWindows.add(index, cwin);
4660            index++;
4661        }
4662        if (!added) {
4663            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
4664                    + index + ": " + win);
4665            win.mRebuilding = false;
4666            mWindows.add(index, win);
4667            index++;
4668        }
4669        mWindowsChanged = true;
4670        return index;
4671    }
4672
4673    private final int reAddAppWindowsLocked(int index, WindowToken token) {
4674        final int NW = token.windows.size();
4675        for (int i=0; i<NW; i++) {
4676            index = reAddWindowLocked(index, token.windows.get(i));
4677        }
4678        return index;
4679    }
4680
4681    public void moveAppToken(int index, IBinder token) {
4682        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4683                "moveAppToken()")) {
4684            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4685        }
4686
4687        synchronized(mWindowMap) {
4688            if (DEBUG_REORDER) Slog.v(TAG, "Initial app tokens:");
4689            if (DEBUG_REORDER) dumpAppTokensLocked();
4690            final AppWindowToken wtoken = findAppWindowToken(token);
4691            final int oldIndex = mAppTokens.indexOf(wtoken);
4692            if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
4693                    "Start moving token " + wtoken + " initially at "
4694                    + oldIndex);
4695            if (oldIndex > index && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET
4696                        && !mAppTransitionRunning) {
4697                // animation towards back has not started, copy old list for duration of animation.
4698                mAnimatingAppTokens.clear();
4699                mAnimatingAppTokens.addAll(mAppTokens);
4700            }
4701            if (wtoken == null || !mAppTokens.remove(wtoken)) {
4702                Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
4703                      + token + " (" + wtoken + ")");
4704                return;
4705            }
4706            mAppTokens.add(index, wtoken);
4707            if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":");
4708            else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index);
4709            if (DEBUG_REORDER) dumpAppTokensLocked();
4710            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET && !mAppTransitionRunning) {
4711                // Not animating, bring animating app list in line with mAppTokens.
4712                mAnimatingAppTokens.clear();
4713                mAnimatingAppTokens.addAll(mAppTokens);
4714
4715                // Bring window ordering, window focus and input window in line with new app token
4716                final long origId = Binder.clearCallingIdentity();
4717                if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":");
4718                if (DEBUG_REORDER) dumpWindowsLocked();
4719                if (tmpRemoveAppWindowsLocked(wtoken)) {
4720                    if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:");
4721                    if (DEBUG_REORDER) dumpWindowsLocked();
4722                    reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
4723                    if (DEBUG_REORDER) Slog.v(TAG, "Final window list:");
4724                    if (DEBUG_REORDER) dumpWindowsLocked();
4725                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4726                            false /*updateInputWindows*/);
4727                    mLayoutNeeded = true;
4728                    mInputMonitor.setUpdateInputWindowsNeededLw();
4729                    performLayoutAndPlaceSurfacesLocked();
4730                    mInputMonitor.updateInputWindowsLw(false /*force*/);
4731                }
4732                Binder.restoreCallingIdentity(origId);
4733            }
4734        }
4735    }
4736
4737    private void removeAppTokensLocked(List<IBinder> tokens) {
4738        // XXX This should be done more efficiently!
4739        // (take advantage of the fact that both lists should be
4740        // ordered in the same way.)
4741        int N = tokens.size();
4742        for (int i=0; i<N; i++) {
4743            IBinder token = tokens.get(i);
4744            final AppWindowToken wtoken = findAppWindowToken(token);
4745            if (DEBUG_REORDER || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
4746                    "Temporarily removing " + wtoken + " from " + mAppTokens.indexOf(wtoken));
4747            if (!mAppTokens.remove(wtoken)) {
4748                Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
4749                      + token + " (" + wtoken + ")");
4750                i--;
4751                N--;
4752            }
4753        }
4754    }
4755
4756    private void moveAppWindowsLocked(AppWindowToken wtoken, int tokenPos,
4757            boolean updateFocusAndLayout) {
4758        // First remove all of the windows from the list.
4759        tmpRemoveAppWindowsLocked(wtoken);
4760
4761        // Where to start adding?
4762        int pos = findWindowOffsetLocked(tokenPos);
4763
4764        // And now add them back at the correct place.
4765        pos = reAddAppWindowsLocked(pos, wtoken);
4766
4767        if (updateFocusAndLayout) {
4768            mInputMonitor.setUpdateInputWindowsNeededLw();
4769            if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4770                    false /*updateInputWindows*/)) {
4771                assignLayersLocked();
4772            }
4773            mLayoutNeeded = true;
4774            if (!mInLayout) {
4775                performLayoutAndPlaceSurfacesLocked();
4776            }
4777            mInputMonitor.updateInputWindowsLw(false /*force*/);
4778        }
4779    }
4780
4781    private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
4782        // First remove all of the windows from the list.
4783        final int N = tokens.size();
4784        int i;
4785        for (i=0; i<N; i++) {
4786            WindowToken token = mTokenMap.get(tokens.get(i));
4787            if (token != null) {
4788                tmpRemoveAppWindowsLocked(token);
4789            }
4790        }
4791
4792        // Where to start adding?
4793        int pos = findWindowOffsetLocked(tokenPos);
4794
4795        // And now add them back at the correct place.
4796        for (i=0; i<N; i++) {
4797            WindowToken token = mTokenMap.get(tokens.get(i));
4798            if (token != null) {
4799                pos = reAddAppWindowsLocked(pos, token);
4800            }
4801        }
4802
4803        mInputMonitor.setUpdateInputWindowsNeededLw();
4804        if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4805                false /*updateInputWindows*/)) {
4806            assignLayersLocked();
4807        }
4808        mLayoutNeeded = true;
4809        performLayoutAndPlaceSurfacesLocked();
4810        mInputMonitor.updateInputWindowsLw(false /*force*/);
4811
4812        //dump();
4813    }
4814
4815    public void moveAppTokensToTop(List<IBinder> tokens) {
4816        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4817                "moveAppTokensToTop()")) {
4818            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4819        }
4820
4821        final long origId = Binder.clearCallingIdentity();
4822        synchronized(mWindowMap) {
4823            removeAppTokensLocked(tokens);
4824            final int N = tokens.size();
4825            for (int i=0; i<N; i++) {
4826                AppWindowToken wt = findAppWindowToken(tokens.get(i));
4827                if (wt != null) {
4828                    if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
4829                            "Adding next to top: " + wt);
4830                    mAppTokens.add(wt);
4831                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4832                        wt.sendingToBottom = false;
4833                    }
4834                }
4835            }
4836
4837            if (!mAppTransitionRunning) {
4838                mAnimatingAppTokens.clear();
4839                mAnimatingAppTokens.addAll(mAppTokens);
4840                moveAppWindowsLocked(tokens, mAppTokens.size());
4841            }
4842        }
4843        Binder.restoreCallingIdentity(origId);
4844    }
4845
4846    @Override
4847    public void moveAppTokensToBottom(List<IBinder> tokens) {
4848        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4849                "moveAppTokensToBottom()")) {
4850            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4851        }
4852
4853        final long origId = Binder.clearCallingIdentity();
4854        synchronized(mWindowMap) {
4855            final int N = tokens.size();
4856            if (N > 0 && !mAppTransitionRunning) {
4857                // animating towards back, hang onto old list for duration of animation.
4858                mAnimatingAppTokens.clear();
4859                mAnimatingAppTokens.addAll(mAppTokens);
4860            }
4861            removeAppTokensLocked(tokens);
4862            int pos = 0;
4863            for (int i=0; i<N; i++) {
4864                AppWindowToken wt = findAppWindowToken(tokens.get(i));
4865                if (wt != null) {
4866                    if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
4867                            "Adding next to bottom: " + wt + " at " + pos);
4868                    mAppTokens.add(pos, wt);
4869                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4870                        wt.sendingToBottom = true;
4871                    }
4872                    pos++;
4873                }
4874            }
4875
4876            if (!mAppTransitionRunning) {
4877                mAnimatingAppTokens.clear();
4878                mAnimatingAppTokens.addAll(mAppTokens);
4879                moveAppWindowsLocked(tokens, 0);
4880            }
4881        }
4882        Binder.restoreCallingIdentity(origId);
4883    }
4884
4885    // -------------------------------------------------------------
4886    // Misc IWindowSession methods
4887    // -------------------------------------------------------------
4888
4889    private boolean shouldAllowDisableKeyguard()
4890    {
4891        // We fail safe and prevent disabling keyguard in the unlikely event this gets
4892        // called before DevicePolicyManagerService has started.
4893        if (mAllowDisableKeyguard == ALLOW_DISABLE_UNKNOWN) {
4894            DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
4895                    Context.DEVICE_POLICY_SERVICE);
4896            if (dpm != null) {
4897                mAllowDisableKeyguard = dpm.getPasswordQuality(null)
4898                        == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ?
4899                                ALLOW_DISABLE_YES : ALLOW_DISABLE_NO;
4900            }
4901        }
4902        return mAllowDisableKeyguard == ALLOW_DISABLE_YES;
4903    }
4904
4905    public void disableKeyguard(IBinder token, String tag) {
4906        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
4907            != PackageManager.PERMISSION_GRANTED) {
4908            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
4909        }
4910
4911        synchronized (mKeyguardTokenWatcher) {
4912            mKeyguardTokenWatcher.acquire(token, tag);
4913        }
4914    }
4915
4916    public void reenableKeyguard(IBinder token) {
4917        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
4918            != PackageManager.PERMISSION_GRANTED) {
4919            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
4920        }
4921
4922        synchronized (mKeyguardTokenWatcher) {
4923            mKeyguardTokenWatcher.release(token);
4924
4925            if (!mKeyguardTokenWatcher.isAcquired()) {
4926                // If we are the last one to reenable the keyguard wait until
4927                // we have actually finished reenabling until returning.
4928                // It is possible that reenableKeyguard() can be called before
4929                // the previous disableKeyguard() is handled, in which case
4930                // neither mKeyguardTokenWatcher.acquired() or released() would
4931                // be called. In that case mKeyguardDisabled will be false here
4932                // and we have nothing to wait for.
4933                while (mKeyguardDisabled) {
4934                    try {
4935                        mKeyguardTokenWatcher.wait();
4936                    } catch (InterruptedException e) {
4937                        Thread.currentThread().interrupt();
4938                    }
4939                }
4940            }
4941        }
4942    }
4943
4944    /**
4945     * @see android.app.KeyguardManager#exitKeyguardSecurely
4946     */
4947    public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
4948        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
4949            != PackageManager.PERMISSION_GRANTED) {
4950            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
4951        }
4952        mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
4953            public void onKeyguardExitResult(boolean success) {
4954                try {
4955                    callback.onKeyguardExitResult(success);
4956                } catch (RemoteException e) {
4957                    // Client has died, we don't care.
4958                }
4959            }
4960        });
4961    }
4962
4963    public boolean inKeyguardRestrictedInputMode() {
4964        return mPolicy.inKeyguardRestrictedKeyInputMode();
4965    }
4966
4967    public boolean isKeyguardLocked() {
4968        return mPolicy.isKeyguardLocked();
4969    }
4970
4971    public boolean isKeyguardSecure() {
4972        return mPolicy.isKeyguardSecure();
4973    }
4974
4975    public void dismissKeyguard() {
4976        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
4977                != PackageManager.PERMISSION_GRANTED) {
4978            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
4979        }
4980        synchronized(mWindowMap) {
4981            mPolicy.dismissKeyguardLw();
4982        }
4983    }
4984
4985    public void closeSystemDialogs(String reason) {
4986        synchronized(mWindowMap) {
4987            for (int i=mWindows.size()-1; i>=0; i--) {
4988                WindowState w = mWindows.get(i);
4989                if (w.mHasSurface) {
4990                    try {
4991                        w.mClient.closeSystemDialogs(reason);
4992                    } catch (RemoteException e) {
4993                    }
4994                }
4995            }
4996        }
4997    }
4998
4999    static float fixScale(float scale) {
5000        if (scale < 0) scale = 0;
5001        else if (scale > 20) scale = 20;
5002        return Math.abs(scale);
5003    }
5004
5005    public void setAnimationScale(int which, float scale) {
5006        if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
5007                "setAnimationScale()")) {
5008            throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
5009        }
5010
5011        if (scale < 0) scale = 0;
5012        else if (scale > 20) scale = 20;
5013        scale = Math.abs(scale);
5014        switch (which) {
5015            case 0: mWindowAnimationScale = fixScale(scale); break;
5016            case 1: mTransitionAnimationScale = fixScale(scale); break;
5017            case 2: mAnimatorDurationScale = fixScale(scale); break;
5018        }
5019
5020        // Persist setting
5021        mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
5022    }
5023
5024    public void setAnimationScales(float[] scales) {
5025        if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
5026                "setAnimationScale()")) {
5027            throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
5028        }
5029
5030        if (scales != null) {
5031            if (scales.length >= 1) {
5032                mWindowAnimationScale = fixScale(scales[0]);
5033            }
5034            if (scales.length >= 2) {
5035                mTransitionAnimationScale = fixScale(scales[1]);
5036            }
5037            if (scales.length >= 3) {
5038                mAnimatorDurationScale = fixScale(scales[2]);
5039            }
5040        }
5041
5042        // Persist setting
5043        mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
5044    }
5045
5046    public float getAnimationScale(int which) {
5047        switch (which) {
5048            case 0: return mWindowAnimationScale;
5049            case 1: return mTransitionAnimationScale;
5050            case 2: return mAnimatorDurationScale;
5051        }
5052        return 0;
5053    }
5054
5055    public float[] getAnimationScales() {
5056        return new float[] { mWindowAnimationScale, mTransitionAnimationScale,
5057                mAnimatorDurationScale };
5058    }
5059
5060    // Called by window manager policy. Not exposed externally.
5061    @Override
5062    public int getLidState() {
5063        int sw = mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY,
5064                InputManagerService.SW_LID);
5065        if (sw > 0) {
5066            // Switch state: AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL.
5067            return LID_CLOSED;
5068        } else if (sw == 0) {
5069            // Switch state: AKEY_STATE_UP.
5070            return LID_OPEN;
5071        } else {
5072            // Switch state: AKEY_STATE_UNKNOWN.
5073            return LID_ABSENT;
5074        }
5075    }
5076
5077    // Called by window manager policy.  Not exposed externally.
5078    @Override
5079    public InputChannel monitorInput(String inputChannelName) {
5080        return mInputManager.monitorInput(inputChannelName);
5081    }
5082
5083    // Called by window manager policy.  Not exposed externally.
5084    @Override
5085    public void switchKeyboardLayout(int deviceId, int direction) {
5086        mInputManager.switchKeyboardLayout(deviceId, direction);
5087    }
5088
5089    // Called by window manager policy.  Not exposed externally.
5090    @Override
5091    public void shutdown() {
5092        ShutdownThread.shutdown(mContext, true);
5093    }
5094
5095    // Called by window manager policy.  Not exposed externally.
5096    @Override
5097    public void rebootSafeMode() {
5098        ShutdownThread.rebootSafeMode(mContext, true);
5099    }
5100
5101    public void setInputFilter(InputFilter filter) {
5102        mInputManager.setInputFilter(filter);
5103    }
5104
5105    public void enableScreenAfterBoot() {
5106        synchronized(mWindowMap) {
5107            if (DEBUG_BOOT) {
5108                RuntimeException here = new RuntimeException("here");
5109                here.fillInStackTrace();
5110                Slog.i(TAG, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled
5111                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5112                        + " mShowingBootMessages=" + mShowingBootMessages
5113                        + " mSystemBooted=" + mSystemBooted, here);
5114            }
5115            if (mSystemBooted) {
5116                return;
5117            }
5118            mSystemBooted = true;
5119            hideBootMessagesLocked();
5120            // If the screen still doesn't come up after 30 seconds, give
5121            // up and turn it on.
5122            Message msg = mH.obtainMessage(H.BOOT_TIMEOUT);
5123            mH.sendMessageDelayed(msg, 30*1000);
5124        }
5125
5126        mPolicy.systemBooted();
5127
5128        performEnableScreen();
5129    }
5130
5131    void enableScreenIfNeededLocked() {
5132        if (DEBUG_BOOT) {
5133            RuntimeException here = new RuntimeException("here");
5134            here.fillInStackTrace();
5135            Slog.i(TAG, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled
5136                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5137                    + " mShowingBootMessages=" + mShowingBootMessages
5138                    + " mSystemBooted=" + mSystemBooted, here);
5139        }
5140        if (mDisplayEnabled) {
5141            return;
5142        }
5143        if (!mSystemBooted && !mShowingBootMessages) {
5144            return;
5145        }
5146        mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
5147    }
5148
5149    public void performBootTimeout() {
5150        synchronized(mWindowMap) {
5151            if (mDisplayEnabled || mHeadless) {
5152                return;
5153            }
5154            Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
5155            mForceDisplayEnabled = true;
5156        }
5157        performEnableScreen();
5158    }
5159
5160    public void performEnableScreen() {
5161        synchronized(mWindowMap) {
5162            if (DEBUG_BOOT) {
5163                RuntimeException here = new RuntimeException("here");
5164                here.fillInStackTrace();
5165                Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
5166                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5167                        + " mShowingBootMessages=" + mShowingBootMessages
5168                        + " mSystemBooted=" + mSystemBooted, here);
5169            }
5170            if (mDisplayEnabled) {
5171                return;
5172            }
5173            if (!mSystemBooted && !mShowingBootMessages) {
5174                return;
5175            }
5176
5177            if (!mForceDisplayEnabled) {
5178                // Don't enable the screen until all existing windows
5179                // have been drawn.
5180                boolean haveBootMsg = false;
5181                boolean haveApp = false;
5182                // if the wallpaper service is disabled on the device, we're never going to have
5183                // wallpaper, don't bother waiting for it
5184                boolean haveWallpaper = false;
5185                boolean wallpaperEnabled = mContext.getResources().getBoolean(
5186                        com.android.internal.R.bool.config_enableWallpaperService);
5187                boolean haveKeyguard = true;
5188                final int N = mWindows.size();
5189                for (int i=0; i<N; i++) {
5190                    WindowState w = mWindows.get(i);
5191                    if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) {
5192                        // Only if there is a keyguard attached to the window manager
5193                        // will we consider ourselves as having a keyguard.  If it
5194                        // isn't attached, we don't know if it wants to be shown or
5195                        // hidden.  If it is attached, we will say we have a keyguard
5196                        // if the window doesn't want to be visible, because in that
5197                        // case it explicitly doesn't want to be shown so we should
5198                        // not delay turning the screen on for it.
5199                        boolean vis = w.mViewVisibility == View.VISIBLE
5200                                && w.mPolicyVisibility;
5201                        haveKeyguard = !vis;
5202                    }
5203                    if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
5204                        return;
5205                    }
5206                    if (w.isDrawnLw()) {
5207                        if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
5208                            haveBootMsg = true;
5209                        } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) {
5210                            haveApp = true;
5211                        } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) {
5212                            haveWallpaper = true;
5213                        } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) {
5214                            haveKeyguard = true;
5215                        }
5216                    }
5217                }
5218
5219                if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
5220                    Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
5221                            + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
5222                            + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
5223                            + " haveKeyguard=" + haveKeyguard);
5224                }
5225
5226                // If we are turning on the screen to show the boot message,
5227                // don't do it until the boot message is actually displayed.
5228                if (!mSystemBooted && !haveBootMsg) {
5229                    return;
5230                }
5231
5232                // If we are turning on the screen after the boot is completed
5233                // normally, don't do so until we have the application and
5234                // wallpaper.
5235                if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
5236                        (wallpaperEnabled && !haveWallpaper))) {
5237                    return;
5238                }
5239            }
5240
5241            mDisplayEnabled = true;
5242            if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
5243            if (false) {
5244                StringWriter sw = new StringWriter();
5245                PrintWriter pw = new PrintWriter(sw);
5246                this.dump(null, pw, null);
5247                Slog.i(TAG, sw.toString());
5248            }
5249            try {
5250                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
5251                if (surfaceFlinger != null) {
5252                    //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
5253                    Parcel data = Parcel.obtain();
5254                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
5255                    surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
5256                                            data, null, 0);
5257                    data.recycle();
5258                }
5259            } catch (RemoteException ex) {
5260                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
5261            }
5262        }
5263
5264        mPolicy.enableScreenAfterBoot();
5265
5266        // Make sure the last requested orientation has been applied.
5267        updateRotationUnchecked(false, false);
5268    }
5269
5270    public void showBootMessage(final CharSequence msg, final boolean always) {
5271        boolean first = false;
5272        synchronized(mWindowMap) {
5273            if (DEBUG_BOOT) {
5274                RuntimeException here = new RuntimeException("here");
5275                here.fillInStackTrace();
5276                Slog.i(TAG, "showBootMessage: msg=" + msg + " always=" + always
5277                        + " mAllowBootMessages=" + mAllowBootMessages
5278                        + " mShowingBootMessages=" + mShowingBootMessages
5279                        + " mSystemBooted=" + mSystemBooted, here);
5280            }
5281            if (!mAllowBootMessages) {
5282                return;
5283            }
5284            if (!mShowingBootMessages) {
5285                if (!always) {
5286                    return;
5287                }
5288                first = true;
5289            }
5290            if (mSystemBooted) {
5291                return;
5292            }
5293            mShowingBootMessages = true;
5294            mPolicy.showBootMessage(msg, always);
5295        }
5296        if (first) {
5297            performEnableScreen();
5298        }
5299    }
5300
5301    public void hideBootMessagesLocked() {
5302        if (DEBUG_BOOT) {
5303            RuntimeException here = new RuntimeException("here");
5304            here.fillInStackTrace();
5305            Slog.i(TAG, "hideBootMessagesLocked: mDisplayEnabled=" + mDisplayEnabled
5306                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5307                    + " mShowingBootMessages=" + mShowingBootMessages
5308                    + " mSystemBooted=" + mSystemBooted, here);
5309        }
5310        if (mShowingBootMessages) {
5311            mShowingBootMessages = false;
5312            mPolicy.hideBootMessages();
5313        }
5314    }
5315
5316    public void setInTouchMode(boolean mode) {
5317        synchronized(mWindowMap) {
5318            mInTouchMode = mode;
5319        }
5320    }
5321
5322    // TODO: more accounting of which pid(s) turned it on, keep count,
5323    // only allow disables from pids which have count on, etc.
5324    @Override
5325    public void showStrictModeViolation(boolean on) {
5326        if (mHeadless) return;
5327        mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, 0));
5328    }
5329
5330    private void showStrictModeViolation(int arg) {
5331        final boolean on = arg != 0;
5332        int pid = Binder.getCallingPid();
5333        synchronized(mWindowMap) {
5334            // Ignoring requests to enable the red border from clients
5335            // which aren't on screen.  (e.g. Broadcast Receivers in
5336            // the background..)
5337            if (on) {
5338                boolean isVisible = false;
5339                for (int i = mWindows.size() - 1; i >= 0; i--) {
5340                    final WindowState ws = mWindows.get(i);
5341                    if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
5342                        isVisible = true;
5343                        break;
5344                    }
5345                }
5346                if (!isVisible) {
5347                    return;
5348                }
5349            }
5350
5351            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5352                    ">>> OPEN TRANSACTION showStrictModeViolation");
5353            Surface.openTransaction();
5354            try {
5355                if (mStrictModeFlash == null) {
5356                    mStrictModeFlash = new StrictModeFlash(mDisplay, mFxSession);
5357                }
5358                mStrictModeFlash.setVisibility(on);
5359            } finally {
5360                Surface.closeTransaction();
5361                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5362                        "<<< CLOSE TRANSACTION showStrictModeViolation");
5363            }
5364        }
5365    }
5366
5367    public void setStrictModeVisualIndicatorPreference(String value) {
5368        SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
5369    }
5370
5371    /**
5372     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
5373     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
5374     * of the target image.
5375     *
5376     * @param width the width of the target bitmap
5377     * @param height the height of the target bitmap
5378     */
5379    public Bitmap screenshotApplications(IBinder appToken, int width, int height) {
5380        if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
5381                "screenshotApplications()")) {
5382            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
5383        }
5384
5385        Bitmap rawss;
5386
5387        int maxLayer = 0;
5388        final Rect frame = new Rect();
5389
5390        float scale;
5391        int dw, dh;
5392        int rot;
5393
5394        synchronized(mWindowMap) {
5395            long ident = Binder.clearCallingIdentity();
5396
5397            dw = mCurDisplayWidth;
5398            dh = mCurDisplayHeight;
5399
5400            int aboveAppLayer = mPolicy.windowTypeToLayerLw(
5401                    WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER
5402                    + TYPE_LAYER_OFFSET;
5403            aboveAppLayer += TYPE_LAYER_MULTIPLIER;
5404
5405            boolean isImeTarget = mInputMethodTarget != null
5406                    && mInputMethodTarget.mAppToken != null
5407                    && mInputMethodTarget.mAppToken.appToken != null
5408                    && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
5409
5410            // Figure out the part of the screen that is actually the app.
5411            boolean including = false;
5412            for (int i=mWindows.size()-1; i>=0; i--) {
5413                WindowState ws = mWindows.get(i);
5414                if (!ws.mHasSurface) {
5415                    continue;
5416                }
5417                if (ws.mLayer >= aboveAppLayer) {
5418                    continue;
5419                }
5420                // When we will skip windows: when we are not including
5421                // ones behind a window we didn't skip, and we are actually
5422                // taking a screenshot of a specific app.
5423                if (!including && appToken != null) {
5424                    // Also, we can possibly skip this window if it is not
5425                    // an IME target or the application for the screenshot
5426                    // is not the current IME target.
5427                    if (!ws.mIsImWindow || !isImeTarget) {
5428                        // And finally, this window is of no interest if it
5429                        // is not associated with the screenshot app.
5430                        if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
5431                            continue;
5432                        }
5433                    }
5434                }
5435
5436                // We keep on including windows until we go past a full-screen
5437                // window.
5438                including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
5439
5440                if (maxLayer < ws.mWinAnimator.mAnimLayer) {
5441                    maxLayer = ws.mWinAnimator.mAnimLayer;
5442                }
5443
5444                // Don't include wallpaper in bounds calculation
5445                if (!ws.mIsWallpaper) {
5446                    final Rect wf = ws.mFrame;
5447                    final Rect cr = ws.mContentInsets;
5448                    int left = wf.left + cr.left;
5449                    int top = wf.top + cr.top;
5450                    int right = wf.right - cr.right;
5451                    int bottom = wf.bottom - cr.bottom;
5452                    frame.union(left, top, right, bottom);
5453                }
5454            }
5455            Binder.restoreCallingIdentity(ident);
5456
5457            // Constrain frame to the screen size.
5458            frame.intersect(0, 0, dw, dh);
5459
5460            if (frame.isEmpty() || maxLayer == 0) {
5461                return null;
5462            }
5463
5464            // The screenshot API does not apply the current screen rotation.
5465            rot = mDisplay.getRotation();
5466            int fw = frame.width();
5467            int fh = frame.height();
5468
5469            // Constrain thumbnail to smaller of screen width or height. Assumes aspect
5470            // of thumbnail is the same as the screen (in landscape) or square.
5471            float targetWidthScale = width / (float) fw;
5472            float targetHeightScale = height / (float) fh;
5473            if (dw <= dh) {
5474                scale = targetWidthScale;
5475                // If aspect of thumbnail is the same as the screen (in landscape),
5476                // select the slightly larger value so we fill the entire bitmap
5477                if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
5478                    scale = targetHeightScale;
5479                }
5480            } else {
5481                scale = targetHeightScale;
5482                // If aspect of thumbnail is the same as the screen (in landscape),
5483                // select the slightly larger value so we fill the entire bitmap
5484                if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
5485                    scale = targetWidthScale;
5486                }
5487            }
5488
5489            // The screen shot will contain the entire screen.
5490            dw = (int)(dw*scale);
5491            dh = (int)(dh*scale);
5492            if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
5493                int tmp = dw;
5494                dw = dh;
5495                dh = tmp;
5496                rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
5497            }
5498            if (DEBUG_SCREENSHOT) {
5499                Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from 0 to " + maxLayer);
5500                for (int i=0; i<mWindows.size(); i++) {
5501                    Slog.i(TAG, mWindows.get(i) + ": " + mWindows.get(i).mLayer
5502                            + " animLayer=" + mWindows.get(i).mWinAnimator.mAnimLayer
5503                            + " surfaceLayer=" + mWindows.get(i).mWinAnimator.mSurfaceLayer);
5504                }
5505            }
5506            rawss = Surface.screenshot(dw, dh, 0, maxLayer);
5507        }
5508
5509        if (rawss == null) {
5510            Slog.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh
5511                    + ") to layer " + maxLayer);
5512            return null;
5513        }
5514
5515        Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
5516        Matrix matrix = new Matrix();
5517        ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
5518        matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
5519        Canvas canvas = new Canvas(bm);
5520        canvas.drawBitmap(rawss, matrix, null);
5521        canvas.setBitmap(null);
5522
5523        rawss.recycle();
5524        return bm;
5525    }
5526
5527    /**
5528     * Freeze rotation changes.  (Enable "rotation lock".)
5529     * Persists across reboots.
5530     * @param rotation The desired rotation to freeze to, or -1 to use the
5531     * current rotation.
5532     */
5533    public void freezeRotation(int rotation) {
5534        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5535                "freezeRotation()")) {
5536            throw new SecurityException("Requires SET_ORIENTATION permission");
5537        }
5538        if (rotation < -1 || rotation > Surface.ROTATION_270) {
5539            throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
5540                    + "rotation constant.");
5541        }
5542
5543        if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
5544
5545        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
5546                rotation == -1 ? mRotation : rotation);
5547        updateRotationUnchecked(false, false);
5548    }
5549
5550    /**
5551     * Thaw rotation changes.  (Disable "rotation lock".)
5552     * Persists across reboots.
5553     */
5554    public void thawRotation() {
5555        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5556                "thawRotation()")) {
5557            throw new SecurityException("Requires SET_ORIENTATION permission");
5558        }
5559
5560        if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
5561
5562        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used
5563        updateRotationUnchecked(false, false);
5564    }
5565
5566    /**
5567     * Recalculate the current rotation.
5568     *
5569     * Called by the window manager policy whenever the state of the system changes
5570     * such that the current rotation might need to be updated, such as when the
5571     * device is docked or rotated into a new posture.
5572     */
5573    public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
5574        updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
5575    }
5576
5577    /**
5578     * Temporarily pauses rotation changes until resumed.
5579     *
5580     * This can be used to prevent rotation changes from occurring while the user is
5581     * performing certain operations, such as drag and drop.
5582     *
5583     * This call nests and must be matched by an equal number of calls to {@link #resumeRotation}.
5584     */
5585    void pauseRotationLocked() {
5586        mDeferredRotationPauseCount += 1;
5587    }
5588
5589    /**
5590     * Resumes normal rotation changes after being paused.
5591     */
5592    void resumeRotationLocked() {
5593        if (mDeferredRotationPauseCount > 0) {
5594            mDeferredRotationPauseCount -= 1;
5595            if (mDeferredRotationPauseCount == 0) {
5596                boolean changed = updateRotationUncheckedLocked(false);
5597                if (changed) {
5598                    mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
5599                }
5600            }
5601        }
5602    }
5603
5604    public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
5605        if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked("
5606                   + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")");
5607
5608        long origId = Binder.clearCallingIdentity();
5609        boolean changed;
5610        synchronized(mWindowMap) {
5611            changed = updateRotationUncheckedLocked(false);
5612            if (!changed || forceRelayout) {
5613                mLayoutNeeded = true;
5614                performLayoutAndPlaceSurfacesLocked();
5615            }
5616        }
5617
5618        if (changed || alwaysSendConfiguration) {
5619            sendNewConfiguration();
5620        }
5621
5622        Binder.restoreCallingIdentity(origId);
5623    }
5624
5625    /**
5626     * Updates the current rotation.
5627     *
5628     * Returns true if the rotation has been changed.  In this case YOU
5629     * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN.
5630     */
5631    public boolean updateRotationUncheckedLocked(boolean inTransaction) {
5632        if (mDeferredRotationPauseCount > 0) {
5633            // Rotation updates have been paused temporarily.  Defer the update until
5634            // updates have been resumed.
5635            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused.");
5636            return false;
5637        }
5638
5639        if (mAnimator.mScreenRotationAnimation != null &&
5640                mAnimator.mScreenRotationAnimation.isAnimating()) {
5641            // Rotation updates cannot be performed while the previous rotation change
5642            // animation is still in progress.  Skip this update.  We will try updating
5643            // again after the animation is finished and the display is unfrozen.
5644            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress.");
5645            return false;
5646        }
5647
5648        if (!mDisplayEnabled) {
5649            // No point choosing a rotation if the display is not enabled.
5650            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled.");
5651            return false;
5652        }
5653
5654        // TODO: Implement forced rotation changes.
5655        //       Set mAltOrientation to indicate that the application is receiving
5656        //       an orientation that has different metrics than it expected.
5657        //       eg. Portrait instead of Landscape.
5658
5659        int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);
5660        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
5661                mForcedAppOrientation, rotation);
5662
5663        if (DEBUG_ORIENTATION) {
5664            Slog.v(TAG, "Application requested orientation "
5665                    + mForcedAppOrientation + ", got rotation " + rotation
5666                    + " which has " + (altOrientation ? "incompatible" : "compatible")
5667                    + " metrics");
5668        }
5669
5670        if (mRotation == rotation && mAltOrientation == altOrientation) {
5671            // No change.
5672            return false;
5673        }
5674
5675        if (DEBUG_ORIENTATION) {
5676            Slog.v(TAG,
5677                "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
5678                + " from " + mRotation + (mAltOrientation ? " (alt)" : "")
5679                + ", forceApp=" + mForcedAppOrientation);
5680        }
5681
5682        mRotation = rotation;
5683        mAltOrientation = altOrientation;
5684        mPolicy.setRotationLw(mRotation);
5685
5686        mWindowsFreezingScreen = true;
5687        mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
5688        mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), 2000);
5689        mWaitingForConfig = true;
5690        mLayoutNeeded = true;
5691        startFreezingDisplayLocked(inTransaction);
5692        mInputManager.setDisplayOrientation(0, rotation,
5693                mDisplay != null ? mDisplay.getExternalRotation() : Surface.ROTATION_0);
5694
5695        // We need to update our screen size information to match the new
5696        // rotation.  Note that this is redundant with the later call to
5697        // sendNewConfiguration() that must be called after this function
5698        // returns...  however we need to do the screen size part of that
5699        // before then so we have the correct size to use when initializiation
5700        // the rotation animation for the new rotation.
5701        computeScreenConfigurationLocked(null);
5702
5703        if (!inTransaction) {
5704            if (SHOW_TRANSACTIONS)  Slog.i(TAG,
5705                    ">>> OPEN TRANSACTION setRotationUnchecked");
5706            Surface.openTransaction();
5707        }
5708        try {
5709            // NOTE: We disable the rotation in the emulator because
5710            //       it doesn't support hardware OpenGL emulation yet.
5711            if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
5712                    && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
5713                if (mAnimator.mScreenRotationAnimation.setRotation(rotation, mFxSession,
5714                        MAX_ANIMATION_DURATION, mTransitionAnimationScale,
5715                        mCurDisplayWidth, mCurDisplayHeight)) {
5716                    scheduleAnimationLocked();
5717                }
5718            }
5719            Surface.setOrientation(0, rotation);
5720        } finally {
5721            if (!inTransaction) {
5722                Surface.closeTransaction();
5723                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5724                        "<<< CLOSE TRANSACTION setRotationUnchecked");
5725            }
5726        }
5727
5728        rebuildBlackFrame();
5729
5730        for (int i=mWindows.size()-1; i>=0; i--) {
5731            WindowState w = mWindows.get(i);
5732            if (w.mHasSurface) {
5733                if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
5734                w.mOrientationChanging = true;
5735                mInnerFields.mOrientationChangeComplete = false;
5736            }
5737        }
5738        for (int i=mRotationWatchers.size()-1; i>=0; i--) {
5739            try {
5740                mRotationWatchers.get(i).onRotationChanged(rotation);
5741            } catch (RemoteException e) {
5742            }
5743        }
5744        return true;
5745    }
5746
5747    public int getRotation() {
5748        return mRotation;
5749    }
5750
5751    public int watchRotation(IRotationWatcher watcher) {
5752        final IBinder watcherBinder = watcher.asBinder();
5753        IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
5754            public void binderDied() {
5755                synchronized (mWindowMap) {
5756                    for (int i=0; i<mRotationWatchers.size(); i++) {
5757                        if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
5758                            IRotationWatcher removed = mRotationWatchers.remove(i);
5759                            if (removed != null) {
5760                                removed.asBinder().unlinkToDeath(this, 0);
5761                            }
5762                            i--;
5763                        }
5764                    }
5765                }
5766            }
5767        };
5768
5769        synchronized (mWindowMap) {
5770            try {
5771                watcher.asBinder().linkToDeath(dr, 0);
5772                mRotationWatchers.add(watcher);
5773            } catch (RemoteException e) {
5774                // Client died, no cleanup needed.
5775            }
5776
5777            return mRotation;
5778        }
5779    }
5780
5781    /**
5782     * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
5783     * theme attribute) on devices that feature a physical options menu key attempt to position
5784     * their menu panel window along the edge of the screen nearest the physical menu key.
5785     * This lowers the travel distance between invoking the menu panel and selecting
5786     * a menu option.
5787     *
5788     * This method helps control where that menu is placed. Its current implementation makes
5789     * assumptions about the menu key and its relationship to the screen based on whether
5790     * the device's natural orientation is portrait (width < height) or landscape.
5791     *
5792     * The menu key is assumed to be located along the bottom edge of natural-portrait
5793     * devices and along the right edge of natural-landscape devices. If these assumptions
5794     * do not hold for the target device, this method should be changed to reflect that.
5795     *
5796     * @return A {@link Gravity} value for placing the options menu window
5797     */
5798    public int getPreferredOptionsPanelGravity() {
5799        synchronized (mWindowMap) {
5800            final int rotation = getRotation();
5801
5802            if (mInitialDisplayWidth < mInitialDisplayHeight) {
5803                // On devices with a natural orientation of portrait
5804                switch (rotation) {
5805                    default:
5806                    case Surface.ROTATION_0:
5807                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5808                    case Surface.ROTATION_90:
5809                        return Gravity.RIGHT | Gravity.BOTTOM;
5810                    case Surface.ROTATION_180:
5811                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5812                    case Surface.ROTATION_270:
5813                        return Gravity.LEFT | Gravity.BOTTOM;
5814                }
5815            } else {
5816                // On devices with a natural orientation of landscape
5817                switch (rotation) {
5818                    default:
5819                    case Surface.ROTATION_0:
5820                        return Gravity.RIGHT | Gravity.BOTTOM;
5821                    case Surface.ROTATION_90:
5822                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5823                    case Surface.ROTATION_180:
5824                        return Gravity.LEFT | Gravity.BOTTOM;
5825                    case Surface.ROTATION_270:
5826                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5827                }
5828            }
5829        }
5830    }
5831
5832    /**
5833     * Starts the view server on the specified port.
5834     *
5835     * @param port The port to listener to.
5836     *
5837     * @return True if the server was successfully started, false otherwise.
5838     *
5839     * @see com.android.server.wm.ViewServer
5840     * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
5841     */
5842    public boolean startViewServer(int port) {
5843        if (isSystemSecure()) {
5844            return false;
5845        }
5846
5847        if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
5848            return false;
5849        }
5850
5851        if (port < 1024) {
5852            return false;
5853        }
5854
5855        if (mViewServer != null) {
5856            if (!mViewServer.isRunning()) {
5857                try {
5858                    return mViewServer.start();
5859                } catch (IOException e) {
5860                    Slog.w(TAG, "View server did not start");
5861                }
5862            }
5863            return false;
5864        }
5865
5866        try {
5867            mViewServer = new ViewServer(this, port);
5868            return mViewServer.start();
5869        } catch (IOException e) {
5870            Slog.w(TAG, "View server did not start");
5871        }
5872        return false;
5873    }
5874
5875    private boolean isSystemSecure() {
5876        return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
5877                "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
5878    }
5879
5880    /**
5881     * Stops the view server if it exists.
5882     *
5883     * @return True if the server stopped, false if it wasn't started or
5884     *         couldn't be stopped.
5885     *
5886     * @see com.android.server.wm.ViewServer
5887     */
5888    public boolean stopViewServer() {
5889        if (isSystemSecure()) {
5890            return false;
5891        }
5892
5893        if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
5894            return false;
5895        }
5896
5897        if (mViewServer != null) {
5898            return mViewServer.stop();
5899        }
5900        return false;
5901    }
5902
5903    /**
5904     * Indicates whether the view server is running.
5905     *
5906     * @return True if the server is running, false otherwise.
5907     *
5908     * @see com.android.server.wm.ViewServer
5909     */
5910    public boolean isViewServerRunning() {
5911        if (isSystemSecure()) {
5912            return false;
5913        }
5914
5915        if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
5916            return false;
5917        }
5918
5919        return mViewServer != null && mViewServer.isRunning();
5920    }
5921
5922    /**
5923     * Lists all availble windows in the system. The listing is written in the
5924     * specified Socket's output stream with the following syntax:
5925     * windowHashCodeInHexadecimal windowName
5926     * Each line of the ouput represents a different window.
5927     *
5928     * @param client The remote client to send the listing to.
5929     * @return False if an error occured, true otherwise.
5930     */
5931    boolean viewServerListWindows(Socket client) {
5932        if (isSystemSecure()) {
5933            return false;
5934        }
5935
5936        boolean result = true;
5937
5938        WindowState[] windows;
5939        synchronized (mWindowMap) {
5940            //noinspection unchecked
5941            windows = mWindows.toArray(new WindowState[mWindows.size()]);
5942        }
5943
5944        BufferedWriter out = null;
5945
5946        // Any uncaught exception will crash the system process
5947        try {
5948            OutputStream clientStream = client.getOutputStream();
5949            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
5950
5951            final int count = windows.length;
5952            for (int i = 0; i < count; i++) {
5953                final WindowState w = windows[i];
5954                out.write(Integer.toHexString(System.identityHashCode(w)));
5955                out.write(' ');
5956                out.append(w.mAttrs.getTitle());
5957                out.write('\n');
5958            }
5959
5960            out.write("DONE.\n");
5961            out.flush();
5962        } catch (Exception e) {
5963            result = false;
5964        } finally {
5965            if (out != null) {
5966                try {
5967                    out.close();
5968                } catch (IOException e) {
5969                    result = false;
5970                }
5971            }
5972        }
5973
5974        return result;
5975    }
5976
5977    /**
5978     * Returns the focused window in the following format:
5979     * windowHashCodeInHexadecimal windowName
5980     *
5981     * @param client The remote client to send the listing to.
5982     * @return False if an error occurred, true otherwise.
5983     */
5984    boolean viewServerGetFocusedWindow(Socket client) {
5985        if (isSystemSecure()) {
5986            return false;
5987        }
5988
5989        boolean result = true;
5990
5991        WindowState focusedWindow = getFocusedWindow();
5992
5993        BufferedWriter out = null;
5994
5995        // Any uncaught exception will crash the system process
5996        try {
5997            OutputStream clientStream = client.getOutputStream();
5998            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
5999
6000            if(focusedWindow != null) {
6001                out.write(Integer.toHexString(System.identityHashCode(focusedWindow)));
6002                out.write(' ');
6003                out.append(focusedWindow.mAttrs.getTitle());
6004            }
6005            out.write('\n');
6006            out.flush();
6007        } catch (Exception e) {
6008            result = false;
6009        } finally {
6010            if (out != null) {
6011                try {
6012                    out.close();
6013                } catch (IOException e) {
6014                    result = false;
6015                }
6016            }
6017        }
6018
6019        return result;
6020    }
6021
6022    /**
6023     * Sends a command to a target window. The result of the command, if any, will be
6024     * written in the output stream of the specified socket.
6025     *
6026     * The parameters must follow this syntax:
6027     * windowHashcode extra
6028     *
6029     * Where XX is the length in characeters of the windowTitle.
6030     *
6031     * The first parameter is the target window. The window with the specified hashcode
6032     * will be the target. If no target can be found, nothing happens. The extra parameters
6033     * will be delivered to the target window and as parameters to the command itself.
6034     *
6035     * @param client The remote client to sent the result, if any, to.
6036     * @param command The command to execute.
6037     * @param parameters The command parameters.
6038     *
6039     * @return True if the command was successfully delivered, false otherwise. This does
6040     *         not indicate whether the command itself was successful.
6041     */
6042    boolean viewServerWindowCommand(Socket client, String command, String parameters) {
6043        if (isSystemSecure()) {
6044            return false;
6045        }
6046
6047        boolean success = true;
6048        Parcel data = null;
6049        Parcel reply = null;
6050
6051        BufferedWriter out = null;
6052
6053        // Any uncaught exception will crash the system process
6054        try {
6055            // Find the hashcode of the window
6056            int index = parameters.indexOf(' ');
6057            if (index == -1) {
6058                index = parameters.length();
6059            }
6060            final String code = parameters.substring(0, index);
6061            int hashCode = (int) Long.parseLong(code, 16);
6062
6063            // Extract the command's parameter after the window description
6064            if (index < parameters.length()) {
6065                parameters = parameters.substring(index + 1);
6066            } else {
6067                parameters = "";
6068            }
6069
6070            final WindowState window = findWindow(hashCode);
6071            if (window == null) {
6072                return false;
6073            }
6074
6075            data = Parcel.obtain();
6076            data.writeInterfaceToken("android.view.IWindow");
6077            data.writeString(command);
6078            data.writeString(parameters);
6079            data.writeInt(1);
6080            ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
6081
6082            reply = Parcel.obtain();
6083
6084            final IBinder binder = window.mClient.asBinder();
6085            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
6086            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
6087
6088            reply.readException();
6089
6090            if (!client.isOutputShutdown()) {
6091                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
6092                out.write("DONE\n");
6093                out.flush();
6094            }
6095
6096        } catch (Exception e) {
6097            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
6098            success = false;
6099        } finally {
6100            if (data != null) {
6101                data.recycle();
6102            }
6103            if (reply != null) {
6104                reply.recycle();
6105            }
6106            if (out != null) {
6107                try {
6108                    out.close();
6109                } catch (IOException e) {
6110
6111                }
6112            }
6113        }
6114
6115        return success;
6116    }
6117
6118    public void addWindowChangeListener(WindowChangeListener listener) {
6119        synchronized(mWindowMap) {
6120            mWindowChangeListeners.add(listener);
6121        }
6122    }
6123
6124    public void removeWindowChangeListener(WindowChangeListener listener) {
6125        synchronized(mWindowMap) {
6126            mWindowChangeListeners.remove(listener);
6127        }
6128    }
6129
6130    private void notifyWindowsChanged() {
6131        WindowChangeListener[] windowChangeListeners;
6132        synchronized(mWindowMap) {
6133            if(mWindowChangeListeners.isEmpty()) {
6134                return;
6135            }
6136            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6137            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6138        }
6139        int N = windowChangeListeners.length;
6140        for(int i = 0; i < N; i++) {
6141            windowChangeListeners[i].windowsChanged();
6142        }
6143    }
6144
6145    private void notifyFocusChanged() {
6146        WindowChangeListener[] windowChangeListeners;
6147        synchronized(mWindowMap) {
6148            if(mWindowChangeListeners.isEmpty()) {
6149                return;
6150            }
6151            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6152            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6153        }
6154        int N = windowChangeListeners.length;
6155        for(int i = 0; i < N; i++) {
6156            windowChangeListeners[i].focusChanged();
6157        }
6158    }
6159
6160    private WindowState findWindow(int hashCode) {
6161        if (hashCode == -1) {
6162            return getFocusedWindow();
6163        }
6164
6165        synchronized (mWindowMap) {
6166            final ArrayList<WindowState> windows = mWindows;
6167            final int count = windows.size();
6168
6169            for (int i = 0; i < count; i++) {
6170                WindowState w = windows.get(i);
6171                if (System.identityHashCode(w) == hashCode) {
6172                    return w;
6173                }
6174            }
6175        }
6176
6177        return null;
6178    }
6179
6180    /*
6181     * Instruct the Activity Manager to fetch the current configuration and broadcast
6182     * that to config-changed listeners if appropriate.
6183     */
6184    void sendNewConfiguration() {
6185        try {
6186            mActivityManager.updateConfiguration(null);
6187        } catch (RemoteException e) {
6188        }
6189    }
6190
6191    public Configuration computeNewConfiguration() {
6192        synchronized (mWindowMap) {
6193            Configuration config = computeNewConfigurationLocked();
6194            if (config == null && mWaitingForConfig) {
6195                // Nothing changed but we are waiting for something... stop that!
6196                mWaitingForConfig = false;
6197                performLayoutAndPlaceSurfacesLocked();
6198            }
6199            return config;
6200        }
6201    }
6202
6203    Configuration computeNewConfigurationLocked() {
6204        Configuration config = new Configuration();
6205        config.fontScale = 0;
6206        if (!computeScreenConfigurationLocked(config)) {
6207            return null;
6208        }
6209        return config;
6210    }
6211
6212    private void adjustDisplaySizeRanges(int rotation, int dw, int dh) {
6213        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
6214        if (width < mSmallestDisplayWidth) {
6215            mSmallestDisplayWidth = width;
6216        }
6217        if (width > mLargestDisplayWidth) {
6218            mLargestDisplayWidth = width;
6219        }
6220        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation);
6221        if (height < mSmallestDisplayHeight) {
6222            mSmallestDisplayHeight = height;
6223        }
6224        if (height > mLargestDisplayHeight) {
6225            mLargestDisplayHeight = height;
6226        }
6227    }
6228
6229    private int reduceConfigLayout(int curLayout, int rotation, float density,
6230            int dw, int dh) {
6231        // Get the app screen size at this rotation.
6232        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6233        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6234
6235        // Compute the screen layout size class for this rotation.
6236        int screenLayoutSize;
6237        boolean screenLayoutLong;
6238        boolean screenLayoutCompatNeeded;
6239        int longSize = w;
6240        int shortSize = h;
6241        if (longSize < shortSize) {
6242            int tmp = longSize;
6243            longSize = shortSize;
6244            shortSize = tmp;
6245        }
6246        longSize = (int)(longSize/density);
6247        shortSize = (int)(shortSize/density);
6248
6249        // These semi-magic numbers define our compatibility modes for
6250        // applications with different screens.  These are guarantees to
6251        // app developers about the space they can expect for a particular
6252        // configuration.  DO NOT CHANGE!
6253        if (longSize < 470) {
6254            // This is shorter than an HVGA normal density screen (which
6255            // is 480 pixels on its long side).
6256            screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_SMALL;
6257            screenLayoutLong = false;
6258            screenLayoutCompatNeeded = false;
6259        } else {
6260            // What size is this screen screen?
6261            if (longSize >= 960 && shortSize >= 720) {
6262                // 1.5xVGA or larger screens at medium density are the point
6263                // at which we consider it to be an extra large screen.
6264                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_XLARGE;
6265            } else if (longSize >= 640 && shortSize >= 480) {
6266                // VGA or larger screens at medium density are the point
6267                // at which we consider it to be a large screen.
6268                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_LARGE;
6269            } else {
6270                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_NORMAL;
6271            }
6272
6273            // If this screen is wider than normal HVGA, or taller
6274            // than FWVGA, then for old apps we want to run in size
6275            // compatibility mode.
6276            if (shortSize > 321 || longSize > 570) {
6277                screenLayoutCompatNeeded = true;
6278            } else {
6279                screenLayoutCompatNeeded = false;
6280            }
6281
6282            // Is this a long screen?
6283            if (((longSize*3)/5) >= (shortSize-1)) {
6284                // Anything wider than WVGA (5:3) is considering to be long.
6285                screenLayoutLong = true;
6286            } else {
6287                screenLayoutLong = false;
6288            }
6289        }
6290
6291        // Now reduce the last screenLayout to not be better than what we
6292        // have found.
6293        if (!screenLayoutLong) {
6294            curLayout = (curLayout&~Configuration.SCREENLAYOUT_LONG_MASK)
6295                    | Configuration.SCREENLAYOUT_LONG_NO;
6296        }
6297        if (screenLayoutCompatNeeded) {
6298            curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
6299        }
6300        int curSize = curLayout&Configuration.SCREENLAYOUT_SIZE_MASK;
6301        if (screenLayoutSize < curSize) {
6302            curLayout = (curLayout&~Configuration.SCREENLAYOUT_SIZE_MASK)
6303                    | screenLayoutSize;
6304        }
6305        return curLayout;
6306    }
6307
6308    private void computeSizeRangesAndScreenLayout(boolean rotated, int dw, int dh,
6309            float density, Configuration outConfig) {
6310        // We need to determine the smallest width that will occur under normal
6311        // operation.  To this, start with the base screen size and compute the
6312        // width under the different possible rotations.  We need to un-rotate
6313        // the current screen dimensions before doing this.
6314        int unrotDw, unrotDh;
6315        if (rotated) {
6316            unrotDw = dh;
6317            unrotDh = dw;
6318        } else {
6319            unrotDw = dw;
6320            unrotDh = dh;
6321        }
6322        mSmallestDisplayWidth = 1<<30;
6323        mSmallestDisplayHeight = 1<<30;
6324        mLargestDisplayWidth = 0;
6325        mLargestDisplayHeight = 0;
6326        adjustDisplaySizeRanges(Surface.ROTATION_0, unrotDw, unrotDh);
6327        adjustDisplaySizeRanges(Surface.ROTATION_90, unrotDh, unrotDw);
6328        adjustDisplaySizeRanges(Surface.ROTATION_180, unrotDw, unrotDh);
6329        adjustDisplaySizeRanges(Surface.ROTATION_270, unrotDh, unrotDw);
6330        int sl = Configuration.SCREENLAYOUT_SIZE_XLARGE
6331                | Configuration.SCREENLAYOUT_LONG_YES;
6332        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
6333        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
6334        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
6335        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
6336        outConfig.smallestScreenWidthDp = (int)(mSmallestDisplayWidth / density);
6337        outConfig.screenLayout = sl;
6338    }
6339
6340    private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
6341            int dw, int dh) {
6342        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6343        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6344        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
6345        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
6346        if (curSize == 0 || size < curSize) {
6347            curSize = size;
6348        }
6349        return curSize;
6350    }
6351
6352    private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
6353        mTmpDisplayMetrics.setTo(dm);
6354        dm = mTmpDisplayMetrics;
6355        int unrotDw, unrotDh;
6356        if (rotated) {
6357            unrotDw = dh;
6358            unrotDh = dw;
6359        } else {
6360            unrotDw = dw;
6361            unrotDh = dh;
6362        }
6363        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, dm, unrotDw, unrotDh);
6364        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, dm, unrotDh, unrotDw);
6365        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, dm, unrotDw, unrotDh);
6366        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, dm, unrotDh, unrotDw);
6367        return sw;
6368    }
6369
6370    boolean computeScreenConfigurationLocked(Configuration config) {
6371        if (mDisplay == null) {
6372            return false;
6373        }
6374
6375        // Use the effective "visual" dimensions based on current rotation
6376        final boolean rotated = (mRotation == Surface.ROTATION_90
6377                || mRotation == Surface.ROTATION_270);
6378        final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
6379        final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
6380
6381        synchronized(mDisplaySizeLock) {
6382            if (mAltOrientation) {
6383                mCurDisplayWidth = realdw;
6384                mCurDisplayHeight = realdh;
6385                if (realdw > realdh) {
6386                    // Turn landscape into portrait.
6387                    int maxw = (int)(realdh/1.3f);
6388                    if (maxw < realdw) {
6389                        mCurDisplayWidth = maxw;
6390                    }
6391                } else {
6392                    // Turn portrait into landscape.
6393                    int maxh = (int)(realdw/1.3f);
6394                    if (maxh < realdh) {
6395                        mCurDisplayHeight = maxh;
6396                    }
6397                }
6398            } else {
6399                mCurDisplayWidth = realdw;
6400                mCurDisplayHeight = realdh;
6401            }
6402        }
6403
6404        final int dw = mCurDisplayWidth;
6405        final int dh = mCurDisplayHeight;
6406
6407        if (config != null) {
6408            int orientation = Configuration.ORIENTATION_SQUARE;
6409            if (dw < dh) {
6410                orientation = Configuration.ORIENTATION_PORTRAIT;
6411            } else if (dw > dh) {
6412                orientation = Configuration.ORIENTATION_LANDSCAPE;
6413            }
6414            config.orientation = orientation;
6415        }
6416
6417        // Update real display metrics.
6418        mDisplay.getMetricsWithSize(mRealDisplayMetrics, mCurDisplayWidth, mCurDisplayHeight);
6419
6420        // Update application display metrics.
6421        final DisplayMetrics dm = mDisplayMetrics;
6422        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
6423        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
6424        synchronized(mDisplaySizeLock) {
6425            mAppDisplayWidth = appWidth;
6426            mAppDisplayHeight = appHeight;
6427            mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight,
6428                    mAppDisplayWidth, mAppDisplayHeight);
6429        }
6430        if (false) {
6431            Slog.i(TAG, "Set app display size: " + mAppDisplayWidth
6432                    + " x " + mAppDisplayHeight);
6433        }
6434        mDisplay.getMetricsWithSize(dm, mAppDisplayWidth, mAppDisplayHeight);
6435
6436        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
6437                mCompatDisplayMetrics);
6438
6439        if (config != null) {
6440            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
6441                    / dm.density);
6442            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
6443                    / dm.density);
6444            computeSizeRangesAndScreenLayout(rotated, dw, dh, dm.density, config);
6445
6446            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
6447            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
6448            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
6449
6450            // Update the configuration based on available input devices, lid switch,
6451            // and platform configuration.
6452            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6453            config.keyboard = Configuration.KEYBOARD_NOKEYS;
6454            config.navigation = Configuration.NAVIGATION_NONAV;
6455
6456            int keyboardPresence = 0;
6457            int navigationPresence = 0;
6458            final InputDevice[] devices = mInputManager.getInputDevices();
6459            final int len = devices.length;
6460            for (int i = 0; i < len; i++) {
6461                InputDevice device = devices[i];
6462                if (!device.isVirtual()) {
6463                    final int sources = device.getSources();
6464                    final int presenceFlag = device.isExternal() ?
6465                            WindowManagerPolicy.PRESENCE_EXTERNAL :
6466                                    WindowManagerPolicy.PRESENCE_INTERNAL;
6467
6468                    if (mIsTouchDevice) {
6469                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
6470                                InputDevice.SOURCE_TOUCHSCREEN) {
6471                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
6472                        }
6473                    } else {
6474                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6475                    }
6476
6477                    if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
6478                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
6479                        navigationPresence |= presenceFlag;
6480                    } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
6481                            && config.navigation == Configuration.NAVIGATION_NONAV) {
6482                        config.navigation = Configuration.NAVIGATION_DPAD;
6483                        navigationPresence |= presenceFlag;
6484                    }
6485
6486                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
6487                        config.keyboard = Configuration.KEYBOARD_QWERTY;
6488                        keyboardPresence |= presenceFlag;
6489                    }
6490                }
6491            }
6492
6493            // Determine whether a hard keyboard is available and enabled.
6494            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6495            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6496                mHardKeyboardAvailable = hardKeyboardAvailable;
6497                mHardKeyboardEnabled = hardKeyboardAvailable;
6498                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6499                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6500            }
6501            if (!mHardKeyboardEnabled) {
6502                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6503            }
6504
6505            // Let the policy update hidden states.
6506            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6507            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6508            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6509            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
6510        }
6511
6512        return true;
6513    }
6514
6515    public boolean isHardKeyboardAvailable() {
6516        synchronized (mWindowMap) {
6517            return mHardKeyboardAvailable;
6518        }
6519    }
6520
6521    public boolean isHardKeyboardEnabled() {
6522        synchronized (mWindowMap) {
6523            return mHardKeyboardEnabled;
6524        }
6525    }
6526
6527    public void setHardKeyboardEnabled(boolean enabled) {
6528        synchronized (mWindowMap) {
6529            if (mHardKeyboardEnabled != enabled) {
6530                mHardKeyboardEnabled = enabled;
6531                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6532            }
6533        }
6534    }
6535
6536    public void setOnHardKeyboardStatusChangeListener(
6537            OnHardKeyboardStatusChangeListener listener) {
6538        synchronized (mWindowMap) {
6539            mHardKeyboardStatusChangeListener = listener;
6540        }
6541    }
6542
6543    void notifyHardKeyboardStatusChange() {
6544        final boolean available, enabled;
6545        final OnHardKeyboardStatusChangeListener listener;
6546        synchronized (mWindowMap) {
6547            listener = mHardKeyboardStatusChangeListener;
6548            available = mHardKeyboardAvailable;
6549            enabled = mHardKeyboardEnabled;
6550        }
6551        if (listener != null) {
6552            listener.onHardKeyboardStatusChange(available, enabled);
6553        }
6554    }
6555
6556    // -------------------------------------------------------------
6557    // Drag and drop
6558    // -------------------------------------------------------------
6559
6560    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
6561            int flags, int width, int height, Surface outSurface) {
6562        if (DEBUG_DRAG) {
6563            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
6564                    + " flags=" + Integer.toHexString(flags) + " win=" + window
6565                    + " asbinder=" + window.asBinder());
6566        }
6567
6568        final int callerPid = Binder.getCallingPid();
6569        final long origId = Binder.clearCallingIdentity();
6570        IBinder token = null;
6571
6572        try {
6573            synchronized (mWindowMap) {
6574                try {
6575                    if (mDragState == null) {
6576                        Surface surface = new Surface(session, callerPid, "drag surface", 0,
6577                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
6578                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
6579                                + surface + ": CREATE");
6580                        outSurface.copyFrom(surface);
6581                        final IBinder winBinder = window.asBinder();
6582                        token = new Binder();
6583                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
6584                        token = mDragState.mToken = new Binder();
6585
6586                        // 5 second timeout for this window to actually begin the drag
6587                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
6588                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
6589                        mH.sendMessageDelayed(msg, 5000);
6590                    } else {
6591                        Slog.w(TAG, "Drag already in progress");
6592                    }
6593                } catch (Surface.OutOfResourcesException e) {
6594                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
6595                    if (mDragState != null) {
6596                        mDragState.reset();
6597                        mDragState = null;
6598                    }
6599                }
6600            }
6601        } finally {
6602            Binder.restoreCallingIdentity(origId);
6603        }
6604
6605        return token;
6606    }
6607
6608    // -------------------------------------------------------------
6609    // Input Events and Focus Management
6610    // -------------------------------------------------------------
6611
6612    final InputMonitor mInputMonitor = new InputMonitor(this);
6613
6614    public void pauseKeyDispatching(IBinder _token) {
6615        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6616                "pauseKeyDispatching()")) {
6617            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6618        }
6619
6620        synchronized (mWindowMap) {
6621            WindowToken token = mTokenMap.get(_token);
6622            if (token != null) {
6623                mInputMonitor.pauseDispatchingLw(token);
6624            }
6625        }
6626    }
6627
6628    public void resumeKeyDispatching(IBinder _token) {
6629        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6630                "resumeKeyDispatching()")) {
6631            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6632        }
6633
6634        synchronized (mWindowMap) {
6635            WindowToken token = mTokenMap.get(_token);
6636            if (token != null) {
6637                mInputMonitor.resumeDispatchingLw(token);
6638            }
6639        }
6640    }
6641
6642    public void setEventDispatching(boolean enabled) {
6643        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6644                "setEventDispatching()")) {
6645            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6646        }
6647
6648        synchronized (mWindowMap) {
6649            mInputMonitor.setEventDispatchingLw(enabled);
6650            sendScreenStatusToClientsLocked();
6651        }
6652    }
6653
6654    public IBinder getFocusedWindowClientToken() {
6655        synchronized (mWindowMap) {
6656            WindowState windowState = getFocusedWindowLocked();
6657            if (windowState != null) {
6658                return windowState.mClient.asBinder();
6659            }
6660            return null;
6661        }
6662    }
6663
6664    private WindowState getFocusedWindow() {
6665        synchronized (mWindowMap) {
6666            return getFocusedWindowLocked();
6667        }
6668    }
6669
6670    private WindowState getFocusedWindowLocked() {
6671        return mCurrentFocus;
6672    }
6673
6674    public boolean detectSafeMode() {
6675        if (!mInputMonitor.waitForInputDevicesReady(
6676                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
6677            Slog.w(TAG, "Devices still not ready after waiting "
6678                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
6679                   + " milliseconds before attempting to detect safe mode.");
6680        }
6681
6682        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6683                KeyEvent.KEYCODE_MENU);
6684        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
6685        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
6686                KeyEvent.KEYCODE_DPAD_CENTER);
6687        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
6688                InputManagerService.BTN_MOUSE);
6689        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6690                KeyEvent.KEYCODE_VOLUME_DOWN);
6691        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
6692                || volumeDownState > 0;
6693        try {
6694            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
6695                mSafeMode = true;
6696                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
6697            }
6698        } catch (IllegalArgumentException e) {
6699        }
6700        if (mSafeMode) {
6701            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
6702                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
6703        } else {
6704            Log.i(TAG, "SAFE MODE not enabled");
6705        }
6706        mPolicy.setSafeMode(mSafeMode);
6707        return mSafeMode;
6708    }
6709
6710    public void displayReady() {
6711        synchronized(mWindowMap) {
6712            if (mDisplay != null) {
6713                throw new IllegalStateException("Display already initialized");
6714            }
6715            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
6716            mDisplay = wm.getDefaultDisplay();
6717            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
6718                    PackageManager.FEATURE_TOUCHSCREEN);
6719            synchronized(mDisplaySizeLock) {
6720                mInitialDisplayWidth = mDisplay.getRawWidth();
6721                mInitialDisplayHeight = mDisplay.getRawHeight();
6722                int rot = mDisplay.getRotation();
6723                if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
6724                    // If the screen is currently rotated, we need to swap the
6725                    // initial width and height to get the true natural values.
6726                    int tmp = mInitialDisplayWidth;
6727                    mInitialDisplayWidth = mInitialDisplayHeight;
6728                    mInitialDisplayHeight = tmp;
6729                }
6730                mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth;
6731                mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight;
6732                mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight,
6733                        mAppDisplayWidth, mAppDisplayHeight);
6734            }
6735            mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
6736                    mDisplay.getRawWidth(), mDisplay.getRawHeight(),
6737                    mDisplay.getRawExternalWidth(), mDisplay.getRawExternalHeight());
6738            mInputManager.setDisplayOrientation(Display.DEFAULT_DISPLAY,
6739                    mDisplay.getRotation(), mDisplay.getExternalRotation());
6740            mPolicy.setInitialDisplaySize(mDisplay, mInitialDisplayWidth, mInitialDisplayHeight);
6741        }
6742
6743        try {
6744            mActivityManager.updateConfiguration(null);
6745        } catch (RemoteException e) {
6746        }
6747
6748        synchronized (mWindowMap) {
6749            readForcedDisplaySizeLocked();
6750        }
6751    }
6752
6753    public void systemReady() {
6754        mPolicy.systemReady();
6755    }
6756
6757    private void sendScreenStatusToClientsLocked() {
6758        final ArrayList<WindowState> windows = mWindows;
6759        final int count = windows.size();
6760        boolean on = mPowerManager.isScreenOn();
6761        for (int i = count - 1; i >= 0; i--) {
6762            WindowState win = mWindows.get(i);
6763            try {
6764                win.mClient.dispatchScreenState(on);
6765            } catch (RemoteException e) {
6766                // Ignored
6767            }
6768        }
6769    }
6770
6771    // -------------------------------------------------------------
6772    // Async Handler
6773    // -------------------------------------------------------------
6774
6775    final class H extends Handler {
6776        public static final int REPORT_FOCUS_CHANGE = 2;
6777        public static final int REPORT_LOSING_FOCUS = 3;
6778        public static final int DO_TRAVERSAL = 4;
6779        public static final int ADD_STARTING = 5;
6780        public static final int REMOVE_STARTING = 6;
6781        public static final int FINISHED_STARTING = 7;
6782        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
6783        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
6784        public static final int WINDOW_FREEZE_TIMEOUT = 11;
6785        public static final int HOLD_SCREEN_CHANGED = 12;
6786        public static final int APP_TRANSITION_TIMEOUT = 13;
6787        public static final int PERSIST_ANIMATION_SCALE = 14;
6788        public static final int FORCE_GC = 15;
6789        public static final int ENABLE_SCREEN = 16;
6790        public static final int APP_FREEZE_TIMEOUT = 17;
6791        public static final int SEND_NEW_CONFIGURATION = 18;
6792        public static final int REPORT_WINDOWS_CHANGE = 19;
6793        public static final int DRAG_START_TIMEOUT = 20;
6794        public static final int DRAG_END_TIMEOUT = 21;
6795        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
6796        public static final int BOOT_TIMEOUT = 23;
6797        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
6798        public static final int BULK_UPDATE_PARAMETERS = 25;
6799        public static final int SHOW_STRICT_MODE_VIOLATION = 26;
6800
6801        public static final int ANIMATOR_WHAT_OFFSET = 100000;
6802        public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
6803        public static final int SET_WALLPAPER_OFFSET = ANIMATOR_WHAT_OFFSET + 2;
6804        public static final int SET_DIM_PARAMETERS = ANIMATOR_WHAT_OFFSET + 3;
6805        public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 4;
6806
6807        private Session mLastReportedHold;
6808
6809        public H() {
6810        }
6811
6812        @Override
6813        public void handleMessage(Message msg) {
6814            if (DEBUG_WINDOW_TRACE) {
6815                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
6816            }
6817            switch (msg.what) {
6818                case REPORT_FOCUS_CHANGE: {
6819                    WindowState lastFocus;
6820                    WindowState newFocus;
6821
6822                    synchronized(mWindowMap) {
6823                        lastFocus = mLastFocus;
6824                        newFocus = mCurrentFocus;
6825                        if (lastFocus == newFocus) {
6826                            // Focus is not changing, so nothing to do.
6827                            return;
6828                        }
6829                        mLastFocus = newFocus;
6830                        //Slog.i(TAG, "Focus moving from " + lastFocus
6831                        //        + " to " + newFocus);
6832                        if (newFocus != null && lastFocus != null
6833                                && !newFocus.isDisplayedLw()) {
6834                            //Slog.i(TAG, "Delaying loss of focus...");
6835                            mLosingFocus.add(lastFocus);
6836                            lastFocus = null;
6837                        }
6838                    }
6839
6840                    if (lastFocus != newFocus) {
6841                        //System.out.println("Changing focus from " + lastFocus
6842                        //                   + " to " + newFocus);
6843                        if (newFocus != null) {
6844                            try {
6845                                //Slog.i(TAG, "Gaining focus: " + newFocus);
6846                                newFocus.mClient.windowFocusChanged(true, mInTouchMode);
6847                            } catch (RemoteException e) {
6848                                // Ignore if process has died.
6849                            }
6850                            notifyFocusChanged();
6851                        }
6852
6853                        if (lastFocus != null) {
6854                            try {
6855                                //Slog.i(TAG, "Losing focus: " + lastFocus);
6856                                lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
6857                            } catch (RemoteException e) {
6858                                // Ignore if process has died.
6859                            }
6860                        }
6861                    }
6862                } break;
6863
6864                case REPORT_LOSING_FOCUS: {
6865                    ArrayList<WindowState> losers;
6866
6867                    synchronized(mWindowMap) {
6868                        losers = mLosingFocus;
6869                        mLosingFocus = new ArrayList<WindowState>();
6870                    }
6871
6872                    final int N = losers.size();
6873                    for (int i=0; i<N; i++) {
6874                        try {
6875                            //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
6876                            losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
6877                        } catch (RemoteException e) {
6878                             // Ignore if process has died.
6879                        }
6880                    }
6881                } break;
6882
6883                case DO_TRAVERSAL: {
6884                    synchronized(mWindowMap) {
6885                        mTraversalScheduled = false;
6886                        performLayoutAndPlaceSurfacesLocked();
6887                    }
6888                } break;
6889
6890                case ADD_STARTING: {
6891                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6892                    final StartingData sd = wtoken.startingData;
6893
6894                    if (sd == null) {
6895                        // Animation has been canceled... do nothing.
6896                        return;
6897                    }
6898
6899                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
6900                            + wtoken + ": pkg=" + sd.pkg);
6901
6902                    View view = null;
6903                    try {
6904                        view = mPolicy.addStartingWindow(
6905                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
6906                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
6907                    } catch (Exception e) {
6908                        Slog.w(TAG, "Exception when adding starting window", e);
6909                    }
6910
6911                    if (view != null) {
6912                        boolean abort = false;
6913
6914                        synchronized(mWindowMap) {
6915                            if (wtoken.removed || wtoken.startingData == null) {
6916                                // If the window was successfully added, then
6917                                // we need to remove it.
6918                                if (wtoken.startingWindow != null) {
6919                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6920                                            "Aborted starting " + wtoken
6921                                            + ": removed=" + wtoken.removed
6922                                            + " startingData=" + wtoken.startingData);
6923                                    wtoken.startingWindow = null;
6924                                    wtoken.startingData = null;
6925                                    abort = true;
6926                                }
6927                            } else {
6928                                wtoken.startingView = view;
6929                            }
6930                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
6931                                    "Added starting " + wtoken
6932                                    + ": startingWindow="
6933                                    + wtoken.startingWindow + " startingView="
6934                                    + wtoken.startingView);
6935                        }
6936
6937                        if (abort) {
6938                            try {
6939                                mPolicy.removeStartingWindow(wtoken.token, view);
6940                            } catch (Exception e) {
6941                                Slog.w(TAG, "Exception when removing starting window", e);
6942                            }
6943                        }
6944                    }
6945                } break;
6946
6947                case REMOVE_STARTING: {
6948                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6949                    IBinder token = null;
6950                    View view = null;
6951                    synchronized (mWindowMap) {
6952                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
6953                                + wtoken + ": startingWindow="
6954                                + wtoken.startingWindow + " startingView="
6955                                + wtoken.startingView);
6956                        if (wtoken.startingWindow != null) {
6957                            view = wtoken.startingView;
6958                            token = wtoken.token;
6959                            wtoken.startingData = null;
6960                            wtoken.startingView = null;
6961                            wtoken.startingWindow = null;
6962                        }
6963                    }
6964                    if (view != null) {
6965                        try {
6966                            mPolicy.removeStartingWindow(token, view);
6967                        } catch (Exception e) {
6968                            Slog.w(TAG, "Exception when removing starting window", e);
6969                        }
6970                    }
6971                } break;
6972
6973                case FINISHED_STARTING: {
6974                    IBinder token = null;
6975                    View view = null;
6976                    while (true) {
6977                        synchronized (mWindowMap) {
6978                            final int N = mFinishedStarting.size();
6979                            if (N <= 0) {
6980                                break;
6981                            }
6982                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
6983
6984                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6985                                    "Finished starting " + wtoken
6986                                    + ": startingWindow=" + wtoken.startingWindow
6987                                    + " startingView=" + wtoken.startingView);
6988
6989                            if (wtoken.startingWindow == null) {
6990                                continue;
6991                            }
6992
6993                            view = wtoken.startingView;
6994                            token = wtoken.token;
6995                            wtoken.startingData = null;
6996                            wtoken.startingView = null;
6997                            wtoken.startingWindow = null;
6998                        }
6999
7000                        try {
7001                            mPolicy.removeStartingWindow(token, view);
7002                        } catch (Exception e) {
7003                            Slog.w(TAG, "Exception when removing starting window", e);
7004                        }
7005                    }
7006                } break;
7007
7008                case REPORT_APPLICATION_TOKEN_DRAWN: {
7009                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7010
7011                    try {
7012                        if (DEBUG_VISIBILITY) Slog.v(
7013                                TAG, "Reporting drawn in " + wtoken);
7014                        wtoken.appToken.windowsDrawn();
7015                    } catch (RemoteException ex) {
7016                    }
7017                } break;
7018
7019                case REPORT_APPLICATION_TOKEN_WINDOWS: {
7020                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7021
7022                    boolean nowVisible = msg.arg1 != 0;
7023                    boolean nowGone = msg.arg2 != 0;
7024
7025                    try {
7026                        if (DEBUG_VISIBILITY) Slog.v(
7027                                TAG, "Reporting visible in " + wtoken
7028                                + " visible=" + nowVisible
7029                                + " gone=" + nowGone);
7030                        if (nowVisible) {
7031                            wtoken.appToken.windowsVisible();
7032                        } else {
7033                            wtoken.appToken.windowsGone();
7034                        }
7035                    } catch (RemoteException ex) {
7036                    }
7037                } break;
7038
7039                case WINDOW_FREEZE_TIMEOUT: {
7040                    synchronized (mWindowMap) {
7041                        Slog.w(TAG, "Window freeze timeout expired.");
7042                        int i = mWindows.size();
7043                        while (i > 0) {
7044                            i--;
7045                            WindowState w = mWindows.get(i);
7046                            if (w.mOrientationChanging) {
7047                                w.mOrientationChanging = false;
7048                                Slog.w(TAG, "Force clearing orientation change: " + w);
7049                            }
7050                        }
7051                        performLayoutAndPlaceSurfacesLocked();
7052                    }
7053                    break;
7054                }
7055
7056                case HOLD_SCREEN_CHANGED: {
7057                    Session oldHold;
7058                    Session newHold;
7059                    synchronized (mWindowMap) {
7060                        oldHold = mLastReportedHold;
7061                        newHold = (Session)msg.obj;
7062                        mLastReportedHold = newHold;
7063                    }
7064
7065                    if (oldHold != newHold) {
7066                        try {
7067                            if (oldHold != null) {
7068                                mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
7069                                        "window",
7070                                        BatteryStats.WAKE_TYPE_WINDOW);
7071                            }
7072                            if (newHold != null) {
7073                                mBatteryStats.noteStartWakelock(newHold.mUid, -1,
7074                                        "window",
7075                                        BatteryStats.WAKE_TYPE_WINDOW);
7076                            }
7077                        } catch (RemoteException e) {
7078                        }
7079                    }
7080                    break;
7081                }
7082
7083                case APP_TRANSITION_TIMEOUT: {
7084                    synchronized (mWindowMap) {
7085                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
7086                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7087                                    "*** APP TRANSITION TIMEOUT");
7088                            mAppTransitionReady = true;
7089                            mAppTransitionTimeout = true;
7090                            mAnimatingAppTokens.clear();
7091                            mAnimatingAppTokens.addAll(mAppTokens);
7092                            performLayoutAndPlaceSurfacesLocked();
7093                        }
7094                    }
7095                    break;
7096                }
7097
7098                case PERSIST_ANIMATION_SCALE: {
7099                    Settings.System.putFloat(mContext.getContentResolver(),
7100                            Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7101                    Settings.System.putFloat(mContext.getContentResolver(),
7102                            Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7103                    Settings.System.putFloat(mContext.getContentResolver(),
7104                            Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
7105                    break;
7106                }
7107
7108                case FORCE_GC: {
7109                    synchronized(mWindowMap) {
7110                        if (mAnimationScheduled) {
7111                            // If we are animating, don't do the gc now but
7112                            // delay a bit so we don't interrupt the animation.
7113                            mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
7114                                    2000);
7115                            return;
7116                        }
7117                        // If we are currently rotating the display, it will
7118                        // schedule a new message when done.
7119                        if (mDisplayFrozen) {
7120                            return;
7121                        }
7122                    }
7123                    Runtime.getRuntime().gc();
7124                    break;
7125                }
7126
7127                case ENABLE_SCREEN: {
7128                    performEnableScreen();
7129                    break;
7130                }
7131
7132                case APP_FREEZE_TIMEOUT: {
7133                    synchronized (mWindowMap) {
7134                        synchronized (mAnimator) {
7135                            Slog.w(TAG, "App freeze timeout expired.");
7136                            int i = mAppTokens.size();
7137                            while (i > 0) {
7138                                i--;
7139                                AppWindowToken tok = mAppTokens.get(i);
7140                                if (tok.mAppAnimator.freezingScreen) {
7141                                    Slog.w(TAG, "Force clearing freeze: " + tok);
7142                                    unsetAppFreezingScreenLocked(tok, true, true);
7143                                }
7144                            }
7145                        }
7146                    }
7147                    break;
7148                }
7149
7150                case SEND_NEW_CONFIGURATION: {
7151                    removeMessages(SEND_NEW_CONFIGURATION);
7152                    sendNewConfiguration();
7153                    break;
7154                }
7155
7156                case REPORT_WINDOWS_CHANGE: {
7157                    if (mWindowsChanged) {
7158                        synchronized (mWindowMap) {
7159                            mWindowsChanged = false;
7160                        }
7161                        notifyWindowsChanged();
7162                    }
7163                    break;
7164                }
7165
7166                case DRAG_START_TIMEOUT: {
7167                    IBinder win = (IBinder)msg.obj;
7168                    if (DEBUG_DRAG) {
7169                        Slog.w(TAG, "Timeout starting drag by win " + win);
7170                    }
7171                    synchronized (mWindowMap) {
7172                        // !!! TODO: ANR the app that has failed to start the drag in time
7173                        if (mDragState != null) {
7174                            mDragState.unregister();
7175                            mInputMonitor.updateInputWindowsLw(true /*force*/);
7176                            mDragState.reset();
7177                            mDragState = null;
7178                        }
7179                    }
7180                    break;
7181                }
7182
7183                case DRAG_END_TIMEOUT: {
7184                    IBinder win = (IBinder)msg.obj;
7185                    if (DEBUG_DRAG) {
7186                        Slog.w(TAG, "Timeout ending drag to win " + win);
7187                    }
7188                    synchronized (mWindowMap) {
7189                        // !!! TODO: ANR the drag-receiving app
7190                        if (mDragState != null) {
7191                            mDragState.mDragResult = false;
7192                            mDragState.endDragLw();
7193                        }
7194                    }
7195                    break;
7196                }
7197
7198                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
7199                    notifyHardKeyboardStatusChange();
7200                    break;
7201                }
7202
7203                case BOOT_TIMEOUT: {
7204                    performBootTimeout();
7205                    break;
7206                }
7207
7208                case WAITING_FOR_DRAWN_TIMEOUT: {
7209                    Pair<WindowState, IRemoteCallback> pair;
7210                    synchronized (mWindowMap) {
7211                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
7212                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
7213                        if (!mWaitingForDrawn.remove(pair)) {
7214                            return;
7215                        }
7216                    }
7217                    try {
7218                        pair.second.sendResult(null);
7219                    } catch (RemoteException e) {
7220                    }
7221                    break;
7222                }
7223
7224                case BULK_UPDATE_PARAMETERS: {
7225                    // Used to send multiple changes from the animation side to the layout side.
7226                    synchronized (mWindowMap) {
7227                        boolean doRequest = false;
7228                        // TODO(cmautner): As the number of bits grows, use masks of bit groups to
7229                        //  eliminate unnecessary tests.
7230                        if ((msg.arg1 & LayoutFields.SET_UPDATE_ROTATION) != 0) {
7231                            mInnerFields.mUpdateRotation = true;
7232                            doRequest = true;
7233                        }
7234                        if ((msg.arg1 & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
7235                            mInnerFields.mWallpaperMayChange = true;
7236                            doRequest = true;
7237                        }
7238                        if ((msg.arg1 & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
7239                            mInnerFields.mWallpaperForceHidingChanged = true;
7240                            doRequest = true;
7241                        }
7242                        if ((msg.arg1 & LayoutFields.CLEAR_ORIENTATION_CHANGE_COMPLETE) != 0) {
7243                            mInnerFields.mOrientationChangeComplete = false;
7244                        } else {
7245                            mInnerFields.mOrientationChangeComplete = true;
7246                            if (mWindowsFreezingScreen) {
7247                                doRequest = true;
7248                            }
7249                        }
7250                        if ((msg.arg1 & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
7251                            mTurnOnScreen = true;
7252                        }
7253
7254                        mPendingLayoutChanges |= msg.arg2;
7255                        if (mPendingLayoutChanges != 0) {
7256                            doRequest = true;
7257                        }
7258
7259                        if (doRequest) {
7260                            mH.sendEmptyMessage(CLEAR_PENDING_ACTIONS);
7261                            performLayoutAndPlaceSurfacesLocked();
7262                        }
7263                    }
7264                    break;
7265                }
7266
7267                case SHOW_STRICT_MODE_VIOLATION: {
7268                    showStrictModeViolation(msg.arg1);
7269                    break;
7270                }
7271
7272                // Animation messages. Move to Window{State}Animator
7273                case SET_TRANSPARENT_REGION: {
7274                    Pair<WindowStateAnimator, Region> pair =
7275                                (Pair<WindowStateAnimator, Region>) msg.obj;
7276                    final WindowStateAnimator winAnimator = pair.first;
7277                    winAnimator.setTransparentRegionHint(pair.second);
7278                    break;
7279                }
7280
7281                case SET_WALLPAPER_OFFSET: {
7282                    final WindowStateAnimator winAnimator = (WindowStateAnimator) msg.obj;
7283                    winAnimator.setWallpaperOffset(msg.arg1, msg.arg2);
7284
7285                    scheduleAnimationLocked();
7286                    break;
7287                }
7288
7289                case SET_DIM_PARAMETERS: {
7290                    mAnimator.mDimParams = (DimAnimator.Parameters) msg.obj;
7291
7292                    scheduleAnimationLocked();
7293                    break;
7294                }
7295
7296                case CLEAR_PENDING_ACTIONS: {
7297                    mAnimator.clearPendingActions();
7298                    break;
7299                }
7300            }
7301            if (DEBUG_WINDOW_TRACE) {
7302                Slog.v(TAG, "handleMessage: exit");
7303            }
7304        }
7305    }
7306
7307    // -------------------------------------------------------------
7308    // IWindowManager API
7309    // -------------------------------------------------------------
7310
7311    @Override
7312    public IWindowSession openSession(IInputMethodClient client,
7313            IInputContext inputContext) {
7314        if (client == null) throw new IllegalArgumentException("null client");
7315        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7316        Session session = new Session(this, client, inputContext);
7317        return session;
7318    }
7319
7320    @Override
7321    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7322        synchronized (mWindowMap) {
7323            // The focus for the client is the window immediately below
7324            // where we would place the input method window.
7325            int idx = findDesiredInputMethodWindowIndexLocked(false);
7326            WindowState imFocus;
7327            if (idx > 0) {
7328                imFocus = mWindows.get(idx-1);
7329                if (DEBUG_INPUT_METHOD) {
7330                    Slog.i(TAG, "Desired input method target: " + imFocus);
7331                    Slog.i(TAG, "Current focus: " + this.mCurrentFocus);
7332                    Slog.i(TAG, "Last focus: " + this.mLastFocus);
7333                }
7334                if (imFocus != null) {
7335                    // This may be a starting window, in which case we still want
7336                    // to count it as okay.
7337                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
7338                            && imFocus.mAppToken != null) {
7339                        // The client has definitely started, so it really should
7340                        // have a window in this app token.  Let's look for it.
7341                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
7342                            WindowState w = imFocus.mAppToken.windows.get(i);
7343                            if (w != imFocus) {
7344                                Log.i(TAG, "Switching to real app window: " + w);
7345                                imFocus = w;
7346                                break;
7347                            }
7348                        }
7349                    }
7350                    if (DEBUG_INPUT_METHOD) {
7351                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
7352                        if (imFocus.mSession.mClient != null) {
7353                            Slog.i(TAG, "IM target client binder: "
7354                                    + imFocus.mSession.mClient.asBinder());
7355                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
7356                        }
7357                    }
7358                    if (imFocus.mSession.mClient != null &&
7359                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7360                        return true;
7361                    }
7362
7363                    // Okay, how about this...  what is the current focus?
7364                    // It seems in some cases we may not have moved the IM
7365                    // target window, such as when it was in a pop-up window,
7366                    // so let's also look at the current focus.  (An example:
7367                    // go to Gmail, start searching so the keyboard goes up,
7368                    // press home.  Sometimes the IME won't go down.)
7369                    // Would be nice to fix this more correctly, but it's
7370                    // way at the end of a release, and this should be good enough.
7371                    if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null &&
7372                            mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7373                        return true;
7374                    }
7375                }
7376            }
7377        }
7378        return false;
7379    }
7380
7381    public void getDisplaySize(Point size) {
7382        synchronized(mDisplaySizeLock) {
7383            size.x = mAppDisplayWidth;
7384            size.y = mAppDisplayHeight;
7385        }
7386    }
7387
7388    public void getRealDisplaySize(Point size) {
7389        synchronized(mDisplaySizeLock) {
7390            size.x = mCurDisplayWidth;
7391            size.y = mCurDisplayHeight;
7392        }
7393    }
7394
7395    public void getInitialDisplaySize(Point size) {
7396        synchronized(mDisplaySizeLock) {
7397            size.x = mInitialDisplayWidth;
7398            size.y = mInitialDisplayHeight;
7399        }
7400    }
7401
7402    public int getMaximumSizeDimension() {
7403        synchronized(mDisplaySizeLock) {
7404            // Do this based on the raw screen size, until we are smarter.
7405            return mBaseDisplayWidth > mBaseDisplayHeight
7406                    ? mBaseDisplayWidth : mBaseDisplayHeight;
7407        }
7408    }
7409
7410    public void getCurrentSizeRange(Point smallestSize, Point largestSize) {
7411        synchronized(mDisplaySizeLock) {
7412            smallestSize.x = mSmallestDisplayWidth;
7413            smallestSize.y = mSmallestDisplayHeight;
7414            largestSize.x = mLargestDisplayWidth;
7415            largestSize.y = mLargestDisplayHeight;
7416        }
7417    }
7418
7419    public void setForcedDisplaySize(int longDimen, int shortDimen) {
7420        synchronized(mWindowMap) {
7421            int width, height;
7422            if (mInitialDisplayWidth < mInitialDisplayHeight) {
7423                width = shortDimen < mInitialDisplayWidth
7424                        ? shortDimen : mInitialDisplayWidth;
7425                height = longDimen < mInitialDisplayHeight
7426                        ? longDimen : mInitialDisplayHeight;
7427            } else {
7428                width = longDimen < mInitialDisplayWidth
7429                        ? longDimen : mInitialDisplayWidth;
7430                height = shortDimen < mInitialDisplayHeight
7431                        ? shortDimen : mInitialDisplayHeight;
7432            }
7433            setForcedDisplaySizeLocked(width, height);
7434            Settings.Secure.putString(mContext.getContentResolver(),
7435                    Settings.Secure.DISPLAY_SIZE_FORCED, width + "," + height);
7436        }
7437    }
7438
7439    private void rebuildBlackFrame() {
7440        if (mBlackFrame != null) {
7441            mBlackFrame.kill();
7442            mBlackFrame = null;
7443        }
7444        if (mBaseDisplayWidth < mInitialDisplayWidth
7445                || mBaseDisplayHeight < mInitialDisplayHeight) {
7446            int initW, initH, baseW, baseH;
7447            final boolean rotated = (mRotation == Surface.ROTATION_90
7448                    || mRotation == Surface.ROTATION_270);
7449            if (rotated) {
7450                initW = mInitialDisplayHeight;
7451                initH = mInitialDisplayWidth;
7452                baseW = mBaseDisplayHeight;
7453                baseH = mBaseDisplayWidth;
7454            } else {
7455                initW = mInitialDisplayWidth;
7456                initH = mInitialDisplayHeight;
7457                baseW = mBaseDisplayWidth;
7458                baseH = mBaseDisplayHeight;
7459            }
7460            Rect outer = new Rect(0, 0, initW, initH);
7461            Rect inner = new Rect(0, 0, baseW, baseH);
7462            try {
7463                mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
7464            } catch (Surface.OutOfResourcesException e) {
7465            }
7466        }
7467    }
7468
7469    private void readForcedDisplaySizeLocked() {
7470        final String str = Settings.Secure.getString(mContext.getContentResolver(),
7471                Settings.Secure.DISPLAY_SIZE_FORCED);
7472        if (str == null || str.length() == 0) {
7473            return;
7474        }
7475        final int pos = str.indexOf(',');
7476        if (pos <= 0 || str.lastIndexOf(',') != pos) {
7477            return;
7478        }
7479        int width, height;
7480        try {
7481            width = Integer.parseInt(str.substring(0, pos));
7482            height = Integer.parseInt(str.substring(pos+1));
7483        } catch (NumberFormatException ex) {
7484            return;
7485        }
7486        setForcedDisplaySizeLocked(width, height);
7487    }
7488
7489    private void setForcedDisplaySizeLocked(int width, int height) {
7490        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7491
7492        synchronized(mDisplaySizeLock) {
7493            mBaseDisplayWidth = width;
7494            mBaseDisplayHeight = height;
7495        }
7496        mPolicy.setInitialDisplaySize(mDisplay, mBaseDisplayWidth, mBaseDisplayHeight);
7497
7498        mLayoutNeeded = true;
7499
7500        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7501        mTempConfiguration.setToDefaults();
7502        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7503        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7504            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7505                configChanged = true;
7506            }
7507        }
7508
7509        if (configChanged) {
7510            mWaitingForConfig = true;
7511            startFreezingDisplayLocked(false);
7512            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7513        }
7514
7515        rebuildBlackFrame();
7516
7517        performLayoutAndPlaceSurfacesLocked();
7518    }
7519
7520    public void clearForcedDisplaySize() {
7521        synchronized(mWindowMap) {
7522            setForcedDisplaySizeLocked(mInitialDisplayWidth, mInitialDisplayHeight);
7523            Settings.Secure.putString(mContext.getContentResolver(),
7524                    Settings.Secure.DISPLAY_SIZE_FORCED, "");
7525        }
7526    }
7527
7528    public boolean hasSystemNavBar() {
7529        return mPolicy.hasSystemNavBar();
7530    }
7531
7532    // -------------------------------------------------------------
7533    // Internals
7534    // -------------------------------------------------------------
7535
7536    final WindowState windowForClientLocked(Session session, IWindow client,
7537            boolean throwOnError) {
7538        return windowForClientLocked(session, client.asBinder(), throwOnError);
7539    }
7540
7541    final WindowState windowForClientLocked(Session session, IBinder client,
7542            boolean throwOnError) {
7543        WindowState win = mWindowMap.get(client);
7544        if (localLOGV) Slog.v(
7545            TAG, "Looking up client " + client + ": " + win);
7546        if (win == null) {
7547            RuntimeException ex = new IllegalArgumentException(
7548                    "Requested window " + client + " does not exist");
7549            if (throwOnError) {
7550                throw ex;
7551            }
7552            Slog.w(TAG, "Failed looking up window", ex);
7553            return null;
7554        }
7555        if (session != null && win.mSession != session) {
7556            RuntimeException ex = new IllegalArgumentException(
7557                    "Requested window " + client + " is in session " +
7558                    win.mSession + ", not " + session);
7559            if (throwOnError) {
7560                throw ex;
7561            }
7562            Slog.w(TAG, "Failed looking up window", ex);
7563            return null;
7564        }
7565
7566        return win;
7567    }
7568
7569    final void rebuildAppWindowListLocked() {
7570        int NW = mWindows.size();
7571        int i;
7572        int lastWallpaper = -1;
7573        int numRemoved = 0;
7574
7575        if (mRebuildTmp.length < NW) {
7576            mRebuildTmp = new WindowState[NW+10];
7577        }
7578
7579        // First remove all existing app windows.
7580        i=0;
7581        while (i < NW) {
7582            WindowState w = mWindows.get(i);
7583            if (w.mAppToken != null) {
7584                WindowState win = mWindows.remove(i);
7585                win.mRebuilding = true;
7586                mRebuildTmp[numRemoved] = win;
7587                mWindowsChanged = true;
7588                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
7589                        "Rebuild removing window: " + win);
7590                NW--;
7591                numRemoved++;
7592                continue;
7593            } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER
7594                    && lastWallpaper == i-1) {
7595                lastWallpaper = i;
7596            }
7597            i++;
7598        }
7599
7600        // The wallpaper window(s) typically live at the bottom of the stack,
7601        // so skip them before adding app tokens.
7602        lastWallpaper++;
7603        i = lastWallpaper;
7604
7605        // First add all of the exiting app tokens...  these are no longer
7606        // in the main app list, but still have windows shown.  We put them
7607        // in the back because now that the animation is over we no longer
7608        // will care about them.
7609        int NT = mExitingAppTokens.size();
7610        for (int j=0; j<NT; j++) {
7611            i = reAddAppWindowsLocked(i, mExitingAppTokens.get(j));
7612        }
7613
7614        // And add in the still active app tokens in Z order.
7615        NT = mAnimatingAppTokens.size();
7616        for (int j=0; j<NT; j++) {
7617            i = reAddAppWindowsLocked(i, mAnimatingAppTokens.get(j));
7618        }
7619
7620        i -= lastWallpaper;
7621        if (i != numRemoved) {
7622            Slog.w(TAG, "Rebuild removed " + numRemoved
7623                    + " windows but added " + i);
7624            for (i=0; i<numRemoved; i++) {
7625                WindowState ws = mRebuildTmp[i];
7626                if (ws.mRebuilding) {
7627                    StringWriter sw = new StringWriter();
7628                    PrintWriter pw = new PrintWriter(sw);
7629                    ws.dump(pw, "", true);
7630                    pw.flush();
7631                    Slog.w(TAG, "This window was lost: " + ws);
7632                    Slog.w(TAG, sw.toString());
7633                    ws.mWinAnimator.destroySurfaceLocked();
7634                }
7635            }
7636            Slog.w(TAG, "Current app token list:");
7637            dumpAnimatingAppTokensLocked();
7638            Slog.w(TAG, "Final window list:");
7639            dumpWindowsLocked();
7640        }
7641    }
7642
7643    private final void assignLayersLocked() {
7644        int N = mWindows.size();
7645        int curBaseLayer = 0;
7646        int curLayer = 0;
7647        int i;
7648
7649        if (DEBUG_LAYERS) {
7650            RuntimeException here = new RuntimeException("here");
7651            here.fillInStackTrace();
7652            Slog.v(TAG, "Assigning layers", here);
7653        }
7654
7655        for (i=0; i<N; i++) {
7656            final WindowState w = mWindows.get(i);
7657            final WindowStateAnimator winAnimator = w.mWinAnimator;
7658            boolean layerChanged = false;
7659            int oldLayer = w.mLayer;
7660            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
7661                    || (i > 0 && w.mIsWallpaper)) {
7662                curLayer += WINDOW_LAYER_MULTIPLIER;
7663                w.mLayer = curLayer;
7664            } else {
7665                curBaseLayer = curLayer = w.mBaseLayer;
7666                w.mLayer = curLayer;
7667            }
7668            if (w.mLayer != oldLayer) {
7669                layerChanged = true;
7670            }
7671            oldLayer = winAnimator.mAnimLayer;
7672            if (w.mTargetAppToken != null) {
7673                winAnimator.mAnimLayer =
7674                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
7675            } else if (w.mAppToken != null) {
7676                winAnimator.mAnimLayer =
7677                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
7678            } else {
7679                winAnimator.mAnimLayer = w.mLayer;
7680            }
7681            if (w.mIsImWindow) {
7682                winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
7683            } else if (w.mIsWallpaper) {
7684                winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
7685            }
7686            if (winAnimator.mAnimLayer != oldLayer) {
7687                layerChanged = true;
7688            }
7689            if (layerChanged && mAnimator.isDimming(winAnimator)) {
7690                // Force an animation pass just to update the mDimAnimator layer.
7691                scheduleAnimationLocked();
7692            }
7693            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
7694                    + winAnimator.mAnimLayer);
7695            //System.out.println(
7696            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7697        }
7698    }
7699
7700    private boolean mInLayout = false;
7701    private final void performLayoutAndPlaceSurfacesLocked() {
7702        if (mInLayout) {
7703            if (DEBUG) {
7704                throw new RuntimeException("Recursive call!");
7705            }
7706            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
7707                    + Debug.getCallers(3));
7708            return;
7709        }
7710
7711        if (mWaitingForConfig) {
7712            // Our configuration has changed (most likely rotation), but we
7713            // don't yet have the complete configuration to report to
7714            // applications.  Don't do any window layout until we have it.
7715            return;
7716        }
7717
7718        if (mDisplay == null) {
7719            // Not yet initialized, nothing to do.
7720            return;
7721        }
7722
7723        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
7724        mInLayout = true;
7725        boolean recoveringMemory = false;
7726
7727        try {
7728            if (mForceRemoves != null) {
7729                recoveringMemory = true;
7730                // Wait a little bit for things to settle down, and off we go.
7731                for (int i=0; i<mForceRemoves.size(); i++) {
7732                    WindowState ws = mForceRemoves.get(i);
7733                    Slog.i(TAG, "Force removing: " + ws);
7734                    removeWindowInnerLocked(ws.mSession, ws);
7735                }
7736                mForceRemoves = null;
7737                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
7738                Object tmp = new Object();
7739                synchronized (tmp) {
7740                    try {
7741                        tmp.wait(250);
7742                    } catch (InterruptedException e) {
7743                    }
7744                }
7745            }
7746        } catch (RuntimeException e) {
7747            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
7748        }
7749
7750        try {
7751            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
7752
7753            final int N = mPendingRemove.size();
7754            if (N > 0) {
7755                if (mPendingRemoveTmp.length < N) {
7756                    mPendingRemoveTmp = new WindowState[N+10];
7757                }
7758                mPendingRemove.toArray(mPendingRemoveTmp);
7759                mPendingRemove.clear();
7760                for (int i=0; i<N; i++) {
7761                    WindowState w = mPendingRemoveTmp[i];
7762                    removeWindowInnerLocked(w.mSession, w);
7763                }
7764
7765                mInLayout = false;
7766                assignLayersLocked();
7767                mLayoutNeeded = true;
7768                // XXX this recursion seems broken!
7769                Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
7770                performLayoutAndPlaceSurfacesLocked();
7771                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
7772
7773            } else {
7774                mInLayout = false;
7775            }
7776
7777            if (mLayoutNeeded) {
7778                if (++mLayoutRepeatCount < 6) {
7779                    requestTraversalLocked();
7780                } else {
7781                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
7782                    mLayoutRepeatCount = 0;
7783                }
7784            } else {
7785                mLayoutRepeatCount = 0;
7786            }
7787
7788            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
7789                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
7790                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
7791            }
7792        } catch (RuntimeException e) {
7793            mInLayout = false;
7794            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
7795        }
7796
7797        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
7798    }
7799
7800    private final void performLayoutLockedInner(boolean initial, boolean updateInputWindows) {
7801        if (!mLayoutNeeded) {
7802            return;
7803        }
7804
7805        mLayoutNeeded = false;
7806
7807        final int dw = mCurDisplayWidth;
7808        final int dh = mCurDisplayHeight;
7809
7810        final int NFW = mFakeWindows.size();
7811        for (int i=0; i<NFW; i++) {
7812            mFakeWindows.get(i).layout(dw, dh);
7813        }
7814
7815        final int N = mWindows.size();
7816        int i;
7817
7818        if (DEBUG_LAYOUT) {
7819            Slog.v(TAG, "-------------------------------------");
7820            Slog.v(TAG, "performLayout: needed="
7821                    + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
7822        }
7823
7824        mPolicy.beginLayoutLw(dw, dh, mRotation);
7825        mSystemDecorLayer = mPolicy.getSystemDecorRectLw(mSystemDecorRect);
7826
7827        int seq = mLayoutSeq+1;
7828        if (seq < 0) seq = 0;
7829        mLayoutSeq = seq;
7830
7831        // First perform layout of any root windows (not attached
7832        // to another window).
7833        int topAttached = -1;
7834        for (i = N-1; i >= 0; i--) {
7835            final WindowState win = mWindows.get(i);
7836
7837            // Don't do layout of a window if it is not visible, or
7838            // soon won't be visible, to avoid wasting time and funky
7839            // changes while a window is animating away.
7840            final boolean gone = win.isGoneForLayoutLw();
7841
7842            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
7843                Slog.v(TAG, "1ST PASS " + win
7844                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
7845                        + " mLayoutAttached=" + win.mLayoutAttached);
7846                final AppWindowToken atoken = win.mAppToken;
7847                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
7848                        + win.mViewVisibility + " mRelayoutCalled="
7849                        + win.mRelayoutCalled + " hidden="
7850                        + win.mRootToken.hidden + " hiddenRequested="
7851                        + (atoken != null && atoken.hiddenRequested)
7852                        + " mAttachedHidden=" + win.mAttachedHidden);
7853                else Slog.v(TAG, "  VIS: mViewVisibility="
7854                        + win.mViewVisibility + " mRelayoutCalled="
7855                        + win.mRelayoutCalled + " hidden="
7856                        + win.mRootToken.hidden + " hiddenRequested="
7857                        + (atoken != null && atoken.hiddenRequested)
7858                        + " mAttachedHidden=" + win.mAttachedHidden);
7859            }
7860
7861            // If this view is GONE, then skip it -- keep the current
7862            // frame, and let the caller know so they can ignore it
7863            // if they want.  (We do the normal layout for INVISIBLE
7864            // windows, since that means "perform layout as normal,
7865            // just don't display").
7866            if (!gone || !win.mHaveFrame || win.mLayoutNeeded) {
7867                if (!win.mLayoutAttached) {
7868                    if (initial) {
7869                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7870                        win.mContentChanged = false;
7871                    }
7872                    win.mLayoutNeeded = false;
7873                    win.prelayout();
7874                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
7875                    win.mLayoutSeq = seq;
7876                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7877                            + win.mFrame + " mContainingFrame="
7878                            + win.mContainingFrame + " mDisplayFrame="
7879                            + win.mDisplayFrame);
7880                } else {
7881                    if (topAttached < 0) topAttached = i;
7882                }
7883            }
7884        }
7885
7886        // Now perform layout of attached windows, which usually
7887        // depend on the position of the window they are attached to.
7888        // XXX does not deal with windows that are attached to windows
7889        // that are themselves attached.
7890        for (i = topAttached; i >= 0; i--) {
7891            final WindowState win = mWindows.get(i);
7892
7893            if (win.mLayoutAttached) {
7894                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
7895                        + " mHaveFrame=" + win.mHaveFrame
7896                        + " mViewVisibility=" + win.mViewVisibility
7897                        + " mRelayoutCalled=" + win.mRelayoutCalled);
7898                // If this view is GONE, then skip it -- keep the current
7899                // frame, and let the caller know so they can ignore it
7900                // if they want.  (We do the normal layout for INVISIBLE
7901                // windows, since that means "perform layout as normal,
7902                // just don't display").
7903                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7904                        || !win.mHaveFrame || win.mLayoutNeeded) {
7905                    if (initial) {
7906                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7907                        win.mContentChanged = false;
7908                    }
7909                    win.mLayoutNeeded = false;
7910                    win.prelayout();
7911                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7912                    win.mLayoutSeq = seq;
7913                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7914                            + win.mFrame + " mContainingFrame="
7915                            + win.mContainingFrame + " mDisplayFrame="
7916                            + win.mDisplayFrame);
7917                }
7918            }
7919        }
7920
7921        // Window frames may have changed.  Tell the input dispatcher about it.
7922        mInputMonitor.setUpdateInputWindowsNeededLw();
7923        if (updateInputWindows) {
7924            mInputMonitor.updateInputWindowsLw(false /*force*/);
7925        }
7926
7927        mPolicy.finishLayoutLw();
7928    }
7929
7930    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
7931        // If the screen is currently frozen or off, then keep
7932        // it frozen/off until this window draws at its new
7933        // orientation.
7934        if (!okToDisplay()) {
7935            if (DEBUG_ORIENTATION) Slog.v(TAG,
7936                    "Changing surface while display frozen: " + w);
7937            w.mOrientationChanging = true;
7938            mInnerFields.mOrientationChangeComplete = false;
7939            if (!mWindowsFreezingScreen) {
7940                mWindowsFreezingScreen = true;
7941                // XXX should probably keep timeout from
7942                // when we first froze the display.
7943                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
7944                mH.sendMessageDelayed(mH.obtainMessage(
7945                        H.WINDOW_FREEZE_TIMEOUT), 2000);
7946            }
7947        }
7948    }
7949
7950    /**
7951     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
7952     *
7953     * @return bitmap indicating if another pass through layout must be made.
7954     */
7955    public int handleAppTransitionReadyLocked() {
7956        int changes = 0;
7957        int i;
7958        int NN = mOpeningApps.size();
7959        boolean goodToGo = true;
7960        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7961                "Checking " + NN + " opening apps (frozen="
7962                + mDisplayFrozen + " timeout="
7963                + mAppTransitionTimeout + ")...");
7964        if (!mDisplayFrozen && !mAppTransitionTimeout) {
7965            // If the display isn't frozen, wait to do anything until
7966            // all of the apps are ready.  Otherwise just go because
7967            // we'll unfreeze the display when everyone is ready.
7968            for (i=0; i<NN && goodToGo; i++) {
7969                AppWindowToken wtoken = mOpeningApps.get(i);
7970                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7971                        "Check opening app=" + wtoken + ": allDrawn="
7972                        + wtoken.allDrawn + " startingDisplayed="
7973                        + wtoken.startingDisplayed + " startingMoved="
7974                        + wtoken.startingMoved);
7975                if (!wtoken.allDrawn && !wtoken.startingDisplayed
7976                        && !wtoken.startingMoved) {
7977                    goodToGo = false;
7978                }
7979            }
7980        }
7981        if (goodToGo) {
7982            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
7983            int transit = mNextAppTransition;
7984            if (mSkipAppTransitionAnimation) {
7985                transit = WindowManagerPolicy.TRANSIT_UNSET;
7986            }
7987            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
7988            mAppTransitionReady = false;
7989            mAppTransitionRunning = true;
7990            mAppTransitionTimeout = false;
7991            mStartingIconInTransition = false;
7992            mSkipAppTransitionAnimation = false;
7993
7994            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
7995
7996            rebuildAppWindowListLocked();
7997
7998            // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
7999            WindowState oldWallpaper =
8000                    mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
8001                        && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
8002                    ? null : mWallpaperTarget;
8003
8004            adjustWallpaperWindowsLocked();
8005            mInnerFields.mWallpaperMayChange = false;
8006
8007            // The top-most window will supply the layout params,
8008            // and we will determine it below.
8009            LayoutParams animLp = null;
8010            int bestAnimLayer = -1;
8011            boolean fullscreenAnim = false;
8012
8013            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8014                    "New wallpaper target=" + mWallpaperTarget
8015                    + ", lower target=" + mLowerWallpaperTarget
8016                    + ", upper target=" + mUpperWallpaperTarget);
8017            int foundWallpapers = 0;
8018            // Do a first pass through the tokens for two
8019            // things:
8020            // (1) Determine if both the closing and opening
8021            // app token sets are wallpaper targets, in which
8022            // case special animations are needed
8023            // (since the wallpaper needs to stay static
8024            // behind them).
8025            // (2) Find the layout params of the top-most
8026            // application window in the tokens, which is
8027            // what will control the animation theme.
8028            final int NC = mClosingApps.size();
8029            NN = NC + mOpeningApps.size();
8030            for (i=0; i<NN; i++) {
8031                AppWindowToken wtoken;
8032                int mode;
8033                if (i < NC) {
8034                    wtoken = mClosingApps.get(i);
8035                    mode = 1;
8036                } else {
8037                    wtoken = mOpeningApps.get(i-NC);
8038                    mode = 2;
8039                }
8040                if (mLowerWallpaperTarget != null) {
8041                    if (mLowerWallpaperTarget.mAppToken == wtoken
8042                            || mUpperWallpaperTarget.mAppToken == wtoken) {
8043                        foundWallpapers |= mode;
8044                    }
8045                }
8046                if (wtoken.appFullscreen) {
8047                    WindowState ws = wtoken.findMainWindow();
8048                    if (ws != null) {
8049                        animLp = ws.mAttrs;
8050                        bestAnimLayer = ws.mLayer;
8051                        fullscreenAnim = true;
8052                    }
8053                } else if (!fullscreenAnim) {
8054                    WindowState ws = wtoken.findMainWindow();
8055                    if (ws != null) {
8056                        if (ws.mLayer > bestAnimLayer) {
8057                            animLp = ws.mAttrs;
8058                            bestAnimLayer = ws.mLayer;
8059                        }
8060                    }
8061                }
8062            }
8063
8064            if (foundWallpapers == 3) {
8065                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8066                        "Wallpaper animation!");
8067                switch (transit) {
8068                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
8069                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
8070                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
8071                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
8072                        break;
8073                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
8074                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
8075                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
8076                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
8077                        break;
8078                }
8079                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8080                        "New transit: " + transit);
8081            } else if (oldWallpaper != null) {
8082                // We are transitioning from an activity with
8083                // a wallpaper to one without.
8084                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
8085                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8086                        "New transit away from wallpaper: " + transit);
8087            } else if (mWallpaperTarget != null) {
8088                // We are transitioning from an activity without
8089                // a wallpaper to now showing the wallpaper
8090                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
8091                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8092                        "New transit into wallpaper: " + transit);
8093            }
8094
8095            // If all closing windows are obscured, then there is
8096            // no need to do an animation.  This is the case, for
8097            // example, when this transition is being done behind
8098            // the lock screen.
8099            if (!mPolicy.allowAppAnimationsLw()) {
8100                animLp = null;
8101            }
8102
8103            AppWindowToken topOpeningApp = null;
8104            int topOpeningLayer = 0;
8105
8106            // TODO(cmautner): Move to animation side.
8107            NN = mOpeningApps.size();
8108            for (i=0; i<NN; i++) {
8109                AppWindowToken wtoken = mOpeningApps.get(i);
8110                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
8111                wtoken.mAppAnimator.clearThumbnail();
8112                wtoken.reportedVisible = false;
8113                wtoken.inPendingTransaction = false;
8114                wtoken.mAppAnimator.animation = null;
8115                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
8116                wtoken.updateReportedVisibilityLocked();
8117                wtoken.waitingToShow = false;
8118                mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked();
8119                if (animLp != null) {
8120                    int layer = -1;
8121                    for (int j=0; j<wtoken.windows.size(); j++) {
8122                        WindowState win = wtoken.windows.get(j);
8123                        if (win.mWinAnimator.mAnimLayer > layer) {
8124                            layer = win.mWinAnimator.mAnimLayer;
8125                        }
8126                    }
8127                    if (topOpeningApp == null || layer > topOpeningLayer) {
8128                        topOpeningApp = wtoken;
8129                        topOpeningLayer = layer;
8130                    }
8131                }
8132            }
8133            NN = mClosingApps.size();
8134            for (i=0; i<NN; i++) {
8135                AppWindowToken wtoken = mClosingApps.get(i);
8136                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8137                        "Now closing app" + wtoken);
8138                wtoken.mAppAnimator.clearThumbnail();
8139                wtoken.inPendingTransaction = false;
8140                wtoken.mAppAnimator.animation = null;
8141                setTokenVisibilityLocked(wtoken, animLp, false,
8142                        transit, false);
8143                wtoken.updateReportedVisibilityLocked();
8144                wtoken.waitingToHide = false;
8145                // Force the allDrawn flag, because we want to start
8146                // this guy's animations regardless of whether it's
8147                // gotten drawn.
8148                wtoken.allDrawn = true;
8149            }
8150
8151            if (mNextAppTransitionThumbnail != null && topOpeningApp != null
8152                    && topOpeningApp.mAppAnimator.animation != null) {
8153                // This thumbnail animation is very special, we need to have
8154                // an extra surface with the thumbnail included with the animation.
8155                Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
8156                        mNextAppTransitionThumbnail.getHeight());
8157                try {
8158                    Surface surface = new Surface(mFxSession, Process.myPid(),
8159                            "thumbnail anim", 0, dirty.width(), dirty.height(),
8160                            PixelFormat.TRANSLUCENT, Surface.HIDDEN);
8161                    topOpeningApp.mAppAnimator.thumbnail = surface;
8162                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
8163                            + surface + ": CREATE");
8164                    Surface drawSurface = new Surface();
8165                    drawSurface.copyFrom(surface);
8166                    Canvas c = drawSurface.lockCanvas(dirty);
8167                    c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
8168                    drawSurface.unlockCanvasAndPost(c);
8169                    drawSurface.release();
8170                    topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
8171                    Animation anim = createThumbnailAnimationLocked(
8172                            transit, true, true, mNextAppTransitionDelayed);
8173                    topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
8174                    anim.restrictDuration(MAX_ANIMATION_DURATION);
8175                    anim.scaleCurrentDuration(mTransitionAnimationScale);
8176                    topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX;
8177                    topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY;
8178                } catch (Surface.OutOfResourcesException e) {
8179                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
8180                            + " h=" + dirty.height(), e);
8181                    topOpeningApp.mAppAnimator.clearThumbnail();
8182                }
8183            }
8184
8185            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
8186            mNextAppTransitionPackage = null;
8187            mNextAppTransitionThumbnail = null;
8188            if (mNextAppTransitionCallback != null) {
8189                try {
8190                    mNextAppTransitionCallback.sendResult(null);
8191                } catch (RemoteException e) {
8192                }
8193            }
8194
8195            mOpeningApps.clear();
8196            mClosingApps.clear();
8197
8198            // This has changed the visibility of windows, so perform
8199            // a new layout to get them all up-to-date.
8200            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
8201                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8202            mLayoutNeeded = true;
8203            if (!moveInputMethodWindowsIfNeededLocked(true)) {
8204                assignLayersLocked();
8205            }
8206            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8207                    false /*updateInputWindows*/);
8208            mFocusMayChange = false;
8209        }
8210
8211        return changes;
8212    }
8213
8214    /**
8215     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8216     *
8217     * @return bitmap indicating if another pass through layout must be made.
8218     */
8219    private int handleAnimatingStoppedAndTransitionLocked() {
8220        int changes = 0;
8221
8222        mAppTransitionRunning = false;
8223        // Restore window app tokens to the ActivityManager views
8224        mAnimatingAppTokens.clear();
8225        mAnimatingAppTokens.addAll(mAppTokens);
8226        rebuildAppWindowListLocked();
8227
8228        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8229        mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
8230        moveInputMethodWindowsIfNeededLocked(true);
8231        mInnerFields.mWallpaperMayChange = true;
8232        // Since the window list has been rebuilt, focus might
8233        // have to be recomputed since the actual order of windows
8234        // might have changed again.
8235        mFocusMayChange = true;
8236
8237        return changes;
8238    }
8239
8240    /**
8241     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8242     *
8243     * @return bitmap indicating if another pass through layout must be made.
8244     */
8245    private int animateAwayWallpaperLocked() {
8246        int changes = 0;
8247        WindowState oldWallpaper = mWallpaperTarget;
8248        if (mLowerWallpaperTarget != null
8249                && mLowerWallpaperTarget.mAppToken != null) {
8250            if (DEBUG_WALLPAPER) Slog.v(TAG,
8251                    "wallpaperForceHiding changed with lower="
8252                    + mLowerWallpaperTarget);
8253            if (DEBUG_WALLPAPER) Slog.v(TAG,
8254                    "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
8255                    " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
8256            if (mLowerWallpaperTarget.mAppToken.hidden) {
8257                // The lower target has become hidden before we
8258                // actually started the animation...  let's completely
8259                // re-evaluate everything.
8260                mLowerWallpaperTarget = mUpperWallpaperTarget = null;
8261                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8262            }
8263        }
8264        mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8265        if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
8266                + " NEW: " + mWallpaperTarget
8267                + " LOWER: " + mLowerWallpaperTarget);
8268        return changes;
8269    }
8270
8271    private void updateResizingWindows(final WindowState w) {
8272        final WindowStateAnimator winAnimator = w.mWinAnimator;
8273        if (w.mHasSurface && !w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
8274            w.mContentInsetsChanged |=
8275                    !w.mLastContentInsets.equals(w.mContentInsets);
8276            w.mVisibleInsetsChanged |=
8277                    !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8278            boolean configChanged =
8279                w.mConfiguration != mCurConfiguration
8280                && (w.mConfiguration == null
8281                        || mCurConfiguration.diff(w.mConfiguration) != 0);
8282            if (DEBUG_CONFIGURATION && configChanged) {
8283                Slog.v(TAG, "Win " + w + " config changed: "
8284                        + mCurConfiguration);
8285            }
8286            if (localLOGV) Slog.v(TAG, "Resizing " + w
8287                    + ": configChanged=" + configChanged
8288                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8289            w.mLastFrame.set(w.mFrame);
8290            if (w.mContentInsetsChanged
8291                    || w.mVisibleInsetsChanged
8292                    || winAnimator.mSurfaceResized
8293                    || configChanged) {
8294                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8295                    Slog.v(TAG, "Resize reasons: "
8296                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8297                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8298                            + " surfaceResized=" + winAnimator.mSurfaceResized
8299                            + " configChanged=" + configChanged);
8300                }
8301
8302                w.mLastContentInsets.set(w.mContentInsets);
8303                w.mLastVisibleInsets.set(w.mVisibleInsets);
8304                makeWindowFreezingScreenIfNeededLocked(w);
8305                // If the orientation is changing, then we need to
8306                // hold off on unfreezing the display until this
8307                // window has been redrawn; to do that, we need
8308                // to go through the process of getting informed
8309                // by the application when it has finished drawing.
8310                if (w.mOrientationChanging) {
8311                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
8312                            "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
8313                            + w + ", surface " + winAnimator.mSurface);
8314                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8315                    if (w.mAppToken != null) {
8316                        w.mAppToken.allDrawn = false;
8317                    }
8318                }
8319                if (!mResizingWindows.contains(w)) {
8320                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8321                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8322                            + "x" + winAnimator.mSurfaceH);
8323                    mResizingWindows.add(w);
8324                }
8325            } else if (w.mOrientationChanging) {
8326                if (w.isDrawnLw()) {
8327                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8328                            "Orientation not waiting for draw in "
8329                            + w + ", surface " + winAnimator.mSurface);
8330                    w.mOrientationChanging = false;
8331                }
8332            }
8333        }
8334    }
8335
8336    /**
8337     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8338     *
8339     * @param w WindowState this method is applied to.
8340     * @param currentTime The time which animations use for calculating transitions.
8341     * @param innerDw Width of app window.
8342     * @param innerDh Height of app window.
8343     */
8344    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8345                                         final int innerDw, final int innerDh) {
8346        final WindowManager.LayoutParams attrs = w.mAttrs;
8347        final int attrFlags = attrs.flags;
8348        final boolean canBeSeen = w.isDisplayedLw();
8349
8350        if (w.mHasSurface) {
8351            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8352                mInnerFields.mHoldScreen = w.mSession;
8353            }
8354            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8355                    && mInnerFields.mScreenBrightness < 0) {
8356                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8357            }
8358            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8359                    && mInnerFields.mButtonBrightness < 0) {
8360                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8361            }
8362            if (canBeSeen
8363                    && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8364                     || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8365                     || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
8366                mInnerFields.mSyswin = true;
8367            }
8368        }
8369
8370        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8371        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8372            // This window completely covers everything behind it,
8373            // so we want to leave all of them as undimmed (for
8374            // performance reasons).
8375            mInnerFields.mObscured = true;
8376        } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0
8377                && !(w.mAppToken != null && w.mAppToken.hiddenRequested)) {
8378            if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured);
8379            if (!mInnerFields.mDimming) {
8380                //Slog.i(TAG, "DIM BEHIND: " + w);
8381                mInnerFields.mDimming = true;
8382                final WindowStateAnimator winAnimator = w.mWinAnimator;
8383                if (!mAnimator.isDimming(winAnimator)) {
8384                    final int width, height;
8385                    if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
8386                        width = mCurDisplayWidth;
8387                        height = mCurDisplayHeight;
8388                    } else {
8389                        width = innerDw;
8390                        height = innerDh;
8391                    }
8392                    mAnimator.startDimming(winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount,
8393                            width, height);
8394                }
8395            }
8396        }
8397    }
8398
8399    // "Something has changed!  Let's make it correct now."
8400    private final void performLayoutAndPlaceSurfacesLockedInner(
8401            boolean recoveringMemory) {
8402        if (DEBUG_WINDOW_TRACE) {
8403            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8404                    + Debug.getCallers(3));
8405        }
8406        if (mDisplay == null) {
8407            Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
8408            return;
8409        }
8410
8411        final long currentTime = SystemClock.uptimeMillis();
8412        final int dw = mCurDisplayWidth;
8413        final int dh = mCurDisplayHeight;
8414        final int innerDw = mAppDisplayWidth;
8415        final int innerDh = mAppDisplayHeight;
8416
8417        int i;
8418
8419        if (mFocusMayChange) {
8420            mFocusMayChange = false;
8421            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8422                    false /*updateInputWindows*/);
8423        }
8424
8425        // Initialize state of exiting tokens.
8426        for (i=mExitingTokens.size()-1; i>=0; i--) {
8427            mExitingTokens.get(i).hasVisible = false;
8428        }
8429
8430        // Initialize state of exiting applications.
8431        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8432            mExitingAppTokens.get(i).hasVisible = false;
8433        }
8434
8435        mInnerFields.mHoldScreen = null;
8436        mInnerFields.mScreenBrightness = -1;
8437        mInnerFields.mButtonBrightness = -1;
8438
8439        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8440                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8441
8442        Surface.openTransaction();
8443
8444        if (mWatermark != null) {
8445            mWatermark.positionSurface(dw, dh);
8446        }
8447        if (mStrictModeFlash != null) {
8448            mStrictModeFlash.positionSurface(dw, dh);
8449        }
8450
8451        try {
8452            int repeats = 0;
8453
8454            do {
8455                repeats++;
8456                if (repeats > 6) {
8457                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
8458                    mLayoutNeeded = false;
8459                    break;
8460                }
8461
8462                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
8463                    mPendingLayoutChanges);
8464
8465                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
8466                    if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8467                        assignLayersLocked();
8468                        mLayoutNeeded = true;
8469                    }
8470                }
8471
8472                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
8473                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
8474                    if (updateOrientationFromAppTokensLocked(true)) {
8475                        mLayoutNeeded = true;
8476                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8477                    }
8478                }
8479
8480                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8481                    mLayoutNeeded = true;
8482                }
8483
8484                // FIRST LOOP: Perform a layout, if needed.
8485                if (repeats < 4) {
8486                    performLayoutLockedInner(repeats == 1, false /*updateInputWindows*/);
8487                } else {
8488                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
8489                }
8490
8491                // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
8492                // it is animating.
8493                mPendingLayoutChanges = 0;
8494                if (DEBUG_LAYOUT_REPEATS)  debugLayoutRepeats("loop number " + mLayoutRepeatCount,
8495                    mPendingLayoutChanges);
8496                mPolicy.beginAnimationLw(dw, dh);
8497                for (i = mWindows.size() - 1; i >= 0; i--) {
8498                    WindowState w = mWindows.get(i);
8499                    if (w.mHasSurface) {
8500                        mPolicy.animatingWindowLw(w, w.mAttrs);
8501                    }
8502                }
8503                mPendingLayoutChanges |= mPolicy.finishAnimationLw();
8504                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishAnimationLw",
8505                    mPendingLayoutChanges);
8506            } while (mPendingLayoutChanges != 0);
8507
8508            final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
8509
8510            mInnerFields.mObscured = false;
8511            mInnerFields.mDimming = false;
8512            mInnerFields.mSyswin = false;
8513
8514            boolean focusDisplayed = false;
8515            final int N = mWindows.size();
8516            for (i=N-1; i>=0; i--) {
8517                WindowState w = mWindows.get(i);
8518
8519                final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
8520
8521                // Update effect.
8522                w.mObscured = mInnerFields.mObscured;
8523                if (!mInnerFields.mObscured) {
8524                    handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
8525                }
8526
8527                if (obscuredChanged && mWallpaperTarget == w) {
8528                    // This is the wallpaper target and its obscured state
8529                    // changed... make sure the current wallaper's visibility
8530                    // has been updated accordingly.
8531                    updateWallpaperVisibilityLocked();
8532                }
8533
8534                final WindowStateAnimator winAnimator = w.mWinAnimator;
8535
8536                // If the window has moved due to its containing
8537                // content frame changing, then we'd like to animate
8538                // it.
8539                if (w.mHasSurface && w.shouldAnimateMove()) {
8540                    // Frame has moved, containing content frame
8541                    // has also moved, and we're not currently animating...
8542                    // let's do something.
8543                    Animation a = AnimationUtils.loadAnimation(mContext,
8544                            com.android.internal.R.anim.window_move_from_decor);
8545                    winAnimator.setAnimation(a);
8546                    winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
8547                    winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
8548                }
8549
8550                //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
8551                w.mContentChanged = false;
8552
8553                // Moved from updateWindowsAndWallpaperLocked().
8554                if (w.mHasSurface) {
8555                    // Take care of the window being ready to display.
8556                    if (winAnimator.commitFinishDrawingLocked(currentTime)) {
8557                        if ((w.mAttrs.flags
8558                                & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
8559                            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
8560                                    "First draw done in potential wallpaper target " + w);
8561                            mInnerFields.mWallpaperMayChange = true;
8562                            mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
8563                            if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
8564                                debugLayoutRepeats("updateWindowsAndWallpaperLocked 1",
8565                                    mPendingLayoutChanges);
8566                            }
8567                        }
8568                    }
8569
8570                    winAnimator.setSurfaceBoundaries(recoveringMemory);
8571                }
8572
8573                if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) {
8574                    focusDisplayed = true;
8575                }
8576
8577                updateResizingWindows(w);
8578            }
8579
8580            if (focusDisplayed) {
8581                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8582            }
8583
8584            if (!mInnerFields.mDimming && mAnimator.isDimming()) {
8585                mAnimator.stopDimming();
8586            }
8587        } catch (RuntimeException e) {
8588            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
8589        } finally {
8590            Surface.closeTransaction();
8591        }
8592
8593        // If we are ready to perform an app transition, check through
8594        // all of the app tokens to be shown and see if they are ready
8595        // to go.
8596        if (mAppTransitionReady) {
8597            mPendingLayoutChanges |= handleAppTransitionReadyLocked();
8598            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
8599                mPendingLayoutChanges);
8600        }
8601
8602        mInnerFields.mAdjResult = 0;
8603
8604        if (!mAnimator.mAnimating && mAppTransitionRunning) {
8605            // We have finished the animation of an app transition.  To do
8606            // this, we have delayed a lot of operations like showing and
8607            // hiding apps, moving apps in Z-order, etc.  The app token list
8608            // reflects the correct Z-order, but the window list may now
8609            // be out of sync with it.  So here we will just rebuild the
8610            // entire app window list.  Fun!
8611            mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
8612            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
8613                mPendingLayoutChanges);
8614        }
8615
8616        if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 &&
8617                !mAppTransitionReady) {
8618            // At this point, there was a window with a wallpaper that
8619            // was force hiding other windows behind it, but now it
8620            // is going away.  This may be simple -- just animate
8621            // away the wallpaper and its window -- or it may be
8622            // hard -- the wallpaper now needs to be shown behind
8623            // something that was hidden.
8624            mPendingLayoutChanges |= animateAwayWallpaperLocked();
8625            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
8626                mPendingLayoutChanges);
8627        }
8628        mInnerFields.mWallpaperForceHidingChanged = false;
8629
8630        if (mInnerFields.mWallpaperMayChange) {
8631            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
8632                    "Wallpaper may change!  Adjusting");
8633            mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8634        }
8635
8636        if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8637            if (DEBUG_WALLPAPER) Slog.v(TAG,
8638                    "Wallpaper layer changed: assigning layers + relayout");
8639            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8640            assignLayersLocked();
8641        } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
8642            if (DEBUG_WALLPAPER) Slog.v(TAG,
8643                    "Wallpaper visibility changed: relayout");
8644            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8645        }
8646
8647        if (mFocusMayChange) {
8648            mFocusMayChange = false;
8649            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8650                    false /*updateInputWindows*/)) {
8651                mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8652                mInnerFields.mAdjResult = 0;
8653            }
8654        }
8655
8656        if (mLayoutNeeded) {
8657            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8658            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges);
8659        }
8660
8661        if (!mResizingWindows.isEmpty()) {
8662            for (i = mResizingWindows.size() - 1; i >= 0; i--) {
8663                WindowState win = mResizingWindows.get(i);
8664                final WindowStateAnimator winAnimator = win.mWinAnimator;
8665                try {
8666                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8667                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
8668                    int diff = 0;
8669                    boolean configChanged =
8670                        win.mConfiguration != mCurConfiguration
8671                        && (win.mConfiguration == null
8672                                || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0);
8673                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
8674                            && configChanged) {
8675                        Slog.i(TAG, "Sending new config to window " + win + ": "
8676                                + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
8677                                + " / " + mCurConfiguration + " / 0x"
8678                                + Integer.toHexString(diff));
8679                    }
8680                    win.mConfiguration = mCurConfiguration;
8681                    if (DEBUG_ORIENTATION &&
8682                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
8683                            TAG, "Resizing " + win + " WITH DRAW PENDING");
8684                    win.mClient.resized((int)winAnimator.mSurfaceW,
8685                            (int)winAnimator.mSurfaceH,
8686                            win.mLastContentInsets, win.mLastVisibleInsets,
8687                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
8688                            configChanged ? win.mConfiguration : null);
8689                    win.mContentInsetsChanged = false;
8690                    win.mVisibleInsetsChanged = false;
8691                    winAnimator.mSurfaceResized = false;
8692                } catch (RemoteException e) {
8693                    win.mOrientationChanging = false;
8694                }
8695            }
8696            mResizingWindows.clear();
8697        }
8698
8699        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
8700                "With display frozen, orientationChangeComplete="
8701                + mInnerFields.mOrientationChangeComplete);
8702        if (mInnerFields.mOrientationChangeComplete) {
8703            if (mWindowsFreezingScreen) {
8704                mWindowsFreezingScreen = false;
8705                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8706            }
8707            stopFreezingDisplayLocked();
8708        }
8709
8710        // Destroy the surface of any windows that are no longer visible.
8711        boolean wallpaperDestroyed = false;
8712        i = mDestroySurface.size();
8713        if (i > 0) {
8714            do {
8715                i--;
8716                WindowState win = mDestroySurface.get(i);
8717                win.mDestroying = false;
8718                if (mInputMethodWindow == win) {
8719                    mInputMethodWindow = null;
8720                }
8721                if (win == mWallpaperTarget) {
8722                    wallpaperDestroyed = true;
8723                }
8724                win.mWinAnimator.destroySurfaceLocked();
8725            } while (i > 0);
8726            mDestroySurface.clear();
8727        }
8728
8729        // Time to remove any exiting tokens?
8730        for (i=mExitingTokens.size()-1; i>=0; i--) {
8731            WindowToken token = mExitingTokens.get(i);
8732            if (!token.hasVisible) {
8733                mExitingTokens.remove(i);
8734                if (token.windowType == TYPE_WALLPAPER) {
8735                    mWallpaperTokens.remove(token);
8736                }
8737            }
8738        }
8739
8740        // Time to remove any exiting applications?
8741        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8742            AppWindowToken token = mExitingAppTokens.get(i);
8743            if (!token.hasVisible && !mClosingApps.contains(token)) {
8744                // Make sure there is no animation running on this token,
8745                // so any windows associated with it will be removed as
8746                // soon as their animations are complete
8747                token.mAppAnimator.clearAnimation();
8748                token.mAppAnimator.animating = false;
8749                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
8750                        "performLayout: App token exiting now removed" + token);
8751                mAppTokens.remove(token);
8752                mAnimatingAppTokens.remove(token);
8753                mExitingAppTokens.remove(i);
8754            }
8755        }
8756
8757        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
8758            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
8759                try {
8760                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
8761                } catch (RemoteException e) {
8762                }
8763            }
8764            mRelayoutWhileAnimating.clear();
8765        }
8766
8767        if (wallpaperDestroyed) {
8768            mLayoutNeeded |= adjustWallpaperWindowsLocked() != 0;
8769        }
8770        if (mPendingLayoutChanges != 0) {
8771            mLayoutNeeded = true;
8772        }
8773
8774        // Finally update all input windows now that the window changes have stabilized.
8775        mInputMonitor.updateInputWindowsLw(true /*force*/);
8776
8777        setHoldScreenLocked(mInnerFields.mHoldScreen != null);
8778        if (!mDisplayFrozen) {
8779            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
8780                mPowerManager.setScreenBrightnessOverride(-1);
8781            } else {
8782                mPowerManager.setScreenBrightnessOverride((int)
8783                        (mInnerFields.mScreenBrightness * PowerManager.BRIGHTNESS_ON));
8784            }
8785            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
8786                mPowerManager.setButtonBrightnessOverride(-1);
8787            } else {
8788                mPowerManager.setButtonBrightnessOverride((int)
8789                        (mInnerFields.mButtonBrightness * PowerManager.BRIGHTNESS_ON));
8790            }
8791        }
8792        if (mInnerFields.mHoldScreen != mHoldingScreenOn) {
8793            mHoldingScreenOn = mInnerFields.mHoldScreen;
8794            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, mInnerFields.mHoldScreen);
8795            mH.sendMessage(m);
8796        }
8797
8798        if (mTurnOnScreen) {
8799            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
8800            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
8801                    LocalPowerManager.BUTTON_EVENT, true);
8802            mTurnOnScreen = false;
8803        }
8804
8805        if (mInnerFields.mUpdateRotation) {
8806            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8807            if (updateRotationUncheckedLocked(false)) {
8808                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8809            } else {
8810                mInnerFields.mUpdateRotation = false;
8811            }
8812        }
8813
8814        if (mInnerFields.mOrientationChangeComplete && !mLayoutNeeded &&
8815                !mInnerFields.mUpdateRotation) {
8816            checkDrawnWindowsLocked();
8817        }
8818
8819        // Check to see if we are now in a state where the screen should
8820        // be enabled, because the window obscured flags have changed.
8821        enableScreenIfNeededLocked();
8822
8823        scheduleAnimationLocked();
8824
8825        if (DEBUG_WINDOW_TRACE) {
8826            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges="
8827                + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded
8828                + " animating=" + mAnimator.mAnimating);
8829        }
8830    }
8831
8832    void checkDrawnWindowsLocked() {
8833        if (mWaitingForDrawn.size() > 0) {
8834            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
8835                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
8836                WindowState win = pair.first;
8837                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
8838                //        + win.mRemoved + " visible=" + win.isVisibleLw()
8839                //        + " shown=" + win.mSurfaceShown);
8840                if (win.mRemoved || !win.isVisibleLw()) {
8841                    // Window has been removed or made invisible; no draw
8842                    // will now happen, so stop waiting.
8843                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
8844                    try {
8845                        pair.second.sendResult(null);
8846                    } catch (RemoteException e) {
8847                    }
8848                    mWaitingForDrawn.remove(pair);
8849                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8850                } else if (win.mWinAnimator.mSurfaceShown) {
8851                    // Window is now drawn (and shown).
8852                    try {
8853                        pair.second.sendResult(null);
8854                    } catch (RemoteException e) {
8855                    }
8856                    mWaitingForDrawn.remove(pair);
8857                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8858                }
8859            }
8860        }
8861    }
8862
8863    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
8864        synchronized (mWindowMap) {
8865            WindowState win = windowForClientLocked(null, token, true);
8866            if (win != null) {
8867                Pair<WindowState, IRemoteCallback> pair =
8868                        new Pair<WindowState, IRemoteCallback>(win, callback);
8869                Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8870                mH.sendMessageDelayed(m, 2000);
8871                mWaitingForDrawn.add(pair);
8872                checkDrawnWindowsLocked();
8873            }
8874        }
8875    }
8876
8877    /**
8878     * Must be called with the main window manager lock held.
8879     */
8880    void setHoldScreenLocked(boolean holding) {
8881        boolean state = mHoldingScreenWakeLock.isHeld();
8882        if (holding != state) {
8883            if (holding) {
8884                mPolicy.screenOnStartedLw();
8885                mHoldingScreenWakeLock.acquire();
8886            } else {
8887                mPolicy.screenOnStoppedLw();
8888                mHoldingScreenWakeLock.release();
8889            }
8890        }
8891    }
8892
8893    void requestTraversalLocked() {
8894        if (!mTraversalScheduled) {
8895            mTraversalScheduled = true;
8896            mH.sendEmptyMessage(H.DO_TRAVERSAL);
8897        }
8898    }
8899
8900    void scheduleAnimationLocked() {
8901        if (!mAnimationScheduled) {
8902            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationRunnable, null);
8903            mAnimationScheduled = true;
8904        }
8905    }
8906
8907    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
8908                                           boolean secure) {
8909        final Surface surface = winAnimator.mSurface;
8910        boolean leakedSurface = false;
8911        boolean killedApps = false;
8912
8913        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
8914                winAnimator.mSession.mPid, operation);
8915
8916        if (mForceRemoves == null) {
8917            mForceRemoves = new ArrayList<WindowState>();
8918        }
8919
8920        long callingIdentity = Binder.clearCallingIdentity();
8921        try {
8922            // There was some problem...   first, do a sanity check of the
8923            // window list to make sure we haven't left any dangling surfaces
8924            // around.
8925            int N = mWindows.size();
8926            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
8927            for (int i=0; i<N; i++) {
8928                WindowState ws = mWindows.get(i);
8929                WindowStateAnimator wsa = ws.mWinAnimator;
8930                if (wsa.mSurface != null) {
8931                    if (!mSessions.contains(wsa.mSession)) {
8932                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8933                                + ws + " surface=" + wsa.mSurface
8934                                + " token=" + ws.mToken
8935                                + " pid=" + ws.mSession.mPid
8936                                + " uid=" + ws.mSession.mUid);
8937                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8938                        wsa.mSurface.destroy();
8939                        wsa.mSurfaceShown = false;
8940                        wsa.mSurface = null;
8941                        ws.mHasSurface = false;
8942                        mForceRemoves.add(ws);
8943                        i--;
8944                        N--;
8945                        leakedSurface = true;
8946                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
8947                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
8948                                + ws + " surface=" + wsa.mSurface
8949                                + " token=" + ws.mAppToken);
8950                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8951                        wsa.mSurface.destroy();
8952                        wsa.mSurfaceShown = false;
8953                        wsa.mSurface = null;
8954                        ws.mHasSurface = false;
8955                        leakedSurface = true;
8956                    }
8957                }
8958            }
8959
8960            if (!leakedSurface) {
8961                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
8962                SparseIntArray pidCandidates = new SparseIntArray();
8963                for (int i=0; i<N; i++) {
8964                    WindowStateAnimator wsa = mWindows.get(i).mWinAnimator;
8965                    if (wsa.mSurface != null) {
8966                        pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
8967                    }
8968                }
8969                if (pidCandidates.size() > 0) {
8970                    int[] pids = new int[pidCandidates.size()];
8971                    for (int i=0; i<pids.length; i++) {
8972                        pids[i] = pidCandidates.keyAt(i);
8973                    }
8974                    try {
8975                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
8976                            killedApps = true;
8977                        }
8978                    } catch (RemoteException e) {
8979                    }
8980                }
8981            }
8982
8983            if (leakedSurface || killedApps) {
8984                // We managed to reclaim some memory, so get rid of the trouble
8985                // surface and ask the app to request another one.
8986                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8987                if (surface != null) {
8988                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
8989                            "RECOVER DESTROY", null);
8990                    surface.destroy();
8991                    winAnimator.mSurfaceShown = false;
8992                    winAnimator.mSurface = null;
8993                    winAnimator.mWin.mHasSurface = false;
8994                }
8995
8996                try {
8997                    winAnimator.mWin.mClient.dispatchGetNewSurface();
8998                } catch (RemoteException e) {
8999                }
9000            }
9001        } finally {
9002            Binder.restoreCallingIdentity(callingIdentity);
9003        }
9004
9005        return leakedSurface || killedApps;
9006    }
9007
9008    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9009        WindowState newFocus = computeFocusedWindowLocked();
9010        if (mCurrentFocus != newFocus) {
9011            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
9012            // This check makes sure that we don't already have the focus
9013            // change message pending.
9014            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9015            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9016            if (localLOGV) Slog.v(
9017                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
9018            final WindowState oldFocus = mCurrentFocus;
9019            mCurrentFocus = newFocus;
9020            mAnimator.setCurrentFocus(newFocus);
9021            mLosingFocus.remove(newFocus);
9022            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9023
9024            final WindowState imWindow = mInputMethodWindow;
9025            if (newFocus != imWindow && oldFocus != imWindow) {
9026                if (moveInputMethodWindowsIfNeededLocked(
9027                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
9028                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
9029                    mLayoutNeeded = true;
9030                }
9031                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9032                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
9033                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9034                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9035                    // Client will do the layout, but we need to assign layers
9036                    // for handleNewWindowLocked() below.
9037                    assignLayersLocked();
9038                }
9039            }
9040
9041            if ((focusChanged&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9042                // The change in focus caused us to need to do a layout.  Okay.
9043                mLayoutNeeded = true;
9044                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9045                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
9046                }
9047            }
9048
9049            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9050                // If we defer assigning layers, then the caller is responsible for
9051                // doing this part.
9052                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9053            }
9054
9055            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
9056            return true;
9057        }
9058        return false;
9059    }
9060
9061    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9062        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9063    }
9064
9065    private WindowState computeFocusedWindowLocked() {
9066        WindowState result = null;
9067        WindowState win;
9068
9069        int nextAppIndex = mAppTokens.size()-1;
9070        WindowToken nextApp = nextAppIndex >= 0
9071            ? mAppTokens.get(nextAppIndex) : null;
9072
9073        for (int i = mWindows.size() - 1; i >= 0; i--) {
9074            win = mWindows.get(i);
9075
9076            if (localLOGV || DEBUG_FOCUS) Slog.v(
9077                TAG, "Looking for focus: " + i
9078                + " = " + win
9079                + ", flags=" + win.mAttrs.flags
9080                + ", canReceive=" + win.canReceiveKeys());
9081
9082            AppWindowToken thisApp = win.mAppToken;
9083
9084            // If this window's application has been removed, just skip it.
9085            if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
9086                continue;
9087            }
9088
9089            // If there is a focused app, don't allow focus to go to any
9090            // windows below it.  If this is an application window, step
9091            // through the app tokens until we find its app.
9092            if (thisApp != null && nextApp != null && thisApp != nextApp
9093                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
9094                int origAppIndex = nextAppIndex;
9095                while (nextAppIndex > 0) {
9096                    if (nextApp == mFocusedApp) {
9097                        // Whoops, we are below the focused app...  no focus
9098                        // for you!
9099                        if (localLOGV || DEBUG_FOCUS) Slog.v(
9100                            TAG, "Reached focused app: " + mFocusedApp);
9101                        return null;
9102                    }
9103                    nextAppIndex--;
9104                    nextApp = mAppTokens.get(nextAppIndex);
9105                    if (nextApp == thisApp) {
9106                        break;
9107                    }
9108                }
9109                if (thisApp != nextApp) {
9110                    // Uh oh, the app token doesn't exist!  This shouldn't
9111                    // happen, but if it does we can get totally hosed...
9112                    // so restart at the original app.
9113                    nextAppIndex = origAppIndex;
9114                    nextApp = mAppTokens.get(nextAppIndex);
9115                }
9116            }
9117
9118            // Dispatch to this window if it is wants key events.
9119            if (win.canReceiveKeys()) {
9120                if (DEBUG_FOCUS) Slog.v(
9121                        TAG, "Found focus @ " + i + " = " + win);
9122                result = win;
9123                break;
9124            }
9125        }
9126
9127        return result;
9128    }
9129
9130    private void startFreezingDisplayLocked(boolean inTransaction) {
9131        if (mDisplayFrozen) {
9132            return;
9133        }
9134
9135        if (mDisplay == null || !mPolicy.isScreenOnFully()) {
9136            // No need to freeze the screen before the system is ready or if
9137            // the screen is off.
9138            return;
9139        }
9140
9141        mScreenFrozenLock.acquire();
9142
9143        mDisplayFrozen = true;
9144
9145        mInputMonitor.freezeInputDispatchingLw();
9146
9147        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
9148            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
9149            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
9150            mNextAppTransitionPackage = null;
9151            mNextAppTransitionThumbnail = null;
9152            mAppTransitionReady = true;
9153        }
9154
9155        if (PROFILE_ORIENTATION) {
9156            File file = new File("/data/system/frozen");
9157            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9158        }
9159
9160        if (CUSTOM_SCREEN_ROTATION) {
9161            if (mAnimator.mScreenRotationAnimation != null) {
9162                mAnimator.mScreenRotationAnimation.kill();
9163                mAnimator.mScreenRotationAnimation = null;
9164            }
9165
9166            mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
9167                    mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight,
9168                    mDisplay.getRotation());
9169
9170            if (!mAnimator.mScreenRotationAnimation.hasScreenshot()) {
9171                Surface.freezeDisplay(0);
9172            }
9173        } else {
9174            Surface.freezeDisplay(0);
9175        }
9176    }
9177
9178    private void stopFreezingDisplayLocked() {
9179        if (!mDisplayFrozen) {
9180            return;
9181        }
9182
9183        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
9184            if (DEBUG_ORIENTATION) Slog.d(TAG,
9185                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
9186                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
9187                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen);
9188            return;
9189        }
9190
9191        mDisplayFrozen = false;
9192        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9193        if (PROFILE_ORIENTATION) {
9194            Debug.stopMethodTracing();
9195        }
9196
9197        boolean updateRotation = false;
9198
9199        if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
9200                && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
9201            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
9202            if (mAnimator.mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9203                    mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
9204                scheduleAnimationLocked();
9205            } else {
9206                mAnimator.mScreenRotationAnimation.kill();
9207                mAnimator.mScreenRotationAnimation = null;
9208                updateRotation = true;
9209            }
9210        } else {
9211            if (mAnimator.mScreenRotationAnimation != null) {
9212                mAnimator.mScreenRotationAnimation.kill();
9213                mAnimator.mScreenRotationAnimation = null;
9214            }
9215            updateRotation = true;
9216        }
9217        Surface.unfreezeDisplay(0);
9218
9219        mInputMonitor.thawInputDispatchingLw();
9220
9221        boolean configChanged;
9222
9223        // While the display is frozen we don't re-compute the orientation
9224        // to avoid inconsistent states.  However, something interesting
9225        // could have actually changed during that time so re-evaluate it
9226        // now to catch that.
9227        configChanged = updateOrientationFromAppTokensLocked(false);
9228
9229        // A little kludge: a lot could have happened while the
9230        // display was frozen, so now that we are coming back we
9231        // do a gc so that any remote references the system
9232        // processes holds on others can be released if they are
9233        // no longer needed.
9234        mH.removeMessages(H.FORCE_GC);
9235        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
9236                2000);
9237
9238        mScreenFrozenLock.release();
9239
9240        if (updateRotation) {
9241            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9242            configChanged |= updateRotationUncheckedLocked(false);
9243        }
9244
9245        if (configChanged) {
9246            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9247        }
9248    }
9249
9250    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
9251            DisplayMetrics dm) {
9252        if (index < tokens.length) {
9253            String str = tokens[index];
9254            if (str != null && str.length() > 0) {
9255                try {
9256                    int val = Integer.parseInt(str);
9257                    return val;
9258                } catch (Exception e) {
9259                }
9260            }
9261        }
9262        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
9263            return defDps;
9264        }
9265        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
9266        return val;
9267    }
9268
9269    void createWatermark() {
9270        if (mWatermark != null) {
9271            return;
9272        }
9273
9274        File file = new File("/system/etc/setup.conf");
9275        FileInputStream in = null;
9276        try {
9277            in = new FileInputStream(file);
9278            DataInputStream ind = new DataInputStream(in);
9279            String line = ind.readLine();
9280            if (line != null) {
9281                String[] toks = line.split("%");
9282                if (toks != null && toks.length > 0) {
9283                    mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks);
9284                }
9285            }
9286        } catch (FileNotFoundException e) {
9287        } catch (IOException e) {
9288        } finally {
9289            if (in != null) {
9290                try {
9291                    in.close();
9292                } catch (IOException e) {
9293                }
9294            }
9295        }
9296    }
9297
9298    @Override
9299    public void statusBarVisibilityChanged(int visibility) {
9300        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
9301                != PackageManager.PERMISSION_GRANTED) {
9302            throw new SecurityException("Caller does not hold permission "
9303                    + android.Manifest.permission.STATUS_BAR);
9304        }
9305
9306        synchronized (mWindowMap) {
9307            mLastStatusBarVisibility = visibility;
9308            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
9309            updateStatusBarVisibilityLocked(visibility);
9310        }
9311    }
9312
9313    void updateStatusBarVisibilityLocked(int visibility) {
9314        mInputManager.setSystemUiVisibility(visibility);
9315        final int N = mWindows.size();
9316        for (int i = 0; i < N; i++) {
9317            WindowState ws = mWindows.get(i);
9318            try {
9319                int curValue = ws.mSystemUiVisibility;
9320                int diff = curValue ^ visibility;
9321                // We are only interested in differences of one of the
9322                // clearable flags...
9323                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
9324                // ...if it has actually been cleared.
9325                diff &= ~visibility;
9326                int newValue = (curValue&~diff) | (visibility&diff);
9327                if (newValue != curValue) {
9328                    ws.mSeq++;
9329                    ws.mSystemUiVisibility = newValue;
9330                }
9331                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
9332                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
9333                            visibility, newValue, diff);
9334                }
9335            } catch (RemoteException e) {
9336                // so sorry
9337            }
9338        }
9339    }
9340
9341    @Override
9342    public void reevaluateStatusBarVisibility() {
9343        synchronized (mWindowMap) {
9344            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
9345            updateStatusBarVisibilityLocked(visibility);
9346            performLayoutAndPlaceSurfacesLocked();
9347        }
9348    }
9349
9350    @Override
9351    public FakeWindow addFakeWindow(Looper looper,
9352            InputEventReceiver.Factory inputEventReceiverFactory,
9353            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
9354            boolean hasFocus, boolean touchFullscreen) {
9355        synchronized (mWindowMap) {
9356            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
9357                    name, windowType,
9358                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
9359            int i=0;
9360            while (i<mFakeWindows.size()) {
9361                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
9362                    break;
9363                }
9364            }
9365            mFakeWindows.add(i, fw);
9366            mInputMonitor.updateInputWindowsLw(true);
9367            return fw;
9368        }
9369    }
9370
9371    boolean removeFakeWindowLocked(FakeWindow window) {
9372        synchronized (mWindowMap) {
9373            if (mFakeWindows.remove(window)) {
9374                mInputMonitor.updateInputWindowsLw(true);
9375                return true;
9376            }
9377            return false;
9378        }
9379    }
9380
9381    // It is assumed that this method is called only by InputMethodManagerService.
9382    public void saveLastInputMethodWindowForTransition() {
9383        synchronized (mWindowMap) {
9384            if (mInputMethodWindow != null) {
9385                mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
9386            }
9387        }
9388    }
9389
9390    @Override
9391    public boolean hasNavigationBar() {
9392        return mPolicy.hasNavigationBar();
9393    }
9394
9395    public void lockNow() {
9396        mPolicy.lockNow();
9397    }
9398
9399    void dumpPolicyLocked(FileDescriptor fd, PrintWriter pw, String[] args, boolean dumpAll) {
9400        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
9401        mPolicy.dump("    ", fd, pw, args);
9402    }
9403
9404    void dumpTokensLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9405        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
9406        if (mTokenMap.size() > 0) {
9407            pw.println("  All tokens:");
9408            Iterator<WindowToken> it = mTokenMap.values().iterator();
9409            while (it.hasNext()) {
9410                WindowToken token = it.next();
9411                pw.print("  Token "); pw.print(token.token);
9412                if (dumpAll) {
9413                    pw.println(':');
9414                    token.dump(pw, "    ");
9415                } else {
9416                    pw.println();
9417                }
9418            }
9419        }
9420        if (mWallpaperTokens.size() > 0) {
9421            pw.println();
9422            pw.println("  Wallpaper tokens:");
9423            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
9424                WindowToken token = mWallpaperTokens.get(i);
9425                pw.print("  Wallpaper #"); pw.print(i);
9426                        pw.print(' '); pw.print(token);
9427                if (dumpAll) {
9428                    pw.println(':');
9429                    token.dump(pw, "    ");
9430                } else {
9431                    pw.println();
9432                }
9433            }
9434        }
9435        if (mAppTokens.size() > 0) {
9436            pw.println();
9437            pw.println("  Application tokens in Z order:");
9438            for (int i=mAppTokens.size()-1; i>=0; i--) {
9439                pw.print("  App #"); pw.print(i); pw.println(": ");
9440                        mAppTokens.get(i).dump(pw, "    ");
9441            }
9442        }
9443        if (mFinishedStarting.size() > 0) {
9444            pw.println();
9445            pw.println("  Finishing start of application tokens:");
9446            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9447                WindowToken token = mFinishedStarting.get(i);
9448                pw.print("  Finished Starting #"); pw.print(i);
9449                        pw.print(' '); pw.print(token);
9450                if (dumpAll) {
9451                    pw.println(':');
9452                    token.dump(pw, "    ");
9453                } else {
9454                    pw.println();
9455                }
9456            }
9457        }
9458        if (mExitingTokens.size() > 0) {
9459            pw.println();
9460            pw.println("  Exiting tokens:");
9461            for (int i=mExitingTokens.size()-1; i>=0; i--) {
9462                WindowToken token = mExitingTokens.get(i);
9463                pw.print("  Exiting #"); pw.print(i);
9464                        pw.print(' '); pw.print(token);
9465                if (dumpAll) {
9466                    pw.println(':');
9467                    token.dump(pw, "    ");
9468                } else {
9469                    pw.println();
9470                }
9471            }
9472        }
9473        if (mExitingAppTokens.size() > 0) {
9474            pw.println();
9475            pw.println("  Exiting application tokens:");
9476            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9477                WindowToken token = mExitingAppTokens.get(i);
9478                pw.print("  Exiting App #"); pw.print(i);
9479                        pw.print(' '); pw.print(token);
9480                if (dumpAll) {
9481                    pw.println(':');
9482                    token.dump(pw, "    ");
9483                } else {
9484                    pw.println();
9485                }
9486            }
9487        }
9488        if (mAppTransitionRunning && mAnimatingAppTokens.size() > 0) {
9489            pw.println();
9490            pw.println("  Application tokens during animation:");
9491            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
9492                WindowToken token = mAnimatingAppTokens.get(i);
9493                pw.print("  App moving to bottom #"); pw.print(i);
9494                        pw.print(' '); pw.print(token);
9495                if (dumpAll) {
9496                    pw.println(':');
9497                    token.dump(pw, "    ");
9498                } else {
9499                    pw.println();
9500                }
9501            }
9502        }
9503        pw.println();
9504        if (mOpeningApps.size() > 0) {
9505            pw.print("  mOpeningApps="); pw.println(mOpeningApps);
9506        }
9507        if (mClosingApps.size() > 0) {
9508            pw.print("  mClosingApps="); pw.println(mClosingApps);
9509        }
9510    }
9511
9512    void dumpSessionsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9513        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
9514        if (mSessions.size() > 0) {
9515            Iterator<Session> it = mSessions.iterator();
9516            while (it.hasNext()) {
9517                Session s = it.next();
9518                pw.print("  Session "); pw.print(s); pw.println(':');
9519                s.dump(pw, "    ");
9520            }
9521        }
9522    }
9523
9524    void dumpWindowsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
9525            ArrayList<WindowState> windows) {
9526        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
9527        for (int i=mWindows.size()-1; i>=0; i--) {
9528            WindowState w = mWindows.get(i);
9529            if (windows == null || windows.contains(w)) {
9530                pw.print("  Window #"); pw.print(i); pw.print(' ');
9531                        pw.print(w); pw.println(":");
9532                w.dump(pw, "    ", dumpAll || windows != null);
9533            }
9534        }
9535        if (mInputMethodDialogs.size() > 0) {
9536            pw.println();
9537            pw.println("  Input method dialogs:");
9538            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
9539                WindowState w = mInputMethodDialogs.get(i);
9540                if (windows == null || windows.contains(w)) {
9541                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
9542                }
9543            }
9544        }
9545        if (mPendingRemove.size() > 0) {
9546            pw.println();
9547            pw.println("  Remove pending for:");
9548            for (int i=mPendingRemove.size()-1; i>=0; i--) {
9549                WindowState w = mPendingRemove.get(i);
9550                if (windows == null || windows.contains(w)) {
9551                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
9552                            pw.print(w);
9553                    if (dumpAll) {
9554                        pw.println(":");
9555                        w.dump(pw, "    ", true);
9556                    } else {
9557                        pw.println();
9558                    }
9559                }
9560            }
9561        }
9562        if (mForceRemoves != null && mForceRemoves.size() > 0) {
9563            pw.println();
9564            pw.println("  Windows force removing:");
9565            for (int i=mForceRemoves.size()-1; i>=0; i--) {
9566                WindowState w = mForceRemoves.get(i);
9567                pw.print("  Removing #"); pw.print(i); pw.print(' ');
9568                        pw.print(w);
9569                if (dumpAll) {
9570                    pw.println(":");
9571                    w.dump(pw, "    ", true);
9572                } else {
9573                    pw.println();
9574                }
9575            }
9576        }
9577        if (mDestroySurface.size() > 0) {
9578            pw.println();
9579            pw.println("  Windows waiting to destroy their surface:");
9580            for (int i=mDestroySurface.size()-1; i>=0; i--) {
9581                WindowState w = mDestroySurface.get(i);
9582                if (windows == null || windows.contains(w)) {
9583                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
9584                            pw.print(w);
9585                    if (dumpAll) {
9586                        pw.println(":");
9587                        w.dump(pw, "    ", true);
9588                    } else {
9589                        pw.println();
9590                    }
9591                }
9592            }
9593        }
9594        if (mLosingFocus.size() > 0) {
9595            pw.println();
9596            pw.println("  Windows losing focus:");
9597            for (int i=mLosingFocus.size()-1; i>=0; i--) {
9598                WindowState w = mLosingFocus.get(i);
9599                if (windows == null || windows.contains(w)) {
9600                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
9601                            pw.print(w);
9602                    if (dumpAll) {
9603                        pw.println(":");
9604                        w.dump(pw, "    ", true);
9605                    } else {
9606                        pw.println();
9607                    }
9608                }
9609            }
9610        }
9611        if (mResizingWindows.size() > 0) {
9612            pw.println();
9613            pw.println("  Windows waiting to resize:");
9614            for (int i=mResizingWindows.size()-1; i>=0; i--) {
9615                WindowState w = mResizingWindows.get(i);
9616                if (windows == null || windows.contains(w)) {
9617                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
9618                            pw.print(w);
9619                    if (dumpAll) {
9620                        pw.println(":");
9621                        w.dump(pw, "    ", true);
9622                    } else {
9623                        pw.println();
9624                    }
9625                }
9626            }
9627        }
9628        if (mWaitingForDrawn.size() > 0) {
9629            pw.println();
9630            pw.println("  Clients waiting for these windows to be drawn:");
9631            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
9632                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
9633                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
9634                        pw.print(": "); pw.println(pair.second);
9635            }
9636        }
9637        pw.println();
9638        if (mDisplay != null) {
9639            pw.print("  Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
9640                    pw.print(mInitialDisplayHeight);
9641                    if (mInitialDisplayWidth != mBaseDisplayWidth
9642                            || mInitialDisplayHeight != mBaseDisplayHeight) {
9643                        pw.print(" base=");
9644                        pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
9645                    }
9646                    final int rawWidth = mDisplay.getRawWidth();
9647                    final int rawHeight = mDisplay.getRawHeight();
9648                    if (rawWidth != mCurDisplayWidth || rawHeight != mCurDisplayHeight) {
9649                        pw.print(" raw="); pw.print(rawWidth); pw.print("x"); pw.print(rawHeight);
9650                    }
9651                    pw.print(" cur=");
9652                    pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
9653                    pw.print(" app=");
9654                    pw.print(mAppDisplayWidth); pw.print("x"); pw.print(mAppDisplayHeight);
9655                    pw.print(" rng="); pw.print(mSmallestDisplayWidth);
9656                    pw.print("x"); pw.print(mSmallestDisplayHeight);
9657                    pw.print("-"); pw.print(mLargestDisplayWidth);
9658                    pw.print("x"); pw.println(mLargestDisplayHeight);
9659        } else {
9660            pw.println("  NO DISPLAY");
9661        }
9662        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
9663        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
9664        if (mLastFocus != mCurrentFocus) {
9665            pw.print("  mLastFocus="); pw.println(mLastFocus);
9666        }
9667        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
9668        if (mInputMethodTarget != null) {
9669            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
9670        }
9671        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
9672                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
9673        if (dumpAll) {
9674            pw.print("  mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
9675                    pw.print(" mSystemDecorLayer="); pw.println(mSystemDecorLayer);
9676            if (mLastStatusBarVisibility != 0) {
9677                pw.print("  mLastStatusBarVisibility=0x");
9678                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
9679            }
9680            if (mInputMethodWindow != null) {
9681                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
9682            }
9683            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
9684            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
9685                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
9686                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
9687            }
9688            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
9689                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
9690            if (mInputMethodAnimLayerAdjustment != 0 ||
9691                    mWallpaperAnimLayerAdjustment != 0) {
9692                pw.print("  mInputMethodAnimLayerAdjustment=");
9693                        pw.print(mInputMethodAnimLayerAdjustment);
9694                        pw.print("  mWallpaperAnimLayerAdjustment=");
9695                        pw.println(mWallpaperAnimLayerAdjustment);
9696            }
9697            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
9698                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9699            pw.print("  mLayoutNeeded="); pw.println(mLayoutNeeded);
9700            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
9701                    pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9702                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
9703                    pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
9704            pw.print("  mRotation="); pw.print(mRotation);
9705                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
9706            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
9707                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
9708            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
9709            if (mAnimator.mScreenRotationAnimation != null) {
9710                pw.println("  mScreenRotationAnimation:");
9711                mAnimator.mScreenRotationAnimation.printTo("    ", pw);
9712            }
9713            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9714                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
9715                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
9716            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
9717                    pw.print("  mNextAppTransition=0x");
9718                    pw.print(Integer.toHexString(mNextAppTransition));
9719                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
9720            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
9721                    pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout);
9722            if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) {
9723                pw.print("  mNextAppTransitionType="); pw.println(mNextAppTransitionType);
9724            }
9725            switch (mNextAppTransitionType) {
9726                case ActivityOptions.ANIM_CUSTOM:
9727                    pw.print("  mNextAppTransitionPackage=");
9728                            pw.print(mNextAppTransitionPackage);
9729                            pw.print(" mNextAppTransitionEnter=0x");
9730                            pw.print(Integer.toHexString(mNextAppTransitionEnter));
9731                            pw.print(" mNextAppTransitionExit=0x");
9732                            pw.print(Integer.toHexString(mNextAppTransitionExit));
9733                    break;
9734                case ActivityOptions.ANIM_SCALE_UP:
9735                    pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
9736                            pw.print(" mNextAppTransitionStartY=");
9737                            pw.println(mNextAppTransitionStartY);
9738                    pw.print("  mNextAppTransitionStartWidth=");
9739                            pw.print(mNextAppTransitionStartWidth);
9740                            pw.print(" mNextAppTransitionStartHeight=");
9741                            pw.println(mNextAppTransitionStartHeight);
9742                    break;
9743                case ActivityOptions.ANIM_THUMBNAIL:
9744                case ActivityOptions.ANIM_THUMBNAIL_DELAYED:
9745                    pw.print("  mNextAppTransitionThumbnail=");
9746                            pw.print(mNextAppTransitionThumbnail);
9747                            pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
9748                            pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY);
9749                            pw.print(" mNextAppTransitionDelayed="); pw.println(mNextAppTransitionDelayed);
9750                    break;
9751            }
9752            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9753                    pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9754        }
9755    }
9756
9757    boolean dumpWindows(FileDescriptor fd, PrintWriter pw, String name, String[] args,
9758            int opti, boolean dumpAll) {
9759        ArrayList<WindowState> windows = new ArrayList<WindowState>();
9760        if ("visible".equals(name)) {
9761            synchronized(mWindowMap) {
9762                for (int i=mWindows.size()-1; i>=0; i--) {
9763                    WindowState w = mWindows.get(i);
9764                    if (w.mWinAnimator.mSurfaceShown) {
9765                        windows.add(w);
9766                    }
9767                }
9768            }
9769        } else {
9770            int objectId = 0;
9771            // See if this is an object ID.
9772            try {
9773                objectId = Integer.parseInt(name, 16);
9774                name = null;
9775            } catch (RuntimeException e) {
9776            }
9777            synchronized(mWindowMap) {
9778                for (int i=mWindows.size()-1; i>=0; i--) {
9779                    WindowState w = mWindows.get(i);
9780                    if (name != null) {
9781                        if (w.mAttrs.getTitle().toString().contains(name)) {
9782                            windows.add(w);
9783                        }
9784                    } else if (System.identityHashCode(w) == objectId) {
9785                        windows.add(w);
9786                    }
9787                }
9788            }
9789        }
9790
9791        if (windows.size() <= 0) {
9792            return false;
9793        }
9794
9795        synchronized(mWindowMap) {
9796            dumpWindowsLocked(fd, pw, dumpAll, windows);
9797        }
9798        return true;
9799    }
9800
9801    @Override
9802    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9803        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
9804                != PackageManager.PERMISSION_GRANTED) {
9805            pw.println("Permission Denial: can't dump WindowManager from from pid="
9806                    + Binder.getCallingPid()
9807                    + ", uid=" + Binder.getCallingUid());
9808            return;
9809        }
9810
9811        boolean dumpAll = false;
9812
9813        int opti = 0;
9814        while (opti < args.length) {
9815            String opt = args[opti];
9816            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9817                break;
9818            }
9819            opti++;
9820            if ("-a".equals(opt)) {
9821                dumpAll = true;
9822            } else if ("-h".equals(opt)) {
9823                pw.println("Window manager dump options:");
9824                pw.println("  [-a] [-h] [cmd] ...");
9825                pw.println("  cmd may be one of:");
9826                pw.println("    p[policy]: policy state");
9827                pw.println("    s[essions]: active sessions");
9828                pw.println("    t[okens]: token list");
9829                pw.println("    w[indows]: window list");
9830                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
9831                pw.println("    be a partial substring in a window name, a");
9832                pw.println("    Window hex object identifier, or");
9833                pw.println("    \"all\" for all windows, or");
9834                pw.println("    \"visible\" for the visible windows.");
9835                pw.println("  -a: include all available server state.");
9836                return;
9837            } else {
9838                pw.println("Unknown argument: " + opt + "; use -h for help");
9839            }
9840        }
9841
9842        // Is the caller requesting to dump a particular piece of data?
9843        if (opti < args.length) {
9844            String cmd = args[opti];
9845            opti++;
9846            if ("policy".equals(cmd) || "p".equals(cmd)) {
9847                synchronized(mWindowMap) {
9848                    dumpPolicyLocked(fd, pw, args, true);
9849                }
9850                return;
9851            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
9852                synchronized(mWindowMap) {
9853                    dumpSessionsLocked(fd, pw, true);
9854                }
9855                return;
9856            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
9857                synchronized(mWindowMap) {
9858                    dumpTokensLocked(fd, pw, true);
9859                }
9860                return;
9861            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
9862                synchronized(mWindowMap) {
9863                    dumpWindowsLocked(fd, pw, true, null);
9864                }
9865                return;
9866            } else if ("all".equals(cmd) || "a".equals(cmd)) {
9867                synchronized(mWindowMap) {
9868                    dumpWindowsLocked(fd, pw, true, null);
9869                }
9870                return;
9871            } else {
9872                // Dumping a single name?
9873                if (!dumpWindows(fd, pw, cmd, args, opti, dumpAll)) {
9874                    pw.println("Bad window command, or no windows match: " + cmd);
9875                    pw.println("Use -h for help.");
9876                }
9877                return;
9878            }
9879        }
9880
9881        synchronized(mWindowMap) {
9882            if (dumpAll) {
9883                pw.println("-------------------------------------------------------------------------------");
9884            }
9885            dumpPolicyLocked(fd, pw, args, dumpAll);
9886            pw.println();
9887            if (dumpAll) {
9888                pw.println("-------------------------------------------------------------------------------");
9889            }
9890            dumpSessionsLocked(fd, pw, dumpAll);
9891            pw.println();
9892            if (dumpAll) {
9893                pw.println("-------------------------------------------------------------------------------");
9894            }
9895            dumpTokensLocked(fd, pw, dumpAll);
9896            pw.println();
9897            if (dumpAll) {
9898                pw.println("-------------------------------------------------------------------------------");
9899            }
9900            dumpWindowsLocked(fd, pw, dumpAll, null);
9901        }
9902    }
9903
9904    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
9905    public void monitor() {
9906        synchronized (mWindowMap) { }
9907        synchronized (mKeyguardTokenWatcher) { }
9908    }
9909
9910    public interface OnHardKeyboardStatusChangeListener {
9911        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
9912    }
9913
9914    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
9915        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
9916            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
9917                    Integer.toHexString(pendingLayoutChanges));
9918        }
9919    }
9920
9921    void bulkSetParameters(final int bulkUpdateParams, int pendingLayoutChanges) {
9922        mH.sendMessage(mH.obtainMessage(H.BULK_UPDATE_PARAMETERS, bulkUpdateParams,
9923                pendingLayoutChanges));
9924    }
9925}
9926