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