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