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