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