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