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