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