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