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