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