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