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