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