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