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