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