WindowManagerService.java revision 812d2ca475e88d4e52870a4eeeb096a411f0f077
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) Slog.v(TAG, "Relayout " + win + ": viewVisibility=" + viewVisibility
2752                    + " " + requestedWidth + "x" + requestedHeight + " " + win.mAttrs);
2753
2754            win.mEnforceSizeCompat = (win.mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0;
2755
2756            if ((attrChanges & WindowManager.LayoutParams.ALPHA_CHANGED) != 0) {
2757                winAnimator.mAlpha = attrs.alpha;
2758            }
2759
2760            final boolean scaledWindow =
2761                ((win.mAttrs.flags & WindowManager.LayoutParams.FLAG_SCALED) != 0);
2762
2763            if (scaledWindow) {
2764                // requested{Width|Height} Surface's physical size
2765                // attrs.{width|height} Size on screen
2766                win.mHScale = (attrs.width  != requestedWidth)  ?
2767                        (attrs.width  / (float)requestedWidth) : 1.0f;
2768                win.mVScale = (attrs.height != requestedHeight) ?
2769                        (attrs.height / (float)requestedHeight) : 1.0f;
2770            } else {
2771                win.mHScale = win.mVScale = 1;
2772            }
2773
2774            boolean imMayMove = (flagChanges&(
2775                    WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM |
2776                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) != 0;
2777
2778            final boolean isDefaultDisplay = win.isDefaultDisplay();
2779            boolean focusMayChange = isDefaultDisplay && (win.mViewVisibility != viewVisibility
2780                    || ((flagChanges&WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0)
2781                    || (!win.mRelayoutCalled));
2782
2783            boolean wallpaperMayMove = win.mViewVisibility != viewVisibility
2784                    && (win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
2785            wallpaperMayMove |= (flagChanges & FLAG_SHOW_WALLPAPER) != 0;
2786
2787            win.mRelayoutCalled = true;
2788            final int oldVisibility = win.mViewVisibility;
2789            win.mViewVisibility = viewVisibility;
2790            if (DEBUG_SCREEN_ON) {
2791                RuntimeException stack = new RuntimeException();
2792                stack.fillInStackTrace();
2793                Slog.i(TAG, "Relayout " + win + ": oldVis=" + oldVisibility
2794                        + " newVis=" + viewVisibility, stack);
2795            }
2796            if (viewVisibility == View.VISIBLE &&
2797                    (win.mAppToken == null || !win.mAppToken.clientHidden)) {
2798                toBeDisplayed = !win.isVisibleLw();
2799                if (win.mExiting) {
2800                    winAnimator.cancelExitAnimationForNextAnimationLocked();
2801                    win.mExiting = false;
2802                }
2803                if (win.mDestroying) {
2804                    win.mDestroying = false;
2805                    mDestroySurface.remove(win);
2806                }
2807                if (oldVisibility == View.GONE) {
2808                    winAnimator.mEnterAnimationPending = true;
2809                }
2810                if (toBeDisplayed) {
2811                    if (win.isDrawnLw() && okToDisplay()) {
2812                        winAnimator.applyEnterAnimationLocked();
2813                    }
2814                    if ((win.mAttrs.flags
2815                            & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
2816                        if (DEBUG_VISIBILITY) Slog.v(TAG,
2817                                "Relayout window turning screen on: " + win);
2818                        win.mTurnOnScreen = true;
2819                    }
2820                    int diff = 0;
2821                    if (win.mConfiguration != mCurConfiguration
2822                            && (win.mConfiguration == null
2823                                    || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0)) {
2824                        win.mConfiguration = mCurConfiguration;
2825                        if (DEBUG_CONFIGURATION) {
2826                            Slog.i(TAG, "Window " + win + " visible with new config: "
2827                                    + win.mConfiguration + " / 0x"
2828                                    + Integer.toHexString(diff));
2829                        }
2830                        outConfig.setTo(mCurConfiguration);
2831                    }
2832                }
2833                if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
2834                    // To change the format, we need to re-build the surface.
2835                    winAnimator.destroySurfaceLocked();
2836                    toBeDisplayed = true;
2837                    surfaceChanged = true;
2838                }
2839                try {
2840                    if (!win.mHasSurface) {
2841                        surfaceChanged = true;
2842                    }
2843                    Surface surface = winAnimator.createSurfaceLocked();
2844                    if (surface != null) {
2845                        outSurface.copyFrom(surface);
2846                        if (SHOW_TRANSACTIONS) Slog.i(TAG,
2847                                "  OUT SURFACE " + outSurface + ": copied");
2848                    } else {
2849                        // For some reason there isn't a surface.  Clear the
2850                        // caller's object so they see the same state.
2851                        outSurface.release();
2852                    }
2853                } catch (Exception e) {
2854                    mInputMonitor.updateInputWindowsLw(true /*force*/);
2855
2856                    Slog.w(TAG, "Exception thrown when creating surface for client "
2857                             + client + " (" + win.mAttrs.getTitle() + ")",
2858                             e);
2859                    Binder.restoreCallingIdentity(origId);
2860                    return 0;
2861                }
2862                if (toBeDisplayed) {
2863                    focusMayChange = isDefaultDisplay;
2864                }
2865                if (win.mAttrs.type == TYPE_INPUT_METHOD
2866                        && mInputMethodWindow == null) {
2867                    mInputMethodWindow = win;
2868                    imMayMove = true;
2869                }
2870                if (win.mAttrs.type == TYPE_BASE_APPLICATION
2871                        && win.mAppToken != null
2872                        && win.mAppToken.startingWindow != null) {
2873                    // Special handling of starting window over the base
2874                    // window of the app: propagate lock screen flags to it,
2875                    // to provide the correct semantics while starting.
2876                    final int mask =
2877                        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
2878                        | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
2879                        | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
2880                    WindowManager.LayoutParams sa = win.mAppToken.startingWindow.mAttrs;
2881                    sa.flags = (sa.flags&~mask) | (win.mAttrs.flags&mask);
2882                }
2883            } else {
2884                winAnimator.mEnterAnimationPending = false;
2885                if (winAnimator.mSurface != null) {
2886                    if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
2887                            + ": mExiting=" + win.mExiting);
2888                    // If we are not currently running the exit animation, we
2889                    // need to see about starting one.
2890                    if (!win.mExiting) {
2891                        surfaceChanged = true;
2892                        // Try starting an animation; if there isn't one, we
2893                        // can destroy the surface right away.
2894                        int transit = WindowManagerPolicy.TRANSIT_EXIT;
2895                        if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
2896                            transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
2897                        }
2898                        if (win.isWinVisibleLw() &&
2899                                winAnimator.applyAnimationLocked(transit, false)) {
2900                            focusMayChange = isDefaultDisplay;
2901                            win.mExiting = true;
2902                        } else if (win.mWinAnimator.isAnimating()) {
2903                            // Currently in a hide animation... turn this into
2904                            // an exit.
2905                            win.mExiting = true;
2906                        } else if (win == mWallpaperTarget) {
2907                            // If the wallpaper is currently behind this
2908                            // window, we need to change both of them inside
2909                            // of a transaction to avoid artifacts.
2910                            win.mExiting = true;
2911                            win.mWinAnimator.mAnimating = true;
2912                        } else {
2913                            if (mInputMethodWindow == win) {
2914                                mInputMethodWindow = null;
2915                            }
2916                            winAnimator.destroySurfaceLocked();
2917                        }
2918                        scheduleNotifyWindowTranstionIfNeededLocked(win, transit);
2919                    }
2920                }
2921
2922                outSurface.release();
2923                if (DEBUG_VISIBILITY) Slog.i(TAG, "Releasing surface in: " + win);
2924            }
2925
2926            if (focusMayChange) {
2927                //System.out.println("Focus may change: " + win.mAttrs.getTitle());
2928                if (updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
2929                        false /*updateInputWindows*/)) {
2930                    imMayMove = false;
2931                }
2932                //System.out.println("Relayout " + win + ": focus=" + mCurrentFocus);
2933            }
2934
2935            // updateFocusedWindowLocked() already assigned layers so we only need to
2936            // reassign them at this point if the IM window state gets shuffled
2937            boolean assignLayers = false;
2938
2939            if (imMayMove) {
2940                if (moveInputMethodWindowsIfNeededLocked(false) || toBeDisplayed) {
2941                    // Little hack here -- we -should- be able to rely on the
2942                    // function to return true if the IME has moved and needs
2943                    // its layer recomputed.  However, if the IME was hidden
2944                    // and isn't actually moved in the list, its layer may be
2945                    // out of data so we make sure to recompute it.
2946                    assignLayers = true;
2947                }
2948            }
2949            if (wallpaperMayMove) {
2950                if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
2951                    assignLayers = true;
2952                }
2953            }
2954
2955            win.mDisplayContent.layoutNeeded = true;
2956            win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
2957            if (assignLayers) {
2958                assignLayersLocked(win.getWindowList());
2959            }
2960            configChanged = updateOrientationFromAppTokensLocked(false);
2961            performLayoutAndPlaceSurfacesLocked();
2962            if (toBeDisplayed && win.mIsWallpaper) {
2963                DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
2964                updateWallpaperOffsetLocked(win,
2965                        displayInfo.appWidth, displayInfo.appHeight, false);
2966            }
2967            if (win.mAppToken != null) {
2968                win.mAppToken.updateReportedVisibilityLocked();
2969            }
2970            outFrame.set(win.mCompatFrame);
2971            outContentInsets.set(win.mContentInsets);
2972            outVisibleInsets.set(win.mVisibleInsets);
2973            if (localLOGV) Slog.v(
2974                TAG, "Relayout given client " + client.asBinder()
2975                + ", requestedWidth=" + requestedWidth
2976                + ", requestedHeight=" + requestedHeight
2977                + ", viewVisibility=" + viewVisibility
2978                + "\nRelayout returning frame=" + outFrame
2979                + ", surface=" + outSurface);
2980
2981            if (localLOGV || DEBUG_FOCUS) Slog.v(
2982                TAG, "Relayout of " + win + ": focusMayChange=" + focusMayChange);
2983
2984            inTouchMode = mInTouchMode;
2985            animating = mAnimator.mAnimating;
2986            if (animating && !mRelayoutWhileAnimating.contains(win)) {
2987                mRelayoutWhileAnimating.add(win);
2988            }
2989
2990            mInputMonitor.updateInputWindowsLw(true /*force*/);
2991        }
2992
2993        if (configChanged) {
2994            sendNewConfiguration();
2995        }
2996
2997        Binder.restoreCallingIdentity(origId);
2998
2999        return (inTouchMode ? WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE : 0)
3000                | (toBeDisplayed ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0)
3001                | (surfaceChanged ? WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED : 0)
3002                | (animating ? WindowManagerGlobal.RELAYOUT_RES_ANIMATING : 0);
3003    }
3004
3005    public void performDeferredDestroyWindow(Session session, IWindow client) {
3006        long origId = Binder.clearCallingIdentity();
3007
3008        try {
3009            synchronized(mWindowMap) {
3010                WindowState win = windowForClientLocked(session, client, false);
3011                if (win == null) {
3012                    return;
3013                }
3014                win.mWinAnimator.destroyDeferredSurfaceLocked();
3015            }
3016        } finally {
3017            Binder.restoreCallingIdentity(origId);
3018        }
3019    }
3020
3021    public boolean outOfMemoryWindow(Session session, IWindow client) {
3022        long origId = Binder.clearCallingIdentity();
3023
3024        try {
3025            synchronized(mWindowMap) {
3026                WindowState win = windowForClientLocked(session, client, false);
3027                if (win == null) {
3028                    return false;
3029                }
3030                return reclaimSomeSurfaceMemoryLocked(win.mWinAnimator, "from-client", false);
3031            }
3032        } finally {
3033            Binder.restoreCallingIdentity(origId);
3034        }
3035    }
3036
3037    public void finishDrawingWindow(Session session, IWindow client) {
3038        final long origId = Binder.clearCallingIdentity();
3039        synchronized(mWindowMap) {
3040            WindowState win = windowForClientLocked(session, client, false);
3041            if (win != null && win.mWinAnimator.finishDrawingLocked()) {
3042                if ((win.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
3043                    adjustWallpaperWindowsLocked();
3044                }
3045                win.mDisplayContent.layoutNeeded = true;
3046                performLayoutAndPlaceSurfacesLocked();
3047            }
3048        }
3049        Binder.restoreCallingIdentity(origId);
3050    }
3051
3052    @Override
3053    public float getWindowCompatibilityScale(IBinder windowToken) {
3054        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
3055                "getWindowCompatibilityScale()")) {
3056            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
3057        }
3058        synchronized (mWindowMap) {
3059            WindowState windowState = mWindowMap.get(windowToken);
3060            return (windowState != null) ? windowState.mGlobalScale : 1.0f;
3061        }
3062    }
3063
3064    @Override
3065    public WindowInfo getWindowInfo(IBinder token) {
3066        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
3067                "getWindowInfo()")) {
3068            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
3069        }
3070        synchronized (mWindowMap) {
3071            WindowState window = mWindowMap.get(token);
3072            if (window != null) {
3073                return getWindowInfoForWindowStateLocked(window);
3074            }
3075            return null;
3076        }
3077    }
3078
3079    @Override
3080    public void getVisibleWindowsForDisplay(int displayId, List<WindowInfo> outInfos) {
3081        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
3082                "getWindowInfos()")) {
3083            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
3084        }
3085        synchronized (mWindowMap) {
3086            DisplayContent displayContent = getDisplayContentLocked(displayId);
3087            if (displayContent == null) {
3088                return;
3089            }
3090            WindowList windows = displayContent.getWindowList();
3091            final int windowCount = windows.size();
3092            for (int i = 0; i < windowCount; i++) {
3093                WindowState window = windows.get(i);
3094                if (window.isVisibleLw() ||
3095                        window.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND) {
3096                    WindowInfo info = getWindowInfoForWindowStateLocked(window);
3097                    outInfos.add(info);
3098                }
3099            }
3100        }
3101    }
3102
3103    @Override
3104    public void magnifyDisplay(int displayId, float scale, float offsetX, float offsetY) {
3105        if (!checkCallingPermission(
3106                android.Manifest.permission.MAGNIFY_DISPLAY, "magnifyDisplay()")) {
3107            throw new SecurityException("Requires MAGNIFY_DISPLAY permission");
3108        }
3109        synchronized (mWindowMap) {
3110            MagnificationSpec spec = getDisplayMagnificationSpecLocked(displayId);
3111            if (spec != null) {
3112                final boolean scaleChanged = spec.mScale != scale;
3113                final boolean offsetChanged = spec.mOffsetX != offsetX || spec.mOffsetY != offsetY;
3114                if (!scaleChanged && !offsetChanged) {
3115                    return;
3116                }
3117                spec.initialize(scale, offsetX, offsetY);
3118                // If the offset has changed we need to re-add the input windows
3119                // since the offsets have to be propagated to the input system.
3120                if (offsetChanged) {
3121                    // TODO(multidisplay): Input only occurs on the default display.
3122                    if (displayId == Display.DEFAULT_DISPLAY) {
3123                        mInputMonitor.updateInputWindowsLw(true);
3124                    }
3125                }
3126                scheduleAnimationLocked();
3127            }
3128        }
3129    }
3130
3131    MagnificationSpec getDisplayMagnificationSpecLocked(int displayId) {
3132        DisplayContent displayContent = getDisplayContentLocked(displayId);
3133        if (displayContent != null) {
3134            if (displayContent.mMagnificationSpec == null) {
3135                displayContent.mMagnificationSpec = new MagnificationSpec();
3136            }
3137            return displayContent.mMagnificationSpec;
3138        }
3139        return null;
3140    }
3141
3142    private WindowInfo getWindowInfoForWindowStateLocked(WindowState window) {
3143        WindowInfo info = WindowInfo.obtain();
3144        info.token = window.mToken.token;
3145        info.frame.set(window.mFrame);
3146        info.type = window.mAttrs.type;
3147        info.displayId = window.getDisplayId();
3148        info.compatibilityScale = window.mGlobalScale;
3149        info.visible = window.isVisibleLw()
3150                || info.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND;
3151        info.layer = window.mLayer;
3152        window.getTouchableRegion(mTempRegion);
3153        mTempRegion.getBounds(info.touchableRegion);
3154        return info;
3155    }
3156
3157    private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
3158        if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: layout params pkg="
3159                + (lp != null ? lp.packageName : null)
3160                + " resId=0x" + (lp != null ? Integer.toHexString(lp.windowAnimations) : null));
3161        if (lp != null && lp.windowAnimations != 0) {
3162            // If this is a system resource, don't try to load it from the
3163            // application resources.  It is nice to avoid loading application
3164            // resources if we can.
3165            String packageName = lp.packageName != null ? lp.packageName : "android";
3166            int resId = lp.windowAnimations;
3167            if ((resId&0xFF000000) == 0x01000000) {
3168                packageName = "android";
3169            }
3170            if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
3171                    + packageName);
3172            return AttributeCache.instance().get(packageName, resId,
3173                    com.android.internal.R.styleable.WindowAnimation);
3174        }
3175        return null;
3176    }
3177
3178    private AttributeCache.Entry getCachedAnimations(String packageName, int resId) {
3179        if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: package="
3180                + packageName + " resId=0x" + Integer.toHexString(resId));
3181        if (packageName != null) {
3182            if ((resId&0xFF000000) == 0x01000000) {
3183                packageName = "android";
3184            }
3185            if (DEBUG_ANIM) Slog.v(TAG, "Loading animations: picked package="
3186                    + packageName);
3187            return AttributeCache.instance().get(packageName, resId,
3188                    com.android.internal.R.styleable.WindowAnimation);
3189        }
3190        return null;
3191    }
3192
3193    Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
3194        int anim = 0;
3195        Context context = mContext;
3196        if (animAttr >= 0) {
3197            AttributeCache.Entry ent = getCachedAnimations(lp);
3198            if (ent != null) {
3199                context = ent.context;
3200                anim = ent.array.getResourceId(animAttr, 0);
3201            }
3202        }
3203        if (anim != 0) {
3204            return AnimationUtils.loadAnimation(context, anim);
3205        }
3206        return null;
3207    }
3208
3209    private Animation loadAnimation(String packageName, int resId) {
3210        int anim = 0;
3211        Context context = mContext;
3212        if (resId >= 0) {
3213            AttributeCache.Entry ent = getCachedAnimations(packageName, resId);
3214            if (ent != null) {
3215                context = ent.context;
3216                anim = resId;
3217            }
3218        }
3219        if (anim != 0) {
3220            return AnimationUtils.loadAnimation(context, anim);
3221        }
3222        return null;
3223    }
3224
3225    private Animation createExitAnimationLocked(int transit, int duration) {
3226        if (transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN ||
3227                transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE) {
3228            // If we are on top of the wallpaper, we need an animation that
3229            // correctly handles the wallpaper staying static behind all of
3230            // the animated elements.  To do this, will just have the existing
3231            // element fade out.
3232            Animation a = new AlphaAnimation(1, 0);
3233            a.setDetachWallpaper(true);
3234            a.setDuration(duration);
3235            return a;
3236        }
3237        // For normal animations, the exiting element just holds in place.
3238        Animation a = new AlphaAnimation(1, 1);
3239        a.setDuration(duration);
3240        return a;
3241    }
3242
3243    /**
3244     * Compute the pivot point for an animation that is scaling from a small
3245     * rect on screen to a larger rect.  The pivot point varies depending on
3246     * the distance between the inner and outer edges on both sides.  This
3247     * function computes the pivot point for one dimension.
3248     * @param startPos  Offset from left/top edge of outer rectangle to
3249     * left/top edge of inner rectangle.
3250     * @param finalScale The scaling factor between the size of the outer
3251     * and inner rectangles.
3252     */
3253    private static float computePivot(int startPos, float finalScale) {
3254        final float denom = finalScale-1;
3255        if (Math.abs(denom) < .0001f) {
3256            return startPos;
3257        }
3258        return -startPos / denom;
3259    }
3260
3261    private Animation createScaleUpAnimationLocked(int transit, boolean enter) {
3262        Animation a;
3263        // Pick the desired duration.  If this is an inter-activity transition,
3264        // it  is the standard duration for that.  Otherwise we use the longer
3265        // task transition duration.
3266        int duration;
3267        switch (transit) {
3268            case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
3269            case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
3270                duration = mContext.getResources().getInteger(
3271                        com.android.internal.R.integer.config_shortAnimTime);
3272                break;
3273            default:
3274                duration = 300;
3275                break;
3276        }
3277        // TODO(multidisplay): For now assume all app animation is on main display.
3278        final DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
3279        if (enter) {
3280            // Entering app zooms out from the center of the initial rect.
3281            float scaleW = mNextAppTransitionStartWidth / (float) displayInfo.appWidth;
3282            float scaleH = mNextAppTransitionStartHeight / (float) displayInfo.appHeight;
3283            Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
3284                    computePivot(mNextAppTransitionStartX, scaleW),
3285                    computePivot(mNextAppTransitionStartY, scaleH));
3286            scale.setDuration(duration);
3287            AnimationSet set = new AnimationSet(true);
3288            Animation alpha = new AlphaAnimation(0, 1);
3289            scale.setDuration(duration);
3290            set.addAnimation(scale);
3291            alpha.setDuration(duration);
3292            set.addAnimation(alpha);
3293            set.setDetachWallpaper(true);
3294            a = set;
3295        } else {
3296            a = createExitAnimationLocked(transit, duration);
3297        }
3298        a.setFillAfter(true);
3299        final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
3300                com.android.internal.R.interpolator.decelerate_cubic);
3301        a.setInterpolator(interpolator);
3302        a.initialize(displayInfo.appWidth, displayInfo.appHeight,
3303                displayInfo.appWidth, displayInfo.appHeight);
3304        return a;
3305    }
3306
3307    private Animation createThumbnailAnimationLocked(int transit,
3308            boolean enter, boolean thumb, boolean scaleUp) {
3309        Animation a;
3310        final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
3311        final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
3312        final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
3313        final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
3314        // Pick the desired duration.  If this is an inter-activity transition,
3315        // it  is the standard duration for that.  Otherwise we use the longer
3316        // task transition duration.
3317        int duration;
3318        switch (transit) {
3319            case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
3320            case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
3321                duration = mContext.getResources().getInteger(
3322                        com.android.internal.R.integer.config_shortAnimTime);
3323                break;
3324            default:
3325                duration = 250;
3326                break;
3327        }
3328        // TOOD(multidisplay): For now assume all app animation is on the main screen.
3329        DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
3330        if (thumb) {
3331            // Animation for zooming thumbnail from its initial size to
3332            // filling the screen.
3333            if (scaleUp) {
3334                float scaleW = displayInfo.appWidth / thumbWidth;
3335                float scaleH = displayInfo.appHeight / thumbHeight;
3336
3337                Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
3338                        computePivot(mNextAppTransitionStartX, 1 / scaleW),
3339                        computePivot(mNextAppTransitionStartY, 1 / scaleH));
3340                AnimationSet set = new AnimationSet(true);
3341                Animation alpha = new AlphaAnimation(1, 0);
3342                scale.setDuration(duration);
3343                scale.setInterpolator(
3344                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
3345                set.addAnimation(scale);
3346                alpha.setDuration(duration);
3347                set.addAnimation(alpha);
3348                set.setFillBefore(true);
3349                a = set;
3350            } else {
3351                float scaleW = displayInfo.appWidth / thumbWidth;
3352                float scaleH = displayInfo.appHeight / thumbHeight;
3353
3354                Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
3355                        computePivot(mNextAppTransitionStartX, 1 / scaleW),
3356                        computePivot(mNextAppTransitionStartY, 1 / scaleH));
3357                AnimationSet set = new AnimationSet(true);
3358                Animation alpha = new AlphaAnimation(1, 1);
3359                scale.setDuration(duration);
3360                scale.setInterpolator(
3361                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
3362                set.addAnimation(scale);
3363                alpha.setDuration(duration);
3364                set.addAnimation(alpha);
3365                set.setFillBefore(true);
3366
3367                a = set;
3368            }
3369        } else if (enter) {
3370            // Entering app zooms out from the center of the thumbnail.
3371            if (scaleUp) {
3372                float scaleW = thumbWidth / displayInfo.appWidth;
3373                float scaleH = thumbHeight / displayInfo.appHeight;
3374                Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
3375                        computePivot(mNextAppTransitionStartX, scaleW),
3376                        computePivot(mNextAppTransitionStartY, scaleH));
3377                scale.setDuration(duration);
3378                scale.setInterpolator(
3379                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
3380                scale.setFillBefore(true);
3381                a = scale;
3382            } else {
3383                // noop animation
3384                a = new AlphaAnimation(1, 1);
3385                a.setDuration(duration);
3386            }
3387        } else {
3388            // Exiting app
3389            if (scaleUp) {
3390                // noop animation
3391                a = new AlphaAnimation(1, 0);
3392                a.setDuration(duration);
3393            } else {
3394                float scaleW = thumbWidth / displayInfo.appWidth;
3395                float scaleH = thumbHeight / displayInfo.appHeight;
3396                Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
3397                        computePivot(mNextAppTransitionStartX, scaleW),
3398                        computePivot(mNextAppTransitionStartY, scaleH));
3399                scale.setDuration(duration);
3400                scale.setInterpolator(
3401                        new DecelerateInterpolator(THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
3402                scale.setFillBefore(true);
3403                AnimationSet set = new AnimationSet(true);
3404                Animation alpha = new AlphaAnimation(1, 0);
3405                set.addAnimation(scale);
3406                alpha.setDuration(duration);
3407                alpha.setInterpolator(new DecelerateInterpolator(
3408                        THUMBNAIL_ANIMATION_DECELERATE_FACTOR));
3409                set.addAnimation(alpha);
3410                set.setFillBefore(true);
3411                set.setZAdjustment(Animation.ZORDER_TOP);
3412                a = set;
3413            }
3414        }
3415        a.setFillAfter(true);
3416        final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext,
3417                com.android.internal.R.interpolator.decelerate_quad);
3418        a.setInterpolator(interpolator);
3419        a.initialize(displayInfo.appWidth, displayInfo.appHeight,
3420                displayInfo.appWidth, displayInfo.appHeight);
3421        return a;
3422    }
3423
3424    private boolean applyAnimationLocked(AppWindowToken atoken,
3425            WindowManager.LayoutParams lp, int transit, boolean enter) {
3426        // Only apply an animation if the display isn't frozen.  If it is
3427        // frozen, there is no reason to animate and it can cause strange
3428        // artifacts when we unfreeze the display if some different animation
3429        // is running.
3430        if (okToDisplay()) {
3431            Animation a;
3432            boolean initialized = false;
3433            if (mNextAppTransitionType == ActivityOptions.ANIM_CUSTOM) {
3434                a = loadAnimation(mNextAppTransitionPackage, enter ?
3435                        mNextAppTransitionEnter : mNextAppTransitionExit);
3436                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
3437                        "applyAnimation: atoken=" + atoken
3438                        + " anim=" + a + " nextAppTransition=ANIM_CUSTOM"
3439                        + " transit=" + transit + " isEntrance=" + enter
3440                        + " Callers=" + Debug.getCallers(3));
3441            } else if (mNextAppTransitionType == ActivityOptions.ANIM_SCALE_UP) {
3442                a = createScaleUpAnimationLocked(transit, enter);
3443                initialized = true;
3444                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
3445                        "applyAnimation: atoken=" + atoken
3446                        + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
3447                        + " transit=" + transit + " isEntrance=" + enter
3448                        + " Callers=" + Debug.getCallers(3));
3449            } else if (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP ||
3450                    mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN) {
3451                boolean scaleUp = (mNextAppTransitionType == ActivityOptions.ANIM_THUMBNAIL_SCALE_UP);
3452                a = createThumbnailAnimationLocked(transit, enter, false, scaleUp);
3453                initialized = true;
3454                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
3455                    String animName = scaleUp ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
3456                    Slog.v(TAG, "applyAnimation: atoken=" + atoken
3457                            + " anim=" + a + " nextAppTransition=" + animName
3458                            + " transit=" + transit + " isEntrance=" + enter
3459                            + " Callers=" + Debug.getCallers(3));
3460                }
3461            } else {
3462                int animAttr = 0;
3463                switch (transit) {
3464                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
3465                        animAttr = enter
3466                                ? com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation
3467                                : com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
3468                        break;
3469                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
3470                        animAttr = enter
3471                                ? com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation
3472                                : com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
3473                        break;
3474                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
3475                        animAttr = enter
3476                                ? com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation
3477                                : com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
3478                        break;
3479                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
3480                        animAttr = enter
3481                                ? com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation
3482                                : com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
3483                        break;
3484                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
3485                        animAttr = enter
3486                                ? com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation
3487                                : com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
3488                        break;
3489                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
3490                        animAttr = enter
3491                                ? com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation
3492                                : com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
3493                        break;
3494                    case WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN:
3495                        animAttr = enter
3496                                ? com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
3497                                : com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
3498                        break;
3499                    case WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE:
3500                        animAttr = enter
3501                                ? com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
3502                                : com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
3503                        break;
3504                    case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN:
3505                        animAttr = enter
3506                                ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
3507                                : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
3508                        break;
3509                    case WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE:
3510                        animAttr = enter
3511                                ? com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
3512                                : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
3513                        break;
3514                }
3515                a = animAttr != 0 ? loadAnimation(lp, animAttr) : null;
3516                if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
3517                        "applyAnimation: atoken=" + atoken
3518                        + " anim=" + a
3519                        + " animAttr=0x" + Integer.toHexString(animAttr)
3520                        + " transit=" + transit + " isEntrance=" + enter
3521                        + " Callers=" + Debug.getCallers(3));
3522            }
3523            if (a != null) {
3524                if (DEBUG_ANIM) {
3525                    RuntimeException e = null;
3526                    if (!HIDE_STACK_CRAWLS) {
3527                        e = new RuntimeException();
3528                        e.fillInStackTrace();
3529                    }
3530                    Slog.v(TAG, "Loaded animation " + a + " for " + atoken, e);
3531                }
3532                atoken.mAppAnimator.setAnimation(a, initialized);
3533            }
3534        } else {
3535            atoken.mAppAnimator.clearAnimation();
3536        }
3537
3538        return atoken.mAppAnimator.animation != null;
3539    }
3540
3541    // -------------------------------------------------------------
3542    // Application Window Tokens
3543    // -------------------------------------------------------------
3544
3545    public void validateAppTokens(List<IBinder> tokens) {
3546        int v = tokens.size()-1;
3547        int m = mAppTokens.size()-1;
3548        while (v >= 0 && m >= 0) {
3549            AppWindowToken atoken = mAppTokens.get(m);
3550            if (atoken.removed) {
3551                m--;
3552                continue;
3553            }
3554            if (tokens.get(v) != atoken.token) {
3555                Slog.w(TAG, "Tokens out of sync: external is " + tokens.get(v)
3556                      + " @ " + v + ", internal is " + atoken.token + " @ " + m);
3557            }
3558            v--;
3559            m--;
3560        }
3561        while (v >= 0) {
3562            Slog.w(TAG, "External token not found: " + tokens.get(v) + " @ " + v);
3563            v--;
3564        }
3565        while (m >= 0) {
3566            AppWindowToken atoken = mAppTokens.get(m);
3567            if (!atoken.removed) {
3568                Slog.w(TAG, "Invalid internal atoken: " + atoken.token + " @ " + m);
3569            }
3570            m--;
3571        }
3572    }
3573
3574    boolean checkCallingPermission(String permission, String func) {
3575        // Quick check: if the calling permission is me, it's all okay.
3576        if (Binder.getCallingPid() == Process.myPid()) {
3577            return true;
3578        }
3579
3580        if (mContext.checkCallingPermission(permission)
3581                == PackageManager.PERMISSION_GRANTED) {
3582            return true;
3583        }
3584        String msg = "Permission Denial: " + func + " from pid="
3585                + Binder.getCallingPid()
3586                + ", uid=" + Binder.getCallingUid()
3587                + " requires " + permission;
3588        Slog.w(TAG, msg);
3589        return false;
3590    }
3591
3592    boolean okToDisplay() {
3593        return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully();
3594    }
3595
3596    AppWindowToken findAppWindowToken(IBinder token) {
3597        WindowToken wtoken = mTokenMap.get(token);
3598        if (wtoken == null) {
3599            return null;
3600        }
3601        return wtoken.appWindowToken;
3602    }
3603
3604    @Override
3605    public void addWindowToken(IBinder token, int type) {
3606        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3607                "addWindowToken()")) {
3608            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3609        }
3610
3611        synchronized(mWindowMap) {
3612            WindowToken wtoken = mTokenMap.get(token);
3613            if (wtoken != null) {
3614                Slog.w(TAG, "Attempted to add existing input method token: " + token);
3615                return;
3616            }
3617            wtoken = new WindowToken(this, token, type, true);
3618            mTokenMap.put(token, wtoken);
3619            if (type == TYPE_WALLPAPER) {
3620                mWallpaperTokens.add(wtoken);
3621                updateLayoutToAnimWallpaperTokens();
3622            }
3623        }
3624    }
3625
3626    @Override
3627    public void removeWindowToken(IBinder token) {
3628        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3629                "removeWindowToken()")) {
3630            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3631        }
3632
3633        final long origId = Binder.clearCallingIdentity();
3634        synchronized(mWindowMap) {
3635            WindowToken wtoken = mTokenMap.remove(token);
3636            if (wtoken != null) {
3637                boolean delayed = false;
3638                if (!wtoken.hidden) {
3639                    wtoken.hidden = true;
3640
3641                    final int N = wtoken.windows.size();
3642                    boolean changed = false;
3643
3644                    for (int i=0; i<N; i++) {
3645                        WindowState win = wtoken.windows.get(i);
3646
3647                        if (win.mWinAnimator.isAnimating()) {
3648                            delayed = true;
3649                        }
3650
3651                        if (win.isVisibleNow()) {
3652                            win.mWinAnimator.applyAnimationLocked(WindowManagerPolicy.TRANSIT_EXIT,
3653                                    false);
3654                            scheduleNotifyWindowTranstionIfNeededLocked(win,
3655                                    WindowManagerPolicy.TRANSIT_EXIT);
3656                            changed = true;
3657                            win.mDisplayContent.layoutNeeded = true;
3658                        }
3659                    }
3660
3661                    if (changed) {
3662                        performLayoutAndPlaceSurfacesLocked();
3663                        updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
3664                                false /*updateInputWindows*/);
3665                    }
3666
3667                    if (delayed) {
3668                        mExitingTokens.add(wtoken);
3669                    } else if (wtoken.windowType == TYPE_WALLPAPER) {
3670                        mWallpaperTokens.remove(wtoken);
3671                        updateLayoutToAnimWallpaperTokens();
3672                    }
3673                }
3674
3675                mInputMonitor.updateInputWindowsLw(true /*force*/);
3676            } else {
3677                Slog.w(TAG, "Attempted to remove non-existing token: " + token);
3678            }
3679        }
3680        Binder.restoreCallingIdentity(origId);
3681    }
3682
3683    /**
3684     *  Find the location to insert a new AppWindowToken into the window-ordered app token list.
3685     *  Note that mAppTokens.size() == mAnimatingAppTokens.size() + 1.
3686     * @param addPos The location the token was inserted into in mAppTokens.
3687     * @param atoken The token to insert.
3688     */
3689    private void addAppTokenToAnimating(final int addPos, final AppWindowToken atoken) {
3690        if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
3691            // It was inserted into the beginning or end of mAppTokens. Honor that.
3692            mAnimatingAppTokens.add(addPos, atoken);
3693            return;
3694        }
3695        // Find the item immediately above the mAppTokens insertion point and put the token
3696        // immediately below that one in mAnimatingAppTokens.
3697        final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1);
3698        mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), atoken);
3699    }
3700
3701    @Override
3702    public void addAppToken(int addPos, IApplicationToken token,
3703            int groupId, int requestedOrientation, boolean fullscreen) {
3704        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3705                "addAppToken()")) {
3706            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3707        }
3708
3709        // Get the dispatching timeout here while we are not holding any locks so that it
3710        // can be cached by the AppWindowToken.  The timeout value is used later by the
3711        // input dispatcher in code that does hold locks.  If we did not cache the value
3712        // here we would run the chance of introducing a deadlock between the window manager
3713        // (which holds locks while updating the input dispatcher state) and the activity manager
3714        // (which holds locks while querying the application token).
3715        long inputDispatchingTimeoutNanos;
3716        try {
3717            inputDispatchingTimeoutNanos = token.getKeyDispatchingTimeout() * 1000000L;
3718        } catch (RemoteException ex) {
3719            Slog.w(TAG, "Could not get dispatching timeout.", ex);
3720            inputDispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;
3721        }
3722
3723        synchronized(mWindowMap) {
3724            AppWindowToken atoken = findAppWindowToken(token.asBinder());
3725            if (atoken != null) {
3726                Slog.w(TAG, "Attempted to add existing app token: " + token);
3727                return;
3728            }
3729            atoken = new AppWindowToken(this, token);
3730            atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
3731            atoken.groupId = groupId;
3732            atoken.appFullscreen = fullscreen;
3733            atoken.requestedOrientation = requestedOrientation;
3734            if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
3735                    + " at " + addPos);
3736            mAppTokens.add(addPos, atoken);
3737            addAppTokenToAnimating(addPos, atoken);
3738            mTokenMap.put(token.asBinder(), atoken);
3739
3740            // Application tokens start out hidden.
3741            atoken.hidden = true;
3742            atoken.hiddenRequested = true;
3743
3744            //dump();
3745        }
3746    }
3747
3748    @Override
3749    public void setAppGroupId(IBinder token, int groupId) {
3750        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3751                "setAppGroupId()")) {
3752            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3753        }
3754
3755        synchronized(mWindowMap) {
3756            AppWindowToken atoken = findAppWindowToken(token);
3757            if (atoken == null) {
3758                Slog.w(TAG, "Attempted to set group id of non-existing app token: " + token);
3759                return;
3760            }
3761            atoken.groupId = groupId;
3762        }
3763    }
3764
3765    public int getOrientationFromWindowsLocked() {
3766        if (mDisplayFrozen || mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
3767            // If the display is frozen, some activities may be in the middle
3768            // of restarting, and thus have removed their old window.  If the
3769            // window has the flag to hide the lock screen, then the lock screen
3770            // can re-appear and inflict its own orientation on us.  Keep the
3771            // orientation stable until this all settles down.
3772            return mLastWindowForcedOrientation;
3773        }
3774
3775        // TODO(multidisplay): Change to the correct display.
3776        final WindowList windows = getDefaultWindowListLocked();
3777        int pos = windows.size() - 1;
3778        while (pos >= 0) {
3779            WindowState wtoken = windows.get(pos);
3780            pos--;
3781            if (wtoken.mAppToken != null) {
3782                // We hit an application window. so the orientation will be determined by the
3783                // app window. No point in continuing further.
3784                return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
3785            }
3786            if (!wtoken.isVisibleLw() || !wtoken.mPolicyVisibilityAfterAnim) {
3787                continue;
3788            }
3789            int req = wtoken.mAttrs.screenOrientation;
3790            if((req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) ||
3791                    (req == ActivityInfo.SCREEN_ORIENTATION_BEHIND)){
3792                continue;
3793            }
3794
3795            return (mLastWindowForcedOrientation=req);
3796        }
3797        return (mLastWindowForcedOrientation=ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
3798    }
3799
3800    public int getOrientationFromAppTokensLocked() {
3801        int curGroup = 0;
3802        int lastOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3803        boolean findingBehind = false;
3804        boolean haveGroup = false;
3805        boolean lastFullscreen = false;
3806        for (int pos = mAppTokens.size() - 1; pos >= 0; pos--) {
3807            AppWindowToken atoken = mAppTokens.get(pos);
3808
3809            if (DEBUG_APP_ORIENTATION) Slog.v(TAG, "Checking app orientation: " + atoken);
3810
3811            // if we're about to tear down this window and not seek for
3812            // the behind activity, don't use it for orientation
3813            if (!findingBehind
3814                    && (!atoken.hidden && atoken.hiddenRequested)) {
3815                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
3816                        + " -- going to hide");
3817                continue;
3818            }
3819
3820            if (haveGroup == true && curGroup != atoken.groupId) {
3821                // If we have hit a new application group, and the bottom
3822                // of the previous group didn't explicitly say to use
3823                // the orientation behind it, and the last app was
3824                // full screen, then we'll stick with the
3825                // user's orientation.
3826                if (lastOrientation != ActivityInfo.SCREEN_ORIENTATION_BEHIND
3827                        && lastFullscreen) {
3828                    if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
3829                            + " -- end of group, return " + lastOrientation);
3830                    return lastOrientation;
3831                }
3832            }
3833
3834            // We ignore any hidden applications on the top.
3835            if (atoken.hiddenRequested || atoken.willBeHidden) {
3836                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
3837                        + " -- hidden on top");
3838                continue;
3839            }
3840
3841            if (!haveGroup) {
3842                haveGroup = true;
3843                curGroup = atoken.groupId;
3844                lastOrientation = atoken.requestedOrientation;
3845            }
3846
3847            int or = atoken.requestedOrientation;
3848            // If this application is fullscreen, and didn't explicitly say
3849            // to use the orientation behind it, then just take whatever
3850            // orientation it has and ignores whatever is under it.
3851            lastFullscreen = atoken.appFullscreen;
3852            if (lastFullscreen
3853                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
3854                if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
3855                        + " -- full screen, return " + or);
3856                return or;
3857            }
3858            // If this application has requested an explicit orientation,
3859            // then use it.
3860            if (or != ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
3861                    && or != ActivityInfo.SCREEN_ORIENTATION_BEHIND) {
3862                if (DEBUG_ORIENTATION) Slog.v(TAG, "Done at " + atoken
3863                        + " -- explicitly set, return " + or);
3864                return or;
3865            }
3866            findingBehind |= (or == ActivityInfo.SCREEN_ORIENTATION_BEHIND);
3867        }
3868        if (DEBUG_ORIENTATION) Slog.v(TAG, "No app is requesting an orientation");
3869        return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3870    }
3871
3872    @Override
3873    public Configuration updateOrientationFromAppTokens(
3874            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
3875        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3876                "updateOrientationFromAppTokens()")) {
3877            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3878        }
3879
3880        Configuration config = null;
3881        long ident = Binder.clearCallingIdentity();
3882
3883        synchronized(mWindowMap) {
3884            config = updateOrientationFromAppTokensLocked(currentConfig,
3885                    freezeThisOneIfNeeded);
3886        }
3887
3888        Binder.restoreCallingIdentity(ident);
3889        return config;
3890    }
3891
3892    private Configuration updateOrientationFromAppTokensLocked(
3893            Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
3894        Configuration config = null;
3895
3896        if (updateOrientationFromAppTokensLocked(false)) {
3897            if (freezeThisOneIfNeeded != null) {
3898                AppWindowToken atoken = findAppWindowToken(
3899                        freezeThisOneIfNeeded);
3900                if (atoken != null) {
3901                    startAppFreezingScreenLocked(atoken,
3902                            ActivityInfo.CONFIG_ORIENTATION);
3903                }
3904            }
3905            config = computeNewConfigurationLocked();
3906
3907        } else if (currentConfig != null) {
3908            // No obvious action we need to take, but if our current
3909            // state mismatches the activity manager's, update it,
3910            // disregarding font scale, which should remain set to
3911            // the value of the previous configuration.
3912            mTempConfiguration.setToDefaults();
3913            mTempConfiguration.fontScale = currentConfig.fontScale;
3914            if (computeScreenConfigurationLocked(mTempConfiguration)) {
3915                if (currentConfig.diff(mTempConfiguration) != 0) {
3916                    mWaitingForConfig = true;
3917                    getDefaultDisplayContentLocked().layoutNeeded = true;
3918                    startFreezingDisplayLocked(false, 0, 0);
3919                    config = new Configuration(mTempConfiguration);
3920                }
3921            }
3922        }
3923
3924        return config;
3925    }
3926
3927    /*
3928     * Determine the new desired orientation of the display, returning
3929     * a non-null new Configuration if it has changed from the current
3930     * orientation.  IF TRUE IS RETURNED SOMEONE MUST CALL
3931     * setNewConfiguration() TO TELL THE WINDOW MANAGER IT CAN UNFREEZE THE
3932     * SCREEN.  This will typically be done for you if you call
3933     * sendNewConfiguration().
3934     *
3935     * The orientation is computed from non-application windows first. If none of
3936     * the non-application windows specify orientation, the orientation is computed from
3937     * application tokens.
3938     * @see android.view.IWindowManager#updateOrientationFromAppTokens(
3939     * android.os.IBinder)
3940     */
3941    boolean updateOrientationFromAppTokensLocked(boolean inTransaction) {
3942        long ident = Binder.clearCallingIdentity();
3943        try {
3944            int req = computeForcedAppOrientationLocked();
3945
3946            if (req != mForcedAppOrientation) {
3947                mForcedAppOrientation = req;
3948                //send a message to Policy indicating orientation change to take
3949                //action like disabling/enabling sensors etc.,
3950                mPolicy.setCurrentOrientationLw(req);
3951                if (updateRotationUncheckedLocked(inTransaction)) {
3952                    // changed
3953                    return true;
3954                }
3955            }
3956
3957            return false;
3958        } finally {
3959            Binder.restoreCallingIdentity(ident);
3960        }
3961    }
3962
3963    int computeForcedAppOrientationLocked() {
3964        int req = getOrientationFromWindowsLocked();
3965        if (req == ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED) {
3966            req = getOrientationFromAppTokensLocked();
3967        }
3968        return req;
3969    }
3970
3971    @Override
3972    public void setNewConfiguration(Configuration config) {
3973        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3974                "setNewConfiguration()")) {
3975            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3976        }
3977
3978        synchronized(mWindowMap) {
3979            mCurConfiguration = new Configuration(config);
3980            mWaitingForConfig = false;
3981            performLayoutAndPlaceSurfacesLocked();
3982        }
3983    }
3984
3985    @Override
3986    public void setAppOrientation(IApplicationToken token, int requestedOrientation) {
3987        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
3988                "setAppOrientation()")) {
3989            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
3990        }
3991
3992        synchronized(mWindowMap) {
3993            AppWindowToken atoken = findAppWindowToken(token.asBinder());
3994            if (atoken == null) {
3995                Slog.w(TAG, "Attempted to set orientation of non-existing app token: " + token);
3996                return;
3997            }
3998
3999            atoken.requestedOrientation = requestedOrientation;
4000        }
4001    }
4002
4003    @Override
4004    public int getAppOrientation(IApplicationToken token) {
4005        synchronized(mWindowMap) {
4006            AppWindowToken wtoken = findAppWindowToken(token.asBinder());
4007            if (wtoken == null) {
4008                return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
4009            }
4010
4011            return wtoken.requestedOrientation;
4012        }
4013    }
4014
4015    @Override
4016    public void setFocusedApp(IBinder token, boolean moveFocusNow) {
4017        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4018                "setFocusedApp()")) {
4019            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4020        }
4021
4022        synchronized(mWindowMap) {
4023            boolean changed = false;
4024            if (token == null) {
4025                if (DEBUG_FOCUS) Slog.v(TAG, "Clearing focused app, was " + mFocusedApp);
4026                changed = mFocusedApp != null;
4027                mFocusedApp = null;
4028                if (changed) {
4029                    mInputMonitor.setFocusedAppLw(null);
4030                }
4031            } else {
4032                AppWindowToken newFocus = findAppWindowToken(token);
4033                if (newFocus == null) {
4034                    Slog.w(TAG, "Attempted to set focus to non-existing app token: " + token);
4035                    return;
4036                }
4037                changed = mFocusedApp != newFocus;
4038                mFocusedApp = newFocus;
4039                if (DEBUG_FOCUS) Slog.v(TAG, "Set focused app to: " + mFocusedApp
4040                        + " moveFocusNow=" + moveFocusNow);
4041                if (changed) {
4042                    mInputMonitor.setFocusedAppLw(newFocus);
4043                }
4044            }
4045
4046            if (moveFocusNow && changed) {
4047                final long origId = Binder.clearCallingIdentity();
4048                updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
4049                Binder.restoreCallingIdentity(origId);
4050            }
4051        }
4052    }
4053
4054    @Override
4055    public void prepareAppTransition(int transit, boolean alwaysKeepCurrent) {
4056        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4057                "prepareAppTransition()")) {
4058            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4059        }
4060
4061        synchronized(mWindowMap) {
4062            if (DEBUG_APP_TRANSITIONS) Slog.v(
4063                    TAG, "Prepare app transition: transit=" + transit
4064                    + " mNextAppTransition=" + mNextAppTransition
4065                    + " alwaysKeepCurrent=" + alwaysKeepCurrent
4066                    + " Callers=" + Debug.getCallers(3));
4067            if (okToDisplay()) {
4068                if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
4069                        || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
4070                    mNextAppTransition = transit;
4071                } else if (!alwaysKeepCurrent) {
4072                    if (transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
4073                            && mNextAppTransition == WindowManagerPolicy.TRANSIT_TASK_CLOSE) {
4074                        // Opening a new task always supersedes a close for the anim.
4075                        mNextAppTransition = transit;
4076                    } else if (transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
4077                            && mNextAppTransition == WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE) {
4078                        // Opening a new activity always supersedes a close for the anim.
4079                        mNextAppTransition = transit;
4080                    }
4081                }
4082                mAppTransitionReady = false;
4083                mAppTransitionTimeout = false;
4084                mStartingIconInTransition = false;
4085                mSkipAppTransitionAnimation = false;
4086                mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
4087                mH.sendMessageDelayed(mH.obtainMessage(H.APP_TRANSITION_TIMEOUT),
4088                        5000);
4089            }
4090        }
4091    }
4092
4093    @Override
4094    public int getPendingAppTransition() {
4095        return mNextAppTransition;
4096    }
4097
4098    private void scheduleAnimationCallback(IRemoteCallback cb) {
4099        if (cb != null) {
4100            mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, cb));
4101        }
4102    }
4103
4104    @Override
4105    public void overridePendingAppTransition(String packageName,
4106            int enterAnim, int exitAnim, IRemoteCallback startedCallback) {
4107        synchronized(mWindowMap) {
4108            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4109                mNextAppTransitionType = ActivityOptions.ANIM_CUSTOM;
4110                mNextAppTransitionPackage = packageName;
4111                mNextAppTransitionThumbnail = null;
4112                mNextAppTransitionEnter = enterAnim;
4113                mNextAppTransitionExit = exitAnim;
4114                scheduleAnimationCallback(mNextAppTransitionCallback);
4115                mNextAppTransitionCallback = startedCallback;
4116            } else {
4117                scheduleAnimationCallback(startedCallback);
4118            }
4119        }
4120    }
4121
4122    @Override
4123    public void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
4124            int startHeight) {
4125        synchronized(mWindowMap) {
4126            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4127                mNextAppTransitionType = ActivityOptions.ANIM_SCALE_UP;
4128                mNextAppTransitionPackage = null;
4129                mNextAppTransitionThumbnail = null;
4130                mNextAppTransitionStartX = startX;
4131                mNextAppTransitionStartY = startY;
4132                mNextAppTransitionStartWidth = startWidth;
4133                mNextAppTransitionStartHeight = startHeight;
4134                scheduleAnimationCallback(mNextAppTransitionCallback);
4135                mNextAppTransitionCallback = null;
4136            }
4137        }
4138    }
4139
4140    @Override
4141    public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX,
4142            int startY, IRemoteCallback startedCallback, boolean scaleUp) {
4143        synchronized(mWindowMap) {
4144            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4145                mNextAppTransitionType = scaleUp
4146                        ? ActivityOptions.ANIM_THUMBNAIL_SCALE_UP : ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
4147                mNextAppTransitionPackage = null;
4148                mNextAppTransitionThumbnail = srcThumb;
4149                mNextAppTransitionScaleUp = scaleUp;
4150                mNextAppTransitionStartX = startX;
4151                mNextAppTransitionStartY = startY;
4152                scheduleAnimationCallback(mNextAppTransitionCallback);
4153                mNextAppTransitionCallback = startedCallback;
4154            } else {
4155                scheduleAnimationCallback(startedCallback);
4156            }
4157        }
4158    }
4159
4160    @Override
4161    public void executeAppTransition() {
4162        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4163                "executeAppTransition()")) {
4164            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4165        }
4166
4167        synchronized(mWindowMap) {
4168            if (DEBUG_APP_TRANSITIONS) {
4169                RuntimeException e = new RuntimeException("here");
4170                e.fillInStackTrace();
4171                Slog.w(TAG, "Execute app transition: mNextAppTransition="
4172                        + mNextAppTransition, e);
4173            }
4174            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4175                mAppTransitionReady = true;
4176                final long origId = Binder.clearCallingIdentity();
4177                performLayoutAndPlaceSurfacesLocked();
4178                Binder.restoreCallingIdentity(origId);
4179            }
4180        }
4181    }
4182
4183    public void setAppStartingWindow(IBinder token, String pkg,
4184            int theme, CompatibilityInfo compatInfo,
4185            CharSequence nonLocalizedLabel, int labelRes, int icon,
4186            int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
4187        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4188                "setAppStartingWindow()")) {
4189            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4190        }
4191
4192        synchronized(mWindowMap) {
4193            if (DEBUG_STARTING_WINDOW) Slog.v(
4194                    TAG, "setAppStartingWindow: token=" + token + " pkg=" + pkg
4195                    + " transferFrom=" + transferFrom);
4196
4197            AppWindowToken wtoken = findAppWindowToken(token);
4198            if (wtoken == null) {
4199                Slog.w(TAG, "Attempted to set icon of non-existing app token: " + token);
4200                return;
4201            }
4202
4203            // If the display is frozen, we won't do anything until the
4204            // actual window is displayed so there is no reason to put in
4205            // the starting window.
4206            if (!okToDisplay()) {
4207                return;
4208            }
4209
4210            if (wtoken.startingData != null) {
4211                return;
4212            }
4213
4214            if (transferFrom != null) {
4215                AppWindowToken ttoken = findAppWindowToken(transferFrom);
4216                if (ttoken != null) {
4217                    WindowState startingWindow = ttoken.startingWindow;
4218                    if (startingWindow != null) {
4219                        if (mStartingIconInTransition) {
4220                            // In this case, the starting icon has already
4221                            // been displayed, so start letting windows get
4222                            // shown immediately without any more transitions.
4223                            mSkipAppTransitionAnimation = true;
4224                        }
4225                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
4226                                "Moving existing starting " + startingWindow + " from " + ttoken
4227                                + " to " + wtoken);
4228                        final long origId = Binder.clearCallingIdentity();
4229
4230                        // Transfer the starting window over to the new
4231                        // token.
4232                        wtoken.startingData = ttoken.startingData;
4233                        wtoken.startingView = ttoken.startingView;
4234                        wtoken.startingDisplayed = ttoken.startingDisplayed;
4235                        ttoken.startingDisplayed = false;
4236                        wtoken.startingWindow = startingWindow;
4237                        wtoken.reportedVisible = ttoken.reportedVisible;
4238                        ttoken.startingData = null;
4239                        ttoken.startingView = null;
4240                        ttoken.startingWindow = null;
4241                        ttoken.startingMoved = true;
4242                        startingWindow.mToken = wtoken;
4243                        startingWindow.mRootToken = wtoken;
4244                        startingWindow.mAppToken = wtoken;
4245                        startingWindow.mWinAnimator.mAppAnimator = wtoken.mAppAnimator;
4246
4247                        if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) {
4248                            Slog.v(TAG, "Removing starting window: " + startingWindow);
4249                        }
4250                        startingWindow.getWindowList().remove(startingWindow);
4251                        mWindowsChanged = true;
4252                        if (DEBUG_ADD_REMOVE) Slog.v(TAG,
4253                                "Removing starting " + startingWindow + " from " + ttoken);
4254                        ttoken.windows.remove(startingWindow);
4255                        ttoken.allAppWindows.remove(startingWindow);
4256                        addWindowToListInOrderLocked(startingWindow, true);
4257
4258                        // Propagate other interesting state between the
4259                        // tokens.  If the old token is displayed, we should
4260                        // immediately force the new one to be displayed.  If
4261                        // it is animating, we need to move that animation to
4262                        // the new one.
4263                        if (ttoken.allDrawn) {
4264                            wtoken.allDrawn = true;
4265                        }
4266                        if (ttoken.firstWindowDrawn) {
4267                            wtoken.firstWindowDrawn = true;
4268                        }
4269                        if (!ttoken.hidden) {
4270                            wtoken.hidden = false;
4271                            wtoken.hiddenRequested = false;
4272                            wtoken.willBeHidden = false;
4273                        }
4274                        if (wtoken.clientHidden != ttoken.clientHidden) {
4275                            wtoken.clientHidden = ttoken.clientHidden;
4276                            wtoken.sendAppVisibilityToClients();
4277                        }
4278                        final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator;
4279                        final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator;
4280                        if (tAppAnimator.animation != null) {
4281                            wAppAnimator.animation = tAppAnimator.animation;
4282                            wAppAnimator.animating = tAppAnimator.animating;
4283                            wAppAnimator.animLayerAdjustment = tAppAnimator.animLayerAdjustment;
4284                            tAppAnimator.animation = null;
4285                            tAppAnimator.animLayerAdjustment = 0;
4286                            wAppAnimator.updateLayers();
4287                            tAppAnimator.updateLayers();
4288                        }
4289
4290                        updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4291                                true /*updateInputWindows*/);
4292                        getDefaultDisplayContentLocked().layoutNeeded = true;
4293                        performLayoutAndPlaceSurfacesLocked();
4294                        Binder.restoreCallingIdentity(origId);
4295                        return;
4296                    } else if (ttoken.startingData != null) {
4297                        // The previous app was getting ready to show a
4298                        // starting window, but hasn't yet done so.  Steal it!
4299                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
4300                                "Moving pending starting from " + ttoken
4301                                + " to " + wtoken);
4302                        wtoken.startingData = ttoken.startingData;
4303                        ttoken.startingData = null;
4304                        ttoken.startingMoved = true;
4305                        Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
4306                        // Note: we really want to do sendMessageAtFrontOfQueue() because we
4307                        // want to process the message ASAP, before any other queued
4308                        // messages.
4309                        mH.sendMessageAtFrontOfQueue(m);
4310                        return;
4311                    }
4312                    final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator;
4313                    final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator;
4314                    if (tAppAnimator.thumbnail != null) {
4315                        // The old token is animating with a thumbnail, transfer
4316                        // that to the new token.
4317                        if (wAppAnimator.thumbnail != null) {
4318                            wAppAnimator.thumbnail.destroy();
4319                        }
4320                        wAppAnimator.thumbnail = tAppAnimator.thumbnail;
4321                        wAppAnimator.thumbnailX = tAppAnimator.thumbnailX;
4322                        wAppAnimator.thumbnailY = tAppAnimator.thumbnailY;
4323                        wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
4324                        wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
4325                        tAppAnimator.thumbnail = null;
4326                    }
4327                }
4328            }
4329
4330            // There is no existing starting window, and the caller doesn't
4331            // want us to create one, so that's it!
4332            if (!createIfNeeded) {
4333                return;
4334            }
4335
4336            // If this is a translucent window, then don't
4337            // show a starting window -- the current effect (a full-screen
4338            // opaque starting window that fades away to the real contents
4339            // when it is ready) does not work for this.
4340            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Checking theme of starting window: 0x"
4341                    + Integer.toHexString(theme));
4342            if (theme != 0) {
4343                AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
4344                        com.android.internal.R.styleable.Window);
4345                if (ent == null) {
4346                    // Whoops!  App doesn't exist.  Um.  Okay.  We'll just
4347                    // pretend like we didn't see that.
4348                    return;
4349                }
4350                if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Translucent="
4351                        + ent.array.getBoolean(
4352                                com.android.internal.R.styleable.Window_windowIsTranslucent, false)
4353                        + " Floating="
4354                        + ent.array.getBoolean(
4355                                com.android.internal.R.styleable.Window_windowIsFloating, false)
4356                        + " ShowWallpaper="
4357                        + ent.array.getBoolean(
4358                                com.android.internal.R.styleable.Window_windowShowWallpaper, false));
4359                if (ent.array.getBoolean(
4360                        com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
4361                    return;
4362                }
4363                if (ent.array.getBoolean(
4364                        com.android.internal.R.styleable.Window_windowIsFloating, false)) {
4365                    return;
4366                }
4367                if (ent.array.getBoolean(
4368                        com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
4369                    if (mWallpaperTarget == null) {
4370                        // If this theme is requesting a wallpaper, and the wallpaper
4371                        // is not curently visible, then this effectively serves as
4372                        // an opaque window and our starting window transition animation
4373                        // can still work.  We just need to make sure the starting window
4374                        // is also showing the wallpaper.
4375                        windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
4376                    } else {
4377                        return;
4378                    }
4379                }
4380            }
4381
4382            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Creating StartingData");
4383            mStartingIconInTransition = true;
4384            wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
4385                    labelRes, icon, windowFlags);
4386            Message m = mH.obtainMessage(H.ADD_STARTING, wtoken);
4387            // Note: we really want to do sendMessageAtFrontOfQueue() because we
4388            // want to process the message ASAP, before any other queued
4389            // messages.
4390            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING");
4391            mH.sendMessageAtFrontOfQueue(m);
4392        }
4393    }
4394
4395    public void setAppWillBeHidden(IBinder token) {
4396        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4397                "setAppWillBeHidden()")) {
4398            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4399        }
4400
4401        AppWindowToken wtoken;
4402
4403        synchronized(mWindowMap) {
4404            wtoken = findAppWindowToken(token);
4405            if (wtoken == null) {
4406                Slog.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
4407                return;
4408            }
4409            wtoken.willBeHidden = true;
4410        }
4411    }
4412
4413    boolean setTokenVisibilityLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp,
4414            boolean visible, int transit, boolean performLayout) {
4415        boolean delayed = false;
4416
4417        if (wtoken.clientHidden == visible) {
4418            wtoken.clientHidden = !visible;
4419            wtoken.sendAppVisibilityToClients();
4420        }
4421
4422        wtoken.willBeHidden = false;
4423        if (wtoken.hidden == visible) {
4424            boolean changed = false;
4425            if (DEBUG_APP_TRANSITIONS) Slog.v(
4426                TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
4427                + " performLayout=" + performLayout);
4428
4429            boolean runningAppAnimation = false;
4430
4431            if (transit != WindowManagerPolicy.TRANSIT_UNSET) {
4432                if (wtoken.mAppAnimator.animation == AppWindowAnimator.sDummyAnimation) {
4433                    wtoken.mAppAnimator.animation = null;
4434                }
4435                if (applyAnimationLocked(wtoken, lp, transit, visible)) {
4436                    delayed = runningAppAnimation = true;
4437                }
4438                WindowState window = wtoken.findMainWindow();
4439                if (window != null) {
4440                    scheduleNotifyWindowTranstionIfNeededLocked(window, transit);
4441                }
4442                changed = true;
4443            }
4444
4445            final int N = wtoken.allAppWindows.size();
4446            for (int i=0; i<N; i++) {
4447                WindowState win = wtoken.allAppWindows.get(i);
4448                if (win == wtoken.startingWindow) {
4449                    continue;
4450                }
4451
4452                //Slog.i(TAG, "Window " + win + ": vis=" + win.isVisible());
4453                //win.dump("  ");
4454                if (visible) {
4455                    if (!win.isVisibleNow()) {
4456                        if (!runningAppAnimation) {
4457                            win.mWinAnimator.applyAnimationLocked(
4458                                    WindowManagerPolicy.TRANSIT_ENTER, true);
4459                            scheduleNotifyWindowTranstionIfNeededLocked(win,
4460                                    WindowManagerPolicy.TRANSIT_ENTER);
4461                        }
4462                        changed = true;
4463                        win.mDisplayContent.layoutNeeded = true;
4464                    }
4465                } else if (win.isVisibleNow()) {
4466                    if (!runningAppAnimation) {
4467                        win.mWinAnimator.applyAnimationLocked(
4468                                WindowManagerPolicy.TRANSIT_EXIT, false);
4469                        scheduleNotifyWindowTranstionIfNeededLocked(win,
4470                                WindowManagerPolicy.TRANSIT_EXIT);
4471                    }
4472                    changed = true;
4473                    win.mDisplayContent.layoutNeeded = true;
4474                }
4475            }
4476
4477            wtoken.hidden = wtoken.hiddenRequested = !visible;
4478            if (!visible) {
4479                unsetAppFreezingScreenLocked(wtoken, true, true);
4480            } else {
4481                // If we are being set visible, and the starting window is
4482                // not yet displayed, then make sure it doesn't get displayed.
4483                WindowState swin = wtoken.startingWindow;
4484                if (swin != null && !swin.isDrawnLw()) {
4485                    swin.mPolicyVisibility = false;
4486                    swin.mPolicyVisibilityAfterAnim = false;
4487                 }
4488            }
4489
4490            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "setTokenVisibilityLocked: " + wtoken
4491                      + ": hidden=" + wtoken.hidden + " hiddenRequested="
4492                      + wtoken.hiddenRequested);
4493
4494            if (changed) {
4495                mInputMonitor.setUpdateInputWindowsNeededLw();
4496                if (performLayout) {
4497                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4498                            false /*updateInputWindows*/);
4499                    performLayoutAndPlaceSurfacesLocked();
4500                }
4501                mInputMonitor.updateInputWindowsLw(false /*force*/);
4502            }
4503        }
4504
4505        if (wtoken.mAppAnimator.animation != null) {
4506            delayed = true;
4507        }
4508
4509        for (int i = wtoken.allAppWindows.size() - 1; i >= 0 && !delayed; i--) {
4510            if (wtoken.allAppWindows.get(i).mWinAnimator.isWindowAnimating()) {
4511                delayed = true;
4512            }
4513        }
4514
4515        return delayed;
4516    }
4517
4518    public void setAppVisibility(IBinder token, boolean visible) {
4519        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4520                "setAppVisibility()")) {
4521            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4522        }
4523
4524        AppWindowToken wtoken;
4525
4526        synchronized(mWindowMap) {
4527            wtoken = findAppWindowToken(token);
4528            if (wtoken == null) {
4529                Slog.w(TAG, "Attempted to set visibility of non-existing app token: " + token);
4530                return;
4531            }
4532
4533            if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
4534                RuntimeException e = null;
4535                if (!HIDE_STACK_CRAWLS) {
4536                    e = new RuntimeException();
4537                    e.fillInStackTrace();
4538                }
4539                Slog.v(TAG, "setAppVisibility(" + token + ", visible=" + visible
4540                        + "): mNextAppTransition=" + mNextAppTransition
4541                        + " hidden=" + wtoken.hidden
4542                        + " hiddenRequested=" + wtoken.hiddenRequested, e);
4543            }
4544
4545            // If we are preparing an app transition, then delay changing
4546            // the visibility of this token until we execute that transition.
4547            if (okToDisplay() && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4548                // Already in requested state, don't do anything more.
4549                if (wtoken.hiddenRequested != visible) {
4550                    return;
4551                }
4552                wtoken.hiddenRequested = !visible;
4553
4554                if (!wtoken.startingDisplayed) {
4555                    if (DEBUG_APP_TRANSITIONS) Slog.v(
4556                            TAG, "Setting dummy animation on: " + wtoken);
4557                    wtoken.mAppAnimator.setDummyAnimation();
4558                }
4559                mOpeningApps.remove(wtoken);
4560                mClosingApps.remove(wtoken);
4561                wtoken.waitingToShow = wtoken.waitingToHide = false;
4562                wtoken.inPendingTransaction = true;
4563                if (visible) {
4564                    mOpeningApps.add(wtoken);
4565                    wtoken.startingMoved = false;
4566
4567                    // If the token is currently hidden (should be the
4568                    // common case), then we need to set up to wait for
4569                    // its windows to be ready.
4570                    if (wtoken.hidden) {
4571                        wtoken.allDrawn = false;
4572                        wtoken.waitingToShow = true;
4573
4574                        if (wtoken.clientHidden) {
4575                            // In the case where we are making an app visible
4576                            // but holding off for a transition, we still need
4577                            // to tell the client to make its windows visible so
4578                            // they get drawn.  Otherwise, we will wait on
4579                            // performing the transition until all windows have
4580                            // been drawn, they never will be, and we are sad.
4581                            wtoken.clientHidden = false;
4582                            wtoken.sendAppVisibilityToClients();
4583                        }
4584                    }
4585                } else {
4586                    mClosingApps.add(wtoken);
4587
4588                    // If the token is currently visible (should be the
4589                    // common case), then set up to wait for it to be hidden.
4590                    if (!wtoken.hidden) {
4591                        wtoken.waitingToHide = true;
4592                    }
4593                }
4594                return;
4595            }
4596
4597            final long origId = Binder.clearCallingIdentity();
4598            setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET,
4599                    true);
4600            wtoken.updateReportedVisibilityLocked();
4601            Binder.restoreCallingIdentity(origId);
4602        }
4603    }
4604
4605    void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
4606            boolean unfreezeSurfaceNow, boolean force) {
4607        if (wtoken.mAppAnimator.freezingScreen) {
4608            if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + wtoken
4609                    + " force=" + force);
4610            final int N = wtoken.allAppWindows.size();
4611            boolean unfrozeWindows = false;
4612            for (int i=0; i<N; i++) {
4613                WindowState w = wtoken.allAppWindows.get(i);
4614                if (w.mAppFreezing) {
4615                    w.mAppFreezing = false;
4616                    if (w.mHasSurface && !w.mOrientationChanging) {
4617                        if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
4618                        w.mOrientationChanging = true;
4619                        mInnerFields.mOrientationChangeComplete = false;
4620                    }
4621                    unfrozeWindows = true;
4622                    w.mDisplayContent.layoutNeeded = true;
4623                }
4624            }
4625            if (force || unfrozeWindows) {
4626                if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken);
4627                wtoken.mAppAnimator.freezingScreen = false;
4628                mAppsFreezingScreen--;
4629            }
4630            if (unfreezeSurfaceNow) {
4631                if (unfrozeWindows) {
4632                    performLayoutAndPlaceSurfacesLocked();
4633                }
4634                stopFreezingDisplayLocked();
4635            }
4636        }
4637    }
4638
4639    public void startAppFreezingScreenLocked(AppWindowToken wtoken,
4640            int configChanges) {
4641        if (DEBUG_ORIENTATION) {
4642            RuntimeException e = null;
4643            if (!HIDE_STACK_CRAWLS) {
4644                e = new RuntimeException();
4645                e.fillInStackTrace();
4646            }
4647            Slog.i(TAG, "Set freezing of " + wtoken.appToken
4648                    + ": hidden=" + wtoken.hidden + " freezing="
4649                    + wtoken.mAppAnimator.freezingScreen, e);
4650        }
4651        if (!wtoken.hiddenRequested) {
4652            if (!wtoken.mAppAnimator.freezingScreen) {
4653                wtoken.mAppAnimator.freezingScreen = true;
4654                mAppsFreezingScreen++;
4655                if (mAppsFreezingScreen == 1) {
4656                    startFreezingDisplayLocked(false, 0, 0);
4657                    mH.removeMessages(H.APP_FREEZE_TIMEOUT);
4658                    mH.sendMessageDelayed(mH.obtainMessage(H.APP_FREEZE_TIMEOUT),
4659                            5000);
4660                }
4661            }
4662            final int N = wtoken.allAppWindows.size();
4663            for (int i=0; i<N; i++) {
4664                WindowState w = wtoken.allAppWindows.get(i);
4665                w.mAppFreezing = true;
4666            }
4667        }
4668    }
4669
4670    public void startAppFreezingScreen(IBinder token, int configChanges) {
4671        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4672                "setAppFreezingScreen()")) {
4673            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4674        }
4675
4676        synchronized(mWindowMap) {
4677            if (configChanges == 0 && okToDisplay()) {
4678                if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping set freeze of " + token);
4679                return;
4680            }
4681
4682            AppWindowToken wtoken = findAppWindowToken(token);
4683            if (wtoken == null || wtoken.appToken == null) {
4684                Slog.w(TAG, "Attempted to freeze screen with non-existing app token: " + wtoken);
4685                return;
4686            }
4687            final long origId = Binder.clearCallingIdentity();
4688            startAppFreezingScreenLocked(wtoken, configChanges);
4689            Binder.restoreCallingIdentity(origId);
4690        }
4691    }
4692
4693    public void stopAppFreezingScreen(IBinder token, boolean force) {
4694        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4695                "setAppFreezingScreen()")) {
4696            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4697        }
4698
4699        synchronized(mWindowMap) {
4700            AppWindowToken wtoken = findAppWindowToken(token);
4701            if (wtoken == null || wtoken.appToken == null) {
4702                return;
4703            }
4704            final long origId = Binder.clearCallingIdentity();
4705            if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + token
4706                    + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
4707            unsetAppFreezingScreenLocked(wtoken, true, force);
4708            Binder.restoreCallingIdentity(origId);
4709        }
4710    }
4711
4712    public void removeAppToken(IBinder token) {
4713        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4714                "removeAppToken()")) {
4715            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4716        }
4717
4718        AppWindowToken wtoken = null;
4719        AppWindowToken startingToken = null;
4720        boolean delayed = false;
4721
4722        final long origId = Binder.clearCallingIdentity();
4723        synchronized(mWindowMap) {
4724            WindowToken basewtoken = mTokenMap.remove(token);
4725            if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
4726                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Removing app token: " + wtoken);
4727                delayed = setTokenVisibilityLocked(wtoken, null, false,
4728                        WindowManagerPolicy.TRANSIT_UNSET, true);
4729                wtoken.inPendingTransaction = false;
4730                mOpeningApps.remove(wtoken);
4731                wtoken.waitingToShow = false;
4732                if (mClosingApps.contains(wtoken)) {
4733                    delayed = true;
4734                } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
4735                    mClosingApps.add(wtoken);
4736                    wtoken.waitingToHide = true;
4737                    delayed = true;
4738                }
4739                if (DEBUG_APP_TRANSITIONS) Slog.v(
4740                        TAG, "Removing app " + wtoken + " delayed=" + delayed
4741                        + " animation=" + wtoken.mAppAnimator.animation
4742                        + " animating=" + wtoken.mAppAnimator.animating);
4743                if (delayed) {
4744                    // set the token aside because it has an active animation to be finished
4745                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
4746                            "removeAppToken make exiting: " + wtoken);
4747                    mExitingAppTokens.add(wtoken);
4748                } else {
4749                    // Make sure there is no animation running on this token,
4750                    // so any windows associated with it will be removed as
4751                    // soon as their animations are complete
4752                    wtoken.mAppAnimator.clearAnimation();
4753                    wtoken.mAppAnimator.animating = false;
4754                }
4755                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
4756                        "removeAppToken: " + wtoken);
4757                mAppTokens.remove(wtoken);
4758                mAnimatingAppTokens.remove(wtoken);
4759                wtoken.removed = true;
4760                if (wtoken.startingData != null) {
4761                    startingToken = wtoken;
4762                }
4763                unsetAppFreezingScreenLocked(wtoken, true, true);
4764                if (mFocusedApp == wtoken) {
4765                    if (DEBUG_FOCUS) Slog.v(TAG, "Removing focused app token:" + wtoken);
4766                    mFocusedApp = null;
4767                    updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
4768                    mInputMonitor.setFocusedAppLw(null);
4769                }
4770            } else {
4771                Slog.w(TAG, "Attempted to remove non-existing app token: " + token);
4772            }
4773
4774            if (!delayed && wtoken != null) {
4775                wtoken.updateReportedVisibilityLocked();
4776            }
4777        }
4778        Binder.restoreCallingIdentity(origId);
4779
4780        if (startingToken != null) {
4781            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Schedule remove starting "
4782                    + startingToken + ": app token removed");
4783            Message m = mH.obtainMessage(H.REMOVE_STARTING, startingToken);
4784            mH.sendMessage(m);
4785        }
4786    }
4787
4788    private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
4789        final int NW = token.windows.size();
4790        if (NW > 0) {
4791            mWindowsChanged = true;
4792        }
4793        for (int i=0; i<NW; i++) {
4794            WindowState win = token.windows.get(i);
4795            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
4796            win.getWindowList().remove(win);
4797            int j = win.mChildWindows.size();
4798            while (j > 0) {
4799                j--;
4800                WindowState cwin = win.mChildWindows.get(j);
4801                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
4802                        "Tmp removing child window " + cwin);
4803                cwin.getWindowList().remove(cwin);
4804            }
4805        }
4806        return NW > 0;
4807    }
4808
4809    void dumpAppTokensLocked() {
4810        for (int i=mAppTokens.size()-1; i>=0; i--) {
4811            Slog.v(TAG, "  #" + i + ": " + mAppTokens.get(i).token);
4812        }
4813    }
4814
4815    void dumpAnimatingAppTokensLocked() {
4816        for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
4817            Slog.v(TAG, "  #" + i + ": " + mAnimatingAppTokens.get(i).token);
4818        }
4819    }
4820
4821    void dumpWindowsLocked() {
4822        int i = 0;
4823        final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
4824        while (iterator.hasNext()) {
4825            final WindowState w = iterator.next();
4826            Slog.v(TAG, "  #" + i++ + ": " + w);
4827        }
4828    }
4829
4830    private int findWindowOffsetLocked(WindowList windows, int tokenPos) {
4831        final int NW = windows.size();
4832
4833        if (tokenPos >= mAnimatingAppTokens.size()) {
4834            int i = NW;
4835            while (i > 0) {
4836                i--;
4837                WindowState win = windows.get(i);
4838                if (win.getAppToken() != null) {
4839                    return i+1;
4840                }
4841            }
4842        }
4843
4844        while (tokenPos > 0) {
4845            // Find the first app token below the new position that has
4846            // a window displayed.
4847            final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
4848            if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ "
4849                    + tokenPos + " -- " + wtoken.token);
4850            if (wtoken.sendingToBottom) {
4851                if (DEBUG_REORDER) Slog.v(TAG,
4852                        "Skipping token -- currently sending to bottom");
4853                tokenPos--;
4854                continue;
4855            }
4856            int i = wtoken.windows.size();
4857            while (i > 0) {
4858                i--;
4859                WindowState win = wtoken.windows.get(i);
4860                int j = win.mChildWindows.size();
4861                while (j > 0) {
4862                    j--;
4863                    WindowState cwin = win.mChildWindows.get(j);
4864                    if (cwin.mSubLayer >= 0) {
4865                        for (int pos=NW-1; pos>=0; pos--) {
4866                            if (windows.get(pos) == cwin) {
4867                                if (DEBUG_REORDER) Slog.v(TAG,
4868                                        "Found child win @" + (pos+1));
4869                                return pos+1;
4870                            }
4871                        }
4872                    }
4873                }
4874                for (int pos=NW-1; pos>=0; pos--) {
4875                    if (windows.get(pos) == win) {
4876                        if (DEBUG_REORDER) Slog.v(TAG, "Found win @" + (pos+1));
4877                        return pos+1;
4878                    }
4879                }
4880            }
4881            tokenPos--;
4882        }
4883
4884        return 0;
4885    }
4886
4887    private final int reAddWindowLocked(int index, WindowState win) {
4888        final WindowList windows = win.getWindowList();
4889        final int NCW = win.mChildWindows.size();
4890        boolean added = false;
4891        for (int j=0; j<NCW; j++) {
4892            WindowState cwin = win.mChildWindows.get(j);
4893            if (!added && cwin.mSubLayer >= 0) {
4894                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding child window at "
4895                        + index + ": " + cwin);
4896                win.mRebuilding = false;
4897                windows.add(index, win);
4898                index++;
4899                added = true;
4900            }
4901            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
4902                    + index + ": " + cwin);
4903            cwin.mRebuilding = false;
4904            windows.add(index, cwin);
4905            index++;
4906        }
4907        if (!added) {
4908            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Re-adding window at "
4909                    + index + ": " + win);
4910            win.mRebuilding = false;
4911            windows.add(index, win);
4912            index++;
4913        }
4914        mWindowsChanged = true;
4915        return index;
4916    }
4917
4918    private final int reAddAppWindowsLocked(final DisplayContent displayContent, int index,
4919                                            WindowToken token) {
4920        final int NW = token.windows.size();
4921        for (int i=0; i<NW; i++) {
4922            final WindowState win = token.windows.get(i);
4923            if (win.mDisplayContent == displayContent) {
4924                index = reAddWindowLocked(index, win);
4925            }
4926        }
4927        return index;
4928    }
4929
4930    public void moveAppToken(int index, IBinder token) {
4931        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
4932                "moveAppToken()")) {
4933            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
4934        }
4935
4936        synchronized(mWindowMap) {
4937            if (DEBUG_REORDER) Slog.v(TAG, "Initial app tokens:");
4938            if (DEBUG_REORDER) dumpAppTokensLocked();
4939            final AppWindowToken wtoken = findAppWindowToken(token);
4940            final int oldIndex = mAppTokens.indexOf(wtoken);
4941            if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
4942                    "Start moving token " + wtoken + " initially at "
4943                    + oldIndex);
4944            if (oldIndex > index && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET
4945                        && !mAppTransitionRunning) {
4946                // animation towards back has not started, copy old list for duration of animation.
4947                mAnimatingAppTokens.clear();
4948                mAnimatingAppTokens.addAll(mAppTokens);
4949            }
4950            if (wtoken == null || !mAppTokens.remove(wtoken)) {
4951                Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
4952                      + token + " (" + wtoken + ")");
4953                return;
4954            }
4955            mAppTokens.add(index, wtoken);
4956            if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":");
4957            else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index);
4958            if (DEBUG_REORDER) dumpAppTokensLocked();
4959            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET && !mAppTransitionRunning) {
4960                // Not animating, bring animating app list in line with mAppTokens.
4961                mAnimatingAppTokens.clear();
4962                mAnimatingAppTokens.addAll(mAppTokens);
4963
4964                // Bring window ordering, window focus and input window in line with new app token
4965                final long origId = Binder.clearCallingIdentity();
4966                if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":");
4967                if (DEBUG_REORDER) dumpWindowsLocked();
4968                if (tmpRemoveAppWindowsLocked(wtoken)) {
4969                    if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:");
4970                    if (DEBUG_REORDER) dumpWindowsLocked();
4971                    DisplayContentsIterator iterator = new DisplayContentsIterator();
4972                    while(iterator.hasNext()) {
4973                        final DisplayContent displayContent = iterator.next();
4974                        final WindowList windows = displayContent.getWindowList();
4975                        final int pos = findWindowOffsetLocked(windows, index);
4976                        final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
4977                        if (pos != newPos) {
4978                            displayContent.layoutNeeded = true;
4979                        }
4980                    }
4981                    if (DEBUG_REORDER) Slog.v(TAG, "Final window list:");
4982                    if (DEBUG_REORDER) dumpWindowsLocked();
4983                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
4984                            false /*updateInputWindows*/);
4985                    mInputMonitor.setUpdateInputWindowsNeededLw();
4986                    performLayoutAndPlaceSurfacesLocked();
4987                    mInputMonitor.updateInputWindowsLw(false /*force*/);
4988                }
4989                Binder.restoreCallingIdentity(origId);
4990            }
4991        }
4992    }
4993
4994    private void removeAppTokensLocked(List<IBinder> tokens) {
4995        // XXX This should be done more efficiently!
4996        // (take advantage of the fact that both lists should be
4997        // ordered in the same way.)
4998        int N = tokens.size();
4999        for (int i=0; i<N; i++) {
5000            IBinder token = tokens.get(i);
5001            final AppWindowToken wtoken = findAppWindowToken(token);
5002            if (DEBUG_REORDER || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
5003                    "Temporarily removing " + wtoken + " from " + mAppTokens.indexOf(wtoken));
5004            if (!mAppTokens.remove(wtoken)) {
5005                Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
5006                      + token + " (" + wtoken + ")");
5007                i--;
5008                N--;
5009            }
5010        }
5011    }
5012
5013    private void moveAppWindowsLocked(AppWindowToken wtoken, int tokenPos,
5014            boolean updateFocusAndLayout) {
5015        // First remove all of the windows from the list.
5016        tmpRemoveAppWindowsLocked(wtoken);
5017
5018        // And now add them back at the correct place.
5019        DisplayContentsIterator iterator = new DisplayContentsIterator();
5020        while (iterator.hasNext()) {
5021            final DisplayContent displayContent = iterator.next();
5022            final WindowList windows = displayContent.getWindowList();
5023            final int pos = findWindowOffsetLocked(windows, tokenPos);
5024            final int newPos = reAddAppWindowsLocked(displayContent, pos, wtoken);
5025            if (pos != newPos) {
5026                displayContent.layoutNeeded = true;
5027            }
5028
5029            if (updateFocusAndLayout && !updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
5030                    false /*updateInputWindows*/)) {
5031                assignLayersLocked(windows);
5032            }
5033        }
5034
5035        if (updateFocusAndLayout) {
5036            mInputMonitor.setUpdateInputWindowsNeededLw();
5037
5038            // Note that the above updateFocusedWindowLocked conditional used to sit here.
5039
5040            if (!mInLayout) {
5041                performLayoutAndPlaceSurfacesLocked();
5042            }
5043            mInputMonitor.updateInputWindowsLw(false /*force*/);
5044        }
5045    }
5046
5047    private void moveAppWindowsLocked(List<IBinder> tokens, int tokenPos) {
5048        // First remove all of the windows from the list.
5049        final int N = tokens.size();
5050        int i;
5051        for (i=0; i<N; i++) {
5052            WindowToken token = mTokenMap.get(tokens.get(i));
5053            if (token != null) {
5054                tmpRemoveAppWindowsLocked(token);
5055            }
5056        }
5057
5058        // And now add them back at the correct place.
5059        DisplayContentsIterator iterator = new DisplayContentsIterator();
5060        while (iterator.hasNext()) {
5061            final DisplayContent displayContent = iterator.next();
5062            final WindowList windows = displayContent.getWindowList();
5063            // Where to start adding?
5064            int pos = findWindowOffsetLocked(windows, tokenPos);
5065            for (i=0; i<N; i++) {
5066                WindowToken token = mTokenMap.get(tokens.get(i));
5067                if (token != null) {
5068                    final int newPos = reAddAppWindowsLocked(displayContent, pos, token);
5069                    if (newPos != pos) {
5070                        displayContent.layoutNeeded = true;
5071                    }
5072                    pos = newPos;
5073                }
5074            }
5075            if (!updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
5076                    false /*updateInputWindows*/)) {
5077                assignLayersLocked(windows);
5078            }
5079        }
5080
5081        mInputMonitor.setUpdateInputWindowsNeededLw();
5082
5083        // Note that the above updateFocusedWindowLocked used to sit here.
5084
5085        performLayoutAndPlaceSurfacesLocked();
5086        mInputMonitor.updateInputWindowsLw(false /*force*/);
5087
5088        //dump();
5089    }
5090
5091    public void moveAppTokensToTop(List<IBinder> tokens) {
5092        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
5093                "moveAppTokensToTop()")) {
5094            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
5095        }
5096
5097        final long origId = Binder.clearCallingIdentity();
5098        synchronized(mWindowMap) {
5099            removeAppTokensLocked(tokens);
5100            final int N = tokens.size();
5101            for (int i=0; i<N; i++) {
5102                AppWindowToken wt = findAppWindowToken(tokens.get(i));
5103                if (wt != null) {
5104                    if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
5105                            "Adding next to top: " + wt);
5106                    mAppTokens.add(wt);
5107                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
5108                        wt.sendingToBottom = false;
5109                    }
5110                }
5111            }
5112
5113            if (!mAppTransitionRunning) {
5114                mAnimatingAppTokens.clear();
5115                mAnimatingAppTokens.addAll(mAppTokens);
5116                moveAppWindowsLocked(tokens, mAppTokens.size());
5117            }
5118        }
5119        Binder.restoreCallingIdentity(origId);
5120    }
5121
5122    @Override
5123    public void moveAppTokensToBottom(List<IBinder> tokens) {
5124        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
5125                "moveAppTokensToBottom()")) {
5126            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
5127        }
5128
5129        final long origId = Binder.clearCallingIdentity();
5130        synchronized(mWindowMap) {
5131            final int N = tokens.size();
5132            if (N > 0 && !mAppTransitionRunning) {
5133                // animating towards back, hang onto old list for duration of animation.
5134                mAnimatingAppTokens.clear();
5135                mAnimatingAppTokens.addAll(mAppTokens);
5136            }
5137            removeAppTokensLocked(tokens);
5138            int pos = 0;
5139            for (int i=0; i<N; i++) {
5140                AppWindowToken wt = findAppWindowToken(tokens.get(i));
5141                if (wt != null) {
5142                    if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
5143                            "Adding next to bottom: " + wt + " at " + pos);
5144                    mAppTokens.add(pos, wt);
5145                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
5146                        wt.sendingToBottom = true;
5147                    }
5148                    pos++;
5149                }
5150            }
5151
5152            if (!mAppTransitionRunning) {
5153                mAnimatingAppTokens.clear();
5154                mAnimatingAppTokens.addAll(mAppTokens);
5155                moveAppWindowsLocked(tokens, 0);
5156            }
5157        }
5158        Binder.restoreCallingIdentity(origId);
5159    }
5160
5161    // -------------------------------------------------------------
5162    // Misc IWindowSession methods
5163    // -------------------------------------------------------------
5164
5165    @Override
5166    public void startFreezingScreen(int exitAnim, int enterAnim) {
5167        if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
5168                "startFreezingScreen()")) {
5169            throw new SecurityException("Requires FREEZE_SCREEN permission");
5170        }
5171
5172        synchronized(mWindowMap) {
5173            if (!mClientFreezingScreen) {
5174                mClientFreezingScreen = true;
5175                final long origId = Binder.clearCallingIdentity();
5176                try {
5177                    startFreezingDisplayLocked(false, exitAnim, enterAnim);
5178                    mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
5179                    mH.sendMessageDelayed(mH.obtainMessage(H.CLIENT_FREEZE_TIMEOUT),
5180                            5000);
5181                } finally {
5182                    Binder.restoreCallingIdentity(origId);
5183                }
5184            }
5185        }
5186    }
5187
5188    @Override
5189    public void stopFreezingScreen() {
5190        if (!checkCallingPermission(android.Manifest.permission.FREEZE_SCREEN,
5191                "stopFreezingScreen()")) {
5192            throw new SecurityException("Requires FREEZE_SCREEN permission");
5193        }
5194
5195        synchronized(mWindowMap) {
5196            if (mClientFreezingScreen) {
5197                mClientFreezingScreen = false;
5198                final long origId = Binder.clearCallingIdentity();
5199                try {
5200                    stopFreezingDisplayLocked();
5201                } finally {
5202                    Binder.restoreCallingIdentity(origId);
5203                }
5204            }
5205        }
5206    }
5207
5208    @Override
5209    public void disableKeyguard(IBinder token, String tag) {
5210        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5211            != PackageManager.PERMISSION_GRANTED) {
5212            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5213        }
5214
5215        mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
5216                KeyguardDisableHandler.KEYGUARD_DISABLE, new Pair<IBinder, String>(token, tag)));
5217    }
5218
5219    @Override
5220    public void reenableKeyguard(IBinder token) {
5221        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5222            != PackageManager.PERMISSION_GRANTED) {
5223            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5224        }
5225
5226        mKeyguardDisableHandler.sendMessage(mKeyguardDisableHandler.obtainMessage(
5227                KeyguardDisableHandler.KEYGUARD_REENABLE, token));
5228    }
5229
5230    /**
5231     * @see android.app.KeyguardManager#exitKeyguardSecurely
5232     */
5233    public void exitKeyguardSecurely(final IOnKeyguardExitResult callback) {
5234        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5235            != PackageManager.PERMISSION_GRANTED) {
5236            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5237        }
5238        mPolicy.exitKeyguardSecurely(new WindowManagerPolicy.OnKeyguardExitResult() {
5239            public void onKeyguardExitResult(boolean success) {
5240                try {
5241                    callback.onKeyguardExitResult(success);
5242                } catch (RemoteException e) {
5243                    // Client has died, we don't care.
5244                }
5245            }
5246        });
5247    }
5248
5249    public boolean inKeyguardRestrictedInputMode() {
5250        return mPolicy.inKeyguardRestrictedKeyInputMode();
5251    }
5252
5253    public boolean isKeyguardLocked() {
5254        return mPolicy.isKeyguardLocked();
5255    }
5256
5257    public boolean isKeyguardSecure() {
5258        return mPolicy.isKeyguardSecure();
5259    }
5260
5261    public void dismissKeyguard() {
5262        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DISABLE_KEYGUARD)
5263                != PackageManager.PERMISSION_GRANTED) {
5264            throw new SecurityException("Requires DISABLE_KEYGUARD permission");
5265        }
5266        synchronized(mWindowMap) {
5267            mPolicy.dismissKeyguardLw();
5268        }
5269    }
5270
5271    public void closeSystemDialogs(String reason) {
5272        synchronized(mWindowMap) {
5273            final AllWindowsIterator iterator = new AllWindowsIterator();
5274            while (iterator.hasNext()) {
5275                final WindowState w = iterator.next();
5276                if (w.mHasSurface) {
5277                    try {
5278                        w.mClient.closeSystemDialogs(reason);
5279                    } catch (RemoteException e) {
5280                    }
5281                }
5282            }
5283        }
5284    }
5285
5286    static float fixScale(float scale) {
5287        if (scale < 0) scale = 0;
5288        else if (scale > 20) scale = 20;
5289        return Math.abs(scale);
5290    }
5291
5292    public void setAnimationScale(int which, float scale) {
5293        if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
5294                "setAnimationScale()")) {
5295            throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
5296        }
5297
5298        if (scale < 0) scale = 0;
5299        else if (scale > 20) scale = 20;
5300        scale = Math.abs(scale);
5301        switch (which) {
5302            case 0: mWindowAnimationScale = fixScale(scale); break;
5303            case 1: mTransitionAnimationScale = fixScale(scale); break;
5304            case 2: mAnimatorDurationScale = fixScale(scale); break;
5305        }
5306
5307        // Persist setting
5308        mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
5309    }
5310
5311    public void setAnimationScales(float[] scales) {
5312        if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
5313                "setAnimationScale()")) {
5314            throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
5315        }
5316
5317        if (scales != null) {
5318            if (scales.length >= 1) {
5319                mWindowAnimationScale = fixScale(scales[0]);
5320            }
5321            if (scales.length >= 2) {
5322                mTransitionAnimationScale = fixScale(scales[1]);
5323            }
5324            if (scales.length >= 3) {
5325                setAnimatorDurationScale(fixScale(scales[2]));
5326            }
5327        }
5328
5329        // Persist setting
5330        mH.obtainMessage(H.PERSIST_ANIMATION_SCALE).sendToTarget();
5331    }
5332
5333    private void setAnimatorDurationScale(float scale) {
5334        mAnimatorDurationScale = scale;
5335        ValueAnimator.setDurationScale(scale);
5336    }
5337
5338    public float getAnimationScale(int which) {
5339        switch (which) {
5340            case 0: return mWindowAnimationScale;
5341            case 1: return mTransitionAnimationScale;
5342            case 2: return mAnimatorDurationScale;
5343        }
5344        return 0;
5345    }
5346
5347    public float[] getAnimationScales() {
5348        return new float[] { mWindowAnimationScale, mTransitionAnimationScale,
5349                mAnimatorDurationScale };
5350    }
5351
5352    // Called by window manager policy. Not exposed externally.
5353    @Override
5354    public int getLidState() {
5355        int sw = mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY,
5356                InputManagerService.SW_LID);
5357        if (sw > 0) {
5358            // Switch state: AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL.
5359            return LID_CLOSED;
5360        } else if (sw == 0) {
5361            // Switch state: AKEY_STATE_UP.
5362            return LID_OPEN;
5363        } else {
5364            // Switch state: AKEY_STATE_UNKNOWN.
5365            return LID_ABSENT;
5366        }
5367    }
5368
5369    // Called by window manager policy.  Not exposed externally.
5370    @Override
5371    public InputChannel monitorInput(String inputChannelName) {
5372        return mInputManager.monitorInput(inputChannelName);
5373    }
5374
5375    // Called by window manager policy.  Not exposed externally.
5376    @Override
5377    public void switchKeyboardLayout(int deviceId, int direction) {
5378        mInputManager.switchKeyboardLayout(deviceId, direction);
5379    }
5380
5381    // Called by window manager policy.  Not exposed externally.
5382    @Override
5383    public void shutdown(boolean confirm) {
5384        ShutdownThread.shutdown(mContext, confirm);
5385    }
5386
5387    // Called by window manager policy.  Not exposed externally.
5388    @Override
5389    public void rebootSafeMode(boolean confirm) {
5390        ShutdownThread.rebootSafeMode(mContext, confirm);
5391    }
5392
5393    public void setInputFilter(IInputFilter filter) {
5394        if (!checkCallingPermission(android.Manifest.permission.FILTER_EVENTS, "setInputFilter()")) {
5395            throw new SecurityException("Requires FILTER_EVENTS permission");
5396        }
5397        mInputManager.setInputFilter(filter);
5398    }
5399
5400    public void setCurrentUser(final int newUserId) {
5401        synchronized (mWindowMap) {
5402            mCurrentUserId = newUserId;
5403            mPolicy.setCurrentUserLw(newUserId);
5404        }
5405    }
5406
5407    public void enableScreenAfterBoot() {
5408        synchronized(mWindowMap) {
5409            if (DEBUG_BOOT) {
5410                RuntimeException here = new RuntimeException("here");
5411                here.fillInStackTrace();
5412                Slog.i(TAG, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled
5413                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5414                        + " mShowingBootMessages=" + mShowingBootMessages
5415                        + " mSystemBooted=" + mSystemBooted, here);
5416            }
5417            if (mSystemBooted) {
5418                return;
5419            }
5420            mSystemBooted = true;
5421            hideBootMessagesLocked();
5422            // If the screen still doesn't come up after 30 seconds, give
5423            // up and turn it on.
5424            Message msg = mH.obtainMessage(H.BOOT_TIMEOUT);
5425            mH.sendMessageDelayed(msg, 30*1000);
5426        }
5427
5428        mPolicy.systemBooted();
5429
5430        performEnableScreen();
5431    }
5432
5433    void enableScreenIfNeededLocked() {
5434        if (DEBUG_BOOT) {
5435            RuntimeException here = new RuntimeException("here");
5436            here.fillInStackTrace();
5437            Slog.i(TAG, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled
5438                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5439                    + " mShowingBootMessages=" + mShowingBootMessages
5440                    + " mSystemBooted=" + mSystemBooted, here);
5441        }
5442        if (mDisplayEnabled) {
5443            return;
5444        }
5445        if (!mSystemBooted && !mShowingBootMessages) {
5446            return;
5447        }
5448        mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
5449    }
5450
5451    public void performBootTimeout() {
5452        synchronized(mWindowMap) {
5453            if (mDisplayEnabled || mHeadless) {
5454                return;
5455            }
5456            Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
5457            mForceDisplayEnabled = true;
5458        }
5459        performEnableScreen();
5460    }
5461
5462    public void performEnableScreen() {
5463        synchronized(mWindowMap) {
5464            if (DEBUG_BOOT) {
5465                RuntimeException here = new RuntimeException("here");
5466                here.fillInStackTrace();
5467                Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
5468                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5469                        + " mShowingBootMessages=" + mShowingBootMessages
5470                        + " mSystemBooted=" + mSystemBooted
5471                        + " mOnlyCore=" + mOnlyCore, here);
5472            }
5473            if (mDisplayEnabled) {
5474                return;
5475            }
5476            if (!mSystemBooted && !mShowingBootMessages) {
5477                return;
5478            }
5479
5480            if (!mForceDisplayEnabled) {
5481                // Don't enable the screen until all existing windows
5482                // have been drawn.
5483                boolean haveBootMsg = false;
5484                boolean haveApp = false;
5485                // if the wallpaper service is disabled on the device, we're never going to have
5486                // wallpaper, don't bother waiting for it
5487                boolean haveWallpaper = false;
5488                boolean wallpaperEnabled = mContext.getResources().getBoolean(
5489                        com.android.internal.R.bool.config_enableWallpaperService)
5490                        && !mOnlyCore;
5491                boolean haveKeyguard = true;
5492                // TODO(multidisplay): Expand to all displays?
5493                final WindowList windows = getDefaultWindowListLocked();
5494                final int N = windows.size();
5495                for (int i=0; i<N; i++) {
5496                    WindowState w = windows.get(i);
5497                    if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) {
5498                        // Only if there is a keyguard attached to the window manager
5499                        // will we consider ourselves as having a keyguard.  If it
5500                        // isn't attached, we don't know if it wants to be shown or
5501                        // hidden.  If it is attached, we will say we have a keyguard
5502                        // if the window doesn't want to be visible, because in that
5503                        // case it explicitly doesn't want to be shown so we should
5504                        // not delay turning the screen on for it.
5505                        boolean vis = w.mViewVisibility == View.VISIBLE
5506                                && w.mPolicyVisibility;
5507                        haveKeyguard = !vis;
5508                    }
5509                    if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
5510                        return;
5511                    }
5512                    if (w.isDrawnLw()) {
5513                        if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
5514                            haveBootMsg = true;
5515                        } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) {
5516                            haveApp = true;
5517                        } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) {
5518                            haveWallpaper = true;
5519                        } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) {
5520                            haveKeyguard = true;
5521                        }
5522                    }
5523                }
5524
5525                if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
5526                    Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
5527                            + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
5528                            + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
5529                            + " haveKeyguard=" + haveKeyguard);
5530                }
5531
5532                // If we are turning on the screen to show the boot message,
5533                // don't do it until the boot message is actually displayed.
5534                if (!mSystemBooted && !haveBootMsg) {
5535                    return;
5536                }
5537
5538                // If we are turning on the screen after the boot is completed
5539                // normally, don't do so until we have the application and
5540                // wallpaper.
5541                if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
5542                        (wallpaperEnabled && !haveWallpaper))) {
5543                    return;
5544                }
5545            }
5546
5547            mDisplayEnabled = true;
5548            if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
5549            if (false) {
5550                StringWriter sw = new StringWriter();
5551                PrintWriter pw = new PrintWriter(sw);
5552                this.dump(null, pw, null);
5553                Slog.i(TAG, sw.toString());
5554            }
5555            try {
5556                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
5557                if (surfaceFlinger != null) {
5558                    //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
5559                    Parcel data = Parcel.obtain();
5560                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
5561                    surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
5562                                            data, null, 0);
5563                    data.recycle();
5564                }
5565            } catch (RemoteException ex) {
5566                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
5567            }
5568
5569            // Enable input dispatch.
5570            mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
5571        }
5572
5573        mPolicy.enableScreenAfterBoot();
5574
5575        // Make sure the last requested orientation has been applied.
5576        updateRotationUnchecked(false, false);
5577    }
5578
5579    public void showBootMessage(final CharSequence msg, final boolean always) {
5580        boolean first = false;
5581        synchronized(mWindowMap) {
5582            if (DEBUG_BOOT) {
5583                RuntimeException here = new RuntimeException("here");
5584                here.fillInStackTrace();
5585                Slog.i(TAG, "showBootMessage: msg=" + msg + " always=" + always
5586                        + " mAllowBootMessages=" + mAllowBootMessages
5587                        + " mShowingBootMessages=" + mShowingBootMessages
5588                        + " mSystemBooted=" + mSystemBooted, here);
5589            }
5590            if (!mAllowBootMessages) {
5591                return;
5592            }
5593            if (!mShowingBootMessages) {
5594                if (!always) {
5595                    return;
5596                }
5597                first = true;
5598            }
5599            if (mSystemBooted) {
5600                return;
5601            }
5602            mShowingBootMessages = true;
5603            mPolicy.showBootMessage(msg, always);
5604        }
5605        if (first) {
5606            performEnableScreen();
5607        }
5608    }
5609
5610    public void hideBootMessagesLocked() {
5611        if (DEBUG_BOOT) {
5612            RuntimeException here = new RuntimeException("here");
5613            here.fillInStackTrace();
5614            Slog.i(TAG, "hideBootMessagesLocked: mDisplayEnabled=" + mDisplayEnabled
5615                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5616                    + " mShowingBootMessages=" + mShowingBootMessages
5617                    + " mSystemBooted=" + mSystemBooted, here);
5618        }
5619        if (mShowingBootMessages) {
5620            mShowingBootMessages = false;
5621            mPolicy.hideBootMessages();
5622        }
5623    }
5624
5625    public void setInTouchMode(boolean mode) {
5626        synchronized(mWindowMap) {
5627            mInTouchMode = mode;
5628        }
5629    }
5630
5631    // TODO: more accounting of which pid(s) turned it on, keep count,
5632    // only allow disables from pids which have count on, etc.
5633    @Override
5634    public void showStrictModeViolation(boolean on) {
5635        if (mHeadless) return;
5636        mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, 0));
5637    }
5638
5639    private void showStrictModeViolation(int arg) {
5640        final boolean on = arg != 0;
5641        int pid = Binder.getCallingPid();
5642        synchronized(mWindowMap) {
5643            // Ignoring requests to enable the red border from clients
5644            // which aren't on screen.  (e.g. Broadcast Receivers in
5645            // the background..)
5646            if (on) {
5647                boolean isVisible = false;
5648                final AllWindowsIterator iterator = new AllWindowsIterator();
5649                while (iterator.hasNext()) {
5650                    final WindowState ws = iterator.next();
5651                    if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
5652                        isVisible = true;
5653                        break;
5654                    }
5655                }
5656                if (!isVisible) {
5657                    return;
5658                }
5659            }
5660
5661            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5662                    ">>> OPEN TRANSACTION showStrictModeViolation");
5663            Surface.openTransaction();
5664            try {
5665                // TODO(multi-display): support multiple displays
5666                if (mStrictModeFlash == null) {
5667                    mStrictModeFlash = new StrictModeFlash(
5668                            getDefaultDisplayContentLocked().getDisplay(), mFxSession);
5669                }
5670                mStrictModeFlash.setVisibility(on);
5671            } finally {
5672                Surface.closeTransaction();
5673                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5674                        "<<< CLOSE TRANSACTION showStrictModeViolation");
5675            }
5676        }
5677    }
5678
5679    public void setStrictModeVisualIndicatorPreference(String value) {
5680        SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
5681    }
5682
5683    /**
5684     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
5685     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
5686     * of the target image.
5687     *
5688     * @param displayId the Display to take a screenshot of.
5689     * @param width the width of the target bitmap
5690     * @param height the height of the target bitmap
5691     */
5692    public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height) {
5693        if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
5694                "screenshotApplications()")) {
5695            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
5696        }
5697
5698        Bitmap rawss;
5699
5700        int maxLayer = 0;
5701        final Rect frame = new Rect();
5702
5703        float scale;
5704        int dw, dh;
5705        int rot;
5706
5707        synchronized(mWindowMap) {
5708            long ident = Binder.clearCallingIdentity();
5709
5710            final DisplayContent displayContent = getDisplayContentLocked(displayId);
5711            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
5712            dw = displayInfo.logicalWidth;
5713            dh = displayInfo.logicalHeight;
5714
5715            int aboveAppLayer = mPolicy.windowTypeToLayerLw(
5716                    WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER
5717                    + TYPE_LAYER_OFFSET;
5718            aboveAppLayer += TYPE_LAYER_MULTIPLIER;
5719
5720            boolean isImeTarget = mInputMethodTarget != null
5721                    && mInputMethodTarget.mAppToken != null
5722                    && mInputMethodTarget.mAppToken.appToken != null
5723                    && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
5724
5725            // Figure out the part of the screen that is actually the app.
5726            boolean including = false;
5727            final WindowList windows = displayContent.getWindowList();
5728            for (int i = windows.size() - 1; i >= 0; i--) {
5729                WindowState ws = windows.get(i);
5730                if (!ws.mHasSurface) {
5731                    continue;
5732                }
5733                if (ws.mLayer >= aboveAppLayer) {
5734                    continue;
5735                }
5736                // When we will skip windows: when we are not including
5737                // ones behind a window we didn't skip, and we are actually
5738                // taking a screenshot of a specific app.
5739                if (!including && appToken != null) {
5740                    // Also, we can possibly skip this window if it is not
5741                    // an IME target or the application for the screenshot
5742                    // is not the current IME target.
5743                    if (!ws.mIsImWindow || !isImeTarget) {
5744                        // And finally, this window is of no interest if it
5745                        // is not associated with the screenshot app.
5746                        if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
5747                            continue;
5748                        }
5749                    }
5750                }
5751
5752                // We keep on including windows until we go past a full-screen
5753                // window.
5754                including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
5755
5756                if (maxLayer < ws.mWinAnimator.mSurfaceLayer) {
5757                    maxLayer = ws.mWinAnimator.mSurfaceLayer;
5758                }
5759
5760                // Don't include wallpaper in bounds calculation
5761                if (!ws.mIsWallpaper) {
5762                    final Rect wf = ws.mFrame;
5763                    final Rect cr = ws.mContentInsets;
5764                    int left = wf.left + cr.left;
5765                    int top = wf.top + cr.top;
5766                    int right = wf.right - cr.right;
5767                    int bottom = wf.bottom - cr.bottom;
5768                    frame.union(left, top, right, bottom);
5769                }
5770            }
5771            Binder.restoreCallingIdentity(ident);
5772
5773            // Constrain frame to the screen size.
5774            frame.intersect(0, 0, dw, dh);
5775
5776            if (frame.isEmpty() || maxLayer == 0) {
5777                return null;
5778            }
5779
5780            // The screenshot API does not apply the current screen rotation.
5781            rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
5782            int fw = frame.width();
5783            int fh = frame.height();
5784
5785            // Constrain thumbnail to smaller of screen width or height. Assumes aspect
5786            // of thumbnail is the same as the screen (in landscape) or square.
5787            float targetWidthScale = width / (float) fw;
5788            float targetHeightScale = height / (float) fh;
5789            if (dw <= dh) {
5790                scale = targetWidthScale;
5791                // If aspect of thumbnail is the same as the screen (in landscape),
5792                // select the slightly larger value so we fill the entire bitmap
5793                if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
5794                    scale = targetHeightScale;
5795                }
5796            } else {
5797                scale = targetHeightScale;
5798                // If aspect of thumbnail is the same as the screen (in landscape),
5799                // select the slightly larger value so we fill the entire bitmap
5800                if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
5801                    scale = targetWidthScale;
5802                }
5803            }
5804
5805            // The screen shot will contain the entire screen.
5806            dw = (int)(dw*scale);
5807            dh = (int)(dh*scale);
5808            if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
5809                int tmp = dw;
5810                dw = dh;
5811                dh = tmp;
5812                rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
5813            }
5814            if (DEBUG_SCREENSHOT) {
5815                Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from 0 to " + maxLayer);
5816                for (int i = 0; i < windows.size(); i++) {
5817                    WindowState win = windows.get(i);
5818                    Slog.i(TAG, win + ": " + win.mLayer
5819                            + " animLayer=" + win.mWinAnimator.mAnimLayer
5820                            + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
5821                }
5822            }
5823            rawss = Surface.screenshot(dw, dh, 0, maxLayer);
5824        }
5825
5826        if (rawss == null) {
5827            Slog.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh
5828                    + ") to layer " + maxLayer);
5829            return null;
5830        }
5831
5832        Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
5833        Matrix matrix = new Matrix();
5834        ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
5835        matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
5836        Canvas canvas = new Canvas(bm);
5837        canvas.drawBitmap(rawss, matrix, null);
5838        canvas.setBitmap(null);
5839
5840        rawss.recycle();
5841        return bm;
5842    }
5843
5844    /**
5845     * Freeze rotation changes.  (Enable "rotation lock".)
5846     * Persists across reboots.
5847     * @param rotation The desired rotation to freeze to, or -1 to use the
5848     * current rotation.
5849     */
5850    public void freezeRotation(int rotation) {
5851        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5852                "freezeRotation()")) {
5853            throw new SecurityException("Requires SET_ORIENTATION permission");
5854        }
5855        if (rotation < -1 || rotation > Surface.ROTATION_270) {
5856            throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
5857                    + "rotation constant.");
5858        }
5859
5860        if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
5861
5862        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
5863                rotation == -1 ? mRotation : rotation);
5864        updateRotationUnchecked(false, false);
5865    }
5866
5867    /**
5868     * Thaw rotation changes.  (Disable "rotation lock".)
5869     * Persists across reboots.
5870     */
5871    public void thawRotation() {
5872        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5873                "thawRotation()")) {
5874            throw new SecurityException("Requires SET_ORIENTATION permission");
5875        }
5876
5877        if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
5878
5879        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used
5880        updateRotationUnchecked(false, false);
5881    }
5882
5883    /**
5884     * Recalculate the current rotation.
5885     *
5886     * Called by the window manager policy whenever the state of the system changes
5887     * such that the current rotation might need to be updated, such as when the
5888     * device is docked or rotated into a new posture.
5889     */
5890    public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
5891        updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
5892    }
5893
5894    /**
5895     * Temporarily pauses rotation changes until resumed.
5896     *
5897     * This can be used to prevent rotation changes from occurring while the user is
5898     * performing certain operations, such as drag and drop.
5899     *
5900     * This call nests and must be matched by an equal number of calls to {@link #resumeRotation}.
5901     */
5902    void pauseRotationLocked() {
5903        mDeferredRotationPauseCount += 1;
5904    }
5905
5906    /**
5907     * Resumes normal rotation changes after being paused.
5908     */
5909    void resumeRotationLocked() {
5910        if (mDeferredRotationPauseCount > 0) {
5911            mDeferredRotationPauseCount -= 1;
5912            if (mDeferredRotationPauseCount == 0) {
5913                boolean changed = updateRotationUncheckedLocked(false);
5914                if (changed) {
5915                    mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
5916                }
5917            }
5918        }
5919    }
5920
5921    public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
5922        if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked("
5923                   + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")");
5924
5925        long origId = Binder.clearCallingIdentity();
5926        boolean changed;
5927        synchronized(mWindowMap) {
5928            changed = updateRotationUncheckedLocked(false);
5929            if (!changed || forceRelayout) {
5930                getDefaultDisplayContentLocked().layoutNeeded = true;
5931                performLayoutAndPlaceSurfacesLocked();
5932            }
5933        }
5934
5935        if (changed || alwaysSendConfiguration) {
5936            sendNewConfiguration();
5937        }
5938
5939        Binder.restoreCallingIdentity(origId);
5940    }
5941
5942    // TODO(multidisplay): Rotate any display?
5943    /**
5944     * Updates the current rotation.
5945     *
5946     * Returns true if the rotation has been changed.  In this case YOU
5947     * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN.
5948     */
5949    public boolean updateRotationUncheckedLocked(boolean inTransaction) {
5950        if (mDeferredRotationPauseCount > 0) {
5951            // Rotation updates have been paused temporarily.  Defer the update until
5952            // updates have been resumed.
5953            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused.");
5954            return false;
5955        }
5956
5957        ScreenRotationAnimation screenRotationAnimation =
5958                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
5959        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
5960            // Rotation updates cannot be performed while the previous rotation change
5961            // animation is still in progress.  Skip this update.  We will try updating
5962            // again after the animation is finished and the display is unfrozen.
5963            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress.");
5964            return false;
5965        }
5966
5967        if (!mDisplayEnabled) {
5968            // No point choosing a rotation if the display is not enabled.
5969            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled.");
5970            return false;
5971        }
5972
5973        // TODO: Implement forced rotation changes.
5974        //       Set mAltOrientation to indicate that the application is receiving
5975        //       an orientation that has different metrics than it expected.
5976        //       eg. Portrait instead of Landscape.
5977
5978        int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);
5979        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
5980                mForcedAppOrientation, rotation);
5981
5982        if (DEBUG_ORIENTATION) {
5983            Slog.v(TAG, "Application requested orientation "
5984                    + mForcedAppOrientation + ", got rotation " + rotation
5985                    + " which has " + (altOrientation ? "incompatible" : "compatible")
5986                    + " metrics");
5987        }
5988
5989        if (mRotation == rotation && mAltOrientation == altOrientation) {
5990            // No change.
5991            return false;
5992        }
5993
5994        if (DEBUG_ORIENTATION) {
5995            Slog.v(TAG,
5996                "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
5997                + " from " + mRotation + (mAltOrientation ? " (alt)" : "")
5998                + ", forceApp=" + mForcedAppOrientation);
5999        }
6000
6001        mRotation = rotation;
6002        mAltOrientation = altOrientation;
6003        mPolicy.setRotationLw(mRotation);
6004
6005        mWindowsFreezingScreen = true;
6006        mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
6007        mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT), 2000);
6008        mWaitingForConfig = true;
6009        getDefaultDisplayContentLocked().layoutNeeded = true;
6010        startFreezingDisplayLocked(inTransaction, 0, 0);
6011        // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
6012        screenRotationAnimation =
6013                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
6014
6015        // We need to update our screen size information to match the new
6016        // rotation.  Note that this is redundant with the later call to
6017        // sendNewConfiguration() that must be called after this function
6018        // returns...  however we need to do the screen size part of that
6019        // before then so we have the correct size to use when initializing
6020        // the rotation animation for the new rotation.
6021        computeScreenConfigurationLocked(null);
6022
6023        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6024        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
6025        if (!inTransaction) {
6026            if (SHOW_TRANSACTIONS) {
6027                Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");
6028            }
6029            Surface.openTransaction();
6030        }
6031        try {
6032            // NOTE: We disable the rotation in the emulator because
6033            //       it doesn't support hardware OpenGL emulation yet.
6034            if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
6035                    && screenRotationAnimation.hasScreenshot()) {
6036                if (screenRotationAnimation.setRotationInTransaction(
6037                        rotation, mFxSession,
6038                        MAX_ANIMATION_DURATION, mTransitionAnimationScale,
6039                        displayInfo.logicalWidth, displayInfo.logicalHeight)) {
6040                    updateLayoutToAnimationLocked();
6041                }
6042            }
6043
6044            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
6045        } finally {
6046            if (!inTransaction) {
6047                Surface.closeTransaction();
6048                if (SHOW_LIGHT_TRANSACTIONS) {
6049                    Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");
6050                }
6051            }
6052        }
6053
6054        final WindowList windows = displayContent.getWindowList();
6055        for (int i = windows.size() - 1; i >= 0; i--) {
6056            WindowState w = windows.get(i);
6057            if (w.mHasSurface) {
6058                if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
6059                w.mOrientationChanging = true;
6060                mInnerFields.mOrientationChangeComplete = false;
6061            }
6062        }
6063
6064        for (int i=mRotationWatchers.size()-1; i>=0; i--) {
6065            try {
6066                mRotationWatchers.get(i).onRotationChanged(rotation);
6067            } catch (RemoteException e) {
6068            }
6069        }
6070
6071        scheduleNotifyRotationChangedIfNeededLocked(displayContent, rotation);
6072
6073        return true;
6074    }
6075
6076    public int getRotation() {
6077        return mRotation;
6078    }
6079
6080    public int watchRotation(IRotationWatcher watcher) {
6081        final IBinder watcherBinder = watcher.asBinder();
6082        IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
6083            public void binderDied() {
6084                synchronized (mWindowMap) {
6085                    for (int i=0; i<mRotationWatchers.size(); i++) {
6086                        if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
6087                            IRotationWatcher removed = mRotationWatchers.remove(i);
6088                            if (removed != null) {
6089                                removed.asBinder().unlinkToDeath(this, 0);
6090                            }
6091                            i--;
6092                        }
6093                    }
6094                }
6095            }
6096        };
6097
6098        synchronized (mWindowMap) {
6099            try {
6100                watcher.asBinder().linkToDeath(dr, 0);
6101                mRotationWatchers.add(watcher);
6102            } catch (RemoteException e) {
6103                // Client died, no cleanup needed.
6104            }
6105
6106            return mRotation;
6107        }
6108    }
6109
6110    /**
6111     * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
6112     * theme attribute) on devices that feature a physical options menu key attempt to position
6113     * their menu panel window along the edge of the screen nearest the physical menu key.
6114     * This lowers the travel distance between invoking the menu panel and selecting
6115     * a menu option.
6116     *
6117     * This method helps control where that menu is placed. Its current implementation makes
6118     * assumptions about the menu key and its relationship to the screen based on whether
6119     * the device's natural orientation is portrait (width < height) or landscape.
6120     *
6121     * The menu key is assumed to be located along the bottom edge of natural-portrait
6122     * devices and along the right edge of natural-landscape devices. If these assumptions
6123     * do not hold for the target device, this method should be changed to reflect that.
6124     *
6125     * @return A {@link Gravity} value for placing the options menu window
6126     */
6127    public int getPreferredOptionsPanelGravity() {
6128        synchronized (mWindowMap) {
6129            final int rotation = getRotation();
6130
6131            // TODO(multidisplay): Assume that such devices physical keys are on the main screen.
6132            final DisplayContent displayContent = getDefaultDisplayContentLocked();
6133            if (displayContent.mInitialDisplayWidth < displayContent.mInitialDisplayHeight) {
6134                // On devices with a natural orientation of portrait
6135                switch (rotation) {
6136                    default:
6137                    case Surface.ROTATION_0:
6138                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6139                    case Surface.ROTATION_90:
6140                        return Gravity.RIGHT | Gravity.BOTTOM;
6141                    case Surface.ROTATION_180:
6142                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6143                    case Surface.ROTATION_270:
6144                        return Gravity.START | Gravity.BOTTOM;
6145                }
6146            } else {
6147                // On devices with a natural orientation of landscape
6148                switch (rotation) {
6149                    default:
6150                    case Surface.ROTATION_0:
6151                        return Gravity.RIGHT | Gravity.BOTTOM;
6152                    case Surface.ROTATION_90:
6153                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6154                    case Surface.ROTATION_180:
6155                        return Gravity.START | Gravity.BOTTOM;
6156                    case Surface.ROTATION_270:
6157                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6158                }
6159            }
6160        }
6161    }
6162
6163    /**
6164     * Starts the view server on the specified port.
6165     *
6166     * @param port The port to listener to.
6167     *
6168     * @return True if the server was successfully started, false otherwise.
6169     *
6170     * @see com.android.server.wm.ViewServer
6171     * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
6172     */
6173    public boolean startViewServer(int port) {
6174        if (isSystemSecure()) {
6175            return false;
6176        }
6177
6178        if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
6179            return false;
6180        }
6181
6182        if (port < 1024) {
6183            return false;
6184        }
6185
6186        if (mViewServer != null) {
6187            if (!mViewServer.isRunning()) {
6188                try {
6189                    return mViewServer.start();
6190                } catch (IOException e) {
6191                    Slog.w(TAG, "View server did not start");
6192                }
6193            }
6194            return false;
6195        }
6196
6197        try {
6198            mViewServer = new ViewServer(this, port);
6199            return mViewServer.start();
6200        } catch (IOException e) {
6201            Slog.w(TAG, "View server did not start");
6202        }
6203        return false;
6204    }
6205
6206    private boolean isSystemSecure() {
6207        return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
6208                "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
6209    }
6210
6211    /**
6212     * Stops the view server if it exists.
6213     *
6214     * @return True if the server stopped, false if it wasn't started or
6215     *         couldn't be stopped.
6216     *
6217     * @see com.android.server.wm.ViewServer
6218     */
6219    public boolean stopViewServer() {
6220        if (isSystemSecure()) {
6221            return false;
6222        }
6223
6224        if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
6225            return false;
6226        }
6227
6228        if (mViewServer != null) {
6229            return mViewServer.stop();
6230        }
6231        return false;
6232    }
6233
6234    /**
6235     * Indicates whether the view server is running.
6236     *
6237     * @return True if the server is running, false otherwise.
6238     *
6239     * @see com.android.server.wm.ViewServer
6240     */
6241    public boolean isViewServerRunning() {
6242        if (isSystemSecure()) {
6243            return false;
6244        }
6245
6246        if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
6247            return false;
6248        }
6249
6250        return mViewServer != null && mViewServer.isRunning();
6251    }
6252
6253    /**
6254     * Lists all availble windows in the system. The listing is written in the
6255     * specified Socket's output stream with the following syntax:
6256     * windowHashCodeInHexadecimal windowName
6257     * Each line of the ouput represents a different window.
6258     *
6259     * @param client The remote client to send the listing to.
6260     * @return False if an error occured, true otherwise.
6261     */
6262    boolean viewServerListWindows(Socket client) {
6263        if (isSystemSecure()) {
6264            return false;
6265        }
6266
6267        boolean result = true;
6268
6269        WindowList windows = new WindowList();
6270        synchronized (mWindowMap) {
6271            //noinspection unchecked
6272            DisplayContentsIterator iterator = new DisplayContentsIterator();
6273            while(iterator.hasNext()) {
6274                windows.addAll(iterator.next().getWindowList());
6275            }
6276        }
6277
6278        BufferedWriter out = null;
6279
6280        // Any uncaught exception will crash the system process
6281        try {
6282            OutputStream clientStream = client.getOutputStream();
6283            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
6284
6285            final int count = windows.size();
6286            for (int i = 0; i < count; i++) {
6287                final WindowState w = windows.get(i);
6288                out.write(Integer.toHexString(System.identityHashCode(w)));
6289                out.write(' ');
6290                out.append(w.mAttrs.getTitle());
6291                out.write('\n');
6292            }
6293
6294            out.write("DONE.\n");
6295            out.flush();
6296        } catch (Exception e) {
6297            result = false;
6298        } finally {
6299            if (out != null) {
6300                try {
6301                    out.close();
6302                } catch (IOException e) {
6303                    result = false;
6304                }
6305            }
6306        }
6307
6308        return result;
6309    }
6310
6311    // TODO(multidisplay): Extend to multiple displays.
6312    /**
6313     * Returns the focused window in the following format:
6314     * windowHashCodeInHexadecimal windowName
6315     *
6316     * @param client The remote client to send the listing to.
6317     * @return False if an error occurred, true otherwise.
6318     */
6319    boolean viewServerGetFocusedWindow(Socket client) {
6320        if (isSystemSecure()) {
6321            return false;
6322        }
6323
6324        boolean result = true;
6325
6326        WindowState focusedWindow = getFocusedWindow();
6327
6328        BufferedWriter out = null;
6329
6330        // Any uncaught exception will crash the system process
6331        try {
6332            OutputStream clientStream = client.getOutputStream();
6333            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
6334
6335            if(focusedWindow != null) {
6336                out.write(Integer.toHexString(System.identityHashCode(focusedWindow)));
6337                out.write(' ');
6338                out.append(focusedWindow.mAttrs.getTitle());
6339            }
6340            out.write('\n');
6341            out.flush();
6342        } catch (Exception e) {
6343            result = false;
6344        } finally {
6345            if (out != null) {
6346                try {
6347                    out.close();
6348                } catch (IOException e) {
6349                    result = false;
6350                }
6351            }
6352        }
6353
6354        return result;
6355    }
6356
6357    /**
6358     * Sends a command to a target window. The result of the command, if any, will be
6359     * written in the output stream of the specified socket.
6360     *
6361     * The parameters must follow this syntax:
6362     * windowHashcode extra
6363     *
6364     * Where XX is the length in characeters of the windowTitle.
6365     *
6366     * The first parameter is the target window. The window with the specified hashcode
6367     * will be the target. If no target can be found, nothing happens. The extra parameters
6368     * will be delivered to the target window and as parameters to the command itself.
6369     *
6370     * @param client The remote client to sent the result, if any, to.
6371     * @param command The command to execute.
6372     * @param parameters The command parameters.
6373     *
6374     * @return True if the command was successfully delivered, false otherwise. This does
6375     *         not indicate whether the command itself was successful.
6376     */
6377    boolean viewServerWindowCommand(Socket client, String command, String parameters) {
6378        if (isSystemSecure()) {
6379            return false;
6380        }
6381
6382        boolean success = true;
6383        Parcel data = null;
6384        Parcel reply = null;
6385
6386        BufferedWriter out = null;
6387
6388        // Any uncaught exception will crash the system process
6389        try {
6390            // Find the hashcode of the window
6391            int index = parameters.indexOf(' ');
6392            if (index == -1) {
6393                index = parameters.length();
6394            }
6395            final String code = parameters.substring(0, index);
6396            int hashCode = (int) Long.parseLong(code, 16);
6397
6398            // Extract the command's parameter after the window description
6399            if (index < parameters.length()) {
6400                parameters = parameters.substring(index + 1);
6401            } else {
6402                parameters = "";
6403            }
6404
6405            final WindowState window = findWindow(hashCode);
6406            if (window == null) {
6407                return false;
6408            }
6409
6410            data = Parcel.obtain();
6411            data.writeInterfaceToken("android.view.IWindow");
6412            data.writeString(command);
6413            data.writeString(parameters);
6414            data.writeInt(1);
6415            ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
6416
6417            reply = Parcel.obtain();
6418
6419            final IBinder binder = window.mClient.asBinder();
6420            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
6421            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
6422
6423            reply.readException();
6424
6425            if (!client.isOutputShutdown()) {
6426                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
6427                out.write("DONE\n");
6428                out.flush();
6429            }
6430
6431        } catch (Exception e) {
6432            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
6433            success = false;
6434        } finally {
6435            if (data != null) {
6436                data.recycle();
6437            }
6438            if (reply != null) {
6439                reply.recycle();
6440            }
6441            if (out != null) {
6442                try {
6443                    out.close();
6444                } catch (IOException e) {
6445
6446                }
6447            }
6448        }
6449
6450        return success;
6451    }
6452
6453    public void addDisplayContentChangeListener(int displayId,
6454            IDisplayContentChangeListener listener) {
6455        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
6456                "addDisplayContentChangeListener()")) {
6457            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission");
6458        }
6459        synchronized(mWindowMap) {
6460            DisplayContent displayContent = getDisplayContentLocked(displayId);
6461            if (displayContent.mDisplayContentChangeListeners == null) {
6462                displayContent.mDisplayContentChangeListeners =
6463                        new RemoteCallbackList<IDisplayContentChangeListener>();
6464            displayContent.mDisplayContentChangeListeners.register(listener);
6465            }
6466        }
6467    }
6468
6469    public void removeDisplayContentChangeListener(int displayId,
6470            IDisplayContentChangeListener listener) {
6471        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
6472                "removeDisplayContentChangeListener()")) {
6473            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission");
6474        }
6475        synchronized(mWindowMap) {
6476            DisplayContent displayContent = getDisplayContentLocked(displayId);
6477            if (displayContent.mDisplayContentChangeListeners != null) {
6478                displayContent.mDisplayContentChangeListeners.unregister(listener);
6479                if (displayContent.mDisplayContentChangeListeners
6480                        .getRegisteredCallbackCount() == 0) {
6481                    displayContent.mDisplayContentChangeListeners = null;
6482                }
6483            }
6484        }
6485    }
6486
6487    void scheduleNotifyWindowTranstionIfNeededLocked(WindowState window, int transition) {
6488        DisplayContent displayContent = window.mDisplayContent;
6489        if (displayContent.mDisplayContentChangeListeners != null) {
6490            WindowInfo info = getWindowInfoForWindowStateLocked(window);
6491            mH.obtainMessage(H.NOTIFY_WINDOW_TRANSITION, transition, 0, info).sendToTarget();
6492        }
6493    }
6494
6495    private void handleNotifyWindowTranstion(int transition, WindowInfo info) {
6496        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
6497        synchronized (mWindowMap) {
6498            DisplayContent displayContent = getDisplayContentLocked(info.displayId);
6499            if (displayContent == null) {
6500                return;
6501            }
6502            callbacks = displayContent.mDisplayContentChangeListeners;
6503            if (callbacks == null) {
6504                return;
6505            }
6506        }
6507        final int callbackCount = callbacks.beginBroadcast();
6508        try {
6509            for (int i = 0; i < callbackCount; i++) {
6510                try {
6511                    callbacks.getBroadcastItem(i).onWindowTransition(info.displayId,
6512                            transition, info);
6513                } catch (RemoteException re) {
6514                    /* ignore */
6515                }
6516            }
6517        } finally {
6518            callbacks.finishBroadcast();
6519        }
6520    }
6521
6522    private void scheduleNotifyRotationChangedIfNeededLocked(DisplayContent displayContent,
6523            int rotation) {
6524        if (displayContent.mDisplayContentChangeListeners != null
6525                && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) {
6526            mH.obtainMessage(H.NOTIFY_ROTATION_CHANGED, displayContent.getDisplayId(),
6527                    rotation).sendToTarget();
6528        }
6529    }
6530
6531    private void handleNotifyRotationChanged(int displayId, int rotation) {
6532        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
6533        synchronized (mWindowMap) {
6534            DisplayContent displayContent = getDisplayContentLocked(displayId);
6535            if (displayContent == null) {
6536                return;
6537            }
6538            callbacks = displayContent.mDisplayContentChangeListeners;
6539            if (callbacks == null) {
6540                return;
6541            }
6542        }
6543        try {
6544            final int watcherCount = callbacks.beginBroadcast();
6545            for (int i = 0; i < watcherCount; i++) {
6546                try {
6547                    callbacks.getBroadcastItem(i).onRotationChanged(rotation);
6548                } catch (RemoteException re) {
6549                    /* ignore */
6550                }
6551            }
6552        } finally {
6553            callbacks.finishBroadcast();
6554        }
6555    }
6556
6557    public void addWindowChangeListener(WindowChangeListener listener) {
6558        synchronized(mWindowMap) {
6559            mWindowChangeListeners.add(listener);
6560        }
6561    }
6562
6563    public void removeWindowChangeListener(WindowChangeListener listener) {
6564        synchronized(mWindowMap) {
6565            mWindowChangeListeners.remove(listener);
6566        }
6567    }
6568
6569    private void notifyWindowsChanged() {
6570        WindowChangeListener[] windowChangeListeners;
6571        synchronized(mWindowMap) {
6572            if(mWindowChangeListeners.isEmpty()) {
6573                return;
6574            }
6575            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6576            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6577        }
6578        int N = windowChangeListeners.length;
6579        for(int i = 0; i < N; i++) {
6580            windowChangeListeners[i].windowsChanged();
6581        }
6582    }
6583
6584    private void notifyFocusChanged() {
6585        WindowChangeListener[] windowChangeListeners;
6586        synchronized(mWindowMap) {
6587            if(mWindowChangeListeners.isEmpty()) {
6588                return;
6589            }
6590            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6591            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6592        }
6593        int N = windowChangeListeners.length;
6594        for(int i = 0; i < N; i++) {
6595            windowChangeListeners[i].focusChanged();
6596        }
6597    }
6598
6599    private WindowState findWindow(int hashCode) {
6600        if (hashCode == -1) {
6601            // TODO(multidisplay): Extend to multiple displays.
6602            return getFocusedWindow();
6603        }
6604
6605        synchronized (mWindowMap) {
6606            final AllWindowsIterator iterator = new AllWindowsIterator();
6607            while (iterator.hasNext()) {
6608                final WindowState w = iterator.next();
6609                if (System.identityHashCode(w) == hashCode) {
6610                    return w;
6611                }
6612            }
6613        }
6614
6615        return null;
6616    }
6617
6618    /*
6619     * Instruct the Activity Manager to fetch the current configuration and broadcast
6620     * that to config-changed listeners if appropriate.
6621     */
6622    void sendNewConfiguration() {
6623        try {
6624            mActivityManager.updateConfiguration(null);
6625        } catch (RemoteException e) {
6626        }
6627    }
6628
6629    public Configuration computeNewConfiguration() {
6630        synchronized (mWindowMap) {
6631            Configuration config = computeNewConfigurationLocked();
6632            if (config == null && mWaitingForConfig) {
6633                // Nothing changed but we are waiting for something... stop that!
6634                mWaitingForConfig = false;
6635                performLayoutAndPlaceSurfacesLocked();
6636            }
6637            return config;
6638        }
6639    }
6640
6641    Configuration computeNewConfigurationLocked() {
6642        Configuration config = new Configuration();
6643        config.fontScale = 0;
6644        if (!computeScreenConfigurationLocked(config)) {
6645            return null;
6646        }
6647        return config;
6648    }
6649
6650    private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) {
6651        // TODO: Multidisplay: for now only use with default display.
6652        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
6653        if (width < displayInfo.smallestNominalAppWidth) {
6654            displayInfo.smallestNominalAppWidth = width;
6655        }
6656        if (width > displayInfo.largestNominalAppWidth) {
6657            displayInfo.largestNominalAppWidth = width;
6658        }
6659        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation);
6660        if (height < displayInfo.smallestNominalAppHeight) {
6661            displayInfo.smallestNominalAppHeight = height;
6662        }
6663        if (height > displayInfo.largestNominalAppHeight) {
6664            displayInfo.largestNominalAppHeight = height;
6665        }
6666    }
6667
6668    private int reduceConfigLayout(int curLayout, int rotation, float density,
6669            int dw, int dh) {
6670        // TODO: Multidisplay: for now only use with default display.
6671        // Get the app screen size at this rotation.
6672        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6673        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6674
6675        // Compute the screen layout size class for this rotation.
6676        int screenLayoutSize;
6677        boolean screenLayoutLong;
6678        boolean screenLayoutCompatNeeded;
6679        int longSize = w;
6680        int shortSize = h;
6681        if (longSize < shortSize) {
6682            int tmp = longSize;
6683            longSize = shortSize;
6684            shortSize = tmp;
6685        }
6686        longSize = (int)(longSize/density);
6687        shortSize = (int)(shortSize/density);
6688
6689        // These semi-magic numbers define our compatibility modes for
6690        // applications with different screens.  These are guarantees to
6691        // app developers about the space they can expect for a particular
6692        // configuration.  DO NOT CHANGE!
6693        if (longSize < 470) {
6694            // This is shorter than an HVGA normal density screen (which
6695            // is 480 pixels on its long side).
6696            screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_SMALL;
6697            screenLayoutLong = false;
6698            screenLayoutCompatNeeded = false;
6699        } else {
6700            // What size is this screen screen?
6701            if (longSize >= 960 && shortSize >= 720) {
6702                // 1.5xVGA or larger screens at medium density are the point
6703                // at which we consider it to be an extra large screen.
6704                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_XLARGE;
6705            } else if (longSize >= 640 && shortSize >= 480) {
6706                // VGA or larger screens at medium density are the point
6707                // at which we consider it to be a large screen.
6708                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_LARGE;
6709            } else {
6710                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_NORMAL;
6711            }
6712
6713            // If this screen is wider than normal HVGA, or taller
6714            // than FWVGA, then for old apps we want to run in size
6715            // compatibility mode.
6716            if (shortSize > 321 || longSize > 570) {
6717                screenLayoutCompatNeeded = true;
6718            } else {
6719                screenLayoutCompatNeeded = false;
6720            }
6721
6722            // Is this a long screen?
6723            if (((longSize*3)/5) >= (shortSize-1)) {
6724                // Anything wider than WVGA (5:3) is considering to be long.
6725                screenLayoutLong = true;
6726            } else {
6727                screenLayoutLong = false;
6728            }
6729        }
6730
6731        // Now reduce the last screenLayout to not be better than what we
6732        // have found.
6733        if (!screenLayoutLong) {
6734            curLayout = (curLayout&~Configuration.SCREENLAYOUT_LONG_MASK)
6735                    | Configuration.SCREENLAYOUT_LONG_NO;
6736        }
6737        if (screenLayoutCompatNeeded) {
6738            curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
6739        }
6740        int curSize = curLayout&Configuration.SCREENLAYOUT_SIZE_MASK;
6741        if (screenLayoutSize < curSize) {
6742            curLayout = (curLayout&~Configuration.SCREENLAYOUT_SIZE_MASK)
6743                    | screenLayoutSize;
6744        }
6745        return curLayout;
6746    }
6747
6748    private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
6749                  int dw, int dh, float density, Configuration outConfig) {
6750        // TODO: Multidisplay: for now only use with default display.
6751
6752        // We need to determine the smallest width that will occur under normal
6753        // operation.  To this, start with the base screen size and compute the
6754        // width under the different possible rotations.  We need to un-rotate
6755        // the current screen dimensions before doing this.
6756        int unrotDw, unrotDh;
6757        if (rotated) {
6758            unrotDw = dh;
6759            unrotDh = dw;
6760        } else {
6761            unrotDw = dw;
6762            unrotDh = dh;
6763        }
6764        displayInfo.smallestNominalAppWidth = 1<<30;
6765        displayInfo.smallestNominalAppHeight = 1<<30;
6766        displayInfo.largestNominalAppWidth = 0;
6767        displayInfo.largestNominalAppHeight = 0;
6768        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh);
6769        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw);
6770        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh);
6771        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw);
6772        int sl = Configuration.SCREENLAYOUT_SIZE_XLARGE
6773                | Configuration.SCREENLAYOUT_LONG_YES;
6774        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
6775        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
6776        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
6777        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
6778        outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
6779        outConfig.screenLayout =
6780                sl|(outConfig.screenLayout&Configuration.SCREENLAYOUT_LAYOUTDIR_MASK);
6781    }
6782
6783    private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
6784            int dw, int dh) {
6785        // TODO: Multidisplay: for now only use with default display.
6786        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6787        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6788        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
6789        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
6790        if (curSize == 0 || size < curSize) {
6791            curSize = size;
6792        }
6793        return curSize;
6794    }
6795
6796    private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
6797        // TODO: Multidisplay: for now only use with default display.
6798        mTmpDisplayMetrics.setTo(dm);
6799        final DisplayMetrics tmpDm = mTmpDisplayMetrics;
6800        final int unrotDw, unrotDh;
6801        if (rotated) {
6802            unrotDw = dh;
6803            unrotDh = dw;
6804        } else {
6805            unrotDw = dw;
6806            unrotDh = dh;
6807        }
6808        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh);
6809        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw);
6810        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh);
6811        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw);
6812        return sw;
6813    }
6814
6815    boolean computeScreenConfigurationLocked(Configuration config) {
6816        if (!mDisplayReady) {
6817            return false;
6818        }
6819
6820        // TODO(multidisplay): For now, apply Configuration to main screen only.
6821        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6822
6823        // Use the effective "visual" dimensions based on current rotation
6824        final boolean rotated = (mRotation == Surface.ROTATION_90
6825                || mRotation == Surface.ROTATION_270);
6826        final int realdw = rotated ?
6827                displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
6828        final int realdh = rotated ?
6829                displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
6830        int dw = realdw;
6831        int dh = realdh;
6832
6833        if (mAltOrientation) {
6834            if (realdw > realdh) {
6835                // Turn landscape into portrait.
6836                int maxw = (int)(realdh/1.3f);
6837                if (maxw < realdw) {
6838                    dw = maxw;
6839                }
6840            } else {
6841                // Turn portrait into landscape.
6842                int maxh = (int)(realdw/1.3f);
6843                if (maxh < realdh) {
6844                    dh = maxh;
6845                }
6846            }
6847        }
6848
6849        if (config != null) {
6850            config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
6851                    Configuration.ORIENTATION_LANDSCAPE;
6852        }
6853
6854        // Update application display metrics.
6855        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
6856        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
6857        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
6858        synchronized(displayContent.mDisplaySizeLock) {
6859            displayInfo.rotation = mRotation;
6860            displayInfo.logicalWidth = dw;
6861            displayInfo.logicalHeight = dh;
6862            displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
6863            displayInfo.appWidth = appWidth;
6864            displayInfo.appHeight = appHeight;
6865            displayInfo.getLogicalMetrics(mRealDisplayMetrics, null);
6866            displayInfo.getAppMetrics(mDisplayMetrics, null);
6867            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
6868                    displayContent.getDisplayId(), displayInfo);
6869
6870            mAnimator.setDisplayDimensions(dw, dh, appWidth, appHeight);
6871        }
6872        if (false) {
6873            Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);
6874        }
6875
6876        final DisplayMetrics dm = mDisplayMetrics;
6877        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
6878                mCompatDisplayMetrics);
6879
6880        if (config != null) {
6881            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
6882                    / dm.density);
6883            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
6884                    / dm.density);
6885            computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);
6886
6887            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
6888            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
6889            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
6890            config.densityDpi = displayContent.mBaseDisplayDensity;
6891
6892            // Update the configuration based on available input devices, lid switch,
6893            // and platform configuration.
6894            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6895            config.keyboard = Configuration.KEYBOARD_NOKEYS;
6896            config.navigation = Configuration.NAVIGATION_NONAV;
6897
6898            int keyboardPresence = 0;
6899            int navigationPresence = 0;
6900            final InputDevice[] devices = mInputManager.getInputDevices();
6901            final int len = devices.length;
6902            for (int i = 0; i < len; i++) {
6903                InputDevice device = devices[i];
6904                if (!device.isVirtual()) {
6905                    final int sources = device.getSources();
6906                    final int presenceFlag = device.isExternal() ?
6907                            WindowManagerPolicy.PRESENCE_EXTERNAL :
6908                                    WindowManagerPolicy.PRESENCE_INTERNAL;
6909
6910                    if (mIsTouchDevice) {
6911                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
6912                                InputDevice.SOURCE_TOUCHSCREEN) {
6913                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
6914                        }
6915                    } else {
6916                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6917                    }
6918
6919                    if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
6920                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
6921                        navigationPresence |= presenceFlag;
6922                    } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
6923                            && config.navigation == Configuration.NAVIGATION_NONAV) {
6924                        config.navigation = Configuration.NAVIGATION_DPAD;
6925                        navigationPresence |= presenceFlag;
6926                    }
6927
6928                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
6929                        config.keyboard = Configuration.KEYBOARD_QWERTY;
6930                        keyboardPresence |= presenceFlag;
6931                    }
6932                }
6933            }
6934
6935            // Determine whether a hard keyboard is available and enabled.
6936            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6937            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6938                mHardKeyboardAvailable = hardKeyboardAvailable;
6939                mHardKeyboardEnabled = hardKeyboardAvailable;
6940                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6941                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6942            }
6943            if (!mHardKeyboardEnabled) {
6944                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6945            }
6946
6947            // Let the policy update hidden states.
6948            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6949            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6950            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6951            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
6952        }
6953
6954        return true;
6955    }
6956
6957    public boolean isHardKeyboardAvailable() {
6958        synchronized (mWindowMap) {
6959            return mHardKeyboardAvailable;
6960        }
6961    }
6962
6963    public boolean isHardKeyboardEnabled() {
6964        synchronized (mWindowMap) {
6965            return mHardKeyboardEnabled;
6966        }
6967    }
6968
6969    public void setHardKeyboardEnabled(boolean enabled) {
6970        synchronized (mWindowMap) {
6971            if (mHardKeyboardEnabled != enabled) {
6972                mHardKeyboardEnabled = enabled;
6973                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6974            }
6975        }
6976    }
6977
6978    public void setOnHardKeyboardStatusChangeListener(
6979            OnHardKeyboardStatusChangeListener listener) {
6980        synchronized (mWindowMap) {
6981            mHardKeyboardStatusChangeListener = listener;
6982        }
6983    }
6984
6985    void notifyHardKeyboardStatusChange() {
6986        final boolean available, enabled;
6987        final OnHardKeyboardStatusChangeListener listener;
6988        synchronized (mWindowMap) {
6989            listener = mHardKeyboardStatusChangeListener;
6990            available = mHardKeyboardAvailable;
6991            enabled = mHardKeyboardEnabled;
6992        }
6993        if (listener != null) {
6994            listener.onHardKeyboardStatusChange(available, enabled);
6995        }
6996    }
6997
6998    // -------------------------------------------------------------
6999    // Drag and drop
7000    // -------------------------------------------------------------
7001
7002    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
7003            int flags, int width, int height, Surface outSurface) {
7004        if (DEBUG_DRAG) {
7005            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
7006                    + " flags=" + Integer.toHexString(flags) + " win=" + window
7007                    + " asbinder=" + window.asBinder());
7008        }
7009
7010        final int callerPid = Binder.getCallingPid();
7011        final long origId = Binder.clearCallingIdentity();
7012        IBinder token = null;
7013
7014        try {
7015            synchronized (mWindowMap) {
7016                try {
7017                    if (mDragState == null) {
7018                        // TODO(multi-display): support other displays
7019                        final DisplayContent displayContent = getDefaultDisplayContentLocked();
7020                        final Display display = displayContent.getDisplay();
7021                        Surface surface = new Surface(session, "drag surface",
7022                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
7023                        surface.setLayerStack(display.getLayerStack());
7024                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
7025                                + surface + ": CREATE");
7026                        outSurface.copyFrom(surface);
7027                        final IBinder winBinder = window.asBinder();
7028                        token = new Binder();
7029                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
7030                        token = mDragState.mToken = new Binder();
7031
7032                        // 5 second timeout for this window to actually begin the drag
7033                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
7034                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
7035                        mH.sendMessageDelayed(msg, 5000);
7036                    } else {
7037                        Slog.w(TAG, "Drag already in progress");
7038                    }
7039                } catch (Surface.OutOfResourcesException e) {
7040                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
7041                    if (mDragState != null) {
7042                        mDragState.reset();
7043                        mDragState = null;
7044                    }
7045                }
7046            }
7047        } finally {
7048            Binder.restoreCallingIdentity(origId);
7049        }
7050
7051        return token;
7052    }
7053
7054    // -------------------------------------------------------------
7055    // Input Events and Focus Management
7056    // -------------------------------------------------------------
7057
7058    final InputMonitor mInputMonitor = new InputMonitor(this);
7059    private boolean mEventDispatchingEnabled;
7060
7061    public void pauseKeyDispatching(IBinder _token) {
7062        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7063                "pauseKeyDispatching()")) {
7064            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7065        }
7066
7067        synchronized (mWindowMap) {
7068            WindowToken token = mTokenMap.get(_token);
7069            if (token != null) {
7070                mInputMonitor.pauseDispatchingLw(token);
7071            }
7072        }
7073    }
7074
7075    public void resumeKeyDispatching(IBinder _token) {
7076        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7077                "resumeKeyDispatching()")) {
7078            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7079        }
7080
7081        synchronized (mWindowMap) {
7082            WindowToken token = mTokenMap.get(_token);
7083            if (token != null) {
7084                mInputMonitor.resumeDispatchingLw(token);
7085            }
7086        }
7087    }
7088
7089    public void setEventDispatching(boolean enabled) {
7090        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7091                "setEventDispatching()")) {
7092            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7093        }
7094
7095        synchronized (mWindowMap) {
7096            mEventDispatchingEnabled = enabled;
7097            if (mDisplayEnabled) {
7098                mInputMonitor.setEventDispatchingLw(enabled);
7099            }
7100            sendScreenStatusToClientsLocked();
7101        }
7102    }
7103
7104    public IBinder getFocusedWindowToken() {
7105        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
7106                "getFocusedWindowToken()")) {
7107            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
7108        }
7109        synchronized (mWindowMap) {
7110            WindowState windowState = getFocusedWindowLocked();
7111            if (windowState != null) {
7112                return windowState.mClient.asBinder();
7113            }
7114            return null;
7115        }
7116    }
7117
7118    private WindowState getFocusedWindow() {
7119        synchronized (mWindowMap) {
7120            return getFocusedWindowLocked();
7121        }
7122    }
7123
7124    private WindowState getFocusedWindowLocked() {
7125        return mCurrentFocus;
7126    }
7127
7128    public boolean detectSafeMode() {
7129        if (!mInputMonitor.waitForInputDevicesReady(
7130                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
7131            Slog.w(TAG, "Devices still not ready after waiting "
7132                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
7133                   + " milliseconds before attempting to detect safe mode.");
7134        }
7135
7136        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
7137                KeyEvent.KEYCODE_MENU);
7138        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
7139        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
7140                KeyEvent.KEYCODE_DPAD_CENTER);
7141        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
7142                InputManagerService.BTN_MOUSE);
7143        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
7144                KeyEvent.KEYCODE_VOLUME_DOWN);
7145        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
7146                || volumeDownState > 0;
7147        try {
7148            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
7149                mSafeMode = true;
7150                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
7151            }
7152        } catch (IllegalArgumentException e) {
7153        }
7154        if (mSafeMode) {
7155            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
7156                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
7157        } else {
7158            Log.i(TAG, "SAFE MODE not enabled");
7159        }
7160        mPolicy.setSafeMode(mSafeMode);
7161        return mSafeMode;
7162    }
7163
7164    public void displayReady() {
7165        displayReady(Display.DEFAULT_DISPLAY);
7166
7167        synchronized(mWindowMap) {
7168            final DisplayContent displayContent = getDefaultDisplayContentLocked();
7169            final Display display = displayContent.getDisplay();
7170            readForcedDisplaySizeAndDensityLocked(displayContent);
7171
7172            mDisplayReady = true;
7173            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
7174                    PackageManager.FEATURE_TOUCHSCREEN);
7175
7176            final DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
7177            mAnimator.setDisplayDimensions(
7178                    displayInfo.logicalWidth, displayInfo.logicalHeight,
7179                    displayInfo.appWidth, displayInfo.appHeight);
7180
7181            mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
7182                    displayContent.mInitialDisplayWidth,
7183                    displayContent.mInitialDisplayHeight,
7184                    displayContent.mInitialDisplayDensity);
7185        }
7186
7187        try {
7188            mActivityManager.updateConfiguration(null);
7189        } catch (RemoteException e) {
7190        }
7191    }
7192
7193    public void displayReady(int displayId) {
7194        synchronized(mWindowMap) {
7195            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7196            final DisplayInfo displayInfo;
7197            mAnimator.addDisplayLocked(displayId);
7198            synchronized(displayContent.mDisplaySizeLock) {
7199                // Bootstrap the default logical display from the display manager.
7200                displayInfo = displayContent.getDisplayInfo();
7201                DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId);
7202                if (newDisplayInfo != null) {
7203                    displayInfo.copyFrom(newDisplayInfo);
7204                }
7205                displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
7206                displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
7207                displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
7208                displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
7209                displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
7210                displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
7211            }
7212        }
7213    }
7214
7215    public void systemReady() {
7216        mPolicy.systemReady();
7217    }
7218
7219    // TODO(multidisplay): Call isScreenOn for each display.
7220    private void sendScreenStatusToClientsLocked() {
7221        final boolean on = mPowerManager.isScreenOn();
7222        final AllWindowsIterator iterator = new AllWindowsIterator();
7223        while (iterator.hasNext()) {
7224            try {
7225                iterator.next().mClient.dispatchScreenState(on);
7226            } catch (RemoteException e) {
7227                // Ignored
7228            }
7229        }
7230    }
7231
7232    // -------------------------------------------------------------
7233    // Async Handler
7234    // -------------------------------------------------------------
7235
7236    final class H extends Handler {
7237        public static final int REPORT_FOCUS_CHANGE = 2;
7238        public static final int REPORT_LOSING_FOCUS = 3;
7239        public static final int DO_TRAVERSAL = 4;
7240        public static final int ADD_STARTING = 5;
7241        public static final int REMOVE_STARTING = 6;
7242        public static final int FINISHED_STARTING = 7;
7243        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
7244        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
7245        public static final int WINDOW_FREEZE_TIMEOUT = 11;
7246
7247        public static final int APP_TRANSITION_TIMEOUT = 13;
7248        public static final int PERSIST_ANIMATION_SCALE = 14;
7249        public static final int FORCE_GC = 15;
7250        public static final int ENABLE_SCREEN = 16;
7251        public static final int APP_FREEZE_TIMEOUT = 17;
7252        public static final int SEND_NEW_CONFIGURATION = 18;
7253        public static final int REPORT_WINDOWS_CHANGE = 19;
7254        public static final int DRAG_START_TIMEOUT = 20;
7255        public static final int DRAG_END_TIMEOUT = 21;
7256        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
7257        public static final int BOOT_TIMEOUT = 23;
7258        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
7259        public static final int UPDATE_ANIM_PARAMETERS = 25;
7260        public static final int SHOW_STRICT_MODE_VIOLATION = 26;
7261        public static final int DO_ANIMATION_CALLBACK = 27;
7262        public static final int NOTIFY_ROTATION_CHANGED = 28;
7263        public static final int NOTIFY_WINDOW_TRANSITION = 29;
7264        public static final int NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 30;
7265
7266        public static final int DO_DISPLAY_ADDED = 31;
7267        public static final int DO_DISPLAY_REMOVED = 32;
7268        public static final int DO_DISPLAY_CHANGED = 33;
7269
7270        public static final int CLIENT_FREEZE_TIMEOUT = 34;
7271
7272        public static final int ANIMATOR_WHAT_OFFSET = 100000;
7273        public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
7274        public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
7275
7276        public H() {
7277        }
7278
7279        @Override
7280        public void handleMessage(Message msg) {
7281            if (DEBUG_WINDOW_TRACE) {
7282                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
7283            }
7284            switch (msg.what) {
7285                case REPORT_FOCUS_CHANGE: {
7286                    WindowState lastFocus;
7287                    WindowState newFocus;
7288
7289                    synchronized(mWindowMap) {
7290                        lastFocus = mLastFocus;
7291                        newFocus = mCurrentFocus;
7292                        if (lastFocus == newFocus) {
7293                            // Focus is not changing, so nothing to do.
7294                            return;
7295                        }
7296                        mLastFocus = newFocus;
7297                        //Slog.i(TAG, "Focus moving from " + lastFocus
7298                        //        + " to " + newFocus);
7299                        if (newFocus != null && lastFocus != null
7300                                && !newFocus.isDisplayedLw()) {
7301                            //Slog.i(TAG, "Delaying loss of focus...");
7302                            mLosingFocus.add(lastFocus);
7303                            lastFocus = null;
7304                        }
7305                    }
7306
7307                    if (lastFocus != newFocus) {
7308                        //System.out.println("Changing focus from " + lastFocus
7309                        //                   + " to " + newFocus);
7310                        if (newFocus != null) {
7311                            try {
7312                                //Slog.i(TAG, "Gaining focus: " + newFocus);
7313                                newFocus.mClient.windowFocusChanged(true, mInTouchMode);
7314                            } catch (RemoteException e) {
7315                                // Ignore if process has died.
7316                            }
7317                            notifyFocusChanged();
7318                        }
7319
7320                        if (lastFocus != null) {
7321                            try {
7322                                //Slog.i(TAG, "Losing focus: " + lastFocus);
7323                                lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
7324                            } catch (RemoteException e) {
7325                                // Ignore if process has died.
7326                            }
7327                        }
7328                    }
7329                } break;
7330
7331                case REPORT_LOSING_FOCUS: {
7332                    ArrayList<WindowState> losers;
7333
7334                    synchronized(mWindowMap) {
7335                        losers = mLosingFocus;
7336                        mLosingFocus = new ArrayList<WindowState>();
7337                    }
7338
7339                    final int N = losers.size();
7340                    for (int i=0; i<N; i++) {
7341                        try {
7342                            //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
7343                            losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
7344                        } catch (RemoteException e) {
7345                             // Ignore if process has died.
7346                        }
7347                    }
7348                } break;
7349
7350                case DO_TRAVERSAL: {
7351                    synchronized(mWindowMap) {
7352                        mTraversalScheduled = false;
7353                        performLayoutAndPlaceSurfacesLocked();
7354                    }
7355                } break;
7356
7357                case ADD_STARTING: {
7358                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7359                    final StartingData sd = wtoken.startingData;
7360
7361                    if (sd == null) {
7362                        // Animation has been canceled... do nothing.
7363                        return;
7364                    }
7365
7366                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
7367                            + wtoken + ": pkg=" + sd.pkg);
7368
7369                    View view = null;
7370                    try {
7371                        view = mPolicy.addStartingWindow(
7372                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
7373                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
7374                    } catch (Exception e) {
7375                        Slog.w(TAG, "Exception when adding starting window", e);
7376                    }
7377
7378                    if (view != null) {
7379                        boolean abort = false;
7380
7381                        synchronized(mWindowMap) {
7382                            if (wtoken.removed || wtoken.startingData == null) {
7383                                // If the window was successfully added, then
7384                                // we need to remove it.
7385                                if (wtoken.startingWindow != null) {
7386                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7387                                            "Aborted starting " + wtoken
7388                                            + ": removed=" + wtoken.removed
7389                                            + " startingData=" + wtoken.startingData);
7390                                    wtoken.startingWindow = null;
7391                                    wtoken.startingData = null;
7392                                    abort = true;
7393                                }
7394                            } else {
7395                                wtoken.startingView = view;
7396                            }
7397                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
7398                                    "Added starting " + wtoken
7399                                    + ": startingWindow="
7400                                    + wtoken.startingWindow + " startingView="
7401                                    + wtoken.startingView);
7402                        }
7403
7404                        if (abort) {
7405                            try {
7406                                mPolicy.removeStartingWindow(wtoken.token, view);
7407                            } catch (Exception e) {
7408                                Slog.w(TAG, "Exception when removing starting window", e);
7409                            }
7410                        }
7411                    }
7412                } break;
7413
7414                case REMOVE_STARTING: {
7415                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7416                    IBinder token = null;
7417                    View view = null;
7418                    synchronized (mWindowMap) {
7419                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
7420                                + wtoken + ": startingWindow="
7421                                + wtoken.startingWindow + " startingView="
7422                                + wtoken.startingView);
7423                        if (wtoken.startingWindow != null) {
7424                            view = wtoken.startingView;
7425                            token = wtoken.token;
7426                            wtoken.startingData = null;
7427                            wtoken.startingView = null;
7428                            wtoken.startingWindow = null;
7429                            wtoken.startingDisplayed = false;
7430                        }
7431                    }
7432                    if (view != null) {
7433                        try {
7434                            mPolicy.removeStartingWindow(token, view);
7435                        } catch (Exception e) {
7436                            Slog.w(TAG, "Exception when removing starting window", e);
7437                        }
7438                    }
7439                } break;
7440
7441                case FINISHED_STARTING: {
7442                    IBinder token = null;
7443                    View view = null;
7444                    while (true) {
7445                        synchronized (mWindowMap) {
7446                            final int N = mFinishedStarting.size();
7447                            if (N <= 0) {
7448                                break;
7449                            }
7450                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7451
7452                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7453                                    "Finished starting " + wtoken
7454                                    + ": startingWindow=" + wtoken.startingWindow
7455                                    + " startingView=" + wtoken.startingView);
7456
7457                            if (wtoken.startingWindow == null) {
7458                                continue;
7459                            }
7460
7461                            view = wtoken.startingView;
7462                            token = wtoken.token;
7463                            wtoken.startingData = null;
7464                            wtoken.startingView = null;
7465                            wtoken.startingWindow = null;
7466                            wtoken.startingDisplayed = false;
7467                        }
7468
7469                        try {
7470                            mPolicy.removeStartingWindow(token, view);
7471                        } catch (Exception e) {
7472                            Slog.w(TAG, "Exception when removing starting window", e);
7473                        }
7474                    }
7475                } break;
7476
7477                case REPORT_APPLICATION_TOKEN_DRAWN: {
7478                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7479
7480                    try {
7481                        if (DEBUG_VISIBILITY) Slog.v(
7482                                TAG, "Reporting drawn in " + wtoken);
7483                        wtoken.appToken.windowsDrawn();
7484                    } catch (RemoteException ex) {
7485                    }
7486                } break;
7487
7488                case REPORT_APPLICATION_TOKEN_WINDOWS: {
7489                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7490
7491                    boolean nowVisible = msg.arg1 != 0;
7492                    boolean nowGone = msg.arg2 != 0;
7493
7494                    try {
7495                        if (DEBUG_VISIBILITY) Slog.v(
7496                                TAG, "Reporting visible in " + wtoken
7497                                + " visible=" + nowVisible
7498                                + " gone=" + nowGone);
7499                        if (nowVisible) {
7500                            wtoken.appToken.windowsVisible();
7501                        } else {
7502                            wtoken.appToken.windowsGone();
7503                        }
7504                    } catch (RemoteException ex) {
7505                    }
7506                } break;
7507
7508                case WINDOW_FREEZE_TIMEOUT: {
7509                    // TODO(multidisplay): Can non-default displays rotate?
7510                    synchronized (mWindowMap) {
7511                        Slog.w(TAG, "Window freeze timeout expired.");
7512                        final WindowList windows = getDefaultWindowListLocked();
7513                        int i = windows.size();
7514                        while (i > 0) {
7515                            i--;
7516                            WindowState w = windows.get(i);
7517                            if (w.mOrientationChanging) {
7518                                w.mOrientationChanging = false;
7519                                Slog.w(TAG, "Force clearing orientation change: " + w);
7520                            }
7521                        }
7522                        performLayoutAndPlaceSurfacesLocked();
7523                    }
7524                    break;
7525                }
7526
7527                case APP_TRANSITION_TIMEOUT: {
7528                    synchronized (mWindowMap) {
7529                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
7530                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7531                                    "*** APP TRANSITION TIMEOUT");
7532                            mAppTransitionReady = true;
7533                            mAppTransitionTimeout = true;
7534                            mAnimatingAppTokens.clear();
7535                            mAnimatingAppTokens.addAll(mAppTokens);
7536                            performLayoutAndPlaceSurfacesLocked();
7537                        }
7538                    }
7539                    break;
7540                }
7541
7542                case PERSIST_ANIMATION_SCALE: {
7543                    Settings.System.putFloat(mContext.getContentResolver(),
7544                            Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7545                    Settings.System.putFloat(mContext.getContentResolver(),
7546                            Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7547                    Settings.System.putFloat(mContext.getContentResolver(),
7548                            Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
7549                    break;
7550                }
7551
7552                case FORCE_GC: {
7553                    synchronized (mWindowMap) {
7554                        synchronized (mAnimator) {
7555                            // Since we're holding both mWindowMap and mAnimator we don't need to
7556                            // hold mAnimator.mLayoutToAnim.
7557                            if (mAnimator.mAnimating || mLayoutToAnim.mAnimationScheduled) {
7558                                // If we are animating, don't do the gc now but
7559                                // delay a bit so we don't interrupt the animation.
7560                                mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
7561                                        2000);
7562                                return;
7563                            }
7564                            // If we are currently rotating the display, it will
7565                            // schedule a new message when done.
7566                            if (mDisplayFrozen) {
7567                                return;
7568                            }
7569                        }
7570                    }
7571                    Runtime.getRuntime().gc();
7572                    break;
7573                }
7574
7575                case ENABLE_SCREEN: {
7576                    performEnableScreen();
7577                    break;
7578                }
7579
7580                case APP_FREEZE_TIMEOUT: {
7581                    synchronized (mWindowMap) {
7582                        synchronized (mAnimator) {
7583                            Slog.w(TAG, "App freeze timeout expired.");
7584                            int i = mAppTokens.size();
7585                            while (i > 0) {
7586                                i--;
7587                                AppWindowToken tok = mAppTokens.get(i);
7588                                if (tok.mAppAnimator.freezingScreen) {
7589                                    Slog.w(TAG, "Force clearing freeze: " + tok);
7590                                    unsetAppFreezingScreenLocked(tok, true, true);
7591                                }
7592                            }
7593                        }
7594                    }
7595                    break;
7596                }
7597
7598                case CLIENT_FREEZE_TIMEOUT: {
7599                    synchronized (mWindowMap) {
7600                        if (mClientFreezingScreen) {
7601                            mClientFreezingScreen = false;
7602                            stopFreezingDisplayLocked();
7603                        }
7604                    }
7605                    break;
7606                }
7607
7608                case SEND_NEW_CONFIGURATION: {
7609                    removeMessages(SEND_NEW_CONFIGURATION);
7610                    sendNewConfiguration();
7611                    break;
7612                }
7613
7614                case REPORT_WINDOWS_CHANGE: {
7615                    if (mWindowsChanged) {
7616                        synchronized (mWindowMap) {
7617                            mWindowsChanged = false;
7618                        }
7619                        notifyWindowsChanged();
7620                    }
7621                    break;
7622                }
7623
7624                case DRAG_START_TIMEOUT: {
7625                    IBinder win = (IBinder)msg.obj;
7626                    if (DEBUG_DRAG) {
7627                        Slog.w(TAG, "Timeout starting drag by win " + win);
7628                    }
7629                    synchronized (mWindowMap) {
7630                        // !!! TODO: ANR the app that has failed to start the drag in time
7631                        if (mDragState != null) {
7632                            mDragState.unregister();
7633                            mInputMonitor.updateInputWindowsLw(true /*force*/);
7634                            mDragState.reset();
7635                            mDragState = null;
7636                        }
7637                    }
7638                    break;
7639                }
7640
7641                case DRAG_END_TIMEOUT: {
7642                    IBinder win = (IBinder)msg.obj;
7643                    if (DEBUG_DRAG) {
7644                        Slog.w(TAG, "Timeout ending drag to win " + win);
7645                    }
7646                    synchronized (mWindowMap) {
7647                        // !!! TODO: ANR the drag-receiving app
7648                        if (mDragState != null) {
7649                            mDragState.mDragResult = false;
7650                            mDragState.endDragLw();
7651                        }
7652                    }
7653                    break;
7654                }
7655
7656                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
7657                    notifyHardKeyboardStatusChange();
7658                    break;
7659                }
7660
7661                case BOOT_TIMEOUT: {
7662                    performBootTimeout();
7663                    break;
7664                }
7665
7666                case WAITING_FOR_DRAWN_TIMEOUT: {
7667                    Pair<WindowState, IRemoteCallback> pair;
7668                    synchronized (mWindowMap) {
7669                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
7670                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
7671                        if (!mWaitingForDrawn.remove(pair)) {
7672                            return;
7673                        }
7674                    }
7675                    try {
7676                        pair.second.sendResult(null);
7677                    } catch (RemoteException e) {
7678                    }
7679                    break;
7680                }
7681
7682                case UPDATE_ANIM_PARAMETERS: {
7683                    // Used to send multiple changes from the animation side to the layout side.
7684                    synchronized (mWindowMap) {
7685                        if (copyAnimToLayoutParamsLocked()) {
7686                            mH.sendEmptyMessage(CLEAR_PENDING_ACTIONS);
7687                            performLayoutAndPlaceSurfacesLocked();
7688                        }
7689                    }
7690                    break;
7691                }
7692
7693                case SHOW_STRICT_MODE_VIOLATION: {
7694                    showStrictModeViolation(msg.arg1);
7695                    break;
7696                }
7697
7698                // Animation messages. Move to Window{State}Animator
7699                case SET_TRANSPARENT_REGION: {
7700                    Pair<WindowStateAnimator, Region> pair =
7701                                (Pair<WindowStateAnimator, Region>) msg.obj;
7702                    final WindowStateAnimator winAnimator = pair.first;
7703                    winAnimator.setTransparentRegionHint(pair.second);
7704                    break;
7705                }
7706
7707                case CLEAR_PENDING_ACTIONS: {
7708                    mAnimator.clearPendingActions();
7709                    break;
7710                }
7711
7712                case DO_ANIMATION_CALLBACK: {
7713                    try {
7714                        ((IRemoteCallback)msg.obj).sendResult(null);
7715                    } catch (RemoteException e) {
7716                    }
7717                    break;
7718                }
7719
7720                case NOTIFY_ROTATION_CHANGED: {
7721                    final int displayId = msg.arg1;
7722                    final int rotation = msg.arg2;
7723                    handleNotifyRotationChanged(displayId, rotation);
7724                    break;
7725                }
7726
7727                case NOTIFY_WINDOW_TRANSITION: {
7728                    final int transition = msg.arg1;
7729                    WindowInfo info = (WindowInfo) msg.obj;
7730                    handleNotifyWindowTranstion(transition, info);
7731                    break;
7732                }
7733
7734                case NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
7735                    final int displayId = msg.arg1;
7736                    final boolean immediate = (msg.arg2 == 1);
7737                    Rect rectangle = (Rect) msg.obj;
7738                    handleNotifyRectangleOnScreenRequested(displayId, rectangle, immediate);
7739                    break;
7740                }
7741
7742                case DO_DISPLAY_ADDED:
7743                    synchronized (mWindowMap) {
7744                        handleDisplayAddedLocked(msg.arg1);
7745                    }
7746                    break;
7747
7748                case DO_DISPLAY_REMOVED:
7749                    synchronized (mWindowMap) {
7750                        handleDisplayRemovedLocked(msg.arg1);
7751                    }
7752                    break;
7753
7754                case DO_DISPLAY_CHANGED:
7755                    synchronized (mWindowMap) {
7756                        handleDisplayChangedLocked(msg.arg1);
7757                    }
7758                    break;
7759            }
7760            if (DEBUG_WINDOW_TRACE) {
7761                Slog.v(TAG, "handleMessage: exit");
7762            }
7763        }
7764    }
7765
7766    // -------------------------------------------------------------
7767    // IWindowManager API
7768    // -------------------------------------------------------------
7769
7770    @Override
7771    public IWindowSession openSession(IInputMethodClient client,
7772            IInputContext inputContext) {
7773        if (client == null) throw new IllegalArgumentException("null client");
7774        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7775        Session session = new Session(this, client, inputContext);
7776        return session;
7777    }
7778
7779    @Override
7780    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7781        synchronized (mWindowMap) {
7782            // The focus for the client is the window immediately below
7783            // where we would place the input method window.
7784            int idx = findDesiredInputMethodWindowIndexLocked(false);
7785            if (idx > 0) {
7786                // TODO(multidisplay): IMEs are only supported on the default display.
7787                WindowState imFocus = getDefaultWindowListLocked().get(idx-1);
7788                if (DEBUG_INPUT_METHOD) {
7789                    Slog.i(TAG, "Desired input method target: " + imFocus);
7790                    Slog.i(TAG, "Current focus: " + mCurrentFocus);
7791                    Slog.i(TAG, "Last focus: " + mLastFocus);
7792                }
7793                if (imFocus != null) {
7794                    // This may be a starting window, in which case we still want
7795                    // to count it as okay.
7796                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
7797                            && imFocus.mAppToken != null) {
7798                        // The client has definitely started, so it really should
7799                        // have a window in this app token.  Let's look for it.
7800                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
7801                            WindowState w = imFocus.mAppToken.windows.get(i);
7802                            if (w != imFocus) {
7803                                Log.i(TAG, "Switching to real app window: " + w);
7804                                imFocus = w;
7805                                break;
7806                            }
7807                        }
7808                    }
7809                    if (DEBUG_INPUT_METHOD) {
7810                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
7811                        if (imFocus.mSession.mClient != null) {
7812                            Slog.i(TAG, "IM target client binder: "
7813                                    + imFocus.mSession.mClient.asBinder());
7814                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
7815                        }
7816                    }
7817                    if (imFocus.mSession.mClient != null &&
7818                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7819                        return true;
7820                    }
7821                }
7822            }
7823
7824            // Okay, how about this...  what is the current focus?
7825            // It seems in some cases we may not have moved the IM
7826            // target window, such as when it was in a pop-up window,
7827            // so let's also look at the current focus.  (An example:
7828            // go to Gmail, start searching so the keyboard goes up,
7829            // press home.  Sometimes the IME won't go down.)
7830            // Would be nice to fix this more correctly, but it's
7831            // way at the end of a release, and this should be good enough.
7832            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
7833                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7834                return true;
7835            }
7836        }
7837        return false;
7838    }
7839
7840    public void getInitialDisplaySize(int displayId, Point size) {
7841        // TODO(cmautner): Access to DisplayContent should be locked on mWindowMap. Doing that
7842        //  could lead to deadlock since this is called from ActivityManager.
7843        final DisplayContent displayContent = getDisplayContentLocked(displayId);
7844        synchronized(displayContent.mDisplaySizeLock) {
7845            size.x = displayContent.mInitialDisplayWidth;
7846            size.y = displayContent.mInitialDisplayHeight;
7847        }
7848    }
7849
7850    public void setForcedDisplaySize(int displayId, int width, int height) {
7851        synchronized(mWindowMap) {
7852            // Set some sort of reasonable bounds on the size of the display that we
7853            // will try to emulate.
7854            final int MIN_WIDTH = 200;
7855            final int MIN_HEIGHT = 200;
7856            final int MAX_SCALE = 2;
7857            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7858
7859            width = Math.min(Math.max(width, MIN_WIDTH),
7860                    displayContent.mInitialDisplayWidth * MAX_SCALE);
7861            height = Math.min(Math.max(height, MIN_HEIGHT),
7862                    displayContent.mInitialDisplayHeight * MAX_SCALE);
7863            setForcedDisplaySizeLocked(displayContent, width, height);
7864            Settings.Global.putString(mContext.getContentResolver(),
7865                    Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
7866        }
7867    }
7868
7869    private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) {
7870        final String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
7871                Settings.Global.DISPLAY_SIZE_FORCED);
7872        if (sizeStr != null && sizeStr.length() > 0) {
7873            final int pos = sizeStr.indexOf(',');
7874            if (pos > 0 && sizeStr.lastIndexOf(',') == pos) {
7875                int width, height;
7876                try {
7877                    width = Integer.parseInt(sizeStr.substring(0, pos));
7878                    height = Integer.parseInt(sizeStr.substring(pos+1));
7879                    synchronized(displayContent.mDisplaySizeLock) {
7880                        if (displayContent.mBaseDisplayWidth != width
7881                                || displayContent.mBaseDisplayHeight != height) {
7882                            Slog.i(TAG, "FORCED DISPLAY SIZE: " + width + "x" + height);
7883                            displayContent.mBaseDisplayWidth = width;
7884                            displayContent.mBaseDisplayHeight = height;
7885                        }
7886                    }
7887                } catch (NumberFormatException ex) {
7888                }
7889            }
7890        }
7891        final String densityStr = Settings.Global.getString(mContext.getContentResolver(),
7892                Settings.Global.DISPLAY_DENSITY_FORCED);
7893        if (densityStr != null && densityStr.length() > 0) {
7894            int density;
7895            try {
7896                density = Integer.parseInt(densityStr);
7897                synchronized(displayContent.mDisplaySizeLock) {
7898                    if (displayContent.mBaseDisplayDensity != density) {
7899                        Slog.i(TAG, "FORCED DISPLAY DENSITY: " + density);
7900                        displayContent.mBaseDisplayDensity = density;
7901                    }
7902                }
7903            } catch (NumberFormatException ex) {
7904            }
7905        }
7906    }
7907
7908    private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
7909        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7910
7911        synchronized(displayContent.mDisplaySizeLock) {
7912            displayContent.mBaseDisplayWidth = width;
7913            displayContent.mBaseDisplayHeight = height;
7914        }
7915        reconfigureDisplayLocked(displayContent);
7916    }
7917
7918    public void clearForcedDisplaySize(int displayId) {
7919        synchronized(mWindowMap) {
7920            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7921            setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
7922                    displayContent.mInitialDisplayHeight);
7923            Settings.Global.putString(mContext.getContentResolver(),
7924                    Settings.Global.DISPLAY_SIZE_FORCED, "");
7925        }
7926    }
7927
7928    public void setForcedDisplayDensity(int displayId, int density) {
7929        synchronized(mWindowMap) {
7930            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7931            setForcedDisplayDensityLocked(displayContent, density);
7932            Settings.Global.putString(mContext.getContentResolver(),
7933                    Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
7934        }
7935    }
7936
7937    private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) {
7938        Slog.i(TAG, "Using new display density: " + density);
7939
7940        synchronized(displayContent.mDisplaySizeLock) {
7941            displayContent.mBaseDisplayDensity = density;
7942        }
7943        reconfigureDisplayLocked(displayContent);
7944    }
7945
7946    public void clearForcedDisplayDensity(int displayId) {
7947        synchronized(mWindowMap) {
7948            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7949            setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity);
7950            Settings.Secure.putString(mContext.getContentResolver(),
7951                    Settings.Secure.DISPLAY_DENSITY_FORCED, "");
7952        }
7953    }
7954
7955    private void reconfigureDisplayLocked(DisplayContent displayContent) {
7956        // TODO: Multidisplay: for now only use with default display.
7957        mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
7958                displayContent.mBaseDisplayWidth,
7959                displayContent.mBaseDisplayHeight,
7960                displayContent.mBaseDisplayDensity);
7961
7962        displayContent.layoutNeeded = true;
7963
7964        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7965        mTempConfiguration.setToDefaults();
7966        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7967        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7968            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7969                configChanged = true;
7970            }
7971        }
7972
7973        if (configChanged) {
7974            mWaitingForConfig = true;
7975            startFreezingDisplayLocked(false, 0, 0);
7976            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7977        }
7978
7979        performLayoutAndPlaceSurfacesLocked();
7980    }
7981
7982    public boolean hasSystemNavBar() {
7983        return mPolicy.hasSystemNavBar();
7984    }
7985
7986    // -------------------------------------------------------------
7987    // Internals
7988    // -------------------------------------------------------------
7989
7990    final WindowState windowForClientLocked(Session session, IWindow client,
7991            boolean throwOnError) {
7992        return windowForClientLocked(session, client.asBinder(), throwOnError);
7993    }
7994
7995    final WindowState windowForClientLocked(Session session, IBinder client,
7996            boolean throwOnError) {
7997        WindowState win = mWindowMap.get(client);
7998        if (localLOGV) Slog.v(
7999            TAG, "Looking up client " + client + ": " + win);
8000        if (win == null) {
8001            RuntimeException ex = new IllegalArgumentException(
8002                    "Requested window " + client + " does not exist");
8003            if (throwOnError) {
8004                throw ex;
8005            }
8006            Slog.w(TAG, "Failed looking up window", ex);
8007            return null;
8008        }
8009        if (session != null && win.mSession != session) {
8010            RuntimeException ex = new IllegalArgumentException(
8011                    "Requested window " + client + " is in session " +
8012                    win.mSession + ", not " + session);
8013            if (throwOnError) {
8014                throw ex;
8015            }
8016            Slog.w(TAG, "Failed looking up window", ex);
8017            return null;
8018        }
8019
8020        return win;
8021    }
8022
8023    final void rebuildAppWindowListLocked() {
8024        DisplayContentsIterator iterator = new DisplayContentsIterator();
8025        while (iterator.hasNext()) {
8026            rebuildAppWindowListLocked(iterator.next());
8027        }
8028    }
8029
8030    private void rebuildAppWindowListLocked(final DisplayContent displayContent) {
8031        final WindowList windows = displayContent.getWindowList();
8032        int NW = windows.size();
8033        int i;
8034        int lastBelow = -1;
8035        int numRemoved = 0;
8036
8037        if (mRebuildTmp.length < NW) {
8038            mRebuildTmp = new WindowState[NW+10];
8039        }
8040
8041        // First remove all existing app windows.
8042        i=0;
8043        while (i < NW) {
8044            WindowState w = windows.get(i);
8045            if (w.mAppToken != null) {
8046                WindowState win = windows.remove(i);
8047                win.mRebuilding = true;
8048                mRebuildTmp[numRemoved] = win;
8049                mWindowsChanged = true;
8050                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
8051                        "Rebuild removing window: " + win);
8052                NW--;
8053                numRemoved++;
8054                continue;
8055            } else if (lastBelow == i-1) {
8056                if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER
8057                        || w.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND) {
8058                    lastBelow = i;
8059                }
8060            }
8061            i++;
8062        }
8063
8064        // Keep whatever windows were below the app windows still below,
8065        // by skipping them.
8066        lastBelow++;
8067        i = lastBelow;
8068
8069        // First add all of the exiting app tokens...  these are no longer
8070        // in the main app list, but still have windows shown.  We put them
8071        // in the back because now that the animation is over we no longer
8072        // will care about them.
8073        int NT = mExitingAppTokens.size();
8074        for (int j=0; j<NT; j++) {
8075            i = reAddAppWindowsLocked(displayContent, i, mExitingAppTokens.get(j));
8076        }
8077
8078        // And add in the still active app tokens in Z order.
8079        NT = mAnimatingAppTokens.size();
8080        for (int j=0; j<NT; j++) {
8081            i = reAddAppWindowsLocked(displayContent, i, mAnimatingAppTokens.get(j));
8082        }
8083
8084        i -= lastBelow;
8085        if (i != numRemoved) {
8086            Slog.w(TAG, "Rebuild removed " + numRemoved
8087                    + " windows but added " + i);
8088            for (i=0; i<numRemoved; i++) {
8089                WindowState ws = mRebuildTmp[i];
8090                if (ws.mRebuilding) {
8091                    StringWriter sw = new StringWriter();
8092                    PrintWriter pw = new PrintWriter(sw);
8093                    ws.dump(pw, "", true);
8094                    pw.flush();
8095                    Slog.w(TAG, "This window was lost: " + ws);
8096                    Slog.w(TAG, sw.toString());
8097                    ws.mWinAnimator.destroySurfaceLocked();
8098                }
8099            }
8100            Slog.w(TAG, "Current app token list:");
8101            dumpAnimatingAppTokensLocked();
8102            Slog.w(TAG, "Final window list:");
8103            dumpWindowsLocked();
8104        }
8105    }
8106
8107    private final void assignLayersLocked(WindowList windows) {
8108        int N = windows.size();
8109        int curBaseLayer = 0;
8110        int curLayer = 0;
8111        int i;
8112
8113        if (DEBUG_LAYERS) {
8114            RuntimeException here = new RuntimeException("here");
8115            here.fillInStackTrace();
8116            Slog.v(TAG, "Assigning layers", here);
8117        }
8118
8119        for (i=0; i<N; i++) {
8120            final WindowState w = windows.get(i);
8121            final WindowStateAnimator winAnimator = w.mWinAnimator;
8122            boolean layerChanged = false;
8123            int oldLayer = w.mLayer;
8124            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
8125                    || (i > 0 && w.mIsWallpaper)) {
8126                curLayer += WINDOW_LAYER_MULTIPLIER;
8127                w.mLayer = curLayer;
8128            } else {
8129                curBaseLayer = curLayer = w.mBaseLayer;
8130                w.mLayer = curLayer;
8131            }
8132            if (w.mLayer != oldLayer) {
8133                layerChanged = true;
8134            }
8135            oldLayer = winAnimator.mAnimLayer;
8136            if (w.mTargetAppToken != null) {
8137                winAnimator.mAnimLayer =
8138                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
8139            } else if (w.mAppToken != null) {
8140                winAnimator.mAnimLayer =
8141                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
8142            } else {
8143                winAnimator.mAnimLayer = w.mLayer;
8144            }
8145            if (w.mIsImWindow) {
8146                winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
8147            } else if (w.mIsWallpaper) {
8148                winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
8149            }
8150            if (winAnimator.mAnimLayer != oldLayer) {
8151                layerChanged = true;
8152            }
8153            if (layerChanged && mAnimator.isDimmingLocked(winAnimator)) {
8154                // Force an animation pass just to update the mDimAnimator layer.
8155                updateLayoutToAnimationLocked();
8156            }
8157            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
8158                    + "mBase=" + w.mBaseLayer
8159                    + " mLayer=" + w.mLayer
8160                    + (w.mAppToken == null ?
8161                            "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
8162                    + " =mAnimLayer=" + winAnimator.mAnimLayer);
8163            //System.out.println(
8164            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
8165        }
8166    }
8167
8168    private boolean mInLayout = false;
8169    private final void performLayoutAndPlaceSurfacesLocked() {
8170        if (mInLayout) {
8171            if (DEBUG) {
8172                throw new RuntimeException("Recursive call!");
8173            }
8174            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
8175                    + Debug.getCallers(3));
8176            return;
8177        }
8178
8179        if (mWaitingForConfig) {
8180            // Our configuration has changed (most likely rotation), but we
8181            // don't yet have the complete configuration to report to
8182            // applications.  Don't do any window layout until we have it.
8183            return;
8184        }
8185
8186        if (!mDisplayReady) {
8187            // Not yet initialized, nothing to do.
8188            return;
8189        }
8190
8191        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
8192        mInLayout = true;
8193        boolean recoveringMemory = false;
8194
8195        try {
8196            if (mForceRemoves != null) {
8197                recoveringMemory = true;
8198                // Wait a little bit for things to settle down, and off we go.
8199                for (int i=0; i<mForceRemoves.size(); i++) {
8200                    WindowState ws = mForceRemoves.get(i);
8201                    Slog.i(TAG, "Force removing: " + ws);
8202                    removeWindowInnerLocked(ws.mSession, ws);
8203                }
8204                mForceRemoves = null;
8205                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
8206                Object tmp = new Object();
8207                synchronized (tmp) {
8208                    try {
8209                        tmp.wait(250);
8210                    } catch (InterruptedException e) {
8211                    }
8212                }
8213            }
8214        } catch (RuntimeException e) {
8215            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
8216        }
8217
8218        try {
8219            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
8220
8221            mInLayout = false;
8222
8223            if (needsLayout()) {
8224                if (++mLayoutRepeatCount < 6) {
8225                    requestTraversalLocked();
8226                } else {
8227                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
8228                    mLayoutRepeatCount = 0;
8229                }
8230            } else {
8231                mLayoutRepeatCount = 0;
8232            }
8233
8234            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
8235                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
8236                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
8237            }
8238        } catch (RuntimeException e) {
8239            mInLayout = false;
8240            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
8241        }
8242
8243        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
8244    }
8245
8246    private final void performLayoutLockedInner(final DisplayContent displayContent,
8247                                    boolean initial, boolean updateInputWindows) {
8248        if (!displayContent.layoutNeeded) {
8249            return;
8250        }
8251        displayContent.layoutNeeded = false;
8252        WindowList windows = displayContent.getWindowList();
8253        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
8254
8255        DisplayInfo displayInfo = displayContent.getDisplayInfo();
8256        final int dw = displayInfo.logicalWidth;
8257        final int dh = displayInfo.logicalHeight;
8258
8259        final int NFW = mFakeWindows.size();
8260        for (int i=0; i<NFW; i++) {
8261            mFakeWindows.get(i).layout(dw, dh);
8262        }
8263
8264        final int N = windows.size();
8265        int i;
8266
8267        if (DEBUG_LAYOUT) {
8268            Slog.v(TAG, "-------------------------------------");
8269            Slog.v(TAG, "performLayout: needed="
8270                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
8271        }
8272
8273        WindowStateAnimator universeBackground = null;
8274
8275        mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
8276        if (isDefaultDisplay) {
8277            // Not needed on non-default displays.
8278            mSystemDecorLayer = mPolicy.getSystemDecorRectLw(mSystemDecorRect);
8279            mScreenRect.set(0, 0, dw, dh);
8280        }
8281
8282        int seq = mLayoutSeq+1;
8283        if (seq < 0) seq = 0;
8284        mLayoutSeq = seq;
8285
8286        // First perform layout of any root windows (not attached
8287        // to another window).
8288        int topAttached = -1;
8289        for (i = N-1; i >= 0; i--) {
8290            final WindowState win = windows.get(i);
8291
8292            // Don't do layout of a window if it is not visible, or
8293            // soon won't be visible, to avoid wasting time and funky
8294            // changes while a window is animating away.
8295            final boolean gone = win.isGoneForLayoutLw();
8296
8297            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
8298                Slog.v(TAG, "1ST PASS " + win
8299                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
8300                        + " mLayoutAttached=" + win.mLayoutAttached
8301                        + " screen changed=" + win.isConfigDiff(ActivityInfo.CONFIG_SCREEN_SIZE));
8302                final AppWindowToken atoken = win.mAppToken;
8303                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
8304                        + win.mViewVisibility + " mRelayoutCalled="
8305                        + win.mRelayoutCalled + " hidden="
8306                        + win.mRootToken.hidden + " hiddenRequested="
8307                        + (atoken != null && atoken.hiddenRequested)
8308                        + " mAttachedHidden=" + win.mAttachedHidden);
8309                else Slog.v(TAG, "  VIS: mViewVisibility="
8310                        + win.mViewVisibility + " mRelayoutCalled="
8311                        + win.mRelayoutCalled + " hidden="
8312                        + win.mRootToken.hidden + " hiddenRequested="
8313                        + (atoken != null && atoken.hiddenRequested)
8314                        + " mAttachedHidden=" + win.mAttachedHidden);
8315            }
8316
8317            // If this view is GONE, then skip it -- keep the current
8318            // frame, and let the caller know so they can ignore it
8319            // if they want.  (We do the normal layout for INVISIBLE
8320            // windows, since that means "perform layout as normal,
8321            // just don't display").
8322            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
8323                    || win.isConfigDiff(ActivityInfo.CONFIG_SCREEN_SIZE)
8324                    || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
8325                if (!win.mLayoutAttached) {
8326                    if (initial) {
8327                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8328                        win.mContentChanged = false;
8329                    }
8330                    win.mLayoutNeeded = false;
8331                    win.prelayout();
8332                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
8333                    win.mLayoutSeq = seq;
8334                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8335                            + win.mFrame + " mContainingFrame="
8336                            + win.mContainingFrame + " mDisplayFrame="
8337                            + win.mDisplayFrame);
8338                } else {
8339                    if (topAttached < 0) topAttached = i;
8340                }
8341            }
8342            if (win.mViewVisibility == View.VISIBLE
8343                    && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND
8344                    && universeBackground == null) {
8345                universeBackground = win.mWinAnimator;
8346            }
8347        }
8348
8349        if (mAnimator.mUniverseBackground  != universeBackground) {
8350            mFocusMayChange = true;
8351            mAnimator.mUniverseBackground = universeBackground;
8352        }
8353
8354        // Now perform layout of attached windows, which usually
8355        // depend on the position of the window they are attached to.
8356        // XXX does not deal with windows that are attached to windows
8357        // that are themselves attached.
8358        for (i = topAttached; i >= 0; i--) {
8359            final WindowState win = windows.get(i);
8360
8361            if (win.mLayoutAttached) {
8362                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
8363                        + " mHaveFrame=" + win.mHaveFrame
8364                        + " mViewVisibility=" + win.mViewVisibility
8365                        + " mRelayoutCalled=" + win.mRelayoutCalled);
8366                // If this view is GONE, then skip it -- keep the current
8367                // frame, and let the caller know so they can ignore it
8368                // if they want.  (We do the normal layout for INVISIBLE
8369                // windows, since that means "perform layout as normal,
8370                // just don't display").
8371                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
8372                        || !win.mHaveFrame || win.mLayoutNeeded) {
8373                    if (initial) {
8374                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8375                        win.mContentChanged = false;
8376                    }
8377                    win.mLayoutNeeded = false;
8378                    win.prelayout();
8379                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
8380                    win.mLayoutSeq = seq;
8381                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8382                            + win.mFrame + " mContainingFrame="
8383                            + win.mContainingFrame + " mDisplayFrame="
8384                            + win.mDisplayFrame);
8385                }
8386            }
8387        }
8388
8389        // Window frames may have changed.  Tell the input dispatcher about it.
8390        mInputMonitor.setUpdateInputWindowsNeededLw();
8391        if (updateInputWindows) {
8392            mInputMonitor.updateInputWindowsLw(false /*force*/);
8393        }
8394
8395        mPolicy.finishLayoutLw();
8396    }
8397
8398    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
8399        // If the screen is currently frozen or off, then keep
8400        // it frozen/off until this window draws at its new
8401        // orientation.
8402        if (!okToDisplay()) {
8403            if (DEBUG_ORIENTATION) Slog.v(TAG,
8404                    "Changing surface while display frozen: " + w);
8405            w.mOrientationChanging = true;
8406            mInnerFields.mOrientationChangeComplete = false;
8407            if (!mWindowsFreezingScreen) {
8408                mWindowsFreezingScreen = true;
8409                // XXX should probably keep timeout from
8410                // when we first froze the display.
8411                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8412                mH.sendMessageDelayed(mH.obtainMessage(
8413                        H.WINDOW_FREEZE_TIMEOUT), 2000);
8414            }
8415        }
8416    }
8417
8418    /**
8419     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8420     * @param windows List of windows on default display.
8421     * @return bitmap indicating if another pass through layout must be made.
8422     */
8423    public int handleAppTransitionReadyLocked(WindowList windows) {
8424        int changes = 0;
8425        int i;
8426        int NN = mOpeningApps.size();
8427        boolean goodToGo = true;
8428        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8429                "Checking " + NN + " opening apps (frozen="
8430                + mDisplayFrozen + " timeout="
8431                + mAppTransitionTimeout + ")...");
8432        if (!mDisplayFrozen && !mAppTransitionTimeout) {
8433            // If the display isn't frozen, wait to do anything until
8434            // all of the apps are ready.  Otherwise just go because
8435            // we'll unfreeze the display when everyone is ready.
8436            for (i=0; i<NN && goodToGo; i++) {
8437                AppWindowToken wtoken = mOpeningApps.get(i);
8438                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8439                        "Check opening app=" + wtoken + ": allDrawn="
8440                        + wtoken.allDrawn + " startingDisplayed="
8441                        + wtoken.startingDisplayed + " startingMoved="
8442                        + wtoken.startingMoved);
8443                if (!wtoken.allDrawn && !wtoken.startingDisplayed
8444                        && !wtoken.startingMoved) {
8445                    goodToGo = false;
8446                }
8447            }
8448        }
8449        if (goodToGo) {
8450            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
8451            int transit = mNextAppTransition;
8452            if (mSkipAppTransitionAnimation) {
8453                transit = WindowManagerPolicy.TRANSIT_UNSET;
8454            }
8455            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
8456            mAppTransitionReady = false;
8457            mAppTransitionRunning = true;
8458            mAppTransitionTimeout = false;
8459            mStartingIconInTransition = false;
8460            mSkipAppTransitionAnimation = false;
8461
8462            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8463
8464            rebuildAppWindowListLocked();
8465
8466            // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
8467            WindowState oldWallpaper =
8468                    mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
8469                        && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
8470                    ? null : mWallpaperTarget;
8471
8472            adjustWallpaperWindowsLocked();
8473            mInnerFields.mWallpaperMayChange = false;
8474
8475            // The top-most window will supply the layout params,
8476            // and we will determine it below.
8477            LayoutParams animLp = null;
8478            int bestAnimLayer = -1;
8479            boolean fullscreenAnim = false;
8480
8481            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8482                    "New wallpaper target=" + mWallpaperTarget
8483                    + ", oldWallpaper=" + oldWallpaper
8484                    + ", lower target=" + mLowerWallpaperTarget
8485                    + ", upper target=" + mUpperWallpaperTarget);
8486            int foundWallpapers = 0;
8487            // Do a first pass through the tokens for two
8488            // things:
8489            // (1) Determine if both the closing and opening
8490            // app token sets are wallpaper targets, in which
8491            // case special animations are needed
8492            // (since the wallpaper needs to stay static
8493            // behind them).
8494            // (2) Find the layout params of the top-most
8495            // application window in the tokens, which is
8496            // what will control the animation theme.
8497            final int NC = mClosingApps.size();
8498            NN = NC + mOpeningApps.size();
8499            for (i=0; i<NN; i++) {
8500                AppWindowToken wtoken;
8501                int mode;
8502                if (i < NC) {
8503                    wtoken = mClosingApps.get(i);
8504                    mode = 1;
8505                } else {
8506                    wtoken = mOpeningApps.get(i-NC);
8507                    mode = 2;
8508                }
8509                if (mLowerWallpaperTarget != null) {
8510                    if (mLowerWallpaperTarget.mAppToken == wtoken
8511                            || mUpperWallpaperTarget.mAppToken == wtoken) {
8512                        foundWallpapers |= mode;
8513                    }
8514                }
8515                if (wtoken.appFullscreen) {
8516                    WindowState ws = wtoken.findMainWindow();
8517                    if (ws != null) {
8518                        animLp = ws.mAttrs;
8519                        bestAnimLayer = ws.mLayer;
8520                        fullscreenAnim = true;
8521                    }
8522                } else if (!fullscreenAnim) {
8523                    WindowState ws = wtoken.findMainWindow();
8524                    if (ws != null) {
8525                        if (ws.mLayer > bestAnimLayer) {
8526                            animLp = ws.mAttrs;
8527                            bestAnimLayer = ws.mLayer;
8528                        }
8529                    }
8530                }
8531            }
8532
8533            if (foundWallpapers == 3) {
8534                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8535                        "Wallpaper animation!");
8536                switch (transit) {
8537                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
8538                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
8539                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
8540                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
8541                        break;
8542                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
8543                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
8544                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
8545                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
8546                        break;
8547                }
8548                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8549                        "New transit: " + transit);
8550            } else if ((oldWallpaper != null) && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
8551                // We are transitioning from an activity with
8552                // a wallpaper to one without.
8553                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
8554                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8555                        "New transit away from wallpaper: " + transit);
8556            } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
8557                // We are transitioning from an activity without
8558                // a wallpaper to now showing the wallpaper
8559                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
8560                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8561                        "New transit into wallpaper: " + transit);
8562            }
8563
8564            // If all closing windows are obscured, then there is
8565            // no need to do an animation.  This is the case, for
8566            // example, when this transition is being done behind
8567            // the lock screen.
8568            if (!mPolicy.allowAppAnimationsLw()) {
8569                animLp = null;
8570            }
8571
8572            AppWindowToken topOpeningApp = null;
8573            int topOpeningLayer = 0;
8574
8575            NN = mOpeningApps.size();
8576            for (i=0; i<NN; i++) {
8577                AppWindowToken wtoken = mOpeningApps.get(i);
8578                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
8579                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
8580                appAnimator.clearThumbnail();
8581                wtoken.reportedVisible = false;
8582                wtoken.inPendingTransaction = false;
8583                appAnimator.animation = null;
8584                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
8585                wtoken.updateReportedVisibilityLocked();
8586                wtoken.waitingToShow = false;
8587
8588                appAnimator.mAllAppWinAnimators.clear();
8589                final int N = wtoken.allAppWindows.size();
8590                for (int j = 0; j < N; j++) {
8591                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
8592                }
8593                mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
8594
8595                if (animLp != null) {
8596                    int layer = -1;
8597                    for (int j=0; j<wtoken.windows.size(); j++) {
8598                        WindowState win = wtoken.windows.get(j);
8599                        if (win.mWinAnimator.mAnimLayer > layer) {
8600                            layer = win.mWinAnimator.mAnimLayer;
8601                        }
8602                    }
8603                    if (topOpeningApp == null || layer > topOpeningLayer) {
8604                        topOpeningApp = wtoken;
8605                        topOpeningLayer = layer;
8606                    }
8607                }
8608            }
8609            NN = mClosingApps.size();
8610            for (i=0; i<NN; i++) {
8611                AppWindowToken wtoken = mClosingApps.get(i);
8612                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8613                        "Now closing app " + wtoken);
8614                wtoken.mAppAnimator.clearThumbnail();
8615                wtoken.inPendingTransaction = false;
8616                wtoken.mAppAnimator.animation = null;
8617                setTokenVisibilityLocked(wtoken, animLp, false,
8618                        transit, false);
8619                wtoken.updateReportedVisibilityLocked();
8620                wtoken.waitingToHide = false;
8621                // Force the allDrawn flag, because we want to start
8622                // this guy's animations regardless of whether it's
8623                // gotten drawn.
8624                wtoken.allDrawn = true;
8625            }
8626
8627            if (mNextAppTransitionThumbnail != null && topOpeningApp != null
8628                    && topOpeningApp.mAppAnimator.animation != null) {
8629                // This thumbnail animation is very special, we need to have
8630                // an extra surface with the thumbnail included with the animation.
8631                Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
8632                        mNextAppTransitionThumbnail.getHeight());
8633                try {
8634                    // TODO(multi-display): support other displays
8635                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
8636                    final Display display = displayContent.getDisplay();
8637                    Surface surface = new Surface(mFxSession,
8638                            "thumbnail anim",
8639                            dirty.width(), dirty.height(),
8640                            PixelFormat.TRANSLUCENT, Surface.HIDDEN);
8641                    surface.setLayerStack(display.getLayerStack());
8642                    topOpeningApp.mAppAnimator.thumbnail = surface;
8643                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
8644                            + surface + ": CREATE");
8645                    Surface drawSurface = new Surface();
8646                    drawSurface.copyFrom(surface);
8647                    Canvas c = drawSurface.lockCanvas(dirty);
8648                    c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
8649                    drawSurface.unlockCanvasAndPost(c);
8650                    drawSurface.release();
8651                    topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
8652                    Animation anim = createThumbnailAnimationLocked(
8653                            transit, true, true, mNextAppTransitionScaleUp);
8654                    topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
8655                    anim.restrictDuration(MAX_ANIMATION_DURATION);
8656                    anim.scaleCurrentDuration(mTransitionAnimationScale);
8657                    topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX;
8658                    topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY;
8659                } catch (Surface.OutOfResourcesException e) {
8660                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
8661                            + " h=" + dirty.height(), e);
8662                    topOpeningApp.mAppAnimator.clearThumbnail();
8663                }
8664            }
8665
8666            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
8667            mNextAppTransitionPackage = null;
8668            mNextAppTransitionThumbnail = null;
8669            scheduleAnimationCallback(mNextAppTransitionCallback);
8670            mNextAppTransitionCallback = null;
8671
8672            mOpeningApps.clear();
8673            mClosingApps.clear();
8674
8675            // This has changed the visibility of windows, so perform
8676            // a new layout to get them all up-to-date.
8677            changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
8678                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8679            getDefaultDisplayContentLocked().layoutNeeded = true;
8680
8681            // TODO(multidisplay): IMEs are only supported on the default display.
8682            if (windows == getDefaultWindowListLocked()
8683                    && !moveInputMethodWindowsIfNeededLocked(true)) {
8684                assignLayersLocked(windows);
8685            }
8686            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, false /*updateInputWindows*/);
8687            mFocusMayChange = false;
8688        }
8689
8690        return changes;
8691    }
8692
8693    /**
8694     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8695     * @return bitmap indicating if another pass through layout must be made.
8696     */
8697    private int handleAnimatingStoppedAndTransitionLocked() {
8698        int changes = 0;
8699
8700        mAppTransitionRunning = false;
8701        // Restore window app tokens to the ActivityManager views
8702        for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) {
8703            mAnimatingAppTokens.get(i).sendingToBottom = false;
8704        }
8705        mAnimatingAppTokens.clear();
8706        mAnimatingAppTokens.addAll(mAppTokens);
8707        rebuildAppWindowListLocked();
8708
8709        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8710        mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
8711        moveInputMethodWindowsIfNeededLocked(true);
8712        mInnerFields.mWallpaperMayChange = true;
8713        // Since the window list has been rebuilt, focus might
8714        // have to be recomputed since the actual order of windows
8715        // might have changed again.
8716        mFocusMayChange = true;
8717
8718        return changes;
8719    }
8720
8721    /**
8722     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8723     *
8724     * @return bitmap indicating if another pass through layout must be made.
8725     */
8726    private int animateAwayWallpaperLocked() {
8727        int changes = 0;
8728        WindowState oldWallpaper = mWallpaperTarget;
8729        if (mLowerWallpaperTarget != null
8730                && mLowerWallpaperTarget.mAppToken != null) {
8731            if (DEBUG_WALLPAPER) Slog.v(TAG,
8732                    "wallpaperForceHiding changed with lower="
8733                    + mLowerWallpaperTarget);
8734            if (DEBUG_WALLPAPER) Slog.v(TAG,
8735                    "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
8736                    " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
8737            if (mLowerWallpaperTarget.mAppToken.hidden) {
8738                // The lower target has become hidden before we
8739                // actually started the animation...  let's completely
8740                // re-evaluate everything.
8741                mLowerWallpaperTarget = mUpperWallpaperTarget = null;
8742                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8743            }
8744        }
8745        mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8746        if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
8747                + " NEW: " + mWallpaperTarget
8748                + " LOWER: " + mLowerWallpaperTarget);
8749        return changes;
8750    }
8751
8752    private void updateResizingWindows(final WindowState w) {
8753        final WindowStateAnimator winAnimator = w.mWinAnimator;
8754        if (w.mHasSurface && !w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
8755            w.mContentInsetsChanged |=
8756                    !w.mLastContentInsets.equals(w.mContentInsets);
8757            w.mVisibleInsetsChanged |=
8758                    !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8759            boolean configChanged = w.isConfigChanged();
8760            if (DEBUG_CONFIGURATION && configChanged) {
8761                Slog.v(TAG, "Win " + w + " config changed: "
8762                        + mCurConfiguration);
8763            }
8764            if (localLOGV) Slog.v(TAG, "Resizing " + w
8765                    + ": configChanged=" + configChanged
8766                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8767            w.mLastFrame.set(w.mFrame);
8768            if (w.mContentInsetsChanged
8769                    || w.mVisibleInsetsChanged
8770                    || winAnimator.mSurfaceResized
8771                    || configChanged) {
8772                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8773                    Slog.v(TAG, "Resize reasons: "
8774                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8775                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8776                            + " surfaceResized=" + winAnimator.mSurfaceResized
8777                            + " configChanged=" + configChanged);
8778                }
8779
8780                w.mLastContentInsets.set(w.mContentInsets);
8781                w.mLastVisibleInsets.set(w.mVisibleInsets);
8782                makeWindowFreezingScreenIfNeededLocked(w);
8783                // If the orientation is changing, then we need to
8784                // hold off on unfreezing the display until this
8785                // window has been redrawn; to do that, we need
8786                // to go through the process of getting informed
8787                // by the application when it has finished drawing.
8788                if (w.mOrientationChanging) {
8789                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
8790                            "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
8791                            + w + ", surface " + winAnimator.mSurface);
8792                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8793                    if (w.mAppToken != null) {
8794                        w.mAppToken.allDrawn = false;
8795                    }
8796                }
8797                if (!mResizingWindows.contains(w)) {
8798                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8799                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8800                            + "x" + winAnimator.mSurfaceH);
8801                    mResizingWindows.add(w);
8802                }
8803            } else if (w.mOrientationChanging) {
8804                if (w.isDrawnLw()) {
8805                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8806                            "Orientation not waiting for draw in "
8807                            + w + ", surface " + winAnimator.mSurface);
8808                    w.mOrientationChanging = false;
8809                }
8810            }
8811        }
8812    }
8813
8814    /**
8815     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8816     *
8817     * @param w WindowState this method is applied to.
8818     * @param currentTime The time which animations use for calculating transitions.
8819     * @param innerDw Width of app window.
8820     * @param innerDh Height of app window.
8821     */
8822    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8823                                         final int innerDw, final int innerDh) {
8824        final WindowManager.LayoutParams attrs = w.mAttrs;
8825        final int attrFlags = attrs.flags;
8826        final boolean canBeSeen = w.isDisplayedLw();
8827
8828        if (w.mHasSurface) {
8829            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8830                mInnerFields.mHoldScreen = w.mSession;
8831            }
8832            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8833                    && mInnerFields.mScreenBrightness < 0) {
8834                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8835            }
8836            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8837                    && mInnerFields.mButtonBrightness < 0) {
8838                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8839            }
8840            if (canBeSeen
8841                    && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8842                     || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8843                     || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
8844                mInnerFields.mSyswin = true;
8845            }
8846        }
8847
8848        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8849        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8850            // This window completely covers everything behind it,
8851            // so we want to leave all of them as undimmed (for
8852            // performance reasons).
8853            mInnerFields.mObscured = true;
8854        } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0
8855                && !(w.mAppToken != null && w.mAppToken.hiddenRequested)
8856                && !w.mExiting) {
8857            if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured);
8858            if (!mInnerFields.mDimming) {
8859                //Slog.i(TAG, "DIM BEHIND: " + w);
8860                mInnerFields.mDimming = true;
8861                final WindowStateAnimator winAnimator = w.mWinAnimator;
8862                if (!mAnimator.isDimmingLocked(winAnimator)) {
8863                    final int width, height;
8864                    if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
8865                        final DisplayInfo displayInfo = w.mDisplayContent.getDisplayInfo();
8866                        width = displayInfo.logicalWidth;
8867                        height = displayInfo.logicalHeight;
8868                    } else {
8869                        width = innerDw;
8870                        height = innerDh;
8871                    }
8872                    startDimmingLocked(
8873                        winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount, width, height);
8874                }
8875            }
8876        }
8877    }
8878
8879    private void updateAllDrawnLocked() {
8880        // See if any windows have been drawn, so they (and others
8881        // associated with them) can now be shown.
8882        final ArrayList<AppWindowToken> appTokens = mAnimatingAppTokens;
8883        final int NT = appTokens.size();
8884        for (int i=0; i<NT; i++) {
8885            AppWindowToken wtoken = appTokens.get(i);
8886            if (!wtoken.allDrawn) {
8887                int numInteresting = wtoken.numInterestingWindows;
8888                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8889                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
8890                            "allDrawn: " + wtoken
8891                            + " interesting=" + numInteresting
8892                            + " drawn=" + wtoken.numDrawnWindows);
8893                    wtoken.allDrawn = true;
8894                }
8895            }
8896        }
8897    }
8898
8899    // "Something has changed!  Let's make it correct now."
8900    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
8901        if (DEBUG_WINDOW_TRACE) {
8902            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8903                    + Debug.getCallers(3));
8904        }
8905
8906        final long currentTime = SystemClock.uptimeMillis();
8907
8908        int i;
8909
8910        if (mFocusMayChange) {
8911            mFocusMayChange = false;
8912            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8913                    false /*updateInputWindows*/);
8914        }
8915
8916        // Initialize state of exiting tokens.
8917        for (i=mExitingTokens.size()-1; i>=0; i--) {
8918            mExitingTokens.get(i).hasVisible = false;
8919        }
8920
8921        // Initialize state of exiting applications.
8922        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8923            mExitingAppTokens.get(i).hasVisible = false;
8924        }
8925
8926        mInnerFields.mHoldScreen = null;
8927        mInnerFields.mScreenBrightness = -1;
8928        mInnerFields.mButtonBrightness = -1;
8929        mTransactionSequence++;
8930
8931        final DisplayContent defaultDisplay = getDefaultDisplayContentLocked();
8932        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
8933        final int defaultDw = defaultInfo.logicalWidth;
8934        final int defaultDh = defaultInfo.logicalHeight;
8935
8936        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8937                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8938        Surface.openTransaction();
8939        try {
8940
8941            if (mWatermark != null) {
8942                mWatermark.positionSurface(defaultDw, defaultDh);
8943            }
8944            if (mStrictModeFlash != null) {
8945                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
8946            }
8947
8948            // Give the display manager a chance to adjust properties
8949            // like display rotation if it needs to.
8950            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
8951
8952            boolean focusDisplayed = false;
8953            boolean updateAllDrawn = false;
8954
8955            DisplayContentsIterator iterator = new DisplayContentsIterator();
8956            while (iterator.hasNext()) {
8957                final DisplayContent displayContent = iterator.next();
8958                WindowList windows = displayContent.getWindowList();
8959                DisplayInfo displayInfo = displayContent.getDisplayInfo();
8960                final int displayId = displayContent.getDisplayId();
8961                final int dw = displayInfo.logicalWidth;
8962                final int dh = displayInfo.logicalHeight;
8963                final int innerDw = displayInfo.appWidth;
8964                final int innerDh = displayInfo.appHeight;
8965                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
8966
8967                int repeats = 0;
8968                do {
8969                    repeats++;
8970                    if (repeats > 6) {
8971                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
8972                        displayContent.layoutNeeded = false;
8973                        break;
8974                    }
8975
8976                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
8977                        displayContent.pendingLayoutChanges);
8978
8979                    if (isDefaultDisplay && ((displayContent.pendingLayoutChanges
8980                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0)
8981                            && ((adjustWallpaperWindowsLocked()
8982                                    & ADJUST_WALLPAPER_LAYERS_CHANGED) != 0)) {
8983                        assignLayersLocked(windows);
8984                        displayContent.layoutNeeded = true;
8985                    }
8986
8987                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
8988                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
8989                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
8990                        if (updateOrientationFromAppTokensLocked(true)) {
8991                            displayContent.layoutNeeded = true;
8992                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8993                        }
8994                    }
8995
8996                    if ((displayContent.pendingLayoutChanges
8997                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8998                        displayContent.layoutNeeded = true;
8999                    }
9000
9001                    // FIRST LOOP: Perform a layout, if needed.
9002                    if (repeats < 4) {
9003                        performLayoutLockedInner(displayContent, repeats == 1,
9004                                false /*updateInputWindows*/);
9005                    } else {
9006                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
9007                    }
9008
9009                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
9010                    // it is animating.
9011                    displayContent.pendingLayoutChanges = 0;
9012
9013                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
9014                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
9015
9016                    if (isDefaultDisplay) {
9017                        mPolicy.beginPostLayoutPolicyLw(dw, dh);
9018                        for (i = windows.size() - 1; i >= 0; i--) {
9019                            WindowState w = windows.get(i);
9020                            if (w.mHasSurface) {
9021                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
9022                            }
9023                        }
9024                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
9025                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
9026                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
9027                    }
9028                } while (displayContent.pendingLayoutChanges != 0);
9029
9030                mInnerFields.mObscured = false;
9031                mInnerFields.mDimming = false;
9032                mInnerFields.mSyswin = false;
9033
9034                // Only used if default window
9035                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
9036
9037                final int N = windows.size();
9038                for (i=N-1; i>=0; i--) {
9039                    WindowState w = windows.get(i);
9040
9041                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
9042
9043                    // Update effect.
9044                    w.mObscured = mInnerFields.mObscured;
9045                    if (!mInnerFields.mObscured) {
9046                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
9047                    }
9048
9049                    if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
9050                            && w.isVisibleLw()) {
9051                        // This is the wallpaper target and its obscured state
9052                        // changed... make sure the current wallaper's visibility
9053                        // has been updated accordingly.
9054                        updateWallpaperVisibilityLocked();
9055                    }
9056
9057                    final WindowStateAnimator winAnimator = w.mWinAnimator;
9058
9059                    // If the window has moved due to its containing
9060                    // content frame changing, then we'd like to animate
9061                    // it.
9062                    if (w.mHasSurface && w.shouldAnimateMove()) {
9063                        // Frame has moved, containing content frame
9064                        // has also moved, and we're not currently animating...
9065                        // let's do something.
9066                        Animation a = AnimationUtils.loadAnimation(mContext,
9067                                com.android.internal.R.anim.window_move_from_decor);
9068                        winAnimator.setAnimation(a);
9069                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
9070                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
9071                        try {
9072                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
9073                        } catch (RemoteException e) {
9074                        }
9075                    }
9076
9077                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
9078                    w.mContentChanged = false;
9079
9080                    // Moved from updateWindowsAndWallpaperLocked().
9081                    if (w.mHasSurface) {
9082                        // Take care of the window being ready to display.
9083                        final boolean committed =
9084                                winAnimator.commitFinishDrawingLocked(currentTime);
9085                        if (isDefaultDisplay && committed) {
9086                            if ((w.mAttrs.flags
9087                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
9088                                if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
9089                                        "First draw done in potential wallpaper target " + w);
9090                                mInnerFields.mWallpaperMayChange = true;
9091                                displayContent.pendingLayoutChanges |=
9092                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9093                                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
9094                                    debugLayoutRepeats(
9095                                        "wallpaper and commitFinishDrawingLocked true",
9096                                        displayContent.pendingLayoutChanges);
9097                                }
9098                            }
9099                        }
9100
9101                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
9102
9103                        final AppWindowToken atoken = w.mAppToken;
9104                        if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) {
9105                            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
9106                                + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
9107                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
9108                        }
9109                        if (atoken != null
9110                                && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
9111                            if (atoken.lastTransactionSequence != mTransactionSequence) {
9112                                atoken.lastTransactionSequence = mTransactionSequence;
9113                                atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
9114                                atoken.startingDisplayed = false;
9115                            }
9116                            if ((w.isOnScreen() || winAnimator.mAttrType
9117                                    == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
9118                                    && !w.mExiting && !w.mDestroying) {
9119                                if (WindowManagerService.DEBUG_VISIBILITY ||
9120                                        WindowManagerService.DEBUG_ORIENTATION) {
9121                                    Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
9122                                            + ", isAnimating=" + winAnimator.isAnimating());
9123                                    if (!w.isDrawnLw()) {
9124                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
9125                                                + " pv=" + w.mPolicyVisibility
9126                                                + " mDrawState=" + winAnimator.mDrawState
9127                                                + " ah=" + w.mAttachedHidden
9128                                                + " th=" + atoken.hiddenRequested
9129                                                + " a=" + winAnimator.mAnimating);
9130                                    }
9131                                }
9132                                if (w != atoken.startingWindow) {
9133                                    if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
9134                                        atoken.numInterestingWindows++;
9135                                        if (w.isDrawnLw()) {
9136                                            atoken.numDrawnWindows++;
9137                                            if (WindowManagerService.DEBUG_VISIBILITY ||
9138                                                    WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
9139                                                    "tokenMayBeDrawn: " + atoken
9140                                                    + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
9141                                                    + " mAppFreezing=" + w.mAppFreezing);
9142                                            updateAllDrawn = true;
9143                                        }
9144                                    }
9145                                } else if (w.isDrawnLw()) {
9146                                    atoken.startingDisplayed = true;
9147                                }
9148                            }
9149                        }
9150                    }
9151
9152                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
9153                            && w.isDisplayedLw()) {
9154                        focusDisplayed = true;
9155                    }
9156
9157                    updateResizingWindows(w);
9158                }
9159
9160                if (!mInnerFields.mDimming && mAnimator.isDimmingLocked(displayId)) {
9161                    stopDimmingLocked(displayId);
9162                }
9163            }
9164
9165            if (updateAllDrawn) {
9166                updateAllDrawnLocked();
9167            }
9168
9169            if (focusDisplayed) {
9170                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
9171            }
9172        } catch (RuntimeException e) {
9173            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
9174        } finally {
9175            Surface.closeTransaction();
9176        }
9177
9178        final WindowList defaultWindows = defaultDisplay.getWindowList();
9179
9180        // If we are ready to perform an app transition, check through
9181        // all of the app tokens to be shown and see if they are ready
9182        // to go.
9183        if (mAppTransitionReady) {
9184            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
9185            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
9186                defaultDisplay.pendingLayoutChanges);
9187        }
9188
9189        mInnerFields.mAdjResult = 0;
9190
9191        if (!mAnimator.mAnimating && mAppTransitionRunning) {
9192            // We have finished the animation of an app transition.  To do
9193            // this, we have delayed a lot of operations like showing and
9194            // hiding apps, moving apps in Z-order, etc.  The app token list
9195            // reflects the correct Z-order, but the window list may now
9196            // be out of sync with it.  So here we will just rebuild the
9197            // entire app window list.  Fun!
9198            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
9199            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
9200                defaultDisplay.pendingLayoutChanges);
9201        }
9202
9203        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
9204                && !mAppTransitionReady) {
9205            // At this point, there was a window with a wallpaper that
9206            // was force hiding other windows behind it, but now it
9207            // is going away.  This may be simple -- just animate
9208            // away the wallpaper and its window -- or it may be
9209            // hard -- the wallpaper now needs to be shown behind
9210            // something that was hidden.
9211            defaultDisplay.pendingLayoutChanges |= animateAwayWallpaperLocked();
9212            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
9213                defaultDisplay.pendingLayoutChanges);
9214        }
9215        mInnerFields.mWallpaperForceHidingChanged = false;
9216
9217        if (mInnerFields.mWallpaperMayChange) {
9218            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
9219                    "Wallpaper may change!  Adjusting");
9220            mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
9221        }
9222
9223        if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
9224            if (DEBUG_WALLPAPER) Slog.v(TAG,
9225                    "Wallpaper layer changed: assigning layers + relayout");
9226            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9227            assignLayersLocked(defaultWindows);
9228        } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
9229            if (DEBUG_WALLPAPER) Slog.v(TAG,
9230                    "Wallpaper visibility changed: relayout");
9231            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9232        }
9233
9234        if (mFocusMayChange) {
9235            mFocusMayChange = false;
9236            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
9237                    false /*updateInputWindows*/)) {
9238                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
9239                mInnerFields.mAdjResult = 0;
9240            }
9241        }
9242
9243        if (needsLayout()) {
9244            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9245            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
9246                    defaultDisplay.pendingLayoutChanges);
9247        }
9248
9249        if (!mResizingWindows.isEmpty()) {
9250            for (i = mResizingWindows.size() - 1; i >= 0; i--) {
9251                WindowState win = mResizingWindows.get(i);
9252                final WindowStateAnimator winAnimator = win.mWinAnimator;
9253                try {
9254                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
9255                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
9256                    int diff = 0;
9257                    boolean configChanged = win.isConfigChanged();
9258                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
9259                            && configChanged) {
9260                        Slog.i(TAG, "Sending new config to window " + win + ": "
9261                                + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
9262                                + " / " + mCurConfiguration + " / 0x"
9263                                + Integer.toHexString(diff));
9264                    }
9265                    win.mConfiguration = mCurConfiguration;
9266                    if (DEBUG_ORIENTATION &&
9267                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
9268                            TAG, "Resizing " + win + " WITH DRAW PENDING");
9269                    win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets,
9270                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
9271                            configChanged ? win.mConfiguration : null);
9272                    win.mContentInsetsChanged = false;
9273                    win.mVisibleInsetsChanged = false;
9274                    winAnimator.mSurfaceResized = false;
9275                } catch (RemoteException e) {
9276                    win.mOrientationChanging = false;
9277                }
9278            }
9279            mResizingWindows.clear();
9280        }
9281
9282        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
9283                "With display frozen, orientationChangeComplete="
9284                + mInnerFields.mOrientationChangeComplete);
9285        if (mInnerFields.mOrientationChangeComplete) {
9286            if (mWindowsFreezingScreen) {
9287                mWindowsFreezingScreen = false;
9288                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
9289            }
9290            stopFreezingDisplayLocked();
9291        }
9292
9293        // Destroy the surface of any windows that are no longer visible.
9294        boolean wallpaperDestroyed = false;
9295        i = mDestroySurface.size();
9296        if (i > 0) {
9297            do {
9298                i--;
9299                WindowState win = mDestroySurface.get(i);
9300                win.mDestroying = false;
9301                if (mInputMethodWindow == win) {
9302                    mInputMethodWindow = null;
9303                }
9304                if (win == mWallpaperTarget) {
9305                    wallpaperDestroyed = true;
9306                }
9307                win.mWinAnimator.destroySurfaceLocked();
9308            } while (i > 0);
9309            mDestroySurface.clear();
9310        }
9311
9312        // Time to remove any exiting tokens?
9313        for (i=mExitingTokens.size()-1; i>=0; i--) {
9314            WindowToken token = mExitingTokens.get(i);
9315            if (!token.hasVisible) {
9316                mExitingTokens.remove(i);
9317                if (token.windowType == TYPE_WALLPAPER) {
9318                    mWallpaperTokens.remove(token);
9319                    updateLayoutToAnimWallpaperTokens();
9320                }
9321            }
9322        }
9323
9324        // Time to remove any exiting applications?
9325        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
9326            AppWindowToken token = mExitingAppTokens.get(i);
9327            if (!token.hasVisible && !mClosingApps.contains(token)) {
9328                // Make sure there is no animation running on this token,
9329                // so any windows associated with it will be removed as
9330                // soon as their animations are complete
9331                token.mAppAnimator.clearAnimation();
9332                token.mAppAnimator.animating = false;
9333                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
9334                        "performLayout: App token exiting now removed" + token);
9335                mAppTokens.remove(token);
9336                mAnimatingAppTokens.remove(token);
9337                mExitingAppTokens.remove(i);
9338            }
9339        }
9340
9341        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
9342            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
9343                try {
9344                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
9345                } catch (RemoteException e) {
9346                }
9347            }
9348            mRelayoutWhileAnimating.clear();
9349        }
9350
9351        if (wallpaperDestroyed && (adjustWallpaperWindowsLocked() != 0)) {
9352            getDefaultDisplayContentLocked().layoutNeeded = true;
9353        }
9354
9355        DisplayContentsIterator iterator = new DisplayContentsIterator();
9356        while (iterator.hasNext()) {
9357            DisplayContent displayContent = iterator.next();
9358            if (displayContent.pendingLayoutChanges != 0) {
9359                displayContent.layoutNeeded = true;
9360            }
9361        }
9362
9363        // Finally update all input windows now that the window changes have stabilized.
9364        mInputMonitor.updateInputWindowsLw(true /*force*/);
9365
9366        setHoldScreenLocked(mInnerFields.mHoldScreen);
9367        if (!mDisplayFrozen) {
9368            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
9369                mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
9370            } else {
9371                mPowerManager.setScreenBrightnessOverrideFromWindowManager(
9372                        toBrightnessOverride(mInnerFields.mScreenBrightness));
9373            }
9374            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
9375                mPowerManager.setButtonBrightnessOverrideFromWindowManager(-1);
9376            } else {
9377                mPowerManager.setButtonBrightnessOverrideFromWindowManager(
9378                        toBrightnessOverride(mInnerFields.mButtonBrightness));
9379            }
9380        }
9381
9382        if (mTurnOnScreen) {
9383            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
9384            mPowerManager.wakeUp(SystemClock.uptimeMillis());
9385            mTurnOnScreen = false;
9386        }
9387
9388        if (mInnerFields.mUpdateRotation) {
9389            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9390            if (updateRotationUncheckedLocked(false)) {
9391                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9392            } else {
9393                mInnerFields.mUpdateRotation = false;
9394            }
9395        }
9396
9397        if (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded
9398                && !mInnerFields.mUpdateRotation) {
9399            checkDrawnWindowsLocked();
9400        }
9401
9402        final int N = mPendingRemove.size();
9403        if (N > 0) {
9404            if (mPendingRemoveTmp.length < N) {
9405                mPendingRemoveTmp = new WindowState[N+10];
9406            }
9407            mPendingRemove.toArray(mPendingRemoveTmp);
9408            mPendingRemove.clear();
9409            DisplayContentList displayList = new DisplayContentList();
9410            for (i = 0; i < N; i++) {
9411                WindowState w = mPendingRemoveTmp[i];
9412                removeWindowInnerLocked(w.mSession, w);
9413                if (!displayList.contains(w.mDisplayContent)) {
9414                    displayList.add(w.mDisplayContent);
9415                }
9416            }
9417
9418            for (DisplayContent displayContent : displayList) {
9419                assignLayersLocked(displayContent.getWindowList());
9420                displayContent.layoutNeeded = true;
9421            }
9422        }
9423
9424        // Check to see if we are now in a state where the screen should
9425        // be enabled, because the window obscured flags have changed.
9426        enableScreenIfNeededLocked();
9427
9428        updateLayoutToAnimationLocked();
9429
9430        if (DEBUG_WINDOW_TRACE) {
9431            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
9432                    + mAnimator.mAnimating);
9433        }
9434    }
9435
9436    private int toBrightnessOverride(float value) {
9437        return (int)(value * PowerManager.BRIGHTNESS_ON);
9438    }
9439
9440    void checkDrawnWindowsLocked() {
9441        if (mWaitingForDrawn.size() > 0) {
9442            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
9443                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
9444                WindowState win = pair.first;
9445                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
9446                //        + win.mRemoved + " visible=" + win.isVisibleLw()
9447                //        + " shown=" + win.mSurfaceShown);
9448                if (win.mRemoved || !win.isVisibleLw()) {
9449                    // Window has been removed or made invisible; no draw
9450                    // will now happen, so stop waiting.
9451                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
9452                    try {
9453                        pair.second.sendResult(null);
9454                    } catch (RemoteException e) {
9455                    }
9456                    mWaitingForDrawn.remove(pair);
9457                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9458                } else if (win.mWinAnimator.mSurfaceShown) {
9459                    // Window is now drawn (and shown).
9460                    try {
9461                        pair.second.sendResult(null);
9462                    } catch (RemoteException e) {
9463                    }
9464                    mWaitingForDrawn.remove(pair);
9465                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9466                }
9467            }
9468        }
9469    }
9470
9471    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
9472        synchronized (mWindowMap) {
9473            WindowState win = windowForClientLocked(null, token, true);
9474            if (win != null) {
9475                Pair<WindowState, IRemoteCallback> pair =
9476                        new Pair<WindowState, IRemoteCallback>(win, callback);
9477                Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9478                mH.sendMessageDelayed(m, 2000);
9479                mWaitingForDrawn.add(pair);
9480                checkDrawnWindowsLocked();
9481            }
9482        }
9483    }
9484
9485    void setHoldScreenLocked(final Session newHoldScreen) {
9486        final boolean hold = newHoldScreen != null;
9487
9488        if (hold && mHoldingScreenOn != newHoldScreen) {
9489            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
9490        }
9491        mHoldingScreenOn = newHoldScreen;
9492
9493        final boolean state = mHoldingScreenWakeLock.isHeld();
9494        if (hold != state) {
9495            if (hold) {
9496                mPolicy.screenOnStartedLw();
9497                mHoldingScreenWakeLock.acquire();
9498            } else {
9499                mPolicy.screenOnStoppedLw();
9500                mHoldingScreenWakeLock.release();
9501            }
9502        }
9503    }
9504
9505    @Override
9506    public void requestTraversal() {
9507        synchronized (mWindowMap) {
9508            requestTraversalLocked();
9509        }
9510    }
9511
9512    void requestTraversalLocked() {
9513        if (!mTraversalScheduled) {
9514            mTraversalScheduled = true;
9515            mH.sendEmptyMessage(H.DO_TRAVERSAL);
9516        }
9517    }
9518
9519    /** Note that Locked in this case is on mLayoutToAnim */
9520    void scheduleAnimationLocked() {
9521        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
9522        if (!layoutToAnim.mAnimationScheduled) {
9523            layoutToAnim.mAnimationScheduled = true;
9524            mChoreographer.postCallback(
9525                    Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
9526        }
9527    }
9528
9529    void updateLayoutToAnimationLocked() {
9530        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
9531        synchronized (layoutToAnim) {
9532            // Copy local params to transfer params.
9533            SparseArray<WinAnimatorList> allWinAnimatorLists = layoutToAnim.mWinAnimatorLists;
9534            allWinAnimatorLists.clear();
9535            DisplayContentsIterator iterator = new DisplayContentsIterator();
9536            while (iterator.hasNext()) {
9537                final DisplayContent displayContent = iterator.next();
9538                WinAnimatorList winAnimatorList = new WinAnimatorList();
9539                final WindowList windows = displayContent.getWindowList();
9540                int N = windows.size();
9541                for (int i = 0; i < N; i++) {
9542                    final WindowStateAnimator winAnimator = windows.get(i).mWinAnimator;
9543                    if (winAnimator.mSurface != null) {
9544                        winAnimatorList.add(winAnimator);
9545                    }
9546                }
9547                allWinAnimatorLists.put(displayContent.getDisplayId(), winAnimatorList);
9548            }
9549
9550            layoutToAnim.mWallpaperTarget = mWallpaperTarget;
9551            layoutToAnim.mLowerWallpaperTarget = mLowerWallpaperTarget;
9552            layoutToAnim.mUpperWallpaperTarget = mUpperWallpaperTarget;
9553
9554            final ArrayList<AppWindowAnimParams> paramList = layoutToAnim.mAppWindowAnimParams;
9555            paramList.clear();
9556            int N = mAnimatingAppTokens.size();
9557            for (int i = 0; i < N; i++) {
9558                paramList.add(new AppWindowAnimParams(mAnimatingAppTokens.get(i).mAppAnimator));
9559            }
9560
9561            layoutToAnim.mParamsModified = true;
9562            scheduleAnimationLocked();
9563        }
9564    }
9565
9566    void updateLayoutToAnimWallpaperTokens() {
9567        synchronized(mLayoutToAnim) {
9568            mLayoutToAnim.mWallpaperTokens = new ArrayList<WindowToken>(mWallpaperTokens);
9569            mLayoutToAnim.mChanges |= LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED;
9570        }
9571    }
9572
9573    void setAnimDimParams(int displayId, DimAnimator.Parameters params) {
9574        synchronized (mLayoutToAnim) {
9575            mLayoutToAnim.mDimParams.put(displayId, params);
9576            scheduleAnimationLocked();
9577        }
9578    }
9579
9580    void startDimmingLocked(final WindowStateAnimator winAnimator, final float target,
9581                      final int width, final int height) {
9582        setAnimDimParams(winAnimator.mWin.getDisplayId(),
9583                new DimAnimator.Parameters(winAnimator, width, height, target));
9584    }
9585
9586    void stopDimmingLocked(int displayId) {
9587        setAnimDimParams(displayId, null);
9588    }
9589
9590    private boolean needsLayout() {
9591        DisplayContentsIterator iterator = new DisplayContentsIterator();
9592        while (iterator.hasNext()) {
9593            if (iterator.next().layoutNeeded) {
9594                return true;
9595            }
9596        }
9597        return false;
9598    }
9599
9600    private boolean copyAnimToLayoutParamsLocked() {
9601        boolean doRequest = false;
9602        final WindowAnimator.AnimatorToLayoutParams animToLayout = mAnimator.mAnimToLayout;
9603        synchronized (animToLayout) {
9604            animToLayout.mUpdateQueued = false;
9605            final int bulkUpdateParams = animToLayout.mBulkUpdateParams;
9606            // TODO(cmautner): As the number of bits grows, use masks of bit groups to
9607            //  eliminate unnecessary tests.
9608            if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
9609                mInnerFields.mUpdateRotation = true;
9610                doRequest = true;
9611            }
9612            if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
9613                mInnerFields.mWallpaperMayChange = true;
9614                doRequest = true;
9615            }
9616            if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
9617                mInnerFields.mWallpaperForceHidingChanged = true;
9618                doRequest = true;
9619            }
9620            if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
9621                mInnerFields.mOrientationChangeComplete = false;
9622            } else {
9623                mInnerFields.mOrientationChangeComplete = true;
9624                if (mWindowsFreezingScreen) {
9625                    doRequest = true;
9626                }
9627            }
9628            if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
9629                mTurnOnScreen = true;
9630            }
9631
9632            SparseIntArray pendingLayouts = animToLayout.mPendingLayoutChanges;
9633            final int count = pendingLayouts.size();
9634            if (count > 0) {
9635                doRequest = true;
9636            }
9637            for (int i = 0; i < count; ++i) {
9638                final DisplayContent displayContent =
9639                        getDisplayContentLocked(pendingLayouts.keyAt(i));
9640                displayContent.pendingLayoutChanges |= pendingLayouts.valueAt(i);
9641            }
9642
9643            mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper;
9644        }
9645        return doRequest;
9646    }
9647
9648    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
9649                                           boolean secure) {
9650        final Surface surface = winAnimator.mSurface;
9651        boolean leakedSurface = false;
9652        boolean killedApps = false;
9653
9654        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
9655                winAnimator.mSession.mPid, operation);
9656
9657        if (mForceRemoves == null) {
9658            mForceRemoves = new ArrayList<WindowState>();
9659        }
9660
9661        long callingIdentity = Binder.clearCallingIdentity();
9662        try {
9663            // There was some problem...   first, do a sanity check of the
9664            // window list to make sure we haven't left any dangling surfaces
9665            // around.
9666
9667            AllWindowsIterator iterator = new AllWindowsIterator();
9668            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
9669            while (iterator.hasNext()) {
9670                WindowState ws = iterator.next();
9671                WindowStateAnimator wsa = ws.mWinAnimator;
9672                if (wsa.mSurface != null) {
9673                    if (!mSessions.contains(wsa.mSession)) {
9674                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
9675                                + ws + " surface=" + wsa.mSurface
9676                                + " token=" + ws.mToken
9677                                + " pid=" + ws.mSession.mPid
9678                                + " uid=" + ws.mSession.mUid);
9679                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9680                        wsa.mSurface.destroy();
9681                        wsa.mSurfaceShown = false;
9682                        wsa.mSurface = null;
9683                        ws.mHasSurface = false;
9684                        mForceRemoves.add(ws);
9685                        leakedSurface = true;
9686                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
9687                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
9688                                + ws + " surface=" + wsa.mSurface
9689                                + " token=" + ws.mAppToken);
9690                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9691                        wsa.mSurface.destroy();
9692                        wsa.mSurfaceShown = false;
9693                        wsa.mSurface = null;
9694                        ws.mHasSurface = false;
9695                        leakedSurface = true;
9696                    }
9697                }
9698            }
9699
9700            if (!leakedSurface) {
9701                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
9702                SparseIntArray pidCandidates = new SparseIntArray();
9703                iterator = new AllWindowsIterator();
9704                while (iterator.hasNext()) {
9705                    WindowState ws = iterator.next();
9706                    if (mForceRemoves.contains(ws)) {
9707                        continue;
9708                    }
9709                    WindowStateAnimator wsa = ws.mWinAnimator;
9710                    if (wsa.mSurface != null) {
9711                        pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
9712                    }
9713                }
9714                if (pidCandidates.size() > 0) {
9715                    int[] pids = new int[pidCandidates.size()];
9716                    for (int i=0; i<pids.length; i++) {
9717                        pids[i] = pidCandidates.keyAt(i);
9718                    }
9719                    try {
9720                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
9721                            killedApps = true;
9722                        }
9723                    } catch (RemoteException e) {
9724                    }
9725                }
9726            }
9727
9728            if (leakedSurface || killedApps) {
9729                // We managed to reclaim some memory, so get rid of the trouble
9730                // surface and ask the app to request another one.
9731                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9732                if (surface != null) {
9733                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
9734                            "RECOVER DESTROY", null);
9735                    surface.destroy();
9736                    winAnimator.mSurfaceShown = false;
9737                    winAnimator.mSurface = null;
9738                    winAnimator.mWin.mHasSurface = false;
9739                }
9740
9741                try {
9742                    winAnimator.mWin.mClient.dispatchGetNewSurface();
9743                } catch (RemoteException e) {
9744                }
9745            }
9746        } finally {
9747            Binder.restoreCallingIdentity(callingIdentity);
9748        }
9749
9750        return leakedSurface || killedApps;
9751    }
9752
9753    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9754        WindowState newFocus = computeFocusedWindowLocked();
9755        if (mCurrentFocus != newFocus) {
9756            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
9757            // This check makes sure that we don't already have the focus
9758            // change message pending.
9759            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9760            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9761            if (localLOGV) Slog.v(
9762                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
9763            final WindowState oldFocus = mCurrentFocus;
9764            mCurrentFocus = newFocus;
9765            mAnimator.setCurrentFocus(newFocus);
9766            mLosingFocus.remove(newFocus);
9767            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9768
9769            // TODO(multidisplay): Focused windows on default display only.
9770            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9771
9772            final WindowState imWindow = mInputMethodWindow;
9773            if (newFocus != imWindow && oldFocus != imWindow) {
9774                if (moveInputMethodWindowsIfNeededLocked(
9775                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
9776                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
9777                    getDefaultDisplayContentLocked().layoutNeeded = true;
9778                }
9779                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9780                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9781                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9782                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9783                    // Client will do the layout, but we need to assign layers
9784                    // for handleNewWindowLocked() below.
9785                    assignLayersLocked(displayContent.getWindowList());
9786                }
9787            }
9788
9789            if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9790                // The change in focus caused us to need to do a layout.  Okay.
9791                getDefaultDisplayContentLocked().layoutNeeded = true;
9792                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9793                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9794                }
9795            }
9796
9797            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9798                // If we defer assigning layers, then the caller is responsible for
9799                // doing this part.
9800                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9801            }
9802
9803            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
9804            return true;
9805        }
9806        return false;
9807    }
9808
9809    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9810        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9811    }
9812
9813    private WindowState computeFocusedWindowLocked() {
9814        WindowState result = null;
9815        WindowState win;
9816
9817        if (mAnimator.mUniverseBackground != null
9818                && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) {
9819            return mAnimator.mUniverseBackground.mWin;
9820        }
9821
9822        int nextAppIndex = mAppTokens.size()-1;
9823        WindowToken nextApp = nextAppIndex >= 0
9824            ? mAppTokens.get(nextAppIndex) : null;
9825
9826        // TODO(multidisplay): IMEs are only supported on the default display.
9827        WindowList windows = getDefaultWindowListLocked();
9828        for (int i = windows.size() - 1; i >= 0; i--) {
9829            win = windows.get(i);
9830
9831            if (localLOGV || DEBUG_FOCUS) Slog.v(
9832                TAG, "Looking for focus: " + i
9833                + " = " + win
9834                + ", flags=" + win.mAttrs.flags
9835                + ", canReceive=" + win.canReceiveKeys());
9836
9837            AppWindowToken thisApp = win.mAppToken;
9838
9839            // If this window's application has been removed, just skip it.
9840            if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
9841                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping app because " + (thisApp.removed
9842                        ? "removed" : "sendingToBottom"));
9843                continue;
9844            }
9845
9846            // If there is a focused app, don't allow focus to go to any
9847            // windows below it.  If this is an application window, step
9848            // through the app tokens until we find its app.
9849            if (thisApp != null && nextApp != null && thisApp != nextApp
9850                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
9851                int origAppIndex = nextAppIndex;
9852                while (nextAppIndex > 0) {
9853                    if (nextApp == mFocusedApp) {
9854                        // Whoops, we are below the focused app...  no focus
9855                        // for you!
9856                        if (localLOGV || DEBUG_FOCUS) Slog.v(
9857                            TAG, "Reached focused app: " + mFocusedApp);
9858                        return null;
9859                    }
9860                    nextAppIndex--;
9861                    nextApp = mAppTokens.get(nextAppIndex);
9862                    if (nextApp == thisApp) {
9863                        break;
9864                    }
9865                }
9866                if (thisApp != nextApp) {
9867                    // Uh oh, the app token doesn't exist!  This shouldn't
9868                    // happen, but if it does we can get totally hosed...
9869                    // so restart at the original app.
9870                    nextAppIndex = origAppIndex;
9871                    nextApp = mAppTokens.get(nextAppIndex);
9872                }
9873            }
9874
9875            // Dispatch to this window if it is wants key events.
9876            if (win.canReceiveKeys()) {
9877                if (DEBUG_FOCUS) Slog.v(
9878                        TAG, "Found focus @ " + i + " = " + win);
9879                result = win;
9880                break;
9881            }
9882        }
9883
9884        return result;
9885    }
9886
9887    private void startFreezingDisplayLocked(boolean inTransaction,
9888            int exitAnim, int enterAnim) {
9889        if (mDisplayFrozen) {
9890            return;
9891        }
9892
9893        if (!mDisplayReady || !mPolicy.isScreenOnFully()) {
9894            // No need to freeze the screen before the system is ready or if
9895            // the screen is off.
9896            return;
9897        }
9898
9899        mScreenFrozenLock.acquire();
9900
9901        mDisplayFrozen = true;
9902
9903        mInputMonitor.freezeInputDispatchingLw();
9904
9905        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
9906            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
9907            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
9908            mNextAppTransitionPackage = null;
9909            mNextAppTransitionThumbnail = null;
9910            mAppTransitionReady = true;
9911        }
9912
9913        if (PROFILE_ORIENTATION) {
9914            File file = new File("/data/system/frozen");
9915            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9916        }
9917
9918        if (CUSTOM_SCREEN_ROTATION) {
9919            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9920            final int displayId = displayContent.getDisplayId();
9921            ScreenRotationAnimation screenRotationAnimation =
9922                    mAnimator.getScreenRotationAnimationLocked(displayId);
9923            if (screenRotationAnimation != null) {
9924                screenRotationAnimation.kill();
9925            }
9926
9927            // TODO(multidisplay): rotation on main screen only.
9928            final Display display = displayContent.getDisplay();
9929            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
9930            screenRotationAnimation = new ScreenRotationAnimation(mContext,
9931                    display, mFxSession, inTransaction, displayInfo.logicalWidth,
9932                    displayInfo.logicalHeight, display.getRotation(),
9933                    exitAnim, enterAnim);
9934            mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9935        }
9936    }
9937
9938    private void stopFreezingDisplayLocked() {
9939        if (!mDisplayFrozen) {
9940            return;
9941        }
9942
9943        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
9944                || mClientFreezingScreen) {
9945            if (DEBUG_ORIENTATION) Slog.d(TAG,
9946                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
9947                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
9948                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
9949                + ", mClientFreezingScreen=" + mClientFreezingScreen);
9950            return;
9951        }
9952
9953        mDisplayFrozen = false;
9954        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9955        mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
9956        if (PROFILE_ORIENTATION) {
9957            Debug.stopMethodTracing();
9958        }
9959
9960        boolean updateRotation = false;
9961
9962        final DisplayContent displayContent = getDefaultDisplayContentLocked();
9963        final int displayId = displayContent.getDisplayId();
9964        ScreenRotationAnimation screenRotationAnimation =
9965                mAnimator.getScreenRotationAnimationLocked(displayId);
9966        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
9967                && screenRotationAnimation.hasScreenshot()) {
9968            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
9969            // TODO(multidisplay): rotation on main screen only.
9970            DisplayInfo displayInfo = displayContent.getDisplayInfo();
9971            if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9972                    mTransitionAnimationScale, displayInfo.logicalWidth,
9973                        displayInfo.logicalHeight)) {
9974                updateLayoutToAnimationLocked();
9975            } else {
9976                screenRotationAnimation.kill();
9977                screenRotationAnimation = null;
9978                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9979                updateRotation = true;
9980            }
9981        } else {
9982            if (screenRotationAnimation != null) {
9983                screenRotationAnimation.kill();
9984                screenRotationAnimation = null;
9985                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9986            }
9987            updateRotation = true;
9988        }
9989
9990        mInputMonitor.thawInputDispatchingLw();
9991
9992        boolean configChanged;
9993
9994        // While the display is frozen we don't re-compute the orientation
9995        // to avoid inconsistent states.  However, something interesting
9996        // could have actually changed during that time so re-evaluate it
9997        // now to catch that.
9998        configChanged = updateOrientationFromAppTokensLocked(false);
9999
10000        // A little kludge: a lot could have happened while the
10001        // display was frozen, so now that we are coming back we
10002        // do a gc so that any remote references the system
10003        // processes holds on others can be released if they are
10004        // no longer needed.
10005        mH.removeMessages(H.FORCE_GC);
10006        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
10007                2000);
10008
10009        mScreenFrozenLock.release();
10010
10011        if (updateRotation) {
10012            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
10013            configChanged |= updateRotationUncheckedLocked(false);
10014        }
10015
10016        if (configChanged) {
10017            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
10018        }
10019    }
10020
10021    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
10022            DisplayMetrics dm) {
10023        if (index < tokens.length) {
10024            String str = tokens[index];
10025            if (str != null && str.length() > 0) {
10026                try {
10027                    int val = Integer.parseInt(str);
10028                    return val;
10029                } catch (Exception e) {
10030                }
10031            }
10032        }
10033        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
10034            return defDps;
10035        }
10036        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
10037        return val;
10038    }
10039
10040    void createWatermarkInTransaction() {
10041        if (mWatermark != null) {
10042            return;
10043        }
10044
10045        File file = new File("/system/etc/setup.conf");
10046        FileInputStream in = null;
10047        try {
10048            in = new FileInputStream(file);
10049            DataInputStream ind = new DataInputStream(in);
10050            String line = ind.readLine();
10051            if (line != null) {
10052                String[] toks = line.split("%");
10053                if (toks != null && toks.length > 0) {
10054                    mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
10055                            mRealDisplayMetrics, mFxSession, toks);
10056                }
10057            }
10058        } catch (FileNotFoundException e) {
10059        } catch (IOException e) {
10060        } finally {
10061            if (in != null) {
10062                try {
10063                    in.close();
10064                } catch (IOException e) {
10065                }
10066            }
10067        }
10068    }
10069
10070    @Override
10071    public void statusBarVisibilityChanged(int visibility) {
10072        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
10073                != PackageManager.PERMISSION_GRANTED) {
10074            throw new SecurityException("Caller does not hold permission "
10075                    + android.Manifest.permission.STATUS_BAR);
10076        }
10077
10078        synchronized (mWindowMap) {
10079            mLastStatusBarVisibility = visibility;
10080            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
10081            updateStatusBarVisibilityLocked(visibility);
10082        }
10083    }
10084
10085    // TOOD(multidisplay): StatusBar on multiple screens?
10086    void updateStatusBarVisibilityLocked(int visibility) {
10087        mInputManager.setSystemUiVisibility(visibility);
10088        final WindowList windows = getDefaultWindowListLocked();
10089        final int N = windows.size();
10090        for (int i = 0; i < N; i++) {
10091            WindowState ws = windows.get(i);
10092            try {
10093                int curValue = ws.mSystemUiVisibility;
10094                int diff = curValue ^ visibility;
10095                // We are only interested in differences of one of the
10096                // clearable flags...
10097                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
10098                // ...if it has actually been cleared.
10099                diff &= ~visibility;
10100                int newValue = (curValue&~diff) | (visibility&diff);
10101                if (newValue != curValue) {
10102                    ws.mSeq++;
10103                    ws.mSystemUiVisibility = newValue;
10104                }
10105                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
10106                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
10107                            visibility, newValue, diff);
10108                }
10109            } catch (RemoteException e) {
10110                // so sorry
10111            }
10112        }
10113    }
10114
10115    @Override
10116    public void reevaluateStatusBarVisibility() {
10117        synchronized (mWindowMap) {
10118            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
10119            updateStatusBarVisibilityLocked(visibility);
10120            performLayoutAndPlaceSurfacesLocked();
10121        }
10122    }
10123
10124    @Override
10125    public FakeWindow addFakeWindow(Looper looper,
10126            InputEventReceiver.Factory inputEventReceiverFactory,
10127            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
10128            boolean hasFocus, boolean touchFullscreen) {
10129        synchronized (mWindowMap) {
10130            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
10131                    name, windowType,
10132                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
10133            int i=0;
10134            while (i<mFakeWindows.size()) {
10135                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
10136                    break;
10137                }
10138            }
10139            mFakeWindows.add(i, fw);
10140            mInputMonitor.updateInputWindowsLw(true);
10141            return fw;
10142        }
10143    }
10144
10145    boolean removeFakeWindowLocked(FakeWindow window) {
10146        synchronized (mWindowMap) {
10147            if (mFakeWindows.remove(window)) {
10148                mInputMonitor.updateInputWindowsLw(true);
10149                return true;
10150            }
10151            return false;
10152        }
10153    }
10154
10155    // It is assumed that this method is called only by InputMethodManagerService.
10156    public void saveLastInputMethodWindowForTransition() {
10157        synchronized (mWindowMap) {
10158            // TODO(multidisplay): Pass in the displayID.
10159            DisplayContent displayContent = getDefaultDisplayContentLocked();
10160            if (mInputMethodWindow != null) {
10161                mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
10162            }
10163        }
10164    }
10165
10166    @Override
10167    public boolean hasNavigationBar() {
10168        return mPolicy.hasNavigationBar();
10169    }
10170
10171    public void lockNow() {
10172        mPolicy.lockNow();
10173    }
10174
10175    void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
10176        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
10177        mPolicy.dump("    ", pw, args);
10178    }
10179
10180    void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
10181        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
10182        if (mTokenMap.size() > 0) {
10183            pw.println("  All tokens:");
10184            Iterator<WindowToken> it = mTokenMap.values().iterator();
10185            while (it.hasNext()) {
10186                WindowToken token = it.next();
10187                pw.print("  Token "); pw.print(token.token);
10188                if (dumpAll) {
10189                    pw.println(':');
10190                    token.dump(pw, "    ");
10191                } else {
10192                    pw.println();
10193                }
10194            }
10195        }
10196        if (mWallpaperTokens.size() > 0) {
10197            pw.println();
10198            pw.println("  Wallpaper tokens:");
10199            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
10200                WindowToken token = mWallpaperTokens.get(i);
10201                pw.print("  Wallpaper #"); pw.print(i);
10202                        pw.print(' '); pw.print(token);
10203                if (dumpAll) {
10204                    pw.println(':');
10205                    token.dump(pw, "    ");
10206                } else {
10207                    pw.println();
10208                }
10209            }
10210        }
10211        if (mAppTokens.size() > 0) {
10212            pw.println();
10213            pw.println("  Application tokens in Z order:");
10214            for (int i=mAppTokens.size()-1; i>=0; i--) {
10215                pw.print("  App #"); pw.print(i); pw.println(": ");
10216                        mAppTokens.get(i).dump(pw, "    ");
10217            }
10218        }
10219        if (mFinishedStarting.size() > 0) {
10220            pw.println();
10221            pw.println("  Finishing start of application tokens:");
10222            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
10223                WindowToken token = mFinishedStarting.get(i);
10224                pw.print("  Finished Starting #"); pw.print(i);
10225                        pw.print(' '); pw.print(token);
10226                if (dumpAll) {
10227                    pw.println(':');
10228                    token.dump(pw, "    ");
10229                } else {
10230                    pw.println();
10231                }
10232            }
10233        }
10234        if (mExitingTokens.size() > 0) {
10235            pw.println();
10236            pw.println("  Exiting tokens:");
10237            for (int i=mExitingTokens.size()-1; i>=0; i--) {
10238                WindowToken token = mExitingTokens.get(i);
10239                pw.print("  Exiting #"); pw.print(i);
10240                        pw.print(' '); pw.print(token);
10241                if (dumpAll) {
10242                    pw.println(':');
10243                    token.dump(pw, "    ");
10244                } else {
10245                    pw.println();
10246                }
10247            }
10248        }
10249        if (mExitingAppTokens.size() > 0) {
10250            pw.println();
10251            pw.println("  Exiting application tokens:");
10252            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
10253                WindowToken token = mExitingAppTokens.get(i);
10254                pw.print("  Exiting App #"); pw.print(i);
10255                        pw.print(' '); pw.print(token);
10256                if (dumpAll) {
10257                    pw.println(':');
10258                    token.dump(pw, "    ");
10259                } else {
10260                    pw.println();
10261                }
10262            }
10263        }
10264        if (mAppTransitionRunning && mAnimatingAppTokens.size() > 0) {
10265            pw.println();
10266            pw.println("  Application tokens during animation:");
10267            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
10268                WindowToken token = mAnimatingAppTokens.get(i);
10269                pw.print("  App moving to bottom #"); pw.print(i);
10270                        pw.print(' '); pw.print(token);
10271                if (dumpAll) {
10272                    pw.println(':');
10273                    token.dump(pw, "    ");
10274                } else {
10275                    pw.println();
10276                }
10277            }
10278        }
10279        if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
10280            pw.println();
10281            if (mOpeningApps.size() > 0) {
10282                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
10283            }
10284            if (mClosingApps.size() > 0) {
10285                pw.print("  mClosingApps="); pw.println(mClosingApps);
10286            }
10287        }
10288    }
10289
10290    void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
10291        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
10292        if (mSessions.size() > 0) {
10293            Iterator<Session> it = mSessions.iterator();
10294            while (it.hasNext()) {
10295                Session s = it.next();
10296                pw.print("  Session "); pw.print(s); pw.println(':');
10297                s.dump(pw, "    ");
10298            }
10299        }
10300    }
10301
10302    void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
10303            ArrayList<WindowState> windows) {
10304        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
10305        dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
10306    }
10307
10308    void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
10309            ArrayList<WindowState> windows) {
10310        int j = 0;
10311        final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10312        while (iterator.hasNext()) {
10313            final WindowState w = iterator.next();
10314            if (windows == null || windows.contains(w)) {
10315                pw.print("  Window #"); pw.print(j++); pw.print(' ');
10316                        pw.print(w); pw.println(":");
10317                w.dump(pw, "    ", dumpAll || windows != null);
10318            }
10319        }
10320        if (mInputMethodDialogs.size() > 0) {
10321            pw.println();
10322            pw.println("  Input method dialogs:");
10323            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
10324                WindowState w = mInputMethodDialogs.get(i);
10325                if (windows == null || windows.contains(w)) {
10326                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
10327                }
10328            }
10329        }
10330        if (mPendingRemove.size() > 0) {
10331            pw.println();
10332            pw.println("  Remove pending for:");
10333            for (int i=mPendingRemove.size()-1; i>=0; i--) {
10334                WindowState w = mPendingRemove.get(i);
10335                if (windows == null || windows.contains(w)) {
10336                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
10337                            pw.print(w);
10338                    if (dumpAll) {
10339                        pw.println(":");
10340                        w.dump(pw, "    ", true);
10341                    } else {
10342                        pw.println();
10343                    }
10344                }
10345            }
10346        }
10347        if (mForceRemoves != null && mForceRemoves.size() > 0) {
10348            pw.println();
10349            pw.println("  Windows force removing:");
10350            for (int i=mForceRemoves.size()-1; i>=0; i--) {
10351                WindowState w = mForceRemoves.get(i);
10352                pw.print("  Removing #"); pw.print(i); pw.print(' ');
10353                        pw.print(w);
10354                if (dumpAll) {
10355                    pw.println(":");
10356                    w.dump(pw, "    ", true);
10357                } else {
10358                    pw.println();
10359                }
10360            }
10361        }
10362        if (mDestroySurface.size() > 0) {
10363            pw.println();
10364            pw.println("  Windows waiting to destroy their surface:");
10365            for (int i=mDestroySurface.size()-1; i>=0; i--) {
10366                WindowState w = mDestroySurface.get(i);
10367                if (windows == null || windows.contains(w)) {
10368                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
10369                            pw.print(w);
10370                    if (dumpAll) {
10371                        pw.println(":");
10372                        w.dump(pw, "    ", true);
10373                    } else {
10374                        pw.println();
10375                    }
10376                }
10377            }
10378        }
10379        if (mLosingFocus.size() > 0) {
10380            pw.println();
10381            pw.println("  Windows losing focus:");
10382            for (int i=mLosingFocus.size()-1; i>=0; i--) {
10383                WindowState w = mLosingFocus.get(i);
10384                if (windows == null || windows.contains(w)) {
10385                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
10386                            pw.print(w);
10387                    if (dumpAll) {
10388                        pw.println(":");
10389                        w.dump(pw, "    ", true);
10390                    } else {
10391                        pw.println();
10392                    }
10393                }
10394            }
10395        }
10396        if (mResizingWindows.size() > 0) {
10397            pw.println();
10398            pw.println("  Windows waiting to resize:");
10399            for (int i=mResizingWindows.size()-1; i>=0; i--) {
10400                WindowState w = mResizingWindows.get(i);
10401                if (windows == null || windows.contains(w)) {
10402                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
10403                            pw.print(w);
10404                    if (dumpAll) {
10405                        pw.println(":");
10406                        w.dump(pw, "    ", true);
10407                    } else {
10408                        pw.println();
10409                    }
10410                }
10411            }
10412        }
10413        if (mWaitingForDrawn.size() > 0) {
10414            pw.println();
10415            pw.println("  Clients waiting for these windows to be drawn:");
10416            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
10417                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
10418                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
10419                        pw.print(": "); pw.println(pair.second);
10420            }
10421        }
10422        pw.println("  DisplayContents");
10423        if (mDisplayReady) {
10424            DisplayContentsIterator dCIterator = new DisplayContentsIterator();
10425            while (dCIterator.hasNext()) {
10426                dCIterator.next().dump("    ", pw);
10427            }
10428        } else {
10429            pw.println("  NO DISPLAY");
10430        }
10431        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
10432        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
10433        if (mLastFocus != mCurrentFocus) {
10434            pw.print("  mLastFocus="); pw.println(mLastFocus);
10435        }
10436        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
10437        if (mInputMethodTarget != null) {
10438            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
10439        }
10440        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
10441                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
10442        if (dumpAll) {
10443            pw.print("  mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
10444                    pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
10445                    pw.print(" mScreenRecr="); pw.println(mScreenRect.toShortString());
10446            if (mLastStatusBarVisibility != 0) {
10447                pw.print("  mLastStatusBarVisibility=0x");
10448                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
10449            }
10450            if (mInputMethodWindow != null) {
10451                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
10452            }
10453            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
10454            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
10455                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
10456                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
10457            }
10458            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
10459                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
10460            if (mInputMethodAnimLayerAdjustment != 0 ||
10461                    mWallpaperAnimLayerAdjustment != 0) {
10462                pw.print("  mInputMethodAnimLayerAdjustment=");
10463                        pw.print(mInputMethodAnimLayerAdjustment);
10464                        pw.print("  mWallpaperAnimLayerAdjustment=");
10465                        pw.println(mWallpaperAnimLayerAdjustment);
10466            }
10467            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
10468                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
10469            if (needsLayout()) {
10470                pw.print("  layoutNeeded on displays=");
10471                DisplayContentsIterator dcIterator = new DisplayContentsIterator();
10472                while (dcIterator.hasNext()) {
10473                    final DisplayContent displayContent = dcIterator.next();
10474                    if (displayContent.layoutNeeded) {
10475                        pw.print(displayContent.getDisplayId());
10476                    }
10477                }
10478                pw.println();
10479            }
10480            pw.print("  mTransactionSequence="); pw.println(mTransactionSequence);
10481            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
10482                    pw.print(" windows="); pw.print(mWindowsFreezingScreen);
10483                    pw.print(" client="); pw.print(mClientFreezingScreen);
10484                    pw.print(" apps="); pw.print(mAppsFreezingScreen);
10485                    pw.print(" waitingForConfig="); pw.println(mWaitingForConfig);
10486            pw.print("  mRotation="); pw.print(mRotation);
10487                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
10488            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
10489                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
10490            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
10491            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
10492                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
10493                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
10494            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
10495                    pw.print(" mNextAppTransition=0x");
10496                    pw.print(Integer.toHexString(mNextAppTransition));
10497                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
10498            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
10499                    pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout);
10500            if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) {
10501                pw.print("  mNextAppTransitionType="); pw.println(mNextAppTransitionType);
10502            }
10503            switch (mNextAppTransitionType) {
10504                case ActivityOptions.ANIM_CUSTOM:
10505                    pw.print("  mNextAppTransitionPackage=");
10506                            pw.println(mNextAppTransitionPackage);
10507                    pw.print("  mNextAppTransitionEnter=0x");
10508                            pw.print(Integer.toHexString(mNextAppTransitionEnter));
10509                            pw.print(" mNextAppTransitionExit=0x");
10510                            pw.println(Integer.toHexString(mNextAppTransitionExit));
10511                    break;
10512                case ActivityOptions.ANIM_SCALE_UP:
10513                    pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
10514                            pw.print(" mNextAppTransitionStartY=");
10515                            pw.println(mNextAppTransitionStartY);
10516                    pw.print("  mNextAppTransitionStartWidth=");
10517                            pw.print(mNextAppTransitionStartWidth);
10518                            pw.print(" mNextAppTransitionStartHeight=");
10519                            pw.println(mNextAppTransitionStartHeight);
10520                    break;
10521                case ActivityOptions.ANIM_THUMBNAIL_SCALE_UP:
10522                case ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN:
10523                    pw.print("  mNextAppTransitionThumbnail=");
10524                            pw.print(mNextAppTransitionThumbnail);
10525                            pw.print(" mNextAppTransitionStartX=");
10526                            pw.print(mNextAppTransitionStartX);
10527                            pw.print(" mNextAppTransitionStartY=");
10528                            pw.println(mNextAppTransitionStartY);
10529                    pw.print("  mNextAppTransitionScaleUp="); pw.println(mNextAppTransitionScaleUp);
10530                    break;
10531            }
10532            if (mNextAppTransitionCallback != null) {
10533                pw.print("  mNextAppTransitionCallback=");
10534                        pw.println(mNextAppTransitionCallback);
10535            }
10536            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
10537                    pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
10538            pw.println("  Window Animator:");
10539            mAnimator.dumpLocked(pw, "    ", dumpAll);
10540        }
10541    }
10542
10543    boolean dumpWindows(PrintWriter pw, String name, String[] args,
10544            int opti, boolean dumpAll) {
10545        WindowList windows = new WindowList();
10546        if ("visible".equals(name)) {
10547            synchronized(mWindowMap) {
10548                final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10549                while (iterator.hasNext()) {
10550                    final WindowState w = iterator.next();
10551                    if (w.mWinAnimator.mSurfaceShown) {
10552                        windows.add(w);
10553                    }
10554                }
10555            }
10556        } else {
10557            int objectId = 0;
10558            // See if this is an object ID.
10559            try {
10560                objectId = Integer.parseInt(name, 16);
10561                name = null;
10562            } catch (RuntimeException e) {
10563            }
10564            synchronized(mWindowMap) {
10565                final AllWindowsIterator iterator = new AllWindowsIterator(REVERSE_ITERATOR);
10566                while (iterator.hasNext()) {
10567                    final WindowState w = iterator.next();
10568                    if (name != null) {
10569                        if (w.mAttrs.getTitle().toString().contains(name)) {
10570                            windows.add(w);
10571                        }
10572                    } else if (System.identityHashCode(w) == objectId) {
10573                        windows.add(w);
10574                    }
10575                }
10576            }
10577        }
10578
10579        if (windows.size() <= 0) {
10580            return false;
10581        }
10582
10583        synchronized(mWindowMap) {
10584            dumpWindowsLocked(pw, dumpAll, windows);
10585        }
10586        return true;
10587    }
10588
10589    void dumpLastANRLocked(PrintWriter pw) {
10590        pw.println("WINDOW MANAGER LAST ANR (dumpsys window lastanr)");
10591        if (mLastANRState == null) {
10592            pw.println("  <no ANR has occurred since boot>");
10593        } else {
10594            pw.println(mLastANRState);
10595        }
10596    }
10597
10598    /**
10599     * Saves information about the state of the window manager at
10600     * the time an ANR occurred before anything else in the system changes
10601     * in response.
10602     *
10603     * @param appWindowToken The application that ANR'd, may be null.
10604     * @param windowState The window that ANR'd, may be null.
10605     */
10606    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState) {
10607        StringWriter sw = new StringWriter();
10608        PrintWriter pw = new PrintWriter(sw);
10609        pw.println("  ANR time: " + DateFormat.getInstance().format(new Date()));
10610        if (appWindowToken != null) {
10611            pw.println("  Application at fault: " + appWindowToken.stringName);
10612        }
10613        if (windowState != null) {
10614            pw.println("  Window at fault: " + windowState.mAttrs.getTitle());
10615        }
10616        pw.println();
10617        dumpWindowsNoHeaderLocked(pw, true, null);
10618        pw.close();
10619        mLastANRState = sw.toString();
10620    }
10621
10622    @Override
10623    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
10624        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
10625                != PackageManager.PERMISSION_GRANTED) {
10626            pw.println("Permission Denial: can't dump WindowManager from from pid="
10627                    + Binder.getCallingPid()
10628                    + ", uid=" + Binder.getCallingUid());
10629            return;
10630        }
10631
10632        boolean dumpAll = false;
10633
10634        int opti = 0;
10635        while (opti < args.length) {
10636            String opt = args[opti];
10637            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
10638                break;
10639            }
10640            opti++;
10641            if ("-a".equals(opt)) {
10642                dumpAll = true;
10643            } else if ("-h".equals(opt)) {
10644                pw.println("Window manager dump options:");
10645                pw.println("  [-a] [-h] [cmd] ...");
10646                pw.println("  cmd may be one of:");
10647                pw.println("    l[astanr]: last ANR information");
10648                pw.println("    p[policy]: policy state");
10649                pw.println("    s[essions]: active sessions");
10650                pw.println("    t[okens]: token list");
10651                pw.println("    w[indows]: window list");
10652                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
10653                pw.println("    be a partial substring in a window name, a");
10654                pw.println("    Window hex object identifier, or");
10655                pw.println("    \"all\" for all windows, or");
10656                pw.println("    \"visible\" for the visible windows.");
10657                pw.println("  -a: include all available server state.");
10658                return;
10659            } else {
10660                pw.println("Unknown argument: " + opt + "; use -h for help");
10661            }
10662        }
10663
10664        // Is the caller requesting to dump a particular piece of data?
10665        if (opti < args.length) {
10666            String cmd = args[opti];
10667            opti++;
10668            if ("lastanr".equals(cmd) || "l".equals(cmd)) {
10669                synchronized(mWindowMap) {
10670                    dumpLastANRLocked(pw);
10671                }
10672                return;
10673            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
10674                synchronized(mWindowMap) {
10675                    dumpPolicyLocked(pw, args, true);
10676                }
10677                return;
10678            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
10679                synchronized(mWindowMap) {
10680                    dumpSessionsLocked(pw, true);
10681                }
10682                return;
10683            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
10684                synchronized(mWindowMap) {
10685                    dumpTokensLocked(pw, true);
10686                }
10687                return;
10688            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
10689                synchronized(mWindowMap) {
10690                    dumpWindowsLocked(pw, true, null);
10691                }
10692                return;
10693            } else if ("all".equals(cmd) || "a".equals(cmd)) {
10694                synchronized(mWindowMap) {
10695                    dumpWindowsLocked(pw, true, null);
10696                }
10697                return;
10698            } else {
10699                // Dumping a single name?
10700                if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
10701                    pw.println("Bad window command, or no windows match: " + cmd);
10702                    pw.println("Use -h for help.");
10703                }
10704                return;
10705            }
10706        }
10707
10708        synchronized(mWindowMap) {
10709            pw.println();
10710            if (dumpAll) {
10711                pw.println("-------------------------------------------------------------------------------");
10712            }
10713            dumpLastANRLocked(pw);
10714            pw.println();
10715            if (dumpAll) {
10716                pw.println("-------------------------------------------------------------------------------");
10717            }
10718            dumpPolicyLocked(pw, args, dumpAll);
10719            pw.println();
10720            if (dumpAll) {
10721                pw.println("-------------------------------------------------------------------------------");
10722            }
10723            dumpSessionsLocked(pw, dumpAll);
10724            pw.println();
10725            if (dumpAll) {
10726                pw.println("-------------------------------------------------------------------------------");
10727            }
10728            dumpTokensLocked(pw, dumpAll);
10729            pw.println();
10730            if (dumpAll) {
10731                pw.println("-------------------------------------------------------------------------------");
10732            }
10733            dumpWindowsLocked(pw, dumpAll, null);
10734        }
10735    }
10736
10737    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
10738    public void monitor() {
10739        synchronized (mWindowMap) { }
10740    }
10741
10742    public interface OnHardKeyboardStatusChangeListener {
10743        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
10744    }
10745
10746    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
10747        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
10748            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
10749                    Integer.toHexString(pendingLayoutChanges));
10750        }
10751    }
10752
10753    public void createDisplayContentLocked(final Display display) {
10754        if (display == null) {
10755            throw new IllegalArgumentException("getDisplayContent: display must not be null");
10756        }
10757        final DisplayContent displayContent = new DisplayContent(display);
10758        mDisplayContents.put(display.getDisplayId(), displayContent);
10759    }
10760
10761    public DisplayContent getDisplayContentLocked(final int displayId) {
10762        DisplayContent displayContent = mDisplayContents.get(displayId);
10763        if (displayContent == null) {
10764            displayContent = new DisplayContent(mDisplayManager.getDisplay(displayId));
10765            mDisplayContents.put(displayId, displayContent);
10766        }
10767        return displayContent;
10768    }
10769
10770    class DisplayContentsIterator implements Iterator<DisplayContent> {
10771        private int cur;
10772
10773        @Override
10774        public boolean hasNext() {
10775            return cur < mDisplayContents.size();
10776        }
10777
10778        @Override
10779        public DisplayContent next() {
10780            if (hasNext()) {
10781                return mDisplayContents.valueAt(cur++);
10782            }
10783            throw new NoSuchElementException();
10784        }
10785
10786        @Override
10787        public void remove() {
10788            throw new IllegalArgumentException("AllDisplayContentIterator.remove not implemented");
10789        }
10790    }
10791
10792    final static boolean REVERSE_ITERATOR = true;
10793    class AllWindowsIterator implements Iterator<WindowState> {
10794        private DisplayContent mDisplayContent;
10795        private DisplayContentsIterator mDisplayContentsIterator;
10796        private WindowList mWindowList;
10797        private int mWindowListIndex;
10798        private boolean mReverse;
10799
10800        AllWindowsIterator() {
10801            mDisplayContentsIterator = new DisplayContentsIterator();
10802            mDisplayContent = mDisplayContentsIterator.next();
10803            mWindowList = mDisplayContent.getWindowList();
10804        }
10805
10806        AllWindowsIterator(boolean reverse) {
10807            this();
10808            mReverse = reverse;
10809            mWindowListIndex = reverse ? mWindowList.size() - 1 : 0;
10810        }
10811
10812        @Override
10813        public boolean hasNext() {
10814            if (mReverse) {
10815                return mWindowListIndex >= 0;
10816            }
10817            return mWindowListIndex < mWindowList.size();
10818        }
10819
10820        @Override
10821        public WindowState next() {
10822            if (hasNext()) {
10823                WindowState win = mWindowList.get(mWindowListIndex);
10824                if (mReverse) {
10825                    mWindowListIndex--;
10826                    if (mWindowListIndex < 0 && mDisplayContentsIterator.hasNext()) {
10827                        mDisplayContent = mDisplayContentsIterator.next();
10828                        mWindowList = mDisplayContent.getWindowList();
10829                        mWindowListIndex = mWindowList.size() - 1;
10830                    }
10831                } else {
10832                    mWindowListIndex++;
10833                    if (mWindowListIndex >= mWindowList.size()
10834                            && mDisplayContentsIterator.hasNext()) {
10835                        mDisplayContent = mDisplayContentsIterator.next();
10836                        mWindowList = mDisplayContent.getWindowList();
10837                        mWindowListIndex = 0;
10838                    }
10839                }
10840                return win;
10841            }
10842            throw new NoSuchElementException();
10843        }
10844
10845        @Override
10846        public void remove() {
10847            throw new IllegalArgumentException("AllWindowsIterator.remove not implemented");
10848        }
10849    }
10850
10851    public DisplayContent getDefaultDisplayContentLocked() {
10852        return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
10853    }
10854
10855    public WindowList getDefaultWindowListLocked() {
10856        return getDefaultDisplayContentLocked().getWindowList();
10857    }
10858
10859    public DisplayInfo getDefaultDisplayInfoLocked() {
10860        return getDefaultDisplayContentLocked().getDisplayInfo();
10861    }
10862
10863    public WindowList getWindowListLocked(final Display display) {
10864        return getDisplayContentLocked(display.getDisplayId()).getWindowList();
10865    }
10866
10867    @Override
10868    public void onDisplayAdded(int displayId) {
10869        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
10870    }
10871
10872    private void handleDisplayAddedLocked(int displayId) {
10873        createDisplayContentLocked(mDisplayManager.getDisplay(displayId));
10874        displayReady(displayId);
10875    }
10876
10877    @Override
10878    public void onDisplayRemoved(int displayId) {
10879        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
10880    }
10881
10882    private void handleDisplayRemovedLocked(int displayId) {
10883        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10884        mDisplayContents.delete(displayId);
10885        WindowList windows = displayContent.getWindowList();
10886        for (int i = windows.size() - 1; i >= 0; --i) {
10887            final WindowState win = windows.get(i);
10888            removeWindowLocked(win.mSession, win);
10889        }
10890        mAnimator.removeDisplayLocked(displayId);
10891    }
10892
10893    @Override
10894    public void onDisplayChanged(int displayId) {
10895        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
10896    }
10897
10898    private void handleDisplayChangedLocked(int displayId) {
10899        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10900        if (displayContent != null) {
10901            displayContent.updateDisplayInfo();
10902        }
10903    }
10904}
10905