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