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