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