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