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