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