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