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