WindowManagerService.java revision cff0acb6b1eea23c3f44a078a0a5e81c11faea35
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    @Override
5289    public void enableScreenIfNeeded() {
5290        synchronized (mWindowMap) {
5291            enableScreenIfNeededLocked();
5292        }
5293    }
5294
5295    void enableScreenIfNeededLocked() {
5296        if (DEBUG_BOOT) {
5297            RuntimeException here = new RuntimeException("here");
5298            here.fillInStackTrace();
5299            Slog.i(TAG, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled
5300                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5301                    + " mShowingBootMessages=" + mShowingBootMessages
5302                    + " mSystemBooted=" + mSystemBooted, here);
5303        }
5304        if (mDisplayEnabled) {
5305            return;
5306        }
5307        if (!mSystemBooted && !mShowingBootMessages) {
5308            return;
5309        }
5310        mH.sendEmptyMessage(H.ENABLE_SCREEN);
5311    }
5312
5313    public void performBootTimeout() {
5314        synchronized(mWindowMap) {
5315            if (mDisplayEnabled) {
5316                return;
5317            }
5318            Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
5319            mForceDisplayEnabled = true;
5320        }
5321        performEnableScreen();
5322    }
5323
5324    public void performEnableScreen() {
5325        synchronized(mWindowMap) {
5326            if (DEBUG_BOOT) {
5327                RuntimeException here = new RuntimeException("here");
5328                here.fillInStackTrace();
5329                Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
5330                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5331                        + " mShowingBootMessages=" + mShowingBootMessages
5332                        + " mSystemBooted=" + mSystemBooted
5333                        + " mOnlyCore=" + mOnlyCore, here);
5334            }
5335            if (mDisplayEnabled) {
5336                return;
5337            }
5338            if (!mSystemBooted && !mShowingBootMessages) {
5339                return;
5340            }
5341
5342            if (!mForceDisplayEnabled) {
5343                // Don't enable the screen until all existing windows
5344                // have been drawn.
5345                boolean haveBootMsg = false;
5346                boolean haveApp = false;
5347                // if the wallpaper service is disabled on the device, we're never going to have
5348                // wallpaper, don't bother waiting for it
5349                boolean haveWallpaper = false;
5350                boolean wallpaperEnabled = mContext.getResources().getBoolean(
5351                        com.android.internal.R.bool.config_enableWallpaperService)
5352                        && !mOnlyCore;
5353                boolean haveKeyguard = true;
5354                // TODO(multidisplay): Expand to all displays?
5355                final WindowList windows = getDefaultWindowListLocked();
5356                final int N = windows.size();
5357                for (int i=0; i<N; i++) {
5358                    WindowState w = windows.get(i);
5359                    if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
5360                        return;
5361                    }
5362                    if (w.isDrawnLw()) {
5363                        if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
5364                            haveBootMsg = true;
5365                        } else if (w.mAttrs.type == TYPE_APPLICATION) {
5366                            haveApp = true;
5367                        } else if (w.mAttrs.type == TYPE_WALLPAPER) {
5368                            haveWallpaper = true;
5369                        } else if (w.mAttrs.type == TYPE_STATUS_BAR) {
5370                            haveKeyguard = mPolicy.isKeyguardDrawnLw();
5371                        }
5372                    }
5373                }
5374
5375                if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
5376                    Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
5377                            + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
5378                            + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
5379                            + " haveKeyguard=" + haveKeyguard);
5380                }
5381
5382                // If we are turning on the screen to show the boot message,
5383                // don't do it until the boot message is actually displayed.
5384                if (!mSystemBooted && !haveBootMsg) {
5385                    return;
5386                }
5387
5388                // If we are turning on the screen after the boot is completed
5389                // normally, don't do so until we have the application and
5390                // wallpaper.
5391                if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
5392                        (wallpaperEnabled && !haveWallpaper))) {
5393                    return;
5394                }
5395            }
5396
5397            mDisplayEnabled = true;
5398            if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
5399            if (false) {
5400                StringWriter sw = new StringWriter();
5401                PrintWriter pw = new FastPrintWriter(sw, false, 1024);
5402                this.dump(null, pw, null);
5403                pw.flush();
5404                Slog.i(TAG, sw.toString());
5405            }
5406            try {
5407                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
5408                if (surfaceFlinger != null) {
5409                    //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
5410                    Parcel data = Parcel.obtain();
5411                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
5412                    surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
5413                                            data, null, 0);
5414                    data.recycle();
5415                }
5416            } catch (RemoteException ex) {
5417                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
5418            }
5419
5420            // Enable input dispatch.
5421            mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
5422        }
5423
5424        mPolicy.enableScreenAfterBoot();
5425
5426        // Make sure the last requested orientation has been applied.
5427        updateRotationUnchecked(false, false);
5428    }
5429
5430    public void showBootMessage(final CharSequence msg, final boolean always) {
5431        boolean first = false;
5432        synchronized(mWindowMap) {
5433            if (DEBUG_BOOT) {
5434                RuntimeException here = new RuntimeException("here");
5435                here.fillInStackTrace();
5436                Slog.i(TAG, "showBootMessage: msg=" + msg + " always=" + always
5437                        + " mAllowBootMessages=" + mAllowBootMessages
5438                        + " mShowingBootMessages=" + mShowingBootMessages
5439                        + " mSystemBooted=" + mSystemBooted, here);
5440            }
5441            if (!mAllowBootMessages) {
5442                return;
5443            }
5444            if (!mShowingBootMessages) {
5445                if (!always) {
5446                    return;
5447                }
5448                first = true;
5449            }
5450            if (mSystemBooted) {
5451                return;
5452            }
5453            mShowingBootMessages = true;
5454            mPolicy.showBootMessage(msg, always);
5455        }
5456        if (first) {
5457            performEnableScreen();
5458        }
5459    }
5460
5461    public void hideBootMessagesLocked() {
5462        if (DEBUG_BOOT) {
5463            RuntimeException here = new RuntimeException("here");
5464            here.fillInStackTrace();
5465            Slog.i(TAG, "hideBootMessagesLocked: mDisplayEnabled=" + mDisplayEnabled
5466                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5467                    + " mShowingBootMessages=" + mShowingBootMessages
5468                    + " mSystemBooted=" + mSystemBooted, here);
5469        }
5470        if (mShowingBootMessages) {
5471            mShowingBootMessages = false;
5472            mPolicy.hideBootMessages();
5473        }
5474    }
5475
5476    @Override
5477    public void setInTouchMode(boolean mode) {
5478        synchronized(mWindowMap) {
5479            mInTouchMode = mode;
5480        }
5481    }
5482
5483    // TODO: more accounting of which pid(s) turned it on, keep count,
5484    // only allow disables from pids which have count on, etc.
5485    @Override
5486    public void showStrictModeViolation(boolean on) {
5487        int pid = Binder.getCallingPid();
5488        mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid));
5489    }
5490
5491    private void showStrictModeViolation(int arg, int pid) {
5492        final boolean on = arg != 0;
5493        synchronized(mWindowMap) {
5494            // Ignoring requests to enable the red border from clients
5495            // which aren't on screen.  (e.g. Broadcast Receivers in
5496            // the background..)
5497            if (on) {
5498                boolean isVisible = false;
5499                final int numDisplays = mDisplayContents.size();
5500                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
5501                    final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
5502                    final int numWindows = windows.size();
5503                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
5504                        final WindowState ws = windows.get(winNdx);
5505                        if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
5506                            isVisible = true;
5507                            break;
5508                        }
5509                    }
5510                }
5511                if (!isVisible) {
5512                    return;
5513                }
5514            }
5515
5516            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5517                    ">>> OPEN TRANSACTION showStrictModeViolation");
5518            SurfaceControl.openTransaction();
5519            try {
5520                // TODO(multi-display): support multiple displays
5521                if (mStrictModeFlash == null) {
5522                    mStrictModeFlash = new StrictModeFlash(
5523                            getDefaultDisplayContentLocked().getDisplay(), mFxSession);
5524                }
5525                mStrictModeFlash.setVisibility(on);
5526            } finally {
5527                SurfaceControl.closeTransaction();
5528                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5529                        "<<< CLOSE TRANSACTION showStrictModeViolation");
5530            }
5531        }
5532    }
5533
5534    @Override
5535    public void setStrictModeVisualIndicatorPreference(String value) {
5536        SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
5537    }
5538
5539    /**
5540     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
5541     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
5542     * of the target image.
5543     *
5544     * @param displayId the Display to take a screenshot of.
5545     * @param width the width of the target bitmap
5546     * @param height the height of the target bitmap
5547     * @param force565 if true the returned bitmap will be RGB_565, otherwise it
5548     *                 will be the same config as the surface
5549     */
5550    @Override
5551    public Bitmap screenshotApplications(IBinder appToken, int displayId, int width,
5552            int height, boolean force565) {
5553        if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
5554                "screenshotApplications()")) {
5555            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
5556        }
5557
5558        Bitmap rawss = null;
5559
5560        int maxLayer = 0;
5561        final Rect frame = new Rect();
5562
5563        float scale = 0;
5564        int dw, dh;
5565        int rot = Surface.ROTATION_0;
5566
5567        boolean screenshotReady;
5568        int minLayer;
5569        if (appToken == null) {
5570            screenshotReady = true;
5571            minLayer = 0;
5572        } else {
5573            screenshotReady = false;
5574            minLayer = Integer.MAX_VALUE;
5575        }
5576
5577        int retryCount = 0;
5578        WindowState appWin = null;
5579
5580        do {
5581            if (retryCount++ > 0) {
5582                try {
5583                    Thread.sleep(100);
5584                } catch (InterruptedException e) {
5585                }
5586            }
5587            synchronized(mWindowMap) {
5588                final DisplayContent displayContent = getDisplayContentLocked(displayId);
5589                if (displayContent == null) {
5590                    return null;
5591                }
5592                final DisplayInfo displayInfo = displayContent.getDisplayInfo();
5593                dw = displayInfo.logicalWidth;
5594                dh = displayInfo.logicalHeight;
5595
5596                int aboveAppLayer = mPolicy.windowTypeToLayerLw(TYPE_APPLICATION)
5597                        * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
5598                aboveAppLayer += TYPE_LAYER_MULTIPLIER;
5599
5600                boolean isImeTarget = mInputMethodTarget != null
5601                        && mInputMethodTarget.mAppToken != null
5602                        && mInputMethodTarget.mAppToken.appToken != null
5603                        && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
5604
5605                // Figure out the part of the screen that is actually the app.
5606                boolean including = false;
5607                appWin = null;
5608                final WindowList windows = displayContent.getWindowList();
5609                final Rect stackBounds = new Rect();
5610                for (int i = windows.size() - 1; i >= 0; i--) {
5611                    WindowState ws = windows.get(i);
5612                    if (!ws.mHasSurface) {
5613                        continue;
5614                    }
5615                    if (ws.mLayer >= aboveAppLayer) {
5616                        continue;
5617                    }
5618                    // When we will skip windows: when we are not including
5619                    // ones behind a window we didn't skip, and we are actually
5620                    // taking a screenshot of a specific app.
5621                    if (!including && appToken != null) {
5622                        // Also, we can possibly skip this window if it is not
5623                        // an IME target or the application for the screenshot
5624                        // is not the current IME target.
5625                        if (!ws.mIsImWindow || !isImeTarget) {
5626                            // And finally, this window is of no interest if it
5627                            // is not associated with the screenshot app.
5628                            if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
5629                                continue;
5630                            }
5631                            appWin = ws;
5632                            ws.getStackBounds(stackBounds);
5633                        }
5634                    }
5635
5636                    // We keep on including windows until we go past a full-screen
5637                    // window.
5638                    including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
5639
5640                    final WindowStateAnimator winAnim = ws.mWinAnimator;
5641                    if (maxLayer < winAnim.mSurfaceLayer) {
5642                        maxLayer = winAnim.mSurfaceLayer;
5643                    }
5644                    if (minLayer > winAnim.mSurfaceLayer) {
5645                        minLayer = winAnim.mSurfaceLayer;
5646                    }
5647
5648                    // Don't include wallpaper in bounds calculation
5649                    if (!ws.mIsWallpaper) {
5650                        final Rect wf = ws.mFrame;
5651                        final Rect cr = ws.mContentInsets;
5652                        int left = wf.left + cr.left;
5653                        int top = wf.top + cr.top;
5654                        int right = wf.right - cr.right;
5655                        int bottom = wf.bottom - cr.bottom;
5656                        frame.union(left, top, right, bottom);
5657                        frame.intersect(stackBounds);
5658                    }
5659
5660                    if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
5661                            ws.isDisplayedLw()) {
5662                        screenshotReady = true;
5663                    }
5664                }
5665
5666                if (appToken != null && appWin == null) {
5667                    // Can't find a window to snapshot.
5668                    if (DEBUG_SCREENSHOT) Slog.i(TAG,
5669                            "Screenshot: Couldn't find a surface matching " + appToken);
5670                    return null;
5671                }
5672                if (!screenshotReady) {
5673                    // Delay and hope that window gets drawn.
5674                    if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot: No image ready for " + appToken
5675                            + ", " + appWin + " drawState=" + appWin.mWinAnimator.mDrawState);
5676                    continue;
5677                }
5678
5679                // Constrain frame to the screen size.
5680                frame.intersect(0, 0, dw, dh);
5681
5682                if (frame.isEmpty() || maxLayer == 0) {
5683                    if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot of " + appToken
5684                            + ": returning null frame=" + frame.toShortString() + " maxLayer="
5685                            + maxLayer);
5686                    return null;
5687                }
5688
5689                // The screenshot API does not apply the current screen rotation.
5690                rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
5691                int fw = frame.width();
5692                int fh = frame.height();
5693
5694                // Constrain thumbnail to smaller of screen width or height. Assumes aspect
5695                // of thumbnail is the same as the screen (in landscape) or square.
5696                scale = Math.max(width / (float) fw, height / (float) fh);
5697                /*
5698                float targetWidthScale = width / (float) fw;
5699                float targetHeightScale = height / (float) fh;
5700                if (fw <= fh) {
5701                    scale = targetWidthScale;
5702                    // If aspect of thumbnail is the same as the screen (in landscape),
5703                    // select the slightly larger value so we fill the entire bitmap
5704                    if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
5705                        scale = targetHeightScale;
5706                    }
5707                } else {
5708                    scale = targetHeightScale;
5709                    // If aspect of thumbnail is the same as the screen (in landscape),
5710                    // select the slightly larger value so we fill the entire bitmap
5711                    if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
5712                        scale = targetWidthScale;
5713                    }
5714                }
5715                */
5716
5717                // The screen shot will contain the entire screen.
5718                dw = (int)(dw*scale);
5719                dh = (int)(dh*scale);
5720                if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
5721                    int tmp = dw;
5722                    dw = dh;
5723                    dh = tmp;
5724                    rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
5725                }
5726                if (DEBUG_SCREENSHOT) {
5727                    Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
5728                            + maxLayer + " appToken=" + appToken);
5729                    for (int i = 0; i < windows.size(); i++) {
5730                        WindowState win = windows.get(i);
5731                        Slog.i(TAG, win + ": " + win.mLayer
5732                                + " animLayer=" + win.mWinAnimator.mAnimLayer
5733                                + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
5734                    }
5735                }
5736                // TODO: Replace 'false' in the following line with a variable that indicates
5737                // whether the screenshot should use the identity transformation matrix
5738                // (e.g., enable it when taking a screenshot for recents, since we might be in
5739                // the middle of the rotation animation, but don't want a rotated recent image).
5740                rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer, false);
5741            }
5742        } while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES);
5743        if (retryCount > MAX_SCREENSHOT_RETRIES)  Slog.i(TAG, "Screenshot max retries " +
5744                retryCount + " of " + appToken + " appWin=" + (appWin == null ?
5745                        "null" : (appWin + " drawState=" + appWin.mWinAnimator.mDrawState)));
5746
5747        if (rawss == null) {
5748            Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh
5749                    + ") to layer " + maxLayer);
5750            return null;
5751        }
5752
5753        Bitmap bm = Bitmap.createBitmap(width, height, force565 ? Config.RGB_565 : rawss.getConfig());
5754        frame.scale(scale);
5755        Matrix matrix = new Matrix();
5756        ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
5757        // TODO: Test for RTL vs. LTR and use frame.right-width instead of -frame.left
5758        matrix.postTranslate(-FloatMath.ceil(frame.left), -FloatMath.ceil(frame.top));
5759        Canvas canvas = new Canvas(bm);
5760        canvas.drawColor(0xFF000000);
5761        canvas.drawBitmap(rawss, matrix, null);
5762        canvas.setBitmap(null);
5763
5764        if (DEBUG_SCREENSHOT) {
5765            // TEST IF IT's ALL BLACK
5766            int[] buffer = new int[bm.getWidth() * bm.getHeight()];
5767            bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
5768            boolean allBlack = true;
5769            final int firstColor = buffer[0];
5770            for (int i = 0; i < buffer.length; i++) {
5771                if (buffer[i] != firstColor) {
5772                    allBlack = false;
5773                    break;
5774                }
5775            }
5776            if (allBlack) {
5777                Slog.i(TAG, "Screenshot " + appWin + " was monochrome(" +
5778                        Integer.toHexString(firstColor) + ")! mSurfaceLayer=" +
5779                        (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null") +
5780                        " minLayer=" + minLayer + " maxLayer=" + maxLayer);
5781            }
5782        }
5783
5784        rawss.recycle();
5785        return bm;
5786    }
5787
5788    /**
5789     * Freeze rotation changes.  (Enable "rotation lock".)
5790     * Persists across reboots.
5791     * @param rotation The desired rotation to freeze to, or -1 to use the
5792     * current rotation.
5793     */
5794    @Override
5795    public void freezeRotation(int rotation) {
5796        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5797                "freezeRotation()")) {
5798            throw new SecurityException("Requires SET_ORIENTATION permission");
5799        }
5800        if (rotation < -1 || rotation > Surface.ROTATION_270) {
5801            throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
5802                    + "rotation constant.");
5803        }
5804
5805        if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
5806
5807        long origId = Binder.clearCallingIdentity();
5808        try {
5809            mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
5810                    rotation == -1 ? mRotation : rotation);
5811        } finally {
5812            Binder.restoreCallingIdentity(origId);
5813        }
5814
5815        updateRotationUnchecked(false, false);
5816    }
5817
5818    /**
5819     * Thaw rotation changes.  (Disable "rotation lock".)
5820     * Persists across reboots.
5821     */
5822    @Override
5823    public void thawRotation() {
5824        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5825                "thawRotation()")) {
5826            throw new SecurityException("Requires SET_ORIENTATION permission");
5827        }
5828
5829        if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
5830
5831        long origId = Binder.clearCallingIdentity();
5832        try {
5833            mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE,
5834                    777); // rot not used
5835        } finally {
5836            Binder.restoreCallingIdentity(origId);
5837        }
5838
5839        updateRotationUnchecked(false, false);
5840    }
5841
5842    /**
5843     * Recalculate the current rotation.
5844     *
5845     * Called by the window manager policy whenever the state of the system changes
5846     * such that the current rotation might need to be updated, such as when the
5847     * device is docked or rotated into a new posture.
5848     */
5849    @Override
5850    public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
5851        updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
5852    }
5853
5854    /**
5855     * Temporarily pauses rotation changes until resumed.
5856     *
5857     * This can be used to prevent rotation changes from occurring while the user is
5858     * performing certain operations, such as drag and drop.
5859     *
5860     * This call nests and must be matched by an equal number of calls to
5861     * {@link #resumeRotationLocked}.
5862     */
5863    void pauseRotationLocked() {
5864        mDeferredRotationPauseCount += 1;
5865    }
5866
5867    /**
5868     * Resumes normal rotation changes after being paused.
5869     */
5870    void resumeRotationLocked() {
5871        if (mDeferredRotationPauseCount > 0) {
5872            mDeferredRotationPauseCount -= 1;
5873            if (mDeferredRotationPauseCount == 0) {
5874                boolean changed = updateRotationUncheckedLocked(false);
5875                if (changed) {
5876                    mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
5877                }
5878            }
5879        }
5880    }
5881
5882    public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
5883        if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked("
5884                   + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")");
5885
5886        long origId = Binder.clearCallingIdentity();
5887        boolean changed;
5888        synchronized(mWindowMap) {
5889            changed = updateRotationUncheckedLocked(false);
5890            if (!changed || forceRelayout) {
5891                getDefaultDisplayContentLocked().layoutNeeded = true;
5892                performLayoutAndPlaceSurfacesLocked();
5893            }
5894        }
5895
5896        if (changed || alwaysSendConfiguration) {
5897            sendNewConfiguration();
5898        }
5899
5900        Binder.restoreCallingIdentity(origId);
5901    }
5902
5903    // TODO(multidisplay): Rotate any display?
5904    /**
5905     * Updates the current rotation.
5906     *
5907     * Returns true if the rotation has been changed.  In this case YOU
5908     * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN.
5909     */
5910    public boolean updateRotationUncheckedLocked(boolean inTransaction) {
5911        if (mDeferredRotationPauseCount > 0) {
5912            // Rotation updates have been paused temporarily.  Defer the update until
5913            // updates have been resumed.
5914            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused.");
5915            return false;
5916        }
5917
5918        ScreenRotationAnimation screenRotationAnimation =
5919                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
5920        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
5921            // Rotation updates cannot be performed while the previous rotation change
5922            // animation is still in progress.  Skip this update.  We will try updating
5923            // again after the animation is finished and the display is unfrozen.
5924            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress.");
5925            return false;
5926        }
5927
5928        if (!mDisplayEnabled) {
5929            // No point choosing a rotation if the display is not enabled.
5930            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled.");
5931            return false;
5932        }
5933
5934        // TODO: Implement forced rotation changes.
5935        //       Set mAltOrientation to indicate that the application is receiving
5936        //       an orientation that has different metrics than it expected.
5937        //       eg. Portrait instead of Landscape.
5938
5939        int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);
5940        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
5941                mForcedAppOrientation, rotation);
5942
5943        if (DEBUG_ORIENTATION) {
5944            Slog.v(TAG, "Application requested orientation "
5945                    + mForcedAppOrientation + ", got rotation " + rotation
5946                    + " which has " + (altOrientation ? "incompatible" : "compatible")
5947                    + " metrics");
5948        }
5949
5950        if (mRotation == rotation && mAltOrientation == altOrientation) {
5951            // No change.
5952            return false;
5953        }
5954
5955        if (DEBUG_ORIENTATION) {
5956            Slog.v(TAG,
5957                "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
5958                + " from " + mRotation + (mAltOrientation ? " (alt)" : "")
5959                + ", forceApp=" + mForcedAppOrientation);
5960        }
5961
5962        mRotation = rotation;
5963        mAltOrientation = altOrientation;
5964        mPolicy.setRotationLw(mRotation);
5965
5966        mWindowsFreezingScreen = true;
5967        mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
5968        mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
5969        mWaitingForConfig = true;
5970        final DisplayContent displayContent = getDefaultDisplayContentLocked();
5971        displayContent.layoutNeeded = true;
5972        final int[] anim = new int[2];
5973        if (displayContent.isDimming()) {
5974            anim[0] = anim[1] = 0;
5975        } else {
5976            mPolicy.selectRotationAnimationLw(anim);
5977        }
5978        startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
5979        // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
5980        screenRotationAnimation =
5981                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
5982
5983        // We need to update our screen size information to match the new
5984        // rotation.  Note that this is redundant with the later call to
5985        // sendNewConfiguration() that must be called after this function
5986        // returns...  however we need to do the screen size part of that
5987        // before then so we have the correct size to use when initializing
5988        // the rotation animation for the new rotation.
5989        computeScreenConfigurationLocked(null);
5990
5991        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
5992        if (!inTransaction) {
5993            if (SHOW_TRANSACTIONS) {
5994                Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");
5995            }
5996            SurfaceControl.openTransaction();
5997        }
5998        try {
5999            // NOTE: We disable the rotation in the emulator because
6000            //       it doesn't support hardware OpenGL emulation yet.
6001            if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
6002                    && screenRotationAnimation.hasScreenshot()) {
6003                if (screenRotationAnimation.setRotationInTransaction(
6004                        rotation, mFxSession,
6005                        MAX_ANIMATION_DURATION, mTransitionAnimationScale,
6006                        displayInfo.logicalWidth, displayInfo.logicalHeight)) {
6007                    scheduleAnimationLocked();
6008                }
6009            }
6010
6011            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
6012        } finally {
6013            if (!inTransaction) {
6014                SurfaceControl.closeTransaction();
6015                if (SHOW_LIGHT_TRANSACTIONS) {
6016                    Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");
6017                }
6018            }
6019        }
6020
6021        final WindowList windows = displayContent.getWindowList();
6022        for (int i = windows.size() - 1; i >= 0; i--) {
6023            WindowState w = windows.get(i);
6024            if (w.mHasSurface) {
6025                if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
6026                w.mOrientationChanging = true;
6027                mInnerFields.mOrientationChangeComplete = false;
6028            }
6029            w.mLastFreezeDuration = 0;
6030        }
6031
6032        for (int i=mRotationWatchers.size()-1; i>=0; i--) {
6033            try {
6034                mRotationWatchers.get(i).watcher.onRotationChanged(rotation);
6035            } catch (RemoteException e) {
6036            }
6037        }
6038
6039        //TODO (multidisplay): Magnification is supported only for the default display.
6040        if (mAccessibilityController != null
6041                && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {
6042            mAccessibilityController.onRotationChangedLocked(getDefaultDisplayContentLocked(), rotation);
6043        }
6044
6045        return true;
6046    }
6047
6048    @Override
6049    public int getRotation() {
6050        return mRotation;
6051    }
6052
6053    @Override
6054    public boolean isRotationFrozen() {
6055        return mPolicy.getUserRotationMode() == WindowManagerPolicy.USER_ROTATION_LOCKED;
6056    }
6057
6058    @Override
6059    public int watchRotation(IRotationWatcher watcher) {
6060        final IBinder watcherBinder = watcher.asBinder();
6061        IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
6062            @Override
6063            public void binderDied() {
6064                synchronized (mWindowMap) {
6065                    for (int i=0; i<mRotationWatchers.size(); i++) {
6066                        if (watcherBinder == mRotationWatchers.get(i).watcher.asBinder()) {
6067                            RotationWatcher removed = mRotationWatchers.remove(i);
6068                            IBinder binder = removed.watcher.asBinder();
6069                            if (binder != null) {
6070                                binder.unlinkToDeath(this, 0);
6071                            }
6072                            i--;
6073                        }
6074                    }
6075                }
6076            }
6077        };
6078
6079        synchronized (mWindowMap) {
6080            try {
6081                watcher.asBinder().linkToDeath(dr, 0);
6082                mRotationWatchers.add(new RotationWatcher(watcher, dr));
6083            } catch (RemoteException e) {
6084                // Client died, no cleanup needed.
6085            }
6086
6087            return mRotation;
6088        }
6089    }
6090
6091    @Override
6092    public void removeRotationWatcher(IRotationWatcher watcher) {
6093        final IBinder watcherBinder = watcher.asBinder();
6094        synchronized (mWindowMap) {
6095            for (int i=0; i<mRotationWatchers.size(); i++) {
6096                RotationWatcher rotationWatcher = mRotationWatchers.get(i);
6097                if (watcherBinder == rotationWatcher.watcher.asBinder()) {
6098                    RotationWatcher removed = mRotationWatchers.remove(i);
6099                    IBinder binder = removed.watcher.asBinder();
6100                    if (binder != null) {
6101                        binder.unlinkToDeath(removed.deathRecipient, 0);
6102                    }
6103                    i--;
6104                }
6105            }
6106        }
6107    }
6108
6109    /**
6110     * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
6111     * theme attribute) on devices that feature a physical options menu key attempt to position
6112     * their menu panel window along the edge of the screen nearest the physical menu key.
6113     * This lowers the travel distance between invoking the menu panel and selecting
6114     * a menu option.
6115     *
6116     * This method helps control where that menu is placed. Its current implementation makes
6117     * assumptions about the menu key and its relationship to the screen based on whether
6118     * the device's natural orientation is portrait (width < height) or landscape.
6119     *
6120     * The menu key is assumed to be located along the bottom edge of natural-portrait
6121     * devices and along the right edge of natural-landscape devices. If these assumptions
6122     * do not hold for the target device, this method should be changed to reflect that.
6123     *
6124     * @return A {@link Gravity} value for placing the options menu window
6125     */
6126    @Override
6127    public int getPreferredOptionsPanelGravity() {
6128        synchronized (mWindowMap) {
6129            final int rotation = getRotation();
6130
6131            // TODO(multidisplay): Assume that such devices physical keys are on the main screen.
6132            final DisplayContent displayContent = getDefaultDisplayContentLocked();
6133            if (displayContent.mInitialDisplayWidth < displayContent.mInitialDisplayHeight) {
6134                // On devices with a natural orientation of portrait
6135                switch (rotation) {
6136                    default:
6137                    case Surface.ROTATION_0:
6138                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6139                    case Surface.ROTATION_90:
6140                        return Gravity.RIGHT | Gravity.BOTTOM;
6141                    case Surface.ROTATION_180:
6142                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6143                    case Surface.ROTATION_270:
6144                        return Gravity.START | Gravity.BOTTOM;
6145                }
6146            }
6147
6148            // On devices with a natural orientation of landscape
6149            switch (rotation) {
6150                default:
6151                case Surface.ROTATION_0:
6152                    return Gravity.RIGHT | Gravity.BOTTOM;
6153                case Surface.ROTATION_90:
6154                    return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6155                case Surface.ROTATION_180:
6156                    return Gravity.START | Gravity.BOTTOM;
6157                case Surface.ROTATION_270:
6158                    return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
6159            }
6160        }
6161    }
6162
6163    /**
6164     * Starts the view server on the specified port.
6165     *
6166     * @param port The port to listener to.
6167     *
6168     * @return True if the server was successfully started, false otherwise.
6169     *
6170     * @see com.android.server.wm.ViewServer
6171     * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
6172     */
6173    @Override
6174    public boolean startViewServer(int port) {
6175        if (isSystemSecure()) {
6176            return false;
6177        }
6178
6179        if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
6180            return false;
6181        }
6182
6183        if (port < 1024) {
6184            return false;
6185        }
6186
6187        if (mViewServer != null) {
6188            if (!mViewServer.isRunning()) {
6189                try {
6190                    return mViewServer.start();
6191                } catch (IOException e) {
6192                    Slog.w(TAG, "View server did not start");
6193                }
6194            }
6195            return false;
6196        }
6197
6198        try {
6199            mViewServer = new ViewServer(this, port);
6200            return mViewServer.start();
6201        } catch (IOException e) {
6202            Slog.w(TAG, "View server did not start");
6203        }
6204        return false;
6205    }
6206
6207    private boolean isSystemSecure() {
6208        return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
6209                "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
6210    }
6211
6212    /**
6213     * Stops the view server if it exists.
6214     *
6215     * @return True if the server stopped, false if it wasn't started or
6216     *         couldn't be stopped.
6217     *
6218     * @see com.android.server.wm.ViewServer
6219     */
6220    @Override
6221    public boolean stopViewServer() {
6222        if (isSystemSecure()) {
6223            return false;
6224        }
6225
6226        if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
6227            return false;
6228        }
6229
6230        if (mViewServer != null) {
6231            return mViewServer.stop();
6232        }
6233        return false;
6234    }
6235
6236    /**
6237     * Indicates whether the view server is running.
6238     *
6239     * @return True if the server is running, false otherwise.
6240     *
6241     * @see com.android.server.wm.ViewServer
6242     */
6243    @Override
6244    public boolean isViewServerRunning() {
6245        if (isSystemSecure()) {
6246            return false;
6247        }
6248
6249        if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
6250            return false;
6251        }
6252
6253        return mViewServer != null && mViewServer.isRunning();
6254    }
6255
6256    /**
6257     * Lists all availble windows in the system. The listing is written in the
6258     * specified Socket's output stream with the following syntax:
6259     * windowHashCodeInHexadecimal windowName
6260     * Each line of the ouput represents a different window.
6261     *
6262     * @param client The remote client to send the listing to.
6263     * @return False if an error occured, true otherwise.
6264     */
6265    boolean viewServerListWindows(Socket client) {
6266        if (isSystemSecure()) {
6267            return false;
6268        }
6269
6270        boolean result = true;
6271
6272        WindowList windows = new WindowList();
6273        synchronized (mWindowMap) {
6274            //noinspection unchecked
6275            final int numDisplays = mDisplayContents.size();
6276            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
6277                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
6278                windows.addAll(displayContent.getWindowList());
6279            }
6280        }
6281
6282        BufferedWriter out = null;
6283
6284        // Any uncaught exception will crash the system process
6285        try {
6286            OutputStream clientStream = client.getOutputStream();
6287            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
6288
6289            final int count = windows.size();
6290            for (int i = 0; i < count; i++) {
6291                final WindowState w = windows.get(i);
6292                out.write(Integer.toHexString(System.identityHashCode(w)));
6293                out.write(' ');
6294                out.append(w.mAttrs.getTitle());
6295                out.write('\n');
6296            }
6297
6298            out.write("DONE.\n");
6299            out.flush();
6300        } catch (Exception e) {
6301            result = false;
6302        } finally {
6303            if (out != null) {
6304                try {
6305                    out.close();
6306                } catch (IOException e) {
6307                    result = false;
6308                }
6309            }
6310        }
6311
6312        return result;
6313    }
6314
6315    // TODO(multidisplay): Extend to multiple displays.
6316    /**
6317     * Returns the focused window in the following format:
6318     * windowHashCodeInHexadecimal windowName
6319     *
6320     * @param client The remote client to send the listing to.
6321     * @return False if an error occurred, true otherwise.
6322     */
6323    boolean viewServerGetFocusedWindow(Socket client) {
6324        if (isSystemSecure()) {
6325            return false;
6326        }
6327
6328        boolean result = true;
6329
6330        WindowState focusedWindow = getFocusedWindow();
6331
6332        BufferedWriter out = null;
6333
6334        // Any uncaught exception will crash the system process
6335        try {
6336            OutputStream clientStream = client.getOutputStream();
6337            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
6338
6339            if(focusedWindow != null) {
6340                out.write(Integer.toHexString(System.identityHashCode(focusedWindow)));
6341                out.write(' ');
6342                out.append(focusedWindow.mAttrs.getTitle());
6343            }
6344            out.write('\n');
6345            out.flush();
6346        } catch (Exception e) {
6347            result = false;
6348        } finally {
6349            if (out != null) {
6350                try {
6351                    out.close();
6352                } catch (IOException e) {
6353                    result = false;
6354                }
6355            }
6356        }
6357
6358        return result;
6359    }
6360
6361    /**
6362     * Sends a command to a target window. The result of the command, if any, will be
6363     * written in the output stream of the specified socket.
6364     *
6365     * The parameters must follow this syntax:
6366     * windowHashcode extra
6367     *
6368     * Where XX is the length in characeters of the windowTitle.
6369     *
6370     * The first parameter is the target window. The window with the specified hashcode
6371     * will be the target. If no target can be found, nothing happens. The extra parameters
6372     * will be delivered to the target window and as parameters to the command itself.
6373     *
6374     * @param client The remote client to sent the result, if any, to.
6375     * @param command The command to execute.
6376     * @param parameters The command parameters.
6377     *
6378     * @return True if the command was successfully delivered, false otherwise. This does
6379     *         not indicate whether the command itself was successful.
6380     */
6381    boolean viewServerWindowCommand(Socket client, String command, String parameters) {
6382        if (isSystemSecure()) {
6383            return false;
6384        }
6385
6386        boolean success = true;
6387        Parcel data = null;
6388        Parcel reply = null;
6389
6390        BufferedWriter out = null;
6391
6392        // Any uncaught exception will crash the system process
6393        try {
6394            // Find the hashcode of the window
6395            int index = parameters.indexOf(' ');
6396            if (index == -1) {
6397                index = parameters.length();
6398            }
6399            final String code = parameters.substring(0, index);
6400            int hashCode = (int) Long.parseLong(code, 16);
6401
6402            // Extract the command's parameter after the window description
6403            if (index < parameters.length()) {
6404                parameters = parameters.substring(index + 1);
6405            } else {
6406                parameters = "";
6407            }
6408
6409            final WindowState window = findWindow(hashCode);
6410            if (window == null) {
6411                return false;
6412            }
6413
6414            data = Parcel.obtain();
6415            data.writeInterfaceToken("android.view.IWindow");
6416            data.writeString(command);
6417            data.writeString(parameters);
6418            data.writeInt(1);
6419            ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
6420
6421            reply = Parcel.obtain();
6422
6423            final IBinder binder = window.mClient.asBinder();
6424            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
6425            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
6426
6427            reply.readException();
6428
6429            if (!client.isOutputShutdown()) {
6430                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
6431                out.write("DONE\n");
6432                out.flush();
6433            }
6434
6435        } catch (Exception e) {
6436            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
6437            success = false;
6438        } finally {
6439            if (data != null) {
6440                data.recycle();
6441            }
6442            if (reply != null) {
6443                reply.recycle();
6444            }
6445            if (out != null) {
6446                try {
6447                    out.close();
6448                } catch (IOException e) {
6449
6450                }
6451            }
6452        }
6453
6454        return success;
6455    }
6456
6457    public void addWindowChangeListener(WindowChangeListener listener) {
6458        synchronized(mWindowMap) {
6459            mWindowChangeListeners.add(listener);
6460        }
6461    }
6462
6463    public void removeWindowChangeListener(WindowChangeListener listener) {
6464        synchronized(mWindowMap) {
6465            mWindowChangeListeners.remove(listener);
6466        }
6467    }
6468
6469    private void notifyWindowsChanged() {
6470        WindowChangeListener[] windowChangeListeners;
6471        synchronized(mWindowMap) {
6472            if(mWindowChangeListeners.isEmpty()) {
6473                return;
6474            }
6475            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6476            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6477        }
6478        int N = windowChangeListeners.length;
6479        for(int i = 0; i < N; i++) {
6480            windowChangeListeners[i].windowsChanged();
6481        }
6482    }
6483
6484    private void notifyFocusChanged() {
6485        WindowChangeListener[] windowChangeListeners;
6486        synchronized(mWindowMap) {
6487            if(mWindowChangeListeners.isEmpty()) {
6488                return;
6489            }
6490            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6491            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6492        }
6493        int N = windowChangeListeners.length;
6494        for(int i = 0; i < N; i++) {
6495            windowChangeListeners[i].focusChanged();
6496        }
6497    }
6498
6499    private WindowState findWindow(int hashCode) {
6500        if (hashCode == -1) {
6501            // TODO(multidisplay): Extend to multiple displays.
6502            return getFocusedWindow();
6503        }
6504
6505        synchronized (mWindowMap) {
6506            final int numDisplays = mDisplayContents.size();
6507            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
6508                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
6509                final int numWindows = windows.size();
6510                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
6511                    final WindowState w = windows.get(winNdx);
6512                    if (System.identityHashCode(w) == hashCode) {
6513                        return w;
6514                    }
6515                }
6516            }
6517        }
6518
6519        return null;
6520    }
6521
6522    /*
6523     * Instruct the Activity Manager to fetch the current configuration and broadcast
6524     * that to config-changed listeners if appropriate.
6525     */
6526    void sendNewConfiguration() {
6527        try {
6528            mActivityManager.updateConfiguration(null);
6529        } catch (RemoteException e) {
6530        }
6531    }
6532
6533    public Configuration computeNewConfiguration() {
6534        synchronized (mWindowMap) {
6535            Configuration config = computeNewConfigurationLocked();
6536            if (config == null && mWaitingForConfig) {
6537                // Nothing changed but we are waiting for something... stop that!
6538                mWaitingForConfig = false;
6539                mLastFinishedFreezeSource = "new-config";
6540                performLayoutAndPlaceSurfacesLocked();
6541            }
6542            return config;
6543        }
6544    }
6545
6546    Configuration computeNewConfigurationLocked() {
6547        Configuration config = new Configuration();
6548        config.fontScale = 0;
6549        if (!computeScreenConfigurationLocked(config)) {
6550            return null;
6551        }
6552        return config;
6553    }
6554
6555    private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) {
6556        // TODO: Multidisplay: for now only use with default display.
6557        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
6558        if (width < displayInfo.smallestNominalAppWidth) {
6559            displayInfo.smallestNominalAppWidth = width;
6560        }
6561        if (width > displayInfo.largestNominalAppWidth) {
6562            displayInfo.largestNominalAppWidth = width;
6563        }
6564        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation);
6565        if (height < displayInfo.smallestNominalAppHeight) {
6566            displayInfo.smallestNominalAppHeight = height;
6567        }
6568        if (height > displayInfo.largestNominalAppHeight) {
6569            displayInfo.largestNominalAppHeight = height;
6570        }
6571    }
6572
6573    private int reduceConfigLayout(int curLayout, int rotation, float density,
6574            int dw, int dh) {
6575        // TODO: Multidisplay: for now only use with default display.
6576        // Get the app screen size at this rotation.
6577        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6578        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6579
6580        // Compute the screen layout size class for this rotation.
6581        int longSize = w;
6582        int shortSize = h;
6583        if (longSize < shortSize) {
6584            int tmp = longSize;
6585            longSize = shortSize;
6586            shortSize = tmp;
6587        }
6588        longSize = (int)(longSize/density);
6589        shortSize = (int)(shortSize/density);
6590        return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
6591    }
6592
6593    private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
6594                  int dw, int dh, float density, Configuration outConfig) {
6595        // TODO: Multidisplay: for now only use with default display.
6596
6597        // We need to determine the smallest width that will occur under normal
6598        // operation.  To this, start with the base screen size and compute the
6599        // width under the different possible rotations.  We need to un-rotate
6600        // the current screen dimensions before doing this.
6601        int unrotDw, unrotDh;
6602        if (rotated) {
6603            unrotDw = dh;
6604            unrotDh = dw;
6605        } else {
6606            unrotDw = dw;
6607            unrotDh = dh;
6608        }
6609        displayInfo.smallestNominalAppWidth = 1<<30;
6610        displayInfo.smallestNominalAppHeight = 1<<30;
6611        displayInfo.largestNominalAppWidth = 0;
6612        displayInfo.largestNominalAppHeight = 0;
6613        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh);
6614        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw);
6615        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh);
6616        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw);
6617        int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
6618        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
6619        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
6620        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
6621        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
6622        outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
6623        outConfig.screenLayout = sl;
6624    }
6625
6626    private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
6627            int dw, int dh) {
6628        // TODO: Multidisplay: for now only use with default display.
6629        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6630        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6631        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
6632        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
6633        if (curSize == 0 || size < curSize) {
6634            curSize = size;
6635        }
6636        return curSize;
6637    }
6638
6639    private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
6640        // TODO: Multidisplay: for now only use with default display.
6641        mTmpDisplayMetrics.setTo(dm);
6642        final DisplayMetrics tmpDm = mTmpDisplayMetrics;
6643        final int unrotDw, unrotDh;
6644        if (rotated) {
6645            unrotDw = dh;
6646            unrotDh = dw;
6647        } else {
6648            unrotDw = dw;
6649            unrotDh = dh;
6650        }
6651        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh);
6652        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw);
6653        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh);
6654        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw);
6655        return sw;
6656    }
6657
6658    boolean computeScreenConfigurationLocked(Configuration config) {
6659        if (!mDisplayReady) {
6660            return false;
6661        }
6662
6663        // TODO(multidisplay): For now, apply Configuration to main screen only.
6664        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6665
6666        // Use the effective "visual" dimensions based on current rotation
6667        final boolean rotated = (mRotation == Surface.ROTATION_90
6668                || mRotation == Surface.ROTATION_270);
6669        final int realdw = rotated ?
6670                displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
6671        final int realdh = rotated ?
6672                displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
6673        int dw = realdw;
6674        int dh = realdh;
6675
6676        if (mAltOrientation) {
6677            if (realdw > realdh) {
6678                // Turn landscape into portrait.
6679                int maxw = (int)(realdh/1.3f);
6680                if (maxw < realdw) {
6681                    dw = maxw;
6682                }
6683            } else {
6684                // Turn portrait into landscape.
6685                int maxh = (int)(realdw/1.3f);
6686                if (maxh < realdh) {
6687                    dh = maxh;
6688                }
6689            }
6690        }
6691
6692        if (config != null) {
6693            config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
6694                    Configuration.ORIENTATION_LANDSCAPE;
6695        }
6696
6697        // Update application display metrics.
6698        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
6699        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
6700        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
6701        synchronized(displayContent.mDisplaySizeLock) {
6702            displayInfo.rotation = mRotation;
6703            displayInfo.logicalWidth = dw;
6704            displayInfo.logicalHeight = dh;
6705            displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
6706            displayInfo.appWidth = appWidth;
6707            displayInfo.appHeight = appHeight;
6708            displayInfo.getLogicalMetrics(mRealDisplayMetrics,
6709                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
6710            displayInfo.getAppMetrics(mDisplayMetrics);
6711            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
6712                    displayContent.getDisplayId(), displayInfo);
6713        }
6714        if (false) {
6715            Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);
6716        }
6717
6718        final DisplayMetrics dm = mDisplayMetrics;
6719        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
6720                mCompatDisplayMetrics);
6721
6722        if (config != null) {
6723            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
6724                    / dm.density);
6725            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
6726                    / dm.density);
6727            computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);
6728
6729            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
6730            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
6731            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
6732            config.densityDpi = displayContent.mBaseDisplayDensity;
6733
6734            // Update the configuration based on available input devices, lid switch,
6735            // and platform configuration.
6736            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6737            config.keyboard = Configuration.KEYBOARD_NOKEYS;
6738            config.navigation = Configuration.NAVIGATION_NONAV;
6739
6740            int keyboardPresence = 0;
6741            int navigationPresence = 0;
6742            final InputDevice[] devices = mInputManager.getInputDevices();
6743            final int len = devices.length;
6744            for (int i = 0; i < len; i++) {
6745                InputDevice device = devices[i];
6746                if (!device.isVirtual()) {
6747                    final int sources = device.getSources();
6748                    final int presenceFlag = device.isExternal() ?
6749                            WindowManagerPolicy.PRESENCE_EXTERNAL :
6750                                    WindowManagerPolicy.PRESENCE_INTERNAL;
6751
6752                    if (mIsTouchDevice) {
6753                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
6754                                InputDevice.SOURCE_TOUCHSCREEN) {
6755                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
6756                        }
6757                    } else {
6758                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6759                    }
6760
6761                    if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
6762                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
6763                        navigationPresence |= presenceFlag;
6764                    } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
6765                            && config.navigation == Configuration.NAVIGATION_NONAV) {
6766                        config.navigation = Configuration.NAVIGATION_DPAD;
6767                        navigationPresence |= presenceFlag;
6768                    }
6769
6770                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
6771                        config.keyboard = Configuration.KEYBOARD_QWERTY;
6772                        keyboardPresence |= presenceFlag;
6773                    }
6774                }
6775            }
6776
6777            // Determine whether a hard keyboard is available and enabled.
6778            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6779            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6780                mHardKeyboardAvailable = hardKeyboardAvailable;
6781                mHardKeyboardEnabled = hardKeyboardAvailable;
6782                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6783                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6784            }
6785            if (!mHardKeyboardEnabled) {
6786                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6787            }
6788
6789            // Let the policy update hidden states.
6790            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6791            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6792            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6793            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
6794        }
6795
6796        return true;
6797    }
6798
6799    public boolean isHardKeyboardAvailable() {
6800        synchronized (mWindowMap) {
6801            return mHardKeyboardAvailable;
6802        }
6803    }
6804
6805    public boolean isHardKeyboardEnabled() {
6806        synchronized (mWindowMap) {
6807            return mHardKeyboardEnabled;
6808        }
6809    }
6810
6811    public void setHardKeyboardEnabled(boolean enabled) {
6812        synchronized (mWindowMap) {
6813            if (mHardKeyboardEnabled != enabled) {
6814                mHardKeyboardEnabled = enabled;
6815                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6816            }
6817        }
6818    }
6819
6820    public void setOnHardKeyboardStatusChangeListener(
6821            OnHardKeyboardStatusChangeListener listener) {
6822        synchronized (mWindowMap) {
6823            mHardKeyboardStatusChangeListener = listener;
6824        }
6825    }
6826
6827    void notifyHardKeyboardStatusChange() {
6828        final boolean available, enabled;
6829        final OnHardKeyboardStatusChangeListener listener;
6830        synchronized (mWindowMap) {
6831            listener = mHardKeyboardStatusChangeListener;
6832            available = mHardKeyboardAvailable;
6833            enabled = mHardKeyboardEnabled;
6834        }
6835        if (listener != null) {
6836            listener.onHardKeyboardStatusChange(available, enabled);
6837        }
6838    }
6839
6840    // -------------------------------------------------------------
6841    // Drag and drop
6842    // -------------------------------------------------------------
6843
6844    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
6845            int flags, int width, int height, Surface outSurface) {
6846        if (DEBUG_DRAG) {
6847            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
6848                    + " flags=" + Integer.toHexString(flags) + " win=" + window
6849                    + " asbinder=" + window.asBinder());
6850        }
6851
6852        final int callerPid = Binder.getCallingPid();
6853        final long origId = Binder.clearCallingIdentity();
6854        IBinder token = null;
6855
6856        try {
6857            synchronized (mWindowMap) {
6858                try {
6859                    if (mDragState == null) {
6860                        // TODO(multi-display): support other displays
6861                        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6862                        final Display display = displayContent.getDisplay();
6863                        SurfaceControl surface = new SurfaceControl(session, "drag surface",
6864                                width, height, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
6865                        surface.setLayerStack(display.getLayerStack());
6866                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
6867                                + surface + ": CREATE");
6868                        outSurface.copyFrom(surface);
6869                        final IBinder winBinder = window.asBinder();
6870                        token = new Binder();
6871                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
6872                        token = mDragState.mToken = new Binder();
6873
6874                        // 5 second timeout for this window to actually begin the drag
6875                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
6876                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
6877                        mH.sendMessageDelayed(msg, 5000);
6878                    } else {
6879                        Slog.w(TAG, "Drag already in progress");
6880                    }
6881                } catch (OutOfResourcesException e) {
6882                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
6883                    if (mDragState != null) {
6884                        mDragState.reset();
6885                        mDragState = null;
6886                    }
6887                }
6888            }
6889        } finally {
6890            Binder.restoreCallingIdentity(origId);
6891        }
6892
6893        return token;
6894    }
6895
6896    // -------------------------------------------------------------
6897    // Input Events and Focus Management
6898    // -------------------------------------------------------------
6899
6900    final InputMonitor mInputMonitor = new InputMonitor(this);
6901    private boolean mEventDispatchingEnabled;
6902
6903    @Override
6904    public void pauseKeyDispatching(IBinder _token) {
6905        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6906                "pauseKeyDispatching()")) {
6907            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6908        }
6909
6910        synchronized (mWindowMap) {
6911            WindowToken token = mTokenMap.get(_token);
6912            if (token != null) {
6913                mInputMonitor.pauseDispatchingLw(token);
6914            }
6915        }
6916    }
6917
6918    @Override
6919    public void resumeKeyDispatching(IBinder _token) {
6920        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6921                "resumeKeyDispatching()")) {
6922            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6923        }
6924
6925        synchronized (mWindowMap) {
6926            WindowToken token = mTokenMap.get(_token);
6927            if (token != null) {
6928                mInputMonitor.resumeDispatchingLw(token);
6929            }
6930        }
6931    }
6932
6933    @Override
6934    public void setEventDispatching(boolean enabled) {
6935        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6936                "setEventDispatching()")) {
6937            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6938        }
6939
6940        synchronized (mWindowMap) {
6941            mEventDispatchingEnabled = enabled;
6942            if (mDisplayEnabled) {
6943                mInputMonitor.setEventDispatchingLw(enabled);
6944            }
6945            sendScreenStatusToClientsLocked();
6946        }
6947    }
6948
6949    private WindowState getFocusedWindow() {
6950        synchronized (mWindowMap) {
6951            return getFocusedWindowLocked();
6952        }
6953    }
6954
6955    private WindowState getFocusedWindowLocked() {
6956        return mCurrentFocus;
6957    }
6958
6959    public boolean detectSafeMode() {
6960        if (!mInputMonitor.waitForInputDevicesReady(
6961                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
6962            Slog.w(TAG, "Devices still not ready after waiting "
6963                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
6964                   + " milliseconds before attempting to detect safe mode.");
6965        }
6966
6967        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6968                KeyEvent.KEYCODE_MENU);
6969        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
6970        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
6971                KeyEvent.KEYCODE_DPAD_CENTER);
6972        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
6973                InputManagerService.BTN_MOUSE);
6974        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6975                KeyEvent.KEYCODE_VOLUME_DOWN);
6976        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
6977                || volumeDownState > 0;
6978        try {
6979            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
6980                mSafeMode = true;
6981                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
6982            }
6983        } catch (IllegalArgumentException e) {
6984        }
6985        if (mSafeMode) {
6986            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
6987                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
6988        } else {
6989            Log.i(TAG, "SAFE MODE not enabled");
6990        }
6991        mPolicy.setSafeMode(mSafeMode);
6992        return mSafeMode;
6993    }
6994
6995    public void displayReady() {
6996        displayReady(Display.DEFAULT_DISPLAY);
6997
6998        synchronized(mWindowMap) {
6999            final DisplayContent displayContent = getDefaultDisplayContentLocked();
7000            readForcedDisplaySizeAndDensityLocked(displayContent);
7001            mDisplayReady = true;
7002        }
7003
7004        try {
7005            mActivityManager.updateConfiguration(null);
7006        } catch (RemoteException e) {
7007        }
7008
7009        synchronized(mWindowMap) {
7010            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
7011                    PackageManager.FEATURE_TOUCHSCREEN);
7012            configureDisplayPolicyLocked(getDefaultDisplayContentLocked());
7013        }
7014
7015        try {
7016            mActivityManager.updateConfiguration(null);
7017        } catch (RemoteException e) {
7018        }
7019    }
7020
7021    private void displayReady(int displayId) {
7022        synchronized(mWindowMap) {
7023            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7024            if (displayContent != null) {
7025                mAnimator.addDisplayLocked(displayId);
7026                synchronized(displayContent.mDisplaySizeLock) {
7027                    // Bootstrap the default logical display from the display manager.
7028                    final DisplayInfo displayInfo = displayContent.getDisplayInfo();
7029                    DisplayInfo newDisplayInfo = mDisplayManagerInternal.getDisplayInfo(displayId);
7030                    if (newDisplayInfo != null) {
7031                        displayInfo.copyFrom(newDisplayInfo);
7032                    }
7033                    displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
7034                    displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
7035                    displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
7036                    displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
7037                    displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
7038                    displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
7039                    displayContent.mBaseDisplayRect.set(0, 0,
7040                            displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight);
7041                }
7042            }
7043        }
7044    }
7045
7046    public void systemReady() {
7047        mPolicy.systemReady();
7048    }
7049
7050    // TODO(multidisplay): Call isScreenOn for each display.
7051    private void sendScreenStatusToClientsLocked() {
7052        final boolean on = mPowerManager.isScreenOn();
7053        final int numDisplays = mDisplayContents.size();
7054        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
7055            final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
7056            final int numWindows = windows.size();
7057            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
7058                try {
7059                    windows.get(winNdx).mClient.dispatchScreenState(on);
7060                } catch (RemoteException e) {
7061                    // Ignored
7062                }
7063            }
7064        }
7065    }
7066
7067    // -------------------------------------------------------------
7068    // Async Handler
7069    // -------------------------------------------------------------
7070
7071    final class H extends Handler {
7072        public static final int REPORT_FOCUS_CHANGE = 2;
7073        public static final int REPORT_LOSING_FOCUS = 3;
7074        public static final int DO_TRAVERSAL = 4;
7075        public static final int ADD_STARTING = 5;
7076        public static final int REMOVE_STARTING = 6;
7077        public static final int FINISHED_STARTING = 7;
7078        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
7079        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
7080        public static final int WINDOW_FREEZE_TIMEOUT = 11;
7081
7082        public static final int APP_TRANSITION_TIMEOUT = 13;
7083        public static final int PERSIST_ANIMATION_SCALE = 14;
7084        public static final int FORCE_GC = 15;
7085        public static final int ENABLE_SCREEN = 16;
7086        public static final int APP_FREEZE_TIMEOUT = 17;
7087        public static final int SEND_NEW_CONFIGURATION = 18;
7088        public static final int REPORT_WINDOWS_CHANGE = 19;
7089        public static final int DRAG_START_TIMEOUT = 20;
7090        public static final int DRAG_END_TIMEOUT = 21;
7091        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
7092        public static final int BOOT_TIMEOUT = 23;
7093        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
7094        public static final int SHOW_STRICT_MODE_VIOLATION = 25;
7095        public static final int DO_ANIMATION_CALLBACK = 26;
7096
7097        public static final int DO_DISPLAY_ADDED = 27;
7098        public static final int DO_DISPLAY_REMOVED = 28;
7099        public static final int DO_DISPLAY_CHANGED = 29;
7100
7101        public static final int CLIENT_FREEZE_TIMEOUT = 30;
7102        public static final int TAP_OUTSIDE_STACK = 31;
7103        public static final int NOTIFY_ACTIVITY_DRAWN = 32;
7104
7105        public static final int REMOVE_STARTING_TIMEOUT = 33;
7106
7107        @Override
7108        public void handleMessage(Message msg) {
7109            if (DEBUG_WINDOW_TRACE) {
7110                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
7111            }
7112            switch (msg.what) {
7113                case REPORT_FOCUS_CHANGE: {
7114                    WindowState lastFocus;
7115                    WindowState newFocus;
7116
7117                    synchronized(mWindowMap) {
7118                        lastFocus = mLastFocus;
7119                        newFocus = mCurrentFocus;
7120                        if (lastFocus == newFocus) {
7121                            // Focus is not changing, so nothing to do.
7122                            return;
7123                        }
7124                        mLastFocus = newFocus;
7125                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Focus moving from " + lastFocus +
7126                                " to " + newFocus);
7127                        if (newFocus != null && lastFocus != null
7128                                && !newFocus.isDisplayedLw()) {
7129                            //Slog.i(TAG, "Delaying loss of focus...");
7130                            mLosingFocus.add(lastFocus);
7131                            lastFocus = null;
7132                        }
7133                    }
7134
7135                    //System.out.println("Changing focus from " + lastFocus
7136                    //                   + " to " + newFocus);
7137                    if (newFocus != null) {
7138                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Gaining focus: " + newFocus);
7139                        newFocus.reportFocusChangedSerialized(true, mInTouchMode);
7140                        notifyFocusChanged();
7141                    }
7142
7143                    if (lastFocus != null) {
7144                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing focus: " + lastFocus);
7145                        lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
7146                    }
7147                } break;
7148
7149                case REPORT_LOSING_FOCUS: {
7150                    ArrayList<WindowState> losers;
7151
7152                    synchronized(mWindowMap) {
7153                        losers = mLosingFocus;
7154                        mLosingFocus = new ArrayList<WindowState>();
7155                    }
7156
7157                    final int N = losers.size();
7158                    for (int i=0; i<N; i++) {
7159                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG, "Losing delayed focus: " +
7160                                losers.get(i));
7161                        losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
7162                    }
7163                } break;
7164
7165                case DO_TRAVERSAL: {
7166                    synchronized(mWindowMap) {
7167                        mTraversalScheduled = false;
7168                        performLayoutAndPlaceSurfacesLocked();
7169                    }
7170                } break;
7171
7172                case ADD_STARTING: {
7173                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7174                    final StartingData sd = wtoken.startingData;
7175
7176                    if (sd == null) {
7177                        // Animation has been canceled... do nothing.
7178                        return;
7179                    }
7180
7181                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
7182                            + wtoken + ": pkg=" + sd.pkg);
7183
7184                    View view = null;
7185                    try {
7186                        view = mPolicy.addStartingWindow(
7187                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
7188                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo, sd.windowFlags);
7189                    } catch (Exception e) {
7190                        Slog.w(TAG, "Exception when adding starting window", e);
7191                    }
7192
7193                    if (view != null) {
7194                        boolean abort = false;
7195
7196                        synchronized(mWindowMap) {
7197                            if (wtoken.removed || wtoken.startingData == null) {
7198                                // If the window was successfully added, then
7199                                // we need to remove it.
7200                                if (wtoken.startingWindow != null) {
7201                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7202                                            "Aborted starting " + wtoken
7203                                            + ": removed=" + wtoken.removed
7204                                            + " startingData=" + wtoken.startingData);
7205                                    wtoken.startingWindow = null;
7206                                    wtoken.startingData = null;
7207                                    abort = true;
7208                                }
7209                            } else {
7210                                wtoken.startingView = view;
7211                            }
7212                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
7213                                    "Added starting " + wtoken
7214                                    + ": startingWindow="
7215                                    + wtoken.startingWindow + " startingView="
7216                                    + wtoken.startingView);
7217                        }
7218
7219                        if (abort) {
7220                            try {
7221                                mPolicy.removeStartingWindow(wtoken.token, view);
7222                            } catch (Exception e) {
7223                                Slog.w(TAG, "Exception when removing starting window", e);
7224                            }
7225                        }
7226                    }
7227                } break;
7228
7229                case REMOVE_STARTING: {
7230                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7231                    IBinder token = null;
7232                    View view = null;
7233                    synchronized (mWindowMap) {
7234                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
7235                                + wtoken + ": startingWindow="
7236                                + wtoken.startingWindow + " startingView="
7237                                + wtoken.startingView);
7238                        if (wtoken.startingWindow != null) {
7239                            view = wtoken.startingView;
7240                            token = wtoken.token;
7241                            wtoken.startingData = null;
7242                            wtoken.startingView = null;
7243                            wtoken.startingWindow = null;
7244                            wtoken.startingDisplayed = false;
7245                        }
7246                    }
7247                    if (view != null) {
7248                        try {
7249                            mPolicy.removeStartingWindow(token, view);
7250                        } catch (Exception e) {
7251                            Slog.w(TAG, "Exception when removing starting window", e);
7252                        }
7253                    }
7254                } break;
7255
7256                case FINISHED_STARTING: {
7257                    IBinder token = null;
7258                    View view = null;
7259                    while (true) {
7260                        synchronized (mWindowMap) {
7261                            final int N = mFinishedStarting.size();
7262                            if (N <= 0) {
7263                                break;
7264                            }
7265                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7266
7267                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7268                                    "Finished starting " + wtoken
7269                                    + ": startingWindow=" + wtoken.startingWindow
7270                                    + " startingView=" + wtoken.startingView);
7271
7272                            if (wtoken.startingWindow == null) {
7273                                continue;
7274                            }
7275
7276                            view = wtoken.startingView;
7277                            token = wtoken.token;
7278                            wtoken.startingData = null;
7279                            wtoken.startingView = null;
7280                            wtoken.startingWindow = null;
7281                            wtoken.startingDisplayed = false;
7282                        }
7283
7284                        try {
7285                            mPolicy.removeStartingWindow(token, view);
7286                        } catch (Exception e) {
7287                            Slog.w(TAG, "Exception when removing starting window", e);
7288                        }
7289                    }
7290                } break;
7291
7292                case REPORT_APPLICATION_TOKEN_DRAWN: {
7293                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7294
7295                    try {
7296                        if (DEBUG_VISIBILITY) Slog.v(
7297                                TAG, "Reporting drawn in " + wtoken);
7298                        wtoken.appToken.windowsDrawn();
7299                    } catch (RemoteException ex) {
7300                    }
7301                } break;
7302
7303                case REPORT_APPLICATION_TOKEN_WINDOWS: {
7304                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7305
7306                    boolean nowVisible = msg.arg1 != 0;
7307                    boolean nowGone = msg.arg2 != 0;
7308
7309                    try {
7310                        if (DEBUG_VISIBILITY) Slog.v(
7311                                TAG, "Reporting visible in " + wtoken
7312                                + " visible=" + nowVisible
7313                                + " gone=" + nowGone);
7314                        if (nowVisible) {
7315                            wtoken.appToken.windowsVisible();
7316                        } else {
7317                            wtoken.appToken.windowsGone();
7318                        }
7319                    } catch (RemoteException ex) {
7320                    }
7321                } break;
7322
7323                case WINDOW_FREEZE_TIMEOUT: {
7324                    // TODO(multidisplay): Can non-default displays rotate?
7325                    synchronized (mWindowMap) {
7326                        Slog.w(TAG, "Window freeze timeout expired.");
7327                        final WindowList windows = getDefaultWindowListLocked();
7328                        int i = windows.size();
7329                        while (i > 0) {
7330                            i--;
7331                            WindowState w = windows.get(i);
7332                            if (w.mOrientationChanging) {
7333                                w.mOrientationChanging = false;
7334                                w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
7335                                        - mDisplayFreezeTime);
7336                                Slog.w(TAG, "Force clearing orientation change: " + w);
7337                            }
7338                        }
7339                        performLayoutAndPlaceSurfacesLocked();
7340                    }
7341                    break;
7342                }
7343
7344                case APP_TRANSITION_TIMEOUT: {
7345                    synchronized (mWindowMap) {
7346                        if (mAppTransition.isTransitionSet()) {
7347                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** APP TRANSITION TIMEOUT");
7348                            mAppTransition.setTimeout();
7349                            performLayoutAndPlaceSurfacesLocked();
7350                        }
7351                    }
7352                    break;
7353                }
7354
7355                case PERSIST_ANIMATION_SCALE: {
7356                    Settings.Global.putFloat(mContext.getContentResolver(),
7357                            Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7358                    Settings.Global.putFloat(mContext.getContentResolver(),
7359                            Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7360                    Settings.Global.putFloat(mContext.getContentResolver(),
7361                            Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
7362                    break;
7363                }
7364
7365                case FORCE_GC: {
7366                    synchronized (mWindowMap) {
7367                        // Since we're holding both mWindowMap and mAnimator we don't need to
7368                        // hold mAnimator.mLayoutToAnim.
7369                        if (mAnimator.mAnimating || mAnimationScheduled) {
7370                            // If we are animating, don't do the gc now but
7371                            // delay a bit so we don't interrupt the animation.
7372                            sendEmptyMessageDelayed(H.FORCE_GC, 2000);
7373                            return;
7374                        }
7375                        // If we are currently rotating the display, it will
7376                        // schedule a new message when done.
7377                        if (mDisplayFrozen) {
7378                            return;
7379                        }
7380                    }
7381                    Runtime.getRuntime().gc();
7382                    break;
7383                }
7384
7385                case ENABLE_SCREEN: {
7386                    performEnableScreen();
7387                    break;
7388                }
7389
7390                case APP_FREEZE_TIMEOUT: {
7391                    synchronized (mWindowMap) {
7392                        Slog.w(TAG, "App freeze timeout expired.");
7393                        final int numStacks = mStackIdToStack.size();
7394                        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
7395                            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
7396                            final ArrayList<Task> tasks = stack.getTasks();
7397                            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
7398                                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
7399                                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
7400                                    AppWindowToken tok = tokens.get(tokenNdx);
7401                                    if (tok.mAppAnimator.freezingScreen) {
7402                                        Slog.w(TAG, "Force clearing freeze: " + tok);
7403                                        unsetAppFreezingScreenLocked(tok, true, true);
7404                                    }
7405                                }
7406                            }
7407                        }
7408                    }
7409                    break;
7410                }
7411
7412                case CLIENT_FREEZE_TIMEOUT: {
7413                    synchronized (mWindowMap) {
7414                        if (mClientFreezingScreen) {
7415                            mClientFreezingScreen = false;
7416                            mLastFinishedFreezeSource = "client-timeout";
7417                            stopFreezingDisplayLocked();
7418                        }
7419                    }
7420                    break;
7421                }
7422
7423                case SEND_NEW_CONFIGURATION: {
7424                    removeMessages(SEND_NEW_CONFIGURATION);
7425                    sendNewConfiguration();
7426                    break;
7427                }
7428
7429                case REPORT_WINDOWS_CHANGE: {
7430                    if (mWindowsChanged) {
7431                        synchronized (mWindowMap) {
7432                            mWindowsChanged = false;
7433                        }
7434                        notifyWindowsChanged();
7435                    }
7436                    break;
7437                }
7438
7439                case DRAG_START_TIMEOUT: {
7440                    IBinder win = (IBinder)msg.obj;
7441                    if (DEBUG_DRAG) {
7442                        Slog.w(TAG, "Timeout starting drag by win " + win);
7443                    }
7444                    synchronized (mWindowMap) {
7445                        // !!! TODO: ANR the app that has failed to start the drag in time
7446                        if (mDragState != null) {
7447                            mDragState.unregister();
7448                            mInputMonitor.updateInputWindowsLw(true /*force*/);
7449                            mDragState.reset();
7450                            mDragState = null;
7451                        }
7452                    }
7453                    break;
7454                }
7455
7456                case DRAG_END_TIMEOUT: {
7457                    IBinder win = (IBinder)msg.obj;
7458                    if (DEBUG_DRAG) {
7459                        Slog.w(TAG, "Timeout ending drag to win " + win);
7460                    }
7461                    synchronized (mWindowMap) {
7462                        // !!! TODO: ANR the drag-receiving app
7463                        if (mDragState != null) {
7464                            mDragState.mDragResult = false;
7465                            mDragState.endDragLw();
7466                        }
7467                    }
7468                    break;
7469                }
7470
7471                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
7472                    notifyHardKeyboardStatusChange();
7473                    break;
7474                }
7475
7476                case BOOT_TIMEOUT: {
7477                    performBootTimeout();
7478                    break;
7479                }
7480
7481                case WAITING_FOR_DRAWN_TIMEOUT: {
7482                    Pair<WindowState, IRemoteCallback> pair;
7483                    synchronized (mWindowMap) {
7484                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
7485                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
7486                        if (!mWaitingForDrawn.remove(pair)) {
7487                            return;
7488                        }
7489                    }
7490                    try {
7491                        pair.second.sendResult(null);
7492                    } catch (RemoteException e) {
7493                    }
7494                    break;
7495                }
7496
7497                case SHOW_STRICT_MODE_VIOLATION: {
7498                    showStrictModeViolation(msg.arg1, msg.arg2);
7499                    break;
7500                }
7501
7502                case DO_ANIMATION_CALLBACK: {
7503                    try {
7504                        ((IRemoteCallback)msg.obj).sendResult(null);
7505                    } catch (RemoteException e) {
7506                    }
7507                    break;
7508                }
7509
7510                case DO_DISPLAY_ADDED:
7511                    handleDisplayAdded(msg.arg1);
7512                    break;
7513
7514                case DO_DISPLAY_REMOVED:
7515                    synchronized (mWindowMap) {
7516                        handleDisplayRemovedLocked(msg.arg1);
7517                    }
7518                    break;
7519
7520                case DO_DISPLAY_CHANGED:
7521                    synchronized (mWindowMap) {
7522                        handleDisplayChangedLocked(msg.arg1);
7523                    }
7524                    break;
7525
7526                case TAP_OUTSIDE_STACK: {
7527                    int stackId;
7528                    synchronized (mWindowMap) {
7529                        stackId = ((DisplayContent)msg.obj).stackIdFromPoint(msg.arg1, msg.arg2);
7530                    }
7531                    if (stackId >= 0) {
7532                        try {
7533                            mActivityManager.setFocusedStack(stackId);
7534                        } catch (RemoteException e) {
7535                        }
7536                    }
7537                }
7538                break;
7539                case NOTIFY_ACTIVITY_DRAWN:
7540                    try {
7541                        mActivityManager.notifyActivityDrawn((IBinder) msg.obj);
7542                    } catch (RemoteException e) {
7543                    }
7544                    break;
7545            }
7546            if (DEBUG_WINDOW_TRACE) {
7547                Slog.v(TAG, "handleMessage: exit");
7548            }
7549        }
7550    }
7551
7552    // -------------------------------------------------------------
7553    // IWindowManager API
7554    // -------------------------------------------------------------
7555
7556    @Override
7557    public IWindowSession openSession(IInputMethodClient client,
7558            IInputContext inputContext) {
7559        if (client == null) throw new IllegalArgumentException("null client");
7560        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7561        Session session = new Session(this, client, inputContext);
7562        return session;
7563    }
7564
7565    @Override
7566    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7567        synchronized (mWindowMap) {
7568            // The focus for the client is the window immediately below
7569            // where we would place the input method window.
7570            int idx = findDesiredInputMethodWindowIndexLocked(false);
7571            if (idx > 0) {
7572                // TODO(multidisplay): IMEs are only supported on the default display.
7573                WindowState imFocus = getDefaultWindowListLocked().get(idx-1);
7574                if (DEBUG_INPUT_METHOD) {
7575                    Slog.i(TAG, "Desired input method target: " + imFocus);
7576                    Slog.i(TAG, "Current focus: " + mCurrentFocus);
7577                    Slog.i(TAG, "Last focus: " + mLastFocus);
7578                }
7579                if (imFocus != null) {
7580                    // This may be a starting window, in which case we still want
7581                    // to count it as okay.
7582                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
7583                            && imFocus.mAppToken != null) {
7584                        // The client has definitely started, so it really should
7585                        // have a window in this app token.  Let's look for it.
7586                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
7587                            WindowState w = imFocus.mAppToken.windows.get(i);
7588                            if (w != imFocus) {
7589                                Log.i(TAG, "Switching to real app window: " + w);
7590                                imFocus = w;
7591                                break;
7592                            }
7593                        }
7594                    }
7595                    if (DEBUG_INPUT_METHOD) {
7596                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
7597                        if (imFocus.mSession.mClient != null) {
7598                            Slog.i(TAG, "IM target client binder: "
7599                                    + imFocus.mSession.mClient.asBinder());
7600                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
7601                        }
7602                    }
7603                    if (imFocus.mSession.mClient != null &&
7604                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7605                        return true;
7606                    }
7607                }
7608            }
7609
7610            // Okay, how about this...  what is the current focus?
7611            // It seems in some cases we may not have moved the IM
7612            // target window, such as when it was in a pop-up window,
7613            // so let's also look at the current focus.  (An example:
7614            // go to Gmail, start searching so the keyboard goes up,
7615            // press home.  Sometimes the IME won't go down.)
7616            // Would be nice to fix this more correctly, but it's
7617            // way at the end of a release, and this should be good enough.
7618            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
7619                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7620                return true;
7621            }
7622        }
7623        return false;
7624    }
7625
7626    @Override
7627    public void getInitialDisplaySize(int displayId, Point size) {
7628        synchronized (mWindowMap) {
7629            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7630            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
7631                synchronized(displayContent.mDisplaySizeLock) {
7632                    size.x = displayContent.mInitialDisplayWidth;
7633                    size.y = displayContent.mInitialDisplayHeight;
7634                }
7635            }
7636        }
7637    }
7638
7639    @Override
7640    public void getBaseDisplaySize(int displayId, Point size) {
7641        synchronized (mWindowMap) {
7642            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7643            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
7644                synchronized(displayContent.mDisplaySizeLock) {
7645                    size.x = displayContent.mBaseDisplayWidth;
7646                    size.y = displayContent.mBaseDisplayHeight;
7647                }
7648            }
7649        }
7650    }
7651
7652    @Override
7653    public void setForcedDisplaySize(int displayId, int width, int height) {
7654        if (mContext.checkCallingOrSelfPermission(
7655                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7656                PackageManager.PERMISSION_GRANTED) {
7657            throw new SecurityException("Must hold permission " +
7658                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7659        }
7660        if (displayId != Display.DEFAULT_DISPLAY) {
7661            throw new IllegalArgumentException("Can only set the default display");
7662        }
7663        final long ident = Binder.clearCallingIdentity();
7664        try {
7665            synchronized(mWindowMap) {
7666                // Set some sort of reasonable bounds on the size of the display that we
7667                // will try to emulate.
7668                final int MIN_WIDTH = 200;
7669                final int MIN_HEIGHT = 200;
7670                final int MAX_SCALE = 2;
7671                final DisplayContent displayContent = getDisplayContentLocked(displayId);
7672                if (displayContent != null) {
7673                    width = Math.min(Math.max(width, MIN_WIDTH),
7674                            displayContent.mInitialDisplayWidth * MAX_SCALE);
7675                    height = Math.min(Math.max(height, MIN_HEIGHT),
7676                            displayContent.mInitialDisplayHeight * MAX_SCALE);
7677                    setForcedDisplaySizeLocked(displayContent, width, height);
7678                    Settings.Global.putString(mContext.getContentResolver(),
7679                            Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
7680                }
7681            }
7682        } finally {
7683            Binder.restoreCallingIdentity(ident);
7684        }
7685    }
7686
7687    private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) {
7688        String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
7689                Settings.Global.DISPLAY_SIZE_FORCED);
7690        if (sizeStr == null || sizeStr.length() == 0) {
7691            sizeStr = SystemProperties.get(SIZE_OVERRIDE, null);
7692        }
7693        if (sizeStr != null && sizeStr.length() > 0) {
7694            final int pos = sizeStr.indexOf(',');
7695            if (pos > 0 && sizeStr.lastIndexOf(',') == pos) {
7696                int width, height;
7697                try {
7698                    width = Integer.parseInt(sizeStr.substring(0, pos));
7699                    height = Integer.parseInt(sizeStr.substring(pos+1));
7700                    synchronized(displayContent.mDisplaySizeLock) {
7701                        if (displayContent.mBaseDisplayWidth != width
7702                                || displayContent.mBaseDisplayHeight != height) {
7703                            Slog.i(TAG, "FORCED DISPLAY SIZE: " + width + "x" + height);
7704                            displayContent.mBaseDisplayWidth = width;
7705                            displayContent.mBaseDisplayHeight = height;
7706                        }
7707                    }
7708                } catch (NumberFormatException ex) {
7709                }
7710            }
7711        }
7712        String densityStr = Settings.Global.getString(mContext.getContentResolver(),
7713                Settings.Global.DISPLAY_DENSITY_FORCED);
7714        if (densityStr == null || densityStr.length() == 0) {
7715            densityStr = SystemProperties.get(DENSITY_OVERRIDE, null);
7716        }
7717        if (densityStr != null && densityStr.length() > 0) {
7718            int density;
7719            try {
7720                density = Integer.parseInt(densityStr);
7721                synchronized(displayContent.mDisplaySizeLock) {
7722                    if (displayContent.mBaseDisplayDensity != density) {
7723                        Slog.i(TAG, "FORCED DISPLAY DENSITY: " + density);
7724                        displayContent.mBaseDisplayDensity = density;
7725                    }
7726                }
7727            } catch (NumberFormatException ex) {
7728            }
7729        }
7730    }
7731
7732    // displayContent must not be null
7733    private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
7734        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7735
7736        synchronized(displayContent.mDisplaySizeLock) {
7737            displayContent.mBaseDisplayWidth = width;
7738            displayContent.mBaseDisplayHeight = height;
7739        }
7740        reconfigureDisplayLocked(displayContent);
7741    }
7742
7743    @Override
7744    public void clearForcedDisplaySize(int displayId) {
7745        if (mContext.checkCallingOrSelfPermission(
7746                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7747                PackageManager.PERMISSION_GRANTED) {
7748            throw new SecurityException("Must hold permission " +
7749                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7750        }
7751        if (displayId != Display.DEFAULT_DISPLAY) {
7752            throw new IllegalArgumentException("Can only set the default display");
7753        }
7754        final long ident = Binder.clearCallingIdentity();
7755        try {
7756            synchronized(mWindowMap) {
7757                final DisplayContent displayContent = getDisplayContentLocked(displayId);
7758                if (displayContent != null) {
7759                    setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
7760                            displayContent.mInitialDisplayHeight);
7761                    Settings.Global.putString(mContext.getContentResolver(),
7762                            Settings.Global.DISPLAY_SIZE_FORCED, "");
7763                }
7764            }
7765        } finally {
7766            Binder.restoreCallingIdentity(ident);
7767        }
7768    }
7769
7770    @Override
7771    public int getInitialDisplayDensity(int displayId) {
7772        synchronized (mWindowMap) {
7773            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7774            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
7775                synchronized(displayContent.mDisplaySizeLock) {
7776                    return displayContent.mInitialDisplayDensity;
7777                }
7778            }
7779        }
7780        return -1;
7781    }
7782
7783    @Override
7784    public int getBaseDisplayDensity(int displayId) {
7785        synchronized (mWindowMap) {
7786            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7787            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
7788                synchronized(displayContent.mDisplaySizeLock) {
7789                    return displayContent.mBaseDisplayDensity;
7790                }
7791            }
7792        }
7793        return -1;
7794    }
7795
7796    @Override
7797    public void setForcedDisplayDensity(int displayId, int density) {
7798        if (mContext.checkCallingOrSelfPermission(
7799                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7800                PackageManager.PERMISSION_GRANTED) {
7801            throw new SecurityException("Must hold permission " +
7802                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7803        }
7804        if (displayId != Display.DEFAULT_DISPLAY) {
7805            throw new IllegalArgumentException("Can only set the default display");
7806        }
7807        final long ident = Binder.clearCallingIdentity();
7808        try {
7809            synchronized(mWindowMap) {
7810                final DisplayContent displayContent = getDisplayContentLocked(displayId);
7811                if (displayContent != null) {
7812                    setForcedDisplayDensityLocked(displayContent, density);
7813                    Settings.Global.putString(mContext.getContentResolver(),
7814                            Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
7815                }
7816            }
7817        } finally {
7818            Binder.restoreCallingIdentity(ident);
7819        }
7820    }
7821
7822    // displayContent must not be null
7823    private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) {
7824        Slog.i(TAG, "Using new display density: " + density);
7825
7826        synchronized(displayContent.mDisplaySizeLock) {
7827            displayContent.mBaseDisplayDensity = density;
7828        }
7829        reconfigureDisplayLocked(displayContent);
7830    }
7831
7832    @Override
7833    public void clearForcedDisplayDensity(int displayId) {
7834        if (mContext.checkCallingOrSelfPermission(
7835                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7836                PackageManager.PERMISSION_GRANTED) {
7837            throw new SecurityException("Must hold permission " +
7838                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7839        }
7840        if (displayId != Display.DEFAULT_DISPLAY) {
7841            throw new IllegalArgumentException("Can only set the default display");
7842        }
7843        final long ident = Binder.clearCallingIdentity();
7844        try {
7845            synchronized(mWindowMap) {
7846                final DisplayContent displayContent = getDisplayContentLocked(displayId);
7847                if (displayContent != null) {
7848                    setForcedDisplayDensityLocked(displayContent,
7849                            displayContent.mInitialDisplayDensity);
7850                    Settings.Global.putString(mContext.getContentResolver(),
7851                            Settings.Global.DISPLAY_DENSITY_FORCED, "");
7852                }
7853            }
7854        } finally {
7855            Binder.restoreCallingIdentity(ident);
7856        }
7857    }
7858
7859    // displayContent must not be null
7860    private void reconfigureDisplayLocked(DisplayContent displayContent) {
7861        // TODO: Multidisplay: for now only use with default display.
7862        configureDisplayPolicyLocked(displayContent);
7863        displayContent.layoutNeeded = true;
7864
7865        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7866        mTempConfiguration.setToDefaults();
7867        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7868        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7869            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7870                configChanged = true;
7871            }
7872        }
7873
7874        if (configChanged) {
7875            mWaitingForConfig = true;
7876            startFreezingDisplayLocked(false, 0, 0);
7877            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7878        }
7879
7880        performLayoutAndPlaceSurfacesLocked();
7881    }
7882
7883    private void configureDisplayPolicyLocked(DisplayContent displayContent) {
7884        mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
7885                displayContent.mBaseDisplayWidth,
7886                displayContent.mBaseDisplayHeight,
7887                displayContent.mBaseDisplayDensity);
7888
7889        DisplayInfo displayInfo = displayContent.getDisplayInfo();
7890        mPolicy.setDisplayOverscan(displayContent.getDisplay(),
7891                displayInfo.overscanLeft, displayInfo.overscanTop,
7892                displayInfo.overscanRight, displayInfo.overscanBottom);
7893    }
7894
7895    @Override
7896    public void setOverscan(int displayId, int left, int top, int right, int bottom) {
7897        if (mContext.checkCallingOrSelfPermission(
7898                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7899                PackageManager.PERMISSION_GRANTED) {
7900            throw new SecurityException("Must hold permission " +
7901                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7902        }
7903        final long ident = Binder.clearCallingIdentity();
7904        try {
7905            synchronized(mWindowMap) {
7906                DisplayContent displayContent = getDisplayContentLocked(displayId);
7907                if (displayContent != null) {
7908                    setOverscanLocked(displayContent, left, top, right, bottom);
7909                }
7910            }
7911        } finally {
7912            Binder.restoreCallingIdentity(ident);
7913        }
7914    }
7915
7916    private void setOverscanLocked(DisplayContent displayContent,
7917            int left, int top, int right, int bottom) {
7918        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
7919        synchronized (displayContent.mDisplaySizeLock) {
7920            displayInfo.overscanLeft = left;
7921            displayInfo.overscanTop = top;
7922            displayInfo.overscanRight = right;
7923            displayInfo.overscanBottom = bottom;
7924        }
7925
7926        mDisplaySettings.setOverscanLocked(displayInfo.name, left, top, right, bottom);
7927        mDisplaySettings.writeSettingsLocked();
7928
7929        reconfigureDisplayLocked(displayContent);
7930    }
7931
7932    // -------------------------------------------------------------
7933    // Internals
7934    // -------------------------------------------------------------
7935
7936    final WindowState windowForClientLocked(Session session, IWindow client,
7937            boolean throwOnError) {
7938        return windowForClientLocked(session, client.asBinder(), throwOnError);
7939    }
7940
7941    final WindowState windowForClientLocked(Session session, IBinder client,
7942            boolean throwOnError) {
7943        WindowState win = mWindowMap.get(client);
7944        if (localLOGV) Slog.v(
7945            TAG, "Looking up client " + client + ": " + win);
7946        if (win == null) {
7947            RuntimeException ex = new IllegalArgumentException(
7948                    "Requested window " + client + " does not exist");
7949            if (throwOnError) {
7950                throw ex;
7951            }
7952            Slog.w(TAG, "Failed looking up window", ex);
7953            return null;
7954        }
7955        if (session != null && win.mSession != session) {
7956            RuntimeException ex = new IllegalArgumentException(
7957                    "Requested window " + client + " is in session " +
7958                    win.mSession + ", not " + session);
7959            if (throwOnError) {
7960                throw ex;
7961            }
7962            Slog.w(TAG, "Failed looking up window", ex);
7963            return null;
7964        }
7965
7966        return win;
7967    }
7968
7969    final void rebuildAppWindowListLocked() {
7970        rebuildAppWindowListLocked(getDefaultDisplayContentLocked());
7971    }
7972
7973    private void rebuildAppWindowListLocked(final DisplayContent displayContent) {
7974        final WindowList windows = displayContent.getWindowList();
7975        int NW = windows.size();
7976        int i;
7977        int lastBelow = -1;
7978        int numRemoved = 0;
7979
7980        if (mRebuildTmp.length < NW) {
7981            mRebuildTmp = new WindowState[NW+10];
7982        }
7983
7984        // First remove all existing app windows.
7985        i=0;
7986        while (i < NW) {
7987            WindowState w = windows.get(i);
7988            if (w.mAppToken != null) {
7989                WindowState win = windows.remove(i);
7990                win.mRebuilding = true;
7991                mRebuildTmp[numRemoved] = win;
7992                mWindowsChanged = true;
7993                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Rebuild removing window: " + win);
7994                NW--;
7995                numRemoved++;
7996                continue;
7997            } else if (lastBelow == i-1) {
7998                if (w.mAttrs.type == TYPE_WALLPAPER || w.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
7999                    lastBelow = i;
8000                }
8001            }
8002            i++;
8003        }
8004
8005        // Keep whatever windows were below the app windows still below,
8006        // by skipping them.
8007        lastBelow++;
8008        i = lastBelow;
8009
8010        // First add all of the exiting app tokens...  these are no longer
8011        // in the main app list, but still have windows shown.  We put them
8012        // in the back because now that the animation is over we no longer
8013        // will care about them.
8014        final ArrayList<TaskStack> stacks = displayContent.getStacks();
8015        final int numStacks = stacks.size();
8016        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
8017            AppTokenList exitingAppTokens = stacks.get(stackNdx).mExitingAppTokens;
8018            int NT = exitingAppTokens.size();
8019            for (int j = 0; j < NT; j++) {
8020                i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
8021            }
8022        }
8023
8024        // And add in the still active app tokens in Z order.
8025        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
8026            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
8027            final int numTasks = tasks.size();
8028            for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
8029                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
8030                final int numTokens = tokens.size();
8031                for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
8032                    final AppWindowToken wtoken = tokens.get(tokenNdx);
8033                    if (wtoken.mDeferRemoval) {
8034                        continue;
8035                    }
8036                    i = reAddAppWindowsLocked(displayContent, i, wtoken);
8037                }
8038            }
8039        }
8040
8041        i -= lastBelow;
8042        if (i != numRemoved) {
8043            Slog.w(TAG, "On display=" + displayContent.getDisplayId() + " Rebuild removed " +
8044                    numRemoved + " windows but added " + i,
8045                    new RuntimeException("here").fillInStackTrace());
8046            for (i=0; i<numRemoved; i++) {
8047                WindowState ws = mRebuildTmp[i];
8048                if (ws.mRebuilding) {
8049                    StringWriter sw = new StringWriter();
8050                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
8051                    ws.dump(pw, "", true);
8052                    pw.flush();
8053                    Slog.w(TAG, "This window was lost: " + ws);
8054                    Slog.w(TAG, sw.toString());
8055                    ws.mWinAnimator.destroySurfaceLocked();
8056                }
8057            }
8058            Slog.w(TAG, "Current app token list:");
8059            dumpAppTokensLocked();
8060            Slog.w(TAG, "Final window list:");
8061            dumpWindowsLocked();
8062        }
8063    }
8064
8065    private final void assignLayersLocked(WindowList windows) {
8066        int N = windows.size();
8067        int curBaseLayer = 0;
8068        int curLayer = 0;
8069        int i;
8070
8071        if (DEBUG_LAYERS) Slog.v(TAG, "Assigning layers based on windows=" + windows,
8072                new RuntimeException("here").fillInStackTrace());
8073
8074        boolean anyLayerChanged = false;
8075
8076        for (i=0; i<N; i++) {
8077            final WindowState w = windows.get(i);
8078            final WindowStateAnimator winAnimator = w.mWinAnimator;
8079            boolean layerChanged = false;
8080            int oldLayer = w.mLayer;
8081            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
8082                    || (i > 0 && w.mIsWallpaper)) {
8083                curLayer += WINDOW_LAYER_MULTIPLIER;
8084                w.mLayer = curLayer;
8085            } else {
8086                curBaseLayer = curLayer = w.mBaseLayer;
8087                w.mLayer = curLayer;
8088            }
8089            if (w.mLayer != oldLayer) {
8090                layerChanged = true;
8091                anyLayerChanged = true;
8092            }
8093            final AppWindowToken wtoken = w.mAppToken;
8094            oldLayer = winAnimator.mAnimLayer;
8095            if (w.mTargetAppToken != null) {
8096                winAnimator.mAnimLayer =
8097                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
8098            } else if (wtoken != null) {
8099                winAnimator.mAnimLayer =
8100                        w.mLayer + wtoken.mAppAnimator.animLayerAdjustment;
8101            } else {
8102                winAnimator.mAnimLayer = w.mLayer;
8103            }
8104            if (w.mIsImWindow) {
8105                winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
8106            } else if (w.mIsWallpaper) {
8107                winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
8108            }
8109            if (winAnimator.mAnimLayer != oldLayer) {
8110                layerChanged = true;
8111                anyLayerChanged = true;
8112            }
8113            if (layerChanged && w.getStack().isDimming(winAnimator)) {
8114                // Force an animation pass just to update the mDimLayer layer.
8115                scheduleAnimationLocked();
8116            }
8117            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
8118                    + "mBase=" + w.mBaseLayer
8119                    + " mLayer=" + w.mLayer
8120                    + (wtoken == null ?
8121                            "" : " mAppLayer=" + wtoken.mAppAnimator.animLayerAdjustment)
8122                    + " =mAnimLayer=" + winAnimator.mAnimLayer);
8123            //System.out.println(
8124            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
8125        }
8126
8127        //TODO (multidisplay): Magnification is supported only for the default display.
8128        if (mAccessibilityController != null && anyLayerChanged
8129                && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
8130            mAccessibilityController.onWindowLayersChangedLocked();
8131        }
8132    }
8133
8134    private final void performLayoutAndPlaceSurfacesLocked() {
8135        int loopCount = 6;
8136        do {
8137            mTraversalScheduled = false;
8138            performLayoutAndPlaceSurfacesLockedLoop();
8139            mH.removeMessages(H.DO_TRAVERSAL);
8140            loopCount--;
8141        } while (mTraversalScheduled && loopCount > 0);
8142        mInnerFields.mWallpaperActionPending = false;
8143    }
8144
8145    private boolean mInLayout = false;
8146    private final void performLayoutAndPlaceSurfacesLockedLoop() {
8147        if (mInLayout) {
8148            if (DEBUG) {
8149                throw new RuntimeException("Recursive call!");
8150            }
8151            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
8152                    + Debug.getCallers(3));
8153            return;
8154        }
8155
8156        if (mWaitingForConfig) {
8157            // Our configuration has changed (most likely rotation), but we
8158            // don't yet have the complete configuration to report to
8159            // applications.  Don't do any window layout until we have it.
8160            return;
8161        }
8162
8163        if (!mDisplayReady) {
8164            // Not yet initialized, nothing to do.
8165            return;
8166        }
8167
8168        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
8169        mInLayout = true;
8170        boolean recoveringMemory = false;
8171
8172        try {
8173            if (mForceRemoves != null) {
8174                recoveringMemory = true;
8175                // Wait a little bit for things to settle down, and off we go.
8176                for (int i=0; i<mForceRemoves.size(); i++) {
8177                    WindowState ws = mForceRemoves.get(i);
8178                    Slog.i(TAG, "Force removing: " + ws);
8179                    removeWindowInnerLocked(ws.mSession, ws);
8180                }
8181                mForceRemoves = null;
8182                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
8183                Object tmp = new Object();
8184                synchronized (tmp) {
8185                    try {
8186                        tmp.wait(250);
8187                    } catch (InterruptedException e) {
8188                    }
8189                }
8190            }
8191        } catch (RuntimeException e) {
8192            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
8193        }
8194
8195        try {
8196            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
8197
8198            mInLayout = false;
8199
8200            if (needsLayout()) {
8201                if (++mLayoutRepeatCount < 6) {
8202                    requestTraversalLocked();
8203                } else {
8204                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
8205                    mLayoutRepeatCount = 0;
8206                }
8207            } else {
8208                mLayoutRepeatCount = 0;
8209            }
8210
8211            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
8212                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
8213                mH.sendEmptyMessage(H.REPORT_WINDOWS_CHANGE);
8214            }
8215        } catch (RuntimeException e) {
8216            mInLayout = false;
8217            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
8218        }
8219
8220        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
8221    }
8222
8223    private final void performLayoutLockedInner(final DisplayContent displayContent,
8224                                    boolean initial, boolean updateInputWindows) {
8225        if (!displayContent.layoutNeeded) {
8226            return;
8227        }
8228        displayContent.layoutNeeded = false;
8229        WindowList windows = displayContent.getWindowList();
8230        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
8231
8232        DisplayInfo displayInfo = displayContent.getDisplayInfo();
8233        final int dw = displayInfo.logicalWidth;
8234        final int dh = displayInfo.logicalHeight;
8235
8236        final int NFW = mFakeWindows.size();
8237        for (int i=0; i<NFW; i++) {
8238            mFakeWindows.get(i).layout(dw, dh);
8239        }
8240
8241        final int N = windows.size();
8242        int i;
8243
8244        if (DEBUG_LAYOUT) {
8245            Slog.v(TAG, "-------------------------------------");
8246            Slog.v(TAG, "performLayout: needed="
8247                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
8248        }
8249
8250        WindowStateAnimator universeBackground = null;
8251
8252        mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
8253        if (isDefaultDisplay) {
8254            // Not needed on non-default displays.
8255            mSystemDecorLayer = mPolicy.getSystemDecorLayerLw();
8256            mScreenRect.set(0, 0, dw, dh);
8257        }
8258
8259        mPolicy.getContentRectLw(mTmpContentRect);
8260        displayContent.resize(mTmpContentRect);
8261
8262        int seq = mLayoutSeq+1;
8263        if (seq < 0) seq = 0;
8264        mLayoutSeq = seq;
8265
8266        boolean behindDream = false;
8267
8268        // First perform layout of any root windows (not attached
8269        // to another window).
8270        int topAttached = -1;
8271        for (i = N-1; i >= 0; i--) {
8272            final WindowState win = windows.get(i);
8273
8274            // Don't do layout of a window if it is not visible, or
8275            // soon won't be visible, to avoid wasting time and funky
8276            // changes while a window is animating away.
8277            final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
8278                    || win.isGoneForLayoutLw();
8279
8280            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
8281                Slog.v(TAG, "1ST PASS " + win
8282                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
8283                        + " mLayoutAttached=" + win.mLayoutAttached
8284                        + " screen changed=" + win.isConfigChanged());
8285                final AppWindowToken atoken = win.mAppToken;
8286                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
8287                        + win.mViewVisibility + " mRelayoutCalled="
8288                        + win.mRelayoutCalled + " hidden="
8289                        + win.mRootToken.hidden + " hiddenRequested="
8290                        + (atoken != null && atoken.hiddenRequested)
8291                        + " mAttachedHidden=" + win.mAttachedHidden);
8292                else Slog.v(TAG, "  VIS: mViewVisibility="
8293                        + win.mViewVisibility + " mRelayoutCalled="
8294                        + win.mRelayoutCalled + " hidden="
8295                        + win.mRootToken.hidden + " hiddenRequested="
8296                        + (atoken != null && atoken.hiddenRequested)
8297                        + " mAttachedHidden=" + win.mAttachedHidden);
8298            }
8299
8300            // If this view is GONE, then skip it -- keep the current
8301            // frame, and let the caller know so they can ignore it
8302            // if they want.  (We do the normal layout for INVISIBLE
8303            // windows, since that means "perform layout as normal,
8304            // just don't display").
8305            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
8306                    || ((win.isConfigChanged() || win.setInsetsChanged()) &&
8307                            ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
8308                            win.mAppToken != null && win.mAppToken.layoutConfigChanges))
8309                    || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
8310                if (!win.mLayoutAttached) {
8311                    if (initial) {
8312                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8313                        win.mContentChanged = false;
8314                    }
8315                    if (win.mAttrs.type == TYPE_DREAM) {
8316                        // Don't layout windows behind a dream, so that if it
8317                        // does stuff like hide the status bar we won't get a
8318                        // bad transition when it goes away.
8319                        behindDream = true;
8320                    }
8321                    win.mLayoutNeeded = false;
8322                    win.prelayout();
8323                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
8324                    win.mLayoutSeq = seq;
8325                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8326                            + win.mFrame + " mContainingFrame="
8327                            + win.mContainingFrame + " mDisplayFrame="
8328                            + win.mDisplayFrame);
8329                } else {
8330                    if (topAttached < 0) topAttached = i;
8331                }
8332            }
8333            if (win.mViewVisibility == View.VISIBLE
8334                    && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND
8335                    && universeBackground == null) {
8336                universeBackground = win.mWinAnimator;
8337            }
8338        }
8339
8340        if (mAnimator.mUniverseBackground  != universeBackground) {
8341            mFocusMayChange = true;
8342            mAnimator.mUniverseBackground = universeBackground;
8343        }
8344
8345        boolean attachedBehindDream = false;
8346
8347        // Now perform layout of attached windows, which usually
8348        // depend on the position of the window they are attached to.
8349        // XXX does not deal with windows that are attached to windows
8350        // that are themselves attached.
8351        for (i = topAttached; i >= 0; i--) {
8352            final WindowState win = windows.get(i);
8353
8354            if (win.mLayoutAttached) {
8355                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
8356                        + " mHaveFrame=" + win.mHaveFrame
8357                        + " mViewVisibility=" + win.mViewVisibility
8358                        + " mRelayoutCalled=" + win.mRelayoutCalled);
8359                // If this view is GONE, then skip it -- keep the current
8360                // frame, and let the caller know so they can ignore it
8361                // if they want.  (We do the normal layout for INVISIBLE
8362                // windows, since that means "perform layout as normal,
8363                // just don't display").
8364                if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
8365                    continue;
8366                }
8367                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
8368                        || !win.mHaveFrame || win.mLayoutNeeded) {
8369                    if (initial) {
8370                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8371                        win.mContentChanged = false;
8372                    }
8373                    win.mLayoutNeeded = false;
8374                    win.prelayout();
8375                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
8376                    win.mLayoutSeq = seq;
8377                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8378                            + win.mFrame + " mContainingFrame="
8379                            + win.mContainingFrame + " mDisplayFrame="
8380                            + win.mDisplayFrame);
8381                }
8382            } else if (win.mAttrs.type == TYPE_DREAM) {
8383                // Don't layout windows behind a dream, so that if it
8384                // does stuff like hide the status bar we won't get a
8385                // bad transition when it goes away.
8386                attachedBehindDream = behindDream;
8387            }
8388        }
8389
8390        // Window frames may have changed.  Tell the input dispatcher about it.
8391        mInputMonitor.setUpdateInputWindowsNeededLw();
8392        if (updateInputWindows) {
8393            mInputMonitor.updateInputWindowsLw(false /*force*/);
8394        }
8395
8396        mPolicy.finishLayoutLw();
8397    }
8398
8399    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
8400        // If the screen is currently frozen or off, then keep
8401        // it frozen/off until this window draws at its new
8402        // orientation.
8403        if (!okToDisplay()) {
8404            if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w);
8405            w.mOrientationChanging = true;
8406            w.mLastFreezeDuration = 0;
8407            mInnerFields.mOrientationChangeComplete = false;
8408            if (!mWindowsFreezingScreen) {
8409                mWindowsFreezingScreen = true;
8410                // XXX should probably keep timeout from
8411                // when we first froze the display.
8412                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8413                mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT,
8414                        WINDOW_FREEZE_TIMEOUT_DURATION);
8415            }
8416        }
8417    }
8418
8419    /**
8420     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8421     * @param windows List of windows on default display.
8422     * @return bitmap indicating if another pass through layout must be made.
8423     */
8424    public int handleAppTransitionReadyLocked(WindowList windows) {
8425        int changes = 0;
8426        int i;
8427        int NN = mOpeningApps.size();
8428        boolean goodToGo = true;
8429        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8430                "Checking " + NN + " opening apps (frozen="
8431                + mDisplayFrozen + " timeout="
8432                + mAppTransition.isTimeout() + ")...");
8433        if (!mDisplayFrozen && !mAppTransition.isTimeout()) {
8434            // If the display isn't frozen, wait to do anything until
8435            // all of the apps are ready.  Otherwise just go because
8436            // we'll unfreeze the display when everyone is ready.
8437            for (i=0; i<NN && goodToGo; i++) {
8438                AppWindowToken wtoken = mOpeningApps.get(i);
8439                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8440                        "Check opening app=" + wtoken + ": allDrawn="
8441                        + wtoken.allDrawn + " startingDisplayed="
8442                        + wtoken.startingDisplayed + " startingMoved="
8443                        + wtoken.startingMoved);
8444                if (!wtoken.allDrawn && !wtoken.startingDisplayed
8445                        && !wtoken.startingMoved) {
8446                    goodToGo = false;
8447                }
8448            }
8449        }
8450        if (goodToGo) {
8451            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
8452            int transit = mAppTransition.getAppTransition();
8453            if (mSkipAppTransitionAnimation) {
8454                transit = AppTransition.TRANSIT_UNSET;
8455            }
8456            mAppTransition.goodToGo();
8457            mStartingIconInTransition = false;
8458            mSkipAppTransitionAnimation = false;
8459
8460            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8461
8462            rebuildAppWindowListLocked();
8463
8464            // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
8465            WindowState oldWallpaper =
8466                    mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
8467                        && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
8468                    ? null : mWallpaperTarget;
8469
8470            mInnerFields.mWallpaperMayChange = false;
8471
8472            // The top-most window will supply the layout params,
8473            // and we will determine it below.
8474            LayoutParams animLp = null;
8475            int bestAnimLayer = -1;
8476            boolean fullscreenAnim = false;
8477
8478            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8479                    "New wallpaper target=" + mWallpaperTarget
8480                    + ", oldWallpaper=" + oldWallpaper
8481                    + ", lower target=" + mLowerWallpaperTarget
8482                    + ", upper target=" + mUpperWallpaperTarget);
8483
8484            boolean openingAppHasWallpaper = false;
8485            boolean closingAppHasWallpaper = false;
8486            final AppWindowToken lowerWallpaperAppToken;
8487            final AppWindowToken upperWallpaperAppToken;
8488            if (mLowerWallpaperTarget == null) {
8489                lowerWallpaperAppToken = upperWallpaperAppToken = null;
8490            } else {
8491                lowerWallpaperAppToken = mLowerWallpaperTarget.mAppToken;
8492                upperWallpaperAppToken = mUpperWallpaperTarget.mAppToken;
8493            }
8494
8495            // Do a first pass through the tokens for two
8496            // things:
8497            // (1) Determine if both the closing and opening
8498            // app token sets are wallpaper targets, in which
8499            // case special animations are needed
8500            // (since the wallpaper needs to stay static
8501            // behind them).
8502            // (2) Find the layout params of the top-most
8503            // application window in the tokens, which is
8504            // what will control the animation theme.
8505            final int NC = mClosingApps.size();
8506            NN = NC + mOpeningApps.size();
8507            for (i=0; i<NN; i++) {
8508                final AppWindowToken wtoken;
8509                if (i < NC) {
8510                    wtoken = mClosingApps.get(i);
8511                    if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
8512                        closingAppHasWallpaper = true;
8513                    }
8514                } else {
8515                    wtoken = mOpeningApps.get(i - NC);
8516                    if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
8517                        openingAppHasWallpaper = true;
8518                    }
8519                }
8520
8521                if (wtoken.appFullscreen) {
8522                    WindowState ws = wtoken.findMainWindow();
8523                    if (ws != null) {
8524                        animLp = ws.mAttrs;
8525                        bestAnimLayer = ws.mLayer;
8526                        fullscreenAnim = true;
8527                    }
8528                } else if (!fullscreenAnim) {
8529                    WindowState ws = wtoken.findMainWindow();
8530                    if (ws != null) {
8531                        if (ws.mLayer > bestAnimLayer) {
8532                            animLp = ws.mAttrs;
8533                            bestAnimLayer = ws.mLayer;
8534                        }
8535                    }
8536                }
8537            }
8538
8539            mAnimateWallpaperWithTarget = false;
8540            if (closingAppHasWallpaper && openingAppHasWallpaper) {
8541                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
8542                switch (transit) {
8543                    case AppTransition.TRANSIT_ACTIVITY_OPEN:
8544                    case AppTransition.TRANSIT_TASK_OPEN:
8545                    case AppTransition.TRANSIT_TASK_TO_FRONT:
8546                        transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
8547                        break;
8548                    case AppTransition.TRANSIT_ACTIVITY_CLOSE:
8549                    case AppTransition.TRANSIT_TASK_CLOSE:
8550                    case AppTransition.TRANSIT_TASK_TO_BACK:
8551                        transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
8552                        break;
8553                }
8554                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit: " + transit);
8555            } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
8556                    && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
8557                // We are transitioning from an activity with
8558                // a wallpaper to one without.
8559                transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
8560                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8561                        "New transit away from wallpaper: " + transit);
8562            } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
8563                // We are transitioning from an activity without
8564                // a wallpaper to now showing the wallpaper
8565                transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
8566                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8567                        "New transit into wallpaper: " + transit);
8568            } else {
8569                mAnimateWallpaperWithTarget = true;
8570            }
8571
8572            // If all closing windows are obscured, then there is
8573            // no need to do an animation.  This is the case, for
8574            // example, when this transition is being done behind
8575            // the lock screen.
8576            if (!mPolicy.allowAppAnimationsLw()) {
8577                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8578                        "Animations disallowed by keyguard or dream.");
8579                animLp = null;
8580            }
8581
8582            AppWindowToken topOpeningApp = null;
8583            int topOpeningLayer = 0;
8584
8585            NN = mOpeningApps.size();
8586            for (i=0; i<NN; i++) {
8587                AppWindowToken wtoken = mOpeningApps.get(i);
8588                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
8589                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
8590                appAnimator.clearThumbnail();
8591                wtoken.inPendingTransaction = false;
8592                appAnimator.animation = null;
8593                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
8594                wtoken.updateReportedVisibilityLocked();
8595                wtoken.waitingToShow = false;
8596
8597                appAnimator.mAllAppWinAnimators.clear();
8598                final int N = wtoken.allAppWindows.size();
8599                for (int j = 0; j < N; j++) {
8600                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
8601                }
8602                mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
8603
8604                if (animLp != null) {
8605                    int layer = -1;
8606                    for (int j=0; j<wtoken.windows.size(); j++) {
8607                        WindowState win = wtoken.windows.get(j);
8608                        if (win.mWinAnimator.mAnimLayer > layer) {
8609                            layer = win.mWinAnimator.mAnimLayer;
8610                        }
8611                    }
8612                    if (topOpeningApp == null || layer > topOpeningLayer) {
8613                        topOpeningApp = wtoken;
8614                        topOpeningLayer = layer;
8615                    }
8616                }
8617            }
8618            NN = mClosingApps.size();
8619            for (i=0; i<NN; i++) {
8620                AppWindowToken wtoken = mClosingApps.get(i);
8621                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
8622                wtoken.mAppAnimator.clearThumbnail();
8623                wtoken.inPendingTransaction = false;
8624                wtoken.mAppAnimator.animation = null;
8625                setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
8626                wtoken.updateReportedVisibilityLocked();
8627                wtoken.waitingToHide = false;
8628                // Force the allDrawn flag, because we want to start
8629                // this guy's animations regardless of whether it's
8630                // gotten drawn.
8631                wtoken.allDrawn = true;
8632                wtoken.deferClearAllDrawn = false;
8633            }
8634
8635            boolean useAlternateThumbnailAnimation =
8636                            SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
8637            AppWindowAnimator appAnimator =
8638                    topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
8639            Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
8640            if (!useAlternateThumbnailAnimation && nextAppTransitionThumbnail != null
8641                    && appAnimator != null && appAnimator.animation != null) {
8642                // This thumbnail animation is very special, we need to have
8643                // an extra surface with the thumbnail included with the animation.
8644                Rect dirty = new Rect(0, 0, nextAppTransitionThumbnail.getWidth(),
8645                        nextAppTransitionThumbnail.getHeight());
8646                try {
8647                    // TODO(multi-display): support other displays
8648                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
8649                    final Display display = displayContent.getDisplay();
8650                    SurfaceControl surfaceControl = new SurfaceControl(mFxSession,
8651                            "thumbnail anim",
8652                            dirty.width(), dirty.height(),
8653                            PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
8654                    surfaceControl.setLayerStack(display.getLayerStack());
8655                    appAnimator.thumbnail = surfaceControl;
8656                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");
8657                    Surface drawSurface = new Surface();
8658                    drawSurface.copyFrom(surfaceControl);
8659                    Canvas c = drawSurface.lockCanvas(dirty);
8660                    c.drawBitmap(nextAppTransitionThumbnail, 0, 0, null);
8661                    drawSurface.unlockCanvasAndPost(c);
8662                    drawSurface.release();
8663                    appAnimator.thumbnailLayer = topOpeningLayer;
8664                    DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
8665                    Animation anim = mAppTransition.createThumbnailScaleAnimationLocked(
8666                            displayInfo.appWidth, displayInfo.appHeight, transit);
8667                    appAnimator.thumbnailAnimation = anim;
8668                    anim.restrictDuration(MAX_ANIMATION_DURATION);
8669                    anim.scaleCurrentDuration(mTransitionAnimationScale);
8670                    Point p = new Point();
8671                    mAppTransition.getStartingPoint(p);
8672                    appAnimator.thumbnailX = p.x;
8673                    appAnimator.thumbnailY = p.y;
8674                } catch (OutOfResourcesException e) {
8675                    Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" + dirty.width()
8676                            + " h=" + dirty.height(), e);
8677                    appAnimator.clearThumbnail();
8678                }
8679            }
8680
8681            mAppTransition.postAnimationCallback();
8682            mAppTransition.clear();
8683
8684            mOpeningApps.clear();
8685            mClosingApps.clear();
8686
8687            // This has changed the visibility of windows, so perform
8688            // a new layout to get them all up-to-date.
8689            changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
8690                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8691            getDefaultDisplayContentLocked().layoutNeeded = true;
8692
8693            // TODO(multidisplay): IMEs are only supported on the default display.
8694            if (windows == getDefaultWindowListLocked()
8695                    && !moveInputMethodWindowsIfNeededLocked(true)) {
8696                assignLayersLocked(windows);
8697            }
8698            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, false /*updateInputWindows*/);
8699            mFocusMayChange = false;
8700        }
8701
8702        return changes;
8703    }
8704
8705    /**
8706     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8707     * @return bitmap indicating if another pass through layout must be made.
8708     */
8709    private int handleAnimatingStoppedAndTransitionLocked() {
8710        int changes = 0;
8711
8712        mAppTransition.setIdle();
8713        // Restore window app tokens to the ActivityManager views
8714        ArrayList<TaskStack> stacks = getDefaultDisplayContentLocked().getStacks();
8715        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
8716            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
8717            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
8718                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
8719                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
8720                    tokens.get(tokenNdx).sendingToBottom = false;
8721                }
8722            }
8723        }
8724        rebuildAppWindowListLocked();
8725
8726        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8727        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
8728                "Wallpaper layer changed: assigning layers + relayout");
8729        moveInputMethodWindowsIfNeededLocked(true);
8730        mInnerFields.mWallpaperMayChange = true;
8731        // Since the window list has been rebuilt, focus might
8732        // have to be recomputed since the actual order of windows
8733        // might have changed again.
8734        mFocusMayChange = true;
8735
8736        return changes;
8737    }
8738
8739    private void updateResizingWindows(final WindowState w) {
8740        final WindowStateAnimator winAnimator = w.mWinAnimator;
8741        if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
8742            w.setInsetsChanged();
8743            boolean configChanged = w.isConfigChanged();
8744            if (DEBUG_CONFIGURATION && configChanged) {
8745                Slog.v(TAG, "Win " + w + " config changed: "
8746                        + mCurConfiguration);
8747            }
8748            if (localLOGV) Slog.v(TAG, "Resizing " + w
8749                    + ": configChanged=" + configChanged
8750                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8751            w.mLastFrame.set(w.mFrame);
8752            if (w.mContentInsetsChanged
8753                    || w.mVisibleInsetsChanged
8754                    || winAnimator.mSurfaceResized
8755                    || configChanged) {
8756                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8757                    Slog.v(TAG, "Resize reasons for w=" + w + ": "
8758                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8759                            + " " + w.mContentInsets.toShortString()
8760                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8761                            + " " + w.mVisibleInsets.toShortString()
8762                            + " surfaceResized=" + winAnimator.mSurfaceResized
8763                            + " configChanged=" + configChanged);
8764                }
8765
8766                w.mLastOverscanInsets.set(w.mOverscanInsets);
8767                w.mLastContentInsets.set(w.mContentInsets);
8768                w.mLastVisibleInsets.set(w.mVisibleInsets);
8769                makeWindowFreezingScreenIfNeededLocked(w);
8770                // If the orientation is changing, then we need to
8771                // hold off on unfreezing the display until this
8772                // window has been redrawn; to do that, we need
8773                // to go through the process of getting informed
8774                // by the application when it has finished drawing.
8775                if (w.mOrientationChanging) {
8776                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
8777                            "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
8778                            + w + ", surface " + winAnimator.mSurfaceControl);
8779                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8780                    if (w.mAppToken != null) {
8781                        w.mAppToken.allDrawn = false;
8782                        w.mAppToken.deferClearAllDrawn = false;
8783                    }
8784                }
8785                if (!mResizingWindows.contains(w)) {
8786                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8787                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8788                            + "x" + winAnimator.mSurfaceH);
8789                    mResizingWindows.add(w);
8790                }
8791            } else if (w.mOrientationChanging) {
8792                if (w.isDrawnLw()) {
8793                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8794                            "Orientation not waiting for draw in "
8795                            + w + ", surface " + winAnimator.mSurfaceControl);
8796                    w.mOrientationChanging = false;
8797                    w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
8798                            - mDisplayFreezeTime);
8799                }
8800            }
8801        }
8802    }
8803
8804    /**
8805     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8806     *
8807     * @param w WindowState this method is applied to.
8808     * @param currentTime The time which animations use for calculating transitions.
8809     * @param innerDw Width of app window.
8810     * @param innerDh Height of app window.
8811     */
8812    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8813                                         final int innerDw, final int innerDh) {
8814        final WindowManager.LayoutParams attrs = w.mAttrs;
8815        final int attrFlags = attrs.flags;
8816        final boolean canBeSeen = w.isDisplayedLw();
8817        final boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8818
8819        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8820            // This window completely covers everything behind it,
8821            // so we want to leave all of them as undimmed (for
8822            // performance reasons).
8823            mInnerFields.mObscured = true;
8824        }
8825
8826        if (w.mHasSurface) {
8827            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8828                mInnerFields.mHoldScreen = w.mSession;
8829            }
8830            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8831                    && mInnerFields.mScreenBrightness < 0) {
8832                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8833            }
8834            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8835                    && mInnerFields.mButtonBrightness < 0) {
8836                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8837            }
8838            if (!mInnerFields.mSyswin && w.mAttrs.userActivityTimeout >= 0
8839                    && mInnerFields.mUserActivityTimeout < 0) {
8840                mInnerFields.mUserActivityTimeout = w.mAttrs.userActivityTimeout;
8841            }
8842
8843            final int type = attrs.type;
8844            if (canBeSeen
8845                    && (type == TYPE_SYSTEM_DIALOG
8846                     || type == TYPE_RECENTS_OVERLAY
8847                     || type == TYPE_SYSTEM_ERROR
8848                     || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0)) {
8849                mInnerFields.mSyswin = true;
8850            }
8851
8852            if (canBeSeen) {
8853                // This function assumes that the contents of the default display are
8854                // processed first before secondary displays.
8855                final DisplayContent displayContent = w.getDisplayContent();
8856                if (displayContent != null && displayContent.isDefaultDisplay) {
8857                    // While a dream or keyguard is showing, obscure ordinary application
8858                    // content on secondary displays (by forcibly enabling mirroring unless
8859                    // there is other content we want to show) but still allow opaque
8860                    // keyguard dialogs to be shown.
8861                    if (type == TYPE_DREAM || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
8862                        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
8863                    }
8864                    mInnerFields.mDisplayHasContent = true;
8865                } else if (displayContent != null &&
8866                        (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
8867                        || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG))) {
8868                    // Allow full screen keyguard presentation dialogs to be seen.
8869                    mInnerFields.mDisplayHasContent = true;
8870                }
8871            }
8872        }
8873    }
8874
8875    private void handleFlagDimBehind(WindowState w) {
8876        final WindowManager.LayoutParams attrs = w.mAttrs;
8877        if ((attrs.flags & FLAG_DIM_BEHIND) != 0
8878                && w.isDisplayedLw()
8879                && !w.mExiting) {
8880            final WindowStateAnimator winAnimator = w.mWinAnimator;
8881            final TaskStack stack = w.getStack();
8882            stack.setDimmingTag();
8883            if (!stack.isDimming(winAnimator)) {
8884                if (localLOGV) Slog.v(TAG, "Win " + w + " start dimming.");
8885                stack.startDimmingIfNeeded(winAnimator);
8886            }
8887        }
8888    }
8889
8890    private void updateAllDrawnLocked(DisplayContent displayContent) {
8891        // See if any windows have been drawn, so they (and others
8892        // associated with them) can now be shown.
8893        ArrayList<TaskStack> stacks = displayContent.getStacks();
8894        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
8895            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
8896            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
8897                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
8898                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
8899                    final AppWindowToken wtoken = tokens.get(tokenNdx);
8900                    if (!wtoken.allDrawn) {
8901                        int numInteresting = wtoken.numInterestingWindows;
8902                        if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8903                            if (DEBUG_VISIBILITY) Slog.v(TAG,
8904                                    "allDrawn: " + wtoken
8905                                    + " interesting=" + numInteresting
8906                                    + " drawn=" + wtoken.numDrawnWindows);
8907                            wtoken.allDrawn = true;
8908                            mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
8909                        }
8910                    }
8911                }
8912            }
8913        }
8914    }
8915
8916    // "Something has changed!  Let's make it correct now."
8917    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
8918        if (DEBUG_WINDOW_TRACE) {
8919            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8920                    + Debug.getCallers(3));
8921        }
8922
8923        final long currentTime = SystemClock.uptimeMillis();
8924
8925        int i;
8926
8927        if (mFocusMayChange) {
8928            mFocusMayChange = false;
8929            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8930                    false /*updateInputWindows*/);
8931        }
8932
8933        // Initialize state of exiting tokens.
8934        final int numDisplays = mDisplayContents.size();
8935        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
8936            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
8937            for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
8938                displayContent.mExitingTokens.get(i).hasVisible = false;
8939            }
8940        }
8941
8942        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
8943            // Initialize state of exiting applications.
8944            final AppTokenList exitingAppTokens =
8945                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
8946            for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
8947                exitingAppTokens.get(tokenNdx).hasVisible = false;
8948            }
8949        }
8950
8951        mInnerFields.mHoldScreen = null;
8952        mInnerFields.mScreenBrightness = -1;
8953        mInnerFields.mButtonBrightness = -1;
8954        mInnerFields.mUserActivityTimeout = -1;
8955        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = false;
8956
8957        mTransactionSequence++;
8958
8959        final DisplayContent defaultDisplay = getDefaultDisplayContentLocked();
8960        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
8961        final int defaultDw = defaultInfo.logicalWidth;
8962        final int defaultDh = defaultInfo.logicalHeight;
8963
8964        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8965                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8966        SurfaceControl.openTransaction();
8967        try {
8968
8969            if (mWatermark != null) {
8970                mWatermark.positionSurface(defaultDw, defaultDh);
8971            }
8972            if (mStrictModeFlash != null) {
8973                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
8974            }
8975
8976            boolean focusDisplayed = false;
8977
8978            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
8979                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
8980                boolean updateAllDrawn = false;
8981                WindowList windows = displayContent.getWindowList();
8982                DisplayInfo displayInfo = displayContent.getDisplayInfo();
8983                final int displayId = displayContent.getDisplayId();
8984                final int dw = displayInfo.logicalWidth;
8985                final int dh = displayInfo.logicalHeight;
8986                final int innerDw = displayInfo.appWidth;
8987                final int innerDh = displayInfo.appHeight;
8988                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
8989
8990                // Reset for each display.
8991                mInnerFields.mDisplayHasContent = false;
8992
8993                int repeats = 0;
8994                do {
8995                    repeats++;
8996                    if (repeats > 6) {
8997                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
8998                        displayContent.layoutNeeded = false;
8999                        break;
9000                    }
9001
9002                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
9003                        displayContent.pendingLayoutChanges);
9004
9005                    if ((displayContent.pendingLayoutChanges &
9006                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
9007                            (adjustWallpaperWindowsLocked() &
9008                                    ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
9009                        assignLayersLocked(windows);
9010                        displayContent.layoutNeeded = true;
9011                    }
9012
9013                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
9014                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
9015                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
9016                        if (updateOrientationFromAppTokensLocked(true)) {
9017                            displayContent.layoutNeeded = true;
9018                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9019                        }
9020                    }
9021
9022                    if ((displayContent.pendingLayoutChanges
9023                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9024                        displayContent.layoutNeeded = true;
9025                    }
9026
9027                    // FIRST LOOP: Perform a layout, if needed.
9028                    if (repeats < 4) {
9029                        performLayoutLockedInner(displayContent, repeats == 1,
9030                                false /*updateInputWindows*/);
9031                    } else {
9032                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
9033                    }
9034
9035                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
9036                    // it is animating.
9037                    displayContent.pendingLayoutChanges = 0;
9038
9039                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
9040                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
9041
9042                    if (isDefaultDisplay) {
9043                        mPolicy.beginPostLayoutPolicyLw(dw, dh);
9044                        for (i = windows.size() - 1; i >= 0; i--) {
9045                            WindowState w = windows.get(i);
9046                            if (w.mHasSurface) {
9047                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
9048                            }
9049                        }
9050                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
9051                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
9052                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
9053                    }
9054                } while (displayContent.pendingLayoutChanges != 0);
9055
9056                mInnerFields.mObscured = false;
9057                mInnerFields.mSyswin = false;
9058                displayContent.resetDimming();
9059
9060                // Only used if default window
9061                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
9062
9063                final int N = windows.size();
9064                for (i=N-1; i>=0; i--) {
9065                    WindowState w = windows.get(i);
9066                    final TaskStack stack = w.getStack();
9067                    if (stack == null) {
9068                        continue;
9069                    }
9070
9071                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
9072
9073                    // Update effect.
9074                    w.mObscured = mInnerFields.mObscured;
9075                    if (!mInnerFields.mObscured) {
9076                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
9077                    }
9078
9079                    if (!stack.testDimmingTag()) {
9080                        handleFlagDimBehind(w);
9081                    }
9082
9083                    if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
9084                            && w.isVisibleLw()) {
9085                        // This is the wallpaper target and its obscured state
9086                        // changed... make sure the current wallaper's visibility
9087                        // has been updated accordingly.
9088                        updateWallpaperVisibilityLocked();
9089                    }
9090
9091                    final WindowStateAnimator winAnimator = w.mWinAnimator;
9092
9093                    // If the window has moved due to its containing
9094                    // content frame changing, then we'd like to animate
9095                    // it.
9096                    if (w.mHasSurface && w.shouldAnimateMove()) {
9097                        // Frame has moved, containing content frame
9098                        // has also moved, and we're not currently animating...
9099                        // let's do something.
9100                        Animation a = AnimationUtils.loadAnimation(mContext,
9101                                com.android.internal.R.anim.window_move_from_decor);
9102                        winAnimator.setAnimation(a);
9103                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
9104                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
9105                        try {
9106                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
9107                        } catch (RemoteException e) {
9108                        }
9109                    }
9110
9111                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
9112                    w.mContentChanged = false;
9113
9114                    // Moved from updateWindowsAndWallpaperLocked().
9115                    if (w.mHasSurface) {
9116                        // Take care of the window being ready to display.
9117                        final boolean committed =
9118                                winAnimator.commitFinishDrawingLocked(currentTime);
9119                        if (isDefaultDisplay && committed) {
9120                            if (w.mAttrs.type == TYPE_DREAM) {
9121                                // HACK: When a dream is shown, it may at that
9122                                // point hide the lock screen.  So we need to
9123                                // redo the layout to let the phone window manager
9124                                // make this happen.
9125                                displayContent.pendingLayoutChanges |=
9126                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9127                                if (DEBUG_LAYOUT_REPEATS) {
9128                                    debugLayoutRepeats(
9129                                        "dream and commitFinishDrawingLocked true",
9130                                        displayContent.pendingLayoutChanges);
9131                                }
9132                            }
9133                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
9134                                if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
9135                                        "First draw done in potential wallpaper target " + w);
9136                                mInnerFields.mWallpaperMayChange = true;
9137                                displayContent.pendingLayoutChanges |=
9138                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9139                                if (DEBUG_LAYOUT_REPEATS) {
9140                                    debugLayoutRepeats(
9141                                        "wallpaper and commitFinishDrawingLocked true",
9142                                        displayContent.pendingLayoutChanges);
9143                                }
9144                            }
9145                        }
9146
9147                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
9148
9149                        final AppWindowToken atoken = w.mAppToken;
9150                        if (DEBUG_STARTING_WINDOW && atoken != null
9151                                && w == atoken.startingWindow) {
9152                            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
9153                                + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
9154                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
9155                        }
9156                        if (atoken != null
9157                                && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
9158                            if (atoken.lastTransactionSequence != mTransactionSequence) {
9159                                atoken.lastTransactionSequence = mTransactionSequence;
9160                                atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
9161                                atoken.startingDisplayed = false;
9162                            }
9163                            if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
9164                                    && !w.mExiting && !w.mDestroying) {
9165                                if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
9166                                    Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
9167                                            + ", isAnimating=" + winAnimator.isAnimating());
9168                                    if (!w.isDrawnLw()) {
9169                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceControl
9170                                                + " pv=" + w.mPolicyVisibility
9171                                                + " mDrawState=" + winAnimator.mDrawState
9172                                                + " ah=" + w.mAttachedHidden
9173                                                + " th=" + atoken.hiddenRequested
9174                                                + " a=" + winAnimator.mAnimating);
9175                                    }
9176                                }
9177                                if (w != atoken.startingWindow) {
9178                                    if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
9179                                        atoken.numInterestingWindows++;
9180                                        if (w.isDrawnLw()) {
9181                                            atoken.numDrawnWindows++;
9182                                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
9183                                                    "tokenMayBeDrawn: " + atoken
9184                                                    + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
9185                                                    + " mAppFreezing=" + w.mAppFreezing);
9186                                            updateAllDrawn = true;
9187                                        }
9188                                    }
9189                                } else if (w.isDrawnLw()) {
9190                                    atoken.startingDisplayed = true;
9191                                }
9192                            }
9193                        }
9194                    }
9195
9196                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
9197                            && w.isDisplayedLw()) {
9198                        focusDisplayed = true;
9199                    }
9200
9201                    updateResizingWindows(w);
9202                }
9203
9204                mDisplayManagerInternal.setDisplayHasContent(displayId,
9205                        mInnerFields.mDisplayHasContent,
9206                        true /* inTraversal, must call performTraversalInTrans... below */);
9207
9208                getDisplayContentLocked(displayId).stopDimmingIfNeeded();
9209
9210                if (updateAllDrawn) {
9211                    updateAllDrawnLocked(displayContent);
9212                }
9213            }
9214
9215            if (focusDisplayed) {
9216                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
9217            }
9218
9219            // Give the display manager a chance to adjust properties
9220            // like display rotation if it needs to.
9221            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
9222
9223        } catch (RuntimeException e) {
9224            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
9225        } finally {
9226            SurfaceControl.closeTransaction();
9227            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
9228                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
9229        }
9230
9231        final WindowList defaultWindows = defaultDisplay.getWindowList();
9232
9233        // If we are ready to perform an app transition, check through
9234        // all of the app tokens to be shown and see if they are ready
9235        // to go.
9236        if (mAppTransition.isReady()) {
9237            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
9238            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
9239                    defaultDisplay.pendingLayoutChanges);
9240        }
9241
9242        if (!mAnimator.mAnimating && mAppTransition.isRunning()) {
9243            // We have finished the animation of an app transition.  To do
9244            // this, we have delayed a lot of operations like showing and
9245            // hiding apps, moving apps in Z-order, etc.  The app token list
9246            // reflects the correct Z-order, but the window list may now
9247            // be out of sync with it.  So here we will just rebuild the
9248            // entire app window list.  Fun!
9249            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
9250            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
9251                defaultDisplay.pendingLayoutChanges);
9252        }
9253
9254        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
9255                && !mAppTransition.isReady()) {
9256            // At this point, there was a window with a wallpaper that
9257            // was force hiding other windows behind it, but now it
9258            // is going away.  This may be simple -- just animate
9259            // away the wallpaper and its window -- or it may be
9260            // hard -- the wallpaper now needs to be shown behind
9261            // something that was hidden.
9262            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9263            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
9264                defaultDisplay.pendingLayoutChanges);
9265        }
9266        mInnerFields.mWallpaperForceHidingChanged = false;
9267
9268        if (mInnerFields.mWallpaperMayChange) {
9269            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change!  Adjusting");
9270            defaultDisplay.pendingLayoutChanges |=
9271                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9272            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
9273                    defaultDisplay.pendingLayoutChanges);
9274        }
9275
9276        if (mFocusMayChange) {
9277            mFocusMayChange = false;
9278            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
9279                    false /*updateInputWindows*/)) {
9280                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
9281            }
9282        }
9283
9284        if (needsLayout()) {
9285            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9286            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
9287                    defaultDisplay.pendingLayoutChanges);
9288        }
9289
9290        for (i = mResizingWindows.size() - 1; i >= 0; i--) {
9291            WindowState win = mResizingWindows.get(i);
9292            if (win.mAppFreezing) {
9293                // Don't remove this window until rotation has completed.
9294                continue;
9295            }
9296            win.reportResized();
9297            mResizingWindows.remove(i);
9298        }
9299
9300        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
9301                "With display frozen, orientationChangeComplete="
9302                + mInnerFields.mOrientationChangeComplete);
9303        if (mInnerFields.mOrientationChangeComplete) {
9304            if (mWindowsFreezingScreen) {
9305                mWindowsFreezingScreen = false;
9306                mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
9307                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
9308            }
9309            stopFreezingDisplayLocked();
9310        }
9311
9312        // Destroy the surface of any windows that are no longer visible.
9313        boolean wallpaperDestroyed = false;
9314        i = mDestroySurface.size();
9315        if (i > 0) {
9316            do {
9317                i--;
9318                WindowState win = mDestroySurface.get(i);
9319                win.mDestroying = false;
9320                if (mInputMethodWindow == win) {
9321                    mInputMethodWindow = null;
9322                }
9323                if (win == mWallpaperTarget) {
9324                    wallpaperDestroyed = true;
9325                }
9326                win.mWinAnimator.destroySurfaceLocked();
9327            } while (i > 0);
9328            mDestroySurface.clear();
9329        }
9330
9331        // Time to remove any exiting tokens?
9332        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9333            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
9334            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
9335            for (i = exitingTokens.size() - 1; i >= 0; i--) {
9336                WindowToken token = exitingTokens.get(i);
9337                if (!token.hasVisible) {
9338                    exitingTokens.remove(i);
9339                    if (token.windowType == TYPE_WALLPAPER) {
9340                        mWallpaperTokens.remove(token);
9341                    }
9342                }
9343            }
9344        }
9345
9346        // Time to remove any exiting applications?
9347        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
9348            // Initialize state of exiting applications.
9349            final AppTokenList exitingAppTokens =
9350                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
9351            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
9352                AppWindowToken token = exitingAppTokens.get(i);
9353                if (!token.hasVisible && !mClosingApps.contains(token) && !token.mDeferRemoval) {
9354                    // Make sure there is no animation running on this token,
9355                    // so any windows associated with it will be removed as
9356                    // soon as their animations are complete
9357                    token.mAppAnimator.clearAnimation();
9358                    token.mAppAnimator.animating = false;
9359                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
9360                            "performLayout: App token exiting now removed" + token);
9361                    removeAppFromTaskLocked(token);
9362                    exitingAppTokens.remove(i);
9363                }
9364            }
9365        }
9366
9367        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
9368            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
9369                try {
9370                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
9371                } catch (RemoteException e) {
9372                }
9373            }
9374            mRelayoutWhileAnimating.clear();
9375        }
9376
9377        if (wallpaperDestroyed) {
9378            defaultDisplay.pendingLayoutChanges |=
9379                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9380            defaultDisplay.layoutNeeded = true;
9381        }
9382
9383        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9384            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
9385            if (displayContent.pendingLayoutChanges != 0) {
9386                displayContent.layoutNeeded = true;
9387            }
9388        }
9389
9390        // Finally update all input windows now that the window changes have stabilized.
9391        mInputMonitor.updateInputWindowsLw(true /*force*/);
9392
9393        setHoldScreenLocked(mInnerFields.mHoldScreen);
9394        if (!mDisplayFrozen) {
9395            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
9396                mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
9397            } else {
9398                mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
9399                        toBrightnessOverride(mInnerFields.mScreenBrightness));
9400            }
9401            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
9402                mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
9403            } else {
9404                mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
9405                        toBrightnessOverride(mInnerFields.mButtonBrightness));
9406            }
9407            mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
9408                    mInnerFields.mUserActivityTimeout);
9409        }
9410
9411        if (mTurnOnScreen) {
9412            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
9413            mPowerManager.wakeUp(SystemClock.uptimeMillis());
9414            mTurnOnScreen = false;
9415        }
9416
9417        if (mInnerFields.mUpdateRotation) {
9418            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9419            if (updateRotationUncheckedLocked(false)) {
9420                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9421            } else {
9422                mInnerFields.mUpdateRotation = false;
9423            }
9424        }
9425
9426        if (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded
9427                && !mInnerFields.mUpdateRotation) {
9428            checkDrawnWindowsLocked();
9429        }
9430
9431        final int N = mPendingRemove.size();
9432        if (N > 0) {
9433            if (mPendingRemoveTmp.length < N) {
9434                mPendingRemoveTmp = new WindowState[N+10];
9435            }
9436            mPendingRemove.toArray(mPendingRemoveTmp);
9437            mPendingRemove.clear();
9438            DisplayContentList displayList = new DisplayContentList();
9439            for (i = 0; i < N; i++) {
9440                WindowState w = mPendingRemoveTmp[i];
9441                removeWindowInnerLocked(w.mSession, w);
9442                final DisplayContent displayContent = w.getDisplayContent();
9443                if (displayContent != null && !displayList.contains(displayContent)) {
9444                    displayList.add(displayContent);
9445                }
9446            }
9447
9448            for (DisplayContent displayContent : displayList) {
9449                assignLayersLocked(displayContent.getWindowList());
9450                displayContent.layoutNeeded = true;
9451            }
9452        }
9453
9454        // Remove all deferred displays stacks, tasks, and activities.
9455        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
9456            mDisplayContents.valueAt(displayNdx).checkForDeferredActions();
9457        }
9458
9459        setFocusedStackFrame();
9460
9461        // Check to see if we are now in a state where the screen should
9462        // be enabled, because the window obscured flags have changed.
9463        enableScreenIfNeededLocked();
9464
9465        scheduleAnimationLocked();
9466
9467        if (DEBUG_WINDOW_TRACE) {
9468            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
9469                    + mAnimator.mAnimating);
9470        }
9471    }
9472
9473    private int toBrightnessOverride(float value) {
9474        return (int)(value * PowerManager.BRIGHTNESS_ON);
9475    }
9476
9477    void checkDrawnWindowsLocked() {
9478        if (mWaitingForDrawn.size() > 0) {
9479            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
9480                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
9481                WindowState win = pair.first;
9482                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
9483                //        + win.mRemoved + " visible=" + win.isVisibleLw()
9484                //        + " shown=" + win.mSurfaceShown);
9485                if (win.mRemoved) {
9486                    // Window has been removed; no draw will now happen, so stop waiting.
9487                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
9488                    try {
9489                        pair.second.sendResult(null);
9490                    } catch (RemoteException e) {
9491                    }
9492                    mWaitingForDrawn.remove(pair);
9493                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9494                } else if (win.mWinAnimator.mSurfaceShown) {
9495                    // Window is now drawn (and shown).
9496                    try {
9497                        pair.second.sendResult(null);
9498                    } catch (RemoteException e) {
9499                    }
9500                    mWaitingForDrawn.remove(pair);
9501                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9502                }
9503            }
9504        }
9505    }
9506
9507    @Override
9508    public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
9509        if (token != null && callback != null) {
9510            synchronized (mWindowMap) {
9511                WindowState win = windowForClientLocked(null, token, true);
9512                if (win != null) {
9513                    Pair<WindowState, IRemoteCallback> pair =
9514                            new Pair<WindowState, IRemoteCallback>(win, callback);
9515                    Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9516                    mH.sendMessageDelayed(m, 2000);
9517                    mWaitingForDrawn.add(pair);
9518                    checkDrawnWindowsLocked();
9519                    return true;
9520                }
9521                Slog.i(TAG, "waitForWindowDrawn: win null");
9522            }
9523        }
9524        return false;
9525    }
9526
9527    void setHoldScreenLocked(final Session newHoldScreen) {
9528        final boolean hold = newHoldScreen != null;
9529
9530        if (hold && mHoldingScreenOn != newHoldScreen) {
9531            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
9532        }
9533        mHoldingScreenOn = newHoldScreen;
9534
9535        final boolean state = mHoldingScreenWakeLock.isHeld();
9536        if (hold != state) {
9537            if (hold) {
9538                mHoldingScreenWakeLock.acquire();
9539                mPolicy.keepScreenOnStartedLw();
9540            } else {
9541                mPolicy.keepScreenOnStoppedLw();
9542                mHoldingScreenWakeLock.release();
9543            }
9544        }
9545    }
9546
9547    void requestTraversal() {
9548        synchronized (mWindowMap) {
9549            requestTraversalLocked();
9550        }
9551    }
9552
9553    void requestTraversalLocked() {
9554        if (!mTraversalScheduled) {
9555            mTraversalScheduled = true;
9556            mH.sendEmptyMessage(H.DO_TRAVERSAL);
9557        }
9558    }
9559
9560    /** Note that Locked in this case is on mLayoutToAnim */
9561    void scheduleAnimationLocked() {
9562        if (!mAnimationScheduled) {
9563            mAnimationScheduled = true;
9564            mChoreographer.postCallback(
9565                    Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
9566        }
9567    }
9568
9569    private boolean needsLayout() {
9570        final int numDisplays = mDisplayContents.size();
9571        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9572            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
9573            if (displayContent.layoutNeeded) {
9574                return true;
9575            }
9576        }
9577        return false;
9578    }
9579
9580    boolean copyAnimToLayoutParamsLocked() {
9581        boolean doRequest = false;
9582
9583        final int bulkUpdateParams = mAnimator.mBulkUpdateParams;
9584        if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
9585            mInnerFields.mUpdateRotation = true;
9586            doRequest = true;
9587        }
9588        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
9589            mInnerFields.mWallpaperMayChange = true;
9590            doRequest = true;
9591        }
9592        if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
9593            mInnerFields.mWallpaperForceHidingChanged = true;
9594            doRequest = true;
9595        }
9596        if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
9597            mInnerFields.mOrientationChangeComplete = false;
9598        } else {
9599            mInnerFields.mOrientationChangeComplete = true;
9600            mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
9601            if (mWindowsFreezingScreen) {
9602                doRequest = true;
9603            }
9604        }
9605        if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
9606            mTurnOnScreen = true;
9607        }
9608        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_ACTION_PENDING) != 0) {
9609            mInnerFields.mWallpaperActionPending = true;
9610        }
9611
9612        return doRequest;
9613    }
9614
9615    /** If a window that has an animation specifying a colored background and the current wallpaper
9616     * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to
9617     * suddenly disappear. */
9618    int adjustAnimationBackground(WindowStateAnimator winAnimator) {
9619        WindowList windows = winAnimator.mWin.getWindowList();
9620        for (int i = windows.size() - 1; i >= 0; --i) {
9621            WindowState testWin = windows.get(i);
9622            if (testWin.mIsWallpaper && testWin.isVisibleNow()) {
9623                return testWin.mWinAnimator.mAnimLayer;
9624            }
9625        }
9626        return winAnimator.mAnimLayer;
9627    }
9628
9629    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
9630                                           boolean secure) {
9631        final SurfaceControl surface = winAnimator.mSurfaceControl;
9632        boolean leakedSurface = false;
9633        boolean killedApps = false;
9634
9635        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
9636                winAnimator.mSession.mPid, operation);
9637
9638        if (mForceRemoves == null) {
9639            mForceRemoves = new ArrayList<WindowState>();
9640        }
9641
9642        long callingIdentity = Binder.clearCallingIdentity();
9643        try {
9644            // There was some problem...   first, do a sanity check of the
9645            // window list to make sure we haven't left any dangling surfaces
9646            // around.
9647
9648            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
9649            final int numDisplays = mDisplayContents.size();
9650            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9651                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
9652                final int numWindows = windows.size();
9653                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
9654                    final WindowState ws = windows.get(winNdx);
9655                    WindowStateAnimator wsa = ws.mWinAnimator;
9656                    if (wsa.mSurfaceControl != null) {
9657                        if (!mSessions.contains(wsa.mSession)) {
9658                            Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
9659                                    + ws + " surface=" + wsa.mSurfaceControl
9660                                    + " token=" + ws.mToken
9661                                    + " pid=" + ws.mSession.mPid
9662                                    + " uid=" + ws.mSession.mUid);
9663                            if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9664                            wsa.mSurfaceControl.destroy();
9665                            wsa.mSurfaceShown = false;
9666                            wsa.mSurfaceControl = null;
9667                            ws.mHasSurface = false;
9668                            mForceRemoves.add(ws);
9669                            leakedSurface = true;
9670                        } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
9671                            Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
9672                                    + ws + " surface=" + wsa.mSurfaceControl
9673                                    + " token=" + ws.mAppToken);
9674                            if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9675                            wsa.mSurfaceControl.destroy();
9676                            wsa.mSurfaceShown = false;
9677                            wsa.mSurfaceControl = null;
9678                            ws.mHasSurface = false;
9679                            leakedSurface = true;
9680                        }
9681                    }
9682                }
9683            }
9684
9685            if (!leakedSurface) {
9686                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
9687                SparseIntArray pidCandidates = new SparseIntArray();
9688                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9689                    final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
9690                    final int numWindows = windows.size();
9691                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
9692                        final WindowState ws = windows.get(winNdx);
9693                        if (mForceRemoves.contains(ws)) {
9694                            continue;
9695                        }
9696                        WindowStateAnimator wsa = ws.mWinAnimator;
9697                        if (wsa.mSurfaceControl != null) {
9698                            pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
9699                        }
9700                    }
9701                    if (pidCandidates.size() > 0) {
9702                        int[] pids = new int[pidCandidates.size()];
9703                        for (int i=0; i<pids.length; i++) {
9704                            pids[i] = pidCandidates.keyAt(i);
9705                        }
9706                        try {
9707                            if (mActivityManager.killPids(pids, "Free memory", secure)) {
9708                                killedApps = true;
9709                            }
9710                        } catch (RemoteException e) {
9711                        }
9712                    }
9713                }
9714            }
9715
9716            if (leakedSurface || killedApps) {
9717                // We managed to reclaim some memory, so get rid of the trouble
9718                // surface and ask the app to request another one.
9719                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9720                if (surface != null) {
9721                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
9722                            "RECOVER DESTROY", null);
9723                    surface.destroy();
9724                    winAnimator.mSurfaceShown = false;
9725                    winAnimator.mSurfaceControl = null;
9726                    winAnimator.mWin.mHasSurface = false;
9727                    scheduleRemoveStartingWindow(winAnimator.mWin.mAppToken);
9728                }
9729
9730                try {
9731                    winAnimator.mWin.mClient.dispatchGetNewSurface();
9732                } catch (RemoteException e) {
9733                }
9734            }
9735        } finally {
9736            Binder.restoreCallingIdentity(callingIdentity);
9737        }
9738
9739        return leakedSurface || killedApps;
9740    }
9741
9742    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9743        WindowState newFocus = computeFocusedWindowLocked();
9744        if (mCurrentFocus != newFocus) {
9745            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
9746            // This check makes sure that we don't already have the focus
9747            // change message pending.
9748            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9749            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9750            // TODO(multidisplay): Focused windows on default display only.
9751            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9752            final boolean imWindowChanged = moveInputMethodWindowsIfNeededLocked(
9753                    mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
9754                            && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES);
9755            if (imWindowChanged) {
9756                displayContent.layoutNeeded = true;
9757                newFocus = computeFocusedWindowLocked();
9758            }
9759
9760            if (DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(TAG, "Changing focus from " +
9761                    mCurrentFocus + " to " + newFocus + " Callers=" + Debug.getCallers(4));
9762            final WindowState oldFocus = mCurrentFocus;
9763            mCurrentFocus = newFocus;
9764            mLosingFocus.remove(newFocus);
9765
9766            if (mAccessibilityController != null) {
9767                mAccessibilityController.onWindowFocusChangedLocked();
9768            }
9769
9770            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9771
9772            if (imWindowChanged && oldFocus != mInputMethodWindow) {
9773                // Focus of the input method window changed. Perform layout if needed.
9774                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9775                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9776                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9777                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9778                    // Client will do the layout, but we need to assign layers
9779                    // for handleNewWindowLocked() below.
9780                    assignLayersLocked(displayContent.getWindowList());
9781                }
9782            }
9783
9784            if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9785                // The change in focus caused us to need to do a layout.  Okay.
9786                displayContent.layoutNeeded = true;
9787                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9788                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9789                }
9790            }
9791
9792            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9793                // If we defer assigning layers, then the caller is responsible for
9794                // doing this part.
9795                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9796            }
9797
9798            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
9799            return true;
9800        }
9801        return false;
9802    }
9803
9804    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9805        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9806    }
9807
9808    private WindowState computeFocusedWindowLocked() {
9809        if (mAnimator.mUniverseBackground != null
9810                && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) {
9811            return mAnimator.mUniverseBackground.mWin;
9812        }
9813
9814        final int displayCount = mDisplayContents.size();
9815        for (int i = 0; i < displayCount; i++) {
9816            final DisplayContent displayContent = mDisplayContents.valueAt(i);
9817            WindowState win = findFocusedWindowLocked(displayContent);
9818            if (win != null) {
9819                return win;
9820            }
9821        }
9822        return null;
9823    }
9824
9825    private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
9826        final WindowList windows = displayContent.getWindowList();
9827        for (int i = windows.size() - 1; i >= 0; i--) {
9828            final WindowState win = windows.get(i);
9829
9830            if (localLOGV || DEBUG_FOCUS) Slog.v(
9831                TAG, "Looking for focus: " + i
9832                + " = " + win
9833                + ", flags=" + win.mAttrs.flags
9834                + ", canReceive=" + win.canReceiveKeys());
9835
9836            AppWindowToken wtoken = win.mAppToken;
9837
9838            // If this window's application has been removed, just skip it.
9839            if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) {
9840                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping " + wtoken + " because "
9841                        + (wtoken.removed ? "removed" : "sendingToBottom"));
9842                continue;
9843            }
9844
9845            if (!win.canReceiveKeys()) {
9846                continue;
9847            }
9848
9849            // Descend through all of the app tokens and find the first that either matches
9850            // win.mAppToken (return win) or mFocusedApp (return null).
9851            if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING &&
9852                    mFocusedApp != null) {
9853                ArrayList<Task> tasks = displayContent.getTasks();
9854                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
9855                    AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
9856                    int tokenNdx = tokens.size() - 1;
9857                    for ( ; tokenNdx >= 0; --tokenNdx) {
9858                        final AppWindowToken token = tokens.get(tokenNdx);
9859                        if (wtoken == token) {
9860                            break;
9861                        }
9862                        if (mFocusedApp == token) {
9863                            // Whoops, we are below the focused app...  no focus for you!
9864                            if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG,
9865                                    "findFocusedWindow: Reached focused app=" + mFocusedApp);
9866                            return null;
9867                        }
9868                    }
9869                    if (tokenNdx >= 0) {
9870                        // Early exit from loop, must have found the matching token.
9871                        break;
9872                    }
9873                }
9874            }
9875
9876            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "findFocusedWindow: Found new focus @ " + i +
9877                        " = " + win);
9878            return win;
9879        }
9880
9881        if (DEBUG_FOCUS_LIGHT) Slog.v(TAG, "findFocusedWindow: No focusable windows.");
9882        return null;
9883    }
9884
9885    private void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
9886        if (mDisplayFrozen) {
9887            return;
9888        }
9889
9890        if (!mDisplayReady || !mPolicy.isScreenOnFully()) {
9891            // No need to freeze the screen before the system is ready or if
9892            // the screen is off.
9893            return;
9894        }
9895
9896        mScreenFrozenLock.acquire();
9897
9898        mDisplayFrozen = true;
9899        mDisplayFreezeTime = SystemClock.elapsedRealtime();
9900        mLastFinishedFreezeSource = null;
9901
9902        mInputMonitor.freezeInputDispatchingLw();
9903
9904        // Clear the last input window -- that is just used for
9905        // clean transitions between IMEs, and if we are freezing
9906        // the screen then the whole world is changing behind the scenes.
9907        mPolicy.setLastInputMethodWindowLw(null, null);
9908
9909        if (mAppTransition.isTransitionSet()) {
9910            mAppTransition.freeze();
9911        }
9912
9913        if (PROFILE_ORIENTATION) {
9914            File file = new File("/data/system/frozen");
9915            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9916        }
9917
9918        if (CUSTOM_SCREEN_ROTATION) {
9919            mExitAnimId = exitAnim;
9920            mEnterAnimId = enterAnim;
9921            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9922            final int displayId = displayContent.getDisplayId();
9923            ScreenRotationAnimation screenRotationAnimation =
9924                    mAnimator.getScreenRotationAnimationLocked(displayId);
9925            if (screenRotationAnimation != null) {
9926                screenRotationAnimation.kill();
9927            }
9928
9929            // Check whether the current screen contains any secure content.
9930            boolean isSecure = false;
9931            final WindowList windows = getDefaultWindowListLocked();
9932            final int N = windows.size();
9933            for (int i = 0; i < N; i++) {
9934                WindowState ws = windows.get(i);
9935                if (ws.isOnScreen() && (ws.mAttrs.flags & FLAG_SECURE) != 0) {
9936                    isSecure = true;
9937                    break;
9938                }
9939            }
9940
9941            // TODO(multidisplay): rotation on main screen only.
9942            displayContent.updateDisplayInfo();
9943            screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
9944                    mFxSession, inTransaction, mPolicy.isDefaultOrientationForced(), isSecure);
9945            mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9946        }
9947    }
9948
9949    private void stopFreezingDisplayLocked() {
9950        if (!mDisplayFrozen) {
9951            return;
9952        }
9953
9954        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
9955                || mClientFreezingScreen) {
9956            if (DEBUG_ORIENTATION) Slog.d(TAG,
9957                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
9958                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
9959                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
9960                + ", mClientFreezingScreen=" + mClientFreezingScreen);
9961            return;
9962        }
9963
9964        mDisplayFrozen = false;
9965        mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
9966        StringBuilder sb = new StringBuilder(128);
9967        sb.append("Screen frozen for ");
9968        TimeUtils.formatDuration(mLastDisplayFreezeDuration, sb);
9969        if (mLastFinishedFreezeSource != null) {
9970            sb.append(" due to ");
9971            sb.append(mLastFinishedFreezeSource);
9972        }
9973        Slog.i(TAG, sb.toString());
9974        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9975        mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
9976        if (PROFILE_ORIENTATION) {
9977            Debug.stopMethodTracing();
9978        }
9979
9980        boolean updateRotation = false;
9981
9982        final DisplayContent displayContent = getDefaultDisplayContentLocked();
9983        final int displayId = displayContent.getDisplayId();
9984        ScreenRotationAnimation screenRotationAnimation =
9985                mAnimator.getScreenRotationAnimationLocked(displayId);
9986        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
9987                && screenRotationAnimation.hasScreenshot()) {
9988            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
9989            // TODO(multidisplay): rotation on main screen only.
9990            DisplayInfo displayInfo = displayContent.getDisplayInfo();
9991            // Get rotation animation again, with new top window
9992            boolean isDimming = displayContent.isDimming();
9993            if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
9994                mExitAnimId = mEnterAnimId = 0;
9995            }
9996            if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9997                    mTransitionAnimationScale, displayInfo.logicalWidth,
9998                        displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
9999                scheduleAnimationLocked();
10000            } else {
10001                screenRotationAnimation.kill();
10002                screenRotationAnimation = null;
10003                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
10004                updateRotation = true;
10005            }
10006        } else {
10007            if (screenRotationAnimation != null) {
10008                screenRotationAnimation.kill();
10009                screenRotationAnimation = null;
10010                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
10011            }
10012            updateRotation = true;
10013        }
10014
10015        mInputMonitor.thawInputDispatchingLw();
10016
10017        boolean configChanged;
10018
10019        // While the display is frozen we don't re-compute the orientation
10020        // to avoid inconsistent states.  However, something interesting
10021        // could have actually changed during that time so re-evaluate it
10022        // now to catch that.
10023        configChanged = updateOrientationFromAppTokensLocked(false);
10024
10025        // A little kludge: a lot could have happened while the
10026        // display was frozen, so now that we are coming back we
10027        // do a gc so that any remote references the system
10028        // processes holds on others can be released if they are
10029        // no longer needed.
10030        mH.removeMessages(H.FORCE_GC);
10031        mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);
10032
10033        mScreenFrozenLock.release();
10034
10035        if (updateRotation) {
10036            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
10037            configChanged |= updateRotationUncheckedLocked(false);
10038        }
10039
10040        if (configChanged) {
10041            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
10042        }
10043    }
10044
10045    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
10046            DisplayMetrics dm) {
10047        if (index < tokens.length) {
10048            String str = tokens[index];
10049            if (str != null && str.length() > 0) {
10050                try {
10051                    int val = Integer.parseInt(str);
10052                    return val;
10053                } catch (Exception e) {
10054                }
10055            }
10056        }
10057        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
10058            return defDps;
10059        }
10060        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
10061        return val;
10062    }
10063
10064    void createWatermarkInTransaction() {
10065        if (mWatermark != null) {
10066            return;
10067        }
10068
10069        File file = new File("/system/etc/setup.conf");
10070        FileInputStream in = null;
10071        DataInputStream ind = null;
10072        try {
10073            in = new FileInputStream(file);
10074            ind = new DataInputStream(in);
10075            String line = ind.readLine();
10076            if (line != null) {
10077                String[] toks = line.split("%");
10078                if (toks != null && toks.length > 0) {
10079                    mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
10080                            mRealDisplayMetrics, mFxSession, toks);
10081                }
10082            }
10083        } catch (FileNotFoundException e) {
10084        } catch (IOException e) {
10085        } finally {
10086            if (ind != null) {
10087                try {
10088                    ind.close();
10089                } catch (IOException e) {
10090                }
10091            } else if (in != null) {
10092                try {
10093                    in.close();
10094                } catch (IOException e) {
10095                }
10096            }
10097        }
10098    }
10099
10100    @Override
10101    public void statusBarVisibilityChanged(int visibility) {
10102        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
10103                != PackageManager.PERMISSION_GRANTED) {
10104            throw new SecurityException("Caller does not hold permission "
10105                    + android.Manifest.permission.STATUS_BAR);
10106        }
10107
10108        synchronized (mWindowMap) {
10109            mLastStatusBarVisibility = visibility;
10110            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
10111            updateStatusBarVisibilityLocked(visibility);
10112        }
10113    }
10114
10115    // TOOD(multidisplay): StatusBar on multiple screens?
10116    void updateStatusBarVisibilityLocked(int visibility) {
10117        mInputManager.setSystemUiVisibility(visibility);
10118        final WindowList windows = getDefaultWindowListLocked();
10119        final int N = windows.size();
10120        for (int i = 0; i < N; i++) {
10121            WindowState ws = windows.get(i);
10122            try {
10123                int curValue = ws.mSystemUiVisibility;
10124                int diff = curValue ^ visibility;
10125                // We are only interested in differences of one of the
10126                // clearable flags...
10127                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
10128                // ...if it has actually been cleared.
10129                diff &= ~visibility;
10130                int newValue = (curValue&~diff) | (visibility&diff);
10131                if (newValue != curValue) {
10132                    ws.mSeq++;
10133                    ws.mSystemUiVisibility = newValue;
10134                }
10135                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
10136                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
10137                            visibility, newValue, diff);
10138                }
10139            } catch (RemoteException e) {
10140                // so sorry
10141            }
10142        }
10143    }
10144
10145    @Override
10146    public void reevaluateStatusBarVisibility() {
10147        synchronized (mWindowMap) {
10148            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
10149            updateStatusBarVisibilityLocked(visibility);
10150            performLayoutAndPlaceSurfacesLocked();
10151        }
10152    }
10153
10154    @Override
10155    public FakeWindow addFakeWindow(Looper looper,
10156            InputEventReceiver.Factory inputEventReceiverFactory,
10157            String name, int windowType, int layoutParamsFlags, int layoutParamsPrivateFlags,
10158            boolean canReceiveKeys, boolean hasFocus, boolean touchFullscreen) {
10159        synchronized (mWindowMap) {
10160            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
10161                    name, windowType,
10162                    layoutParamsFlags, layoutParamsPrivateFlags, canReceiveKeys,
10163                    hasFocus, touchFullscreen);
10164            int i=0;
10165            while (i<mFakeWindows.size()) {
10166                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
10167                    break;
10168                }
10169            }
10170            mFakeWindows.add(i, fw);
10171            mInputMonitor.updateInputWindowsLw(true);
10172            return fw;
10173        }
10174    }
10175
10176    boolean removeFakeWindowLocked(FakeWindow window) {
10177        synchronized (mWindowMap) {
10178            if (mFakeWindows.remove(window)) {
10179                mInputMonitor.updateInputWindowsLw(true);
10180                return true;
10181            }
10182            return false;
10183        }
10184    }
10185
10186    // It is assumed that this method is called only by InputMethodManagerService.
10187    public void saveLastInputMethodWindowForTransition() {
10188        synchronized (mWindowMap) {
10189            // TODO(multidisplay): Pass in the displayID.
10190            DisplayContent displayContent = getDefaultDisplayContentLocked();
10191            if (mInputMethodWindow != null) {
10192                mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
10193            }
10194        }
10195    }
10196
10197    public int getInputMethodWindowVisibleHeight() {
10198        synchronized (mWindowMap) {
10199            return mPolicy.getInputMethodWindowVisibleHeightLw();
10200        }
10201    }
10202
10203    @Override
10204    public boolean hasNavigationBar() {
10205        return mPolicy.hasNavigationBar();
10206    }
10207
10208    @Override
10209    public void lockNow(Bundle options) {
10210        mPolicy.lockNow(options);
10211    }
10212
10213    @Override
10214    public boolean isSafeModeEnabled() {
10215        return mSafeMode;
10216    }
10217
10218    void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
10219        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
10220        mPolicy.dump("    ", pw, args);
10221    }
10222
10223    void dumpAnimatorLocked(PrintWriter pw, String[] args, boolean dumpAll) {
10224        pw.println("WINDOW MANAGER ANIMATOR STATE (dumpsys window animator)");
10225        mAnimator.dumpLocked(pw, "    ", dumpAll);
10226    }
10227
10228    void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
10229        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
10230        if (mTokenMap.size() > 0) {
10231            pw.println("  All tokens:");
10232            Iterator<WindowToken> it = mTokenMap.values().iterator();
10233            while (it.hasNext()) {
10234                WindowToken token = it.next();
10235                pw.print("  "); pw.print(token);
10236                if (dumpAll) {
10237                    pw.println(':');
10238                    token.dump(pw, "    ");
10239                } else {
10240                    pw.println();
10241                }
10242            }
10243        }
10244        if (mWallpaperTokens.size() > 0) {
10245            pw.println();
10246            pw.println("  Wallpaper tokens:");
10247            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
10248                WindowToken token = mWallpaperTokens.get(i);
10249                pw.print("  Wallpaper #"); pw.print(i);
10250                        pw.print(' '); pw.print(token);
10251                if (dumpAll) {
10252                    pw.println(':');
10253                    token.dump(pw, "    ");
10254                } else {
10255                    pw.println();
10256                }
10257            }
10258        }
10259        if (mFinishedStarting.size() > 0) {
10260            pw.println();
10261            pw.println("  Finishing start of application tokens:");
10262            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
10263                WindowToken token = mFinishedStarting.get(i);
10264                pw.print("  Finished Starting #"); pw.print(i);
10265                        pw.print(' '); pw.print(token);
10266                if (dumpAll) {
10267                    pw.println(':');
10268                    token.dump(pw, "    ");
10269                } else {
10270                    pw.println();
10271                }
10272            }
10273        }
10274        if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
10275            pw.println();
10276            if (mOpeningApps.size() > 0) {
10277                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
10278            }
10279            if (mClosingApps.size() > 0) {
10280                pw.print("  mClosingApps="); pw.println(mClosingApps);
10281            }
10282        }
10283    }
10284
10285    void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
10286        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
10287        if (mSessions.size() > 0) {
10288            Iterator<Session> it = mSessions.iterator();
10289            while (it.hasNext()) {
10290                Session s = it.next();
10291                pw.print("  Session "); pw.print(s); pw.println(':');
10292                s.dump(pw, "    ");
10293            }
10294        }
10295    }
10296
10297    void dumpDisplayContentsLocked(PrintWriter pw, boolean dumpAll) {
10298        pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)");
10299        if (mDisplayReady) {
10300            final int numDisplays = mDisplayContents.size();
10301            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10302                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
10303                displayContent.dump("  ", pw);
10304            }
10305        } else {
10306            pw.println("  NO DISPLAY");
10307        }
10308    }
10309
10310    void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
10311            ArrayList<WindowState> windows) {
10312        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
10313        dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
10314    }
10315
10316    void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
10317            ArrayList<WindowState> windows) {
10318        final int numDisplays = mDisplayContents.size();
10319        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10320            final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
10321            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10322                final WindowState w = windowList.get(winNdx);
10323                if (windows == null || windows.contains(w)) {
10324                    pw.print("  Window #"); pw.print(winNdx); pw.print(' ');
10325                            pw.print(w); pw.println(":");
10326                    w.dump(pw, "    ", dumpAll || windows != null);
10327                }
10328            }
10329        }
10330        if (mInputMethodDialogs.size() > 0) {
10331            pw.println();
10332            pw.println("  Input method dialogs:");
10333            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
10334                WindowState w = mInputMethodDialogs.get(i);
10335                if (windows == null || windows.contains(w)) {
10336                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
10337                }
10338            }
10339        }
10340        if (mPendingRemove.size() > 0) {
10341            pw.println();
10342            pw.println("  Remove pending for:");
10343            for (int i=mPendingRemove.size()-1; i>=0; i--) {
10344                WindowState w = mPendingRemove.get(i);
10345                if (windows == null || windows.contains(w)) {
10346                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
10347                            pw.print(w);
10348                    if (dumpAll) {
10349                        pw.println(":");
10350                        w.dump(pw, "    ", true);
10351                    } else {
10352                        pw.println();
10353                    }
10354                }
10355            }
10356        }
10357        if (mForceRemoves != null && mForceRemoves.size() > 0) {
10358            pw.println();
10359            pw.println("  Windows force removing:");
10360            for (int i=mForceRemoves.size()-1; i>=0; i--) {
10361                WindowState w = mForceRemoves.get(i);
10362                pw.print("  Removing #"); pw.print(i); pw.print(' ');
10363                        pw.print(w);
10364                if (dumpAll) {
10365                    pw.println(":");
10366                    w.dump(pw, "    ", true);
10367                } else {
10368                    pw.println();
10369                }
10370            }
10371        }
10372        if (mDestroySurface.size() > 0) {
10373            pw.println();
10374            pw.println("  Windows waiting to destroy their surface:");
10375            for (int i=mDestroySurface.size()-1; i>=0; i--) {
10376                WindowState w = mDestroySurface.get(i);
10377                if (windows == null || windows.contains(w)) {
10378                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
10379                            pw.print(w);
10380                    if (dumpAll) {
10381                        pw.println(":");
10382                        w.dump(pw, "    ", true);
10383                    } else {
10384                        pw.println();
10385                    }
10386                }
10387            }
10388        }
10389        if (mLosingFocus.size() > 0) {
10390            pw.println();
10391            pw.println("  Windows losing focus:");
10392            for (int i=mLosingFocus.size()-1; i>=0; i--) {
10393                WindowState w = mLosingFocus.get(i);
10394                if (windows == null || windows.contains(w)) {
10395                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
10396                            pw.print(w);
10397                    if (dumpAll) {
10398                        pw.println(":");
10399                        w.dump(pw, "    ", true);
10400                    } else {
10401                        pw.println();
10402                    }
10403                }
10404            }
10405        }
10406        if (mResizingWindows.size() > 0) {
10407            pw.println();
10408            pw.println("  Windows waiting to resize:");
10409            for (int i=mResizingWindows.size()-1; i>=0; i--) {
10410                WindowState w = mResizingWindows.get(i);
10411                if (windows == null || windows.contains(w)) {
10412                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
10413                            pw.print(w);
10414                    if (dumpAll) {
10415                        pw.println(":");
10416                        w.dump(pw, "    ", true);
10417                    } else {
10418                        pw.println();
10419                    }
10420                }
10421            }
10422        }
10423        if (mWaitingForDrawn.size() > 0) {
10424            pw.println();
10425            pw.println("  Clients waiting for these windows to be drawn:");
10426            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
10427                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
10428                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
10429                        pw.print(": "); pw.println(pair.second);
10430            }
10431        }
10432        pw.println();
10433        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
10434        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
10435        if (mLastFocus != mCurrentFocus) {
10436            pw.print("  mLastFocus="); pw.println(mLastFocus);
10437        }
10438        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
10439        if (mInputMethodTarget != null) {
10440            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
10441        }
10442        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
10443                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
10444        pw.print("  mLastDisplayFreezeDuration=");
10445                TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
10446                if ( mLastFinishedFreezeSource != null) {
10447                    pw.print(" due to ");
10448                    pw.print(mLastFinishedFreezeSource);
10449                }
10450                pw.println();
10451        if (dumpAll) {
10452            pw.print("  mSystemDecorLayer="); pw.print(mSystemDecorLayer);
10453                    pw.print(" mScreenRect="); pw.println(mScreenRect.toShortString());
10454            if (mLastStatusBarVisibility != 0) {
10455                pw.print("  mLastStatusBarVisibility=0x");
10456                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
10457            }
10458            if (mInputMethodWindow != null) {
10459                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
10460            }
10461            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
10462            if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
10463                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
10464                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
10465            }
10466            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
10467                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
10468            if (mInputMethodAnimLayerAdjustment != 0 ||
10469                    mWallpaperAnimLayerAdjustment != 0) {
10470                pw.print("  mInputMethodAnimLayerAdjustment=");
10471                        pw.print(mInputMethodAnimLayerAdjustment);
10472                        pw.print("  mWallpaperAnimLayerAdjustment=");
10473                        pw.println(mWallpaperAnimLayerAdjustment);
10474            }
10475            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
10476                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
10477            if (needsLayout()) {
10478                pw.print("  layoutNeeded on displays=");
10479                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10480                    final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
10481                    if (displayContent.layoutNeeded) {
10482                        pw.print(displayContent.getDisplayId());
10483                    }
10484                }
10485                pw.println();
10486            }
10487            pw.print("  mTransactionSequence="); pw.println(mTransactionSequence);
10488            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
10489                    pw.print(" windows="); pw.print(mWindowsFreezingScreen);
10490                    pw.print(" client="); pw.print(mClientFreezingScreen);
10491                    pw.print(" apps="); pw.print(mAppsFreezingScreen);
10492                    pw.print(" waitingForConfig="); pw.println(mWaitingForConfig);
10493            pw.print("  mRotation="); pw.print(mRotation);
10494                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
10495            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
10496                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
10497            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
10498            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
10499                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
10500                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
10501            pw.print("  mTraversalScheduled="); pw.println(mTraversalScheduled);
10502            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
10503                    pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
10504            pw.println("  mLayoutToAnim:");
10505            mAppTransition.dump(pw);
10506        }
10507    }
10508
10509    boolean dumpWindows(PrintWriter pw, String name, String[] args,
10510            int opti, boolean dumpAll) {
10511        WindowList windows = new WindowList();
10512        if ("visible".equals(name)) {
10513            synchronized(mWindowMap) {
10514                final int numDisplays = mDisplayContents.size();
10515                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10516                    final WindowList windowList =
10517                            mDisplayContents.valueAt(displayNdx).getWindowList();
10518                    for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10519                        final WindowState w = windowList.get(winNdx);
10520                        if (w.mWinAnimator.mSurfaceShown) {
10521                            windows.add(w);
10522                        }
10523                    }
10524                }
10525            }
10526        } else {
10527            int objectId = 0;
10528            // See if this is an object ID.
10529            try {
10530                objectId = Integer.parseInt(name, 16);
10531                name = null;
10532            } catch (RuntimeException e) {
10533            }
10534            synchronized(mWindowMap) {
10535                final int numDisplays = mDisplayContents.size();
10536                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10537                    final WindowList windowList =
10538                            mDisplayContents.valueAt(displayNdx).getWindowList();
10539                    for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10540                        final WindowState w = windowList.get(winNdx);
10541                        if (name != null) {
10542                            if (w.mAttrs.getTitle().toString().contains(name)) {
10543                                windows.add(w);
10544                            }
10545                        } else if (System.identityHashCode(w) == objectId) {
10546                            windows.add(w);
10547                        }
10548                    }
10549                }
10550            }
10551        }
10552
10553        if (windows.size() <= 0) {
10554            return false;
10555        }
10556
10557        synchronized(mWindowMap) {
10558            dumpWindowsLocked(pw, dumpAll, windows);
10559        }
10560        return true;
10561    }
10562
10563    void dumpLastANRLocked(PrintWriter pw) {
10564        pw.println("WINDOW MANAGER LAST ANR (dumpsys window lastanr)");
10565        if (mLastANRState == null) {
10566            pw.println("  <no ANR has occurred since boot>");
10567        } else {
10568            pw.println(mLastANRState);
10569        }
10570    }
10571
10572    /**
10573     * Saves information about the state of the window manager at
10574     * the time an ANR occurred before anything else in the system changes
10575     * in response.
10576     *
10577     * @param appWindowToken The application that ANR'd, may be null.
10578     * @param windowState The window that ANR'd, may be null.
10579     * @param reason The reason for the ANR, may be null.
10580     */
10581    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState,
10582            String reason) {
10583        StringWriter sw = new StringWriter();
10584        PrintWriter pw = new FastPrintWriter(sw, false, 1024);
10585        pw.println("  ANR time: " + DateFormat.getInstance().format(new Date()));
10586        if (appWindowToken != null) {
10587            pw.println("  Application at fault: " + appWindowToken.stringName);
10588        }
10589        if (windowState != null) {
10590            pw.println("  Window at fault: " + windowState.mAttrs.getTitle());
10591        }
10592        if (reason != null) {
10593            pw.println("  Reason: " + reason);
10594        }
10595        pw.println();
10596        dumpWindowsNoHeaderLocked(pw, true, null);
10597        pw.close();
10598        mLastANRState = sw.toString();
10599    }
10600
10601    @Override
10602    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
10603        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
10604                != PackageManager.PERMISSION_GRANTED) {
10605            pw.println("Permission Denial: can't dump WindowManager from from pid="
10606                    + Binder.getCallingPid()
10607                    + ", uid=" + Binder.getCallingUid());
10608            return;
10609        }
10610
10611        boolean dumpAll = false;
10612
10613        int opti = 0;
10614        while (opti < args.length) {
10615            String opt = args[opti];
10616            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
10617                break;
10618            }
10619            opti++;
10620            if ("-a".equals(opt)) {
10621                dumpAll = true;
10622            } else if ("-h".equals(opt)) {
10623                pw.println("Window manager dump options:");
10624                pw.println("  [-a] [-h] [cmd] ...");
10625                pw.println("  cmd may be one of:");
10626                pw.println("    l[astanr]: last ANR information");
10627                pw.println("    p[policy]: policy state");
10628                pw.println("    a[animator]: animator state");
10629                pw.println("    s[essions]: active sessions");
10630                pw.println("    d[isplays]: active display contents");
10631                pw.println("    t[okens]: token list");
10632                pw.println("    w[indows]: window list");
10633                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
10634                pw.println("    be a partial substring in a window name, a");
10635                pw.println("    Window hex object identifier, or");
10636                pw.println("    \"all\" for all windows, or");
10637                pw.println("    \"visible\" for the visible windows.");
10638                pw.println("  -a: include all available server state.");
10639                return;
10640            } else {
10641                pw.println("Unknown argument: " + opt + "; use -h for help");
10642            }
10643        }
10644
10645        // Is the caller requesting to dump a particular piece of data?
10646        if (opti < args.length) {
10647            String cmd = args[opti];
10648            opti++;
10649            if ("lastanr".equals(cmd) || "l".equals(cmd)) {
10650                synchronized(mWindowMap) {
10651                    dumpLastANRLocked(pw);
10652                }
10653                return;
10654            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
10655                synchronized(mWindowMap) {
10656                    dumpPolicyLocked(pw, args, true);
10657                }
10658                return;
10659            } else if ("animator".equals(cmd) || "a".equals(cmd)) {
10660                synchronized(mWindowMap) {
10661                    dumpAnimatorLocked(pw, args, true);
10662                }
10663                return;
10664            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
10665                synchronized(mWindowMap) {
10666                    dumpSessionsLocked(pw, true);
10667                }
10668                return;
10669            } else if ("displays".equals(cmd) || "d".equals(cmd)) {
10670                synchronized(mWindowMap) {
10671                    dumpDisplayContentsLocked(pw, true);
10672                }
10673                return;
10674            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
10675                synchronized(mWindowMap) {
10676                    dumpTokensLocked(pw, true);
10677                }
10678                return;
10679            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
10680                synchronized(mWindowMap) {
10681                    dumpWindowsLocked(pw, true, null);
10682                }
10683                return;
10684            } else if ("all".equals(cmd) || "a".equals(cmd)) {
10685                synchronized(mWindowMap) {
10686                    dumpWindowsLocked(pw, true, null);
10687                }
10688                return;
10689            } else {
10690                // Dumping a single name?
10691                if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
10692                    pw.println("Bad window command, or no windows match: " + cmd);
10693                    pw.println("Use -h for help.");
10694                }
10695                return;
10696            }
10697        }
10698
10699        synchronized(mWindowMap) {
10700            pw.println();
10701            if (dumpAll) {
10702                pw.println("-------------------------------------------------------------------------------");
10703            }
10704            dumpLastANRLocked(pw);
10705            pw.println();
10706            if (dumpAll) {
10707                pw.println("-------------------------------------------------------------------------------");
10708            }
10709            dumpPolicyLocked(pw, args, dumpAll);
10710            pw.println();
10711            if (dumpAll) {
10712                pw.println("-------------------------------------------------------------------------------");
10713            }
10714            dumpAnimatorLocked(pw, args, dumpAll);
10715            pw.println();
10716            if (dumpAll) {
10717                pw.println("-------------------------------------------------------------------------------");
10718            }
10719            dumpSessionsLocked(pw, dumpAll);
10720            pw.println();
10721            if (dumpAll) {
10722                pw.println("-------------------------------------------------------------------------------");
10723            }
10724            dumpDisplayContentsLocked(pw, dumpAll);
10725            pw.println();
10726            if (dumpAll) {
10727                pw.println("-------------------------------------------------------------------------------");
10728            }
10729            dumpTokensLocked(pw, dumpAll);
10730            pw.println();
10731            if (dumpAll) {
10732                pw.println("-------------------------------------------------------------------------------");
10733            }
10734            dumpWindowsLocked(pw, dumpAll, null);
10735        }
10736    }
10737
10738    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
10739    @Override
10740    public void monitor() {
10741        synchronized (mWindowMap) { }
10742    }
10743
10744    public interface OnHardKeyboardStatusChangeListener {
10745        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
10746    }
10747
10748    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
10749        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
10750            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
10751                    Integer.toHexString(pendingLayoutChanges));
10752        }
10753    }
10754
10755    private DisplayContent newDisplayContentLocked(final Display display) {
10756        DisplayContent displayContent = new DisplayContent(display, this);
10757        final int displayId = display.getDisplayId();
10758        if (DEBUG_DISPLAY) Slog.v(TAG, "Adding display=" + display);
10759        mDisplayContents.put(displayId, displayContent);
10760
10761        DisplayInfo displayInfo = displayContent.getDisplayInfo();
10762        final Rect rect = new Rect();
10763        mDisplaySettings.getOverscanLocked(displayInfo.name, rect);
10764        synchronized (displayContent.mDisplaySizeLock) {
10765            displayInfo.overscanLeft = rect.left;
10766            displayInfo.overscanTop = rect.top;
10767            displayInfo.overscanRight = rect.right;
10768            displayInfo.overscanBottom = rect.bottom;
10769            mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(
10770                    displayId, displayInfo);
10771        }
10772        configureDisplayPolicyLocked(displayContent);
10773
10774        // TODO: Create an input channel for each display with touch capability.
10775        if (displayId == Display.DEFAULT_DISPLAY) {
10776            displayContent.mTapDetector = new StackTapPointerEventListener(this, displayContent);
10777            registerPointerEventListener(displayContent.mTapDetector);
10778        }
10779
10780        return displayContent;
10781    }
10782
10783    public void createDisplayContentLocked(final Display display) {
10784        if (display == null) {
10785            throw new IllegalArgumentException("getDisplayContent: display must not be null");
10786        }
10787        getDisplayContentLocked(display.getDisplayId());
10788    }
10789
10790    /**
10791     * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
10792     * there is a Display for the displayId.
10793     * @param displayId The display the caller is interested in.
10794     * @return The DisplayContent associated with displayId or null if there is no Display for it.
10795     */
10796    public DisplayContent getDisplayContentLocked(final int displayId) {
10797        DisplayContent displayContent = mDisplayContents.get(displayId);
10798        if (displayContent == null) {
10799            final Display display = mDisplayManager.getDisplay(displayId);
10800            if (display != null) {
10801                displayContent = newDisplayContentLocked(display);
10802            }
10803        }
10804        return displayContent;
10805    }
10806
10807    // There is an inherent assumption that this will never return null.
10808    public DisplayContent getDefaultDisplayContentLocked() {
10809        return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
10810    }
10811
10812    public WindowList getDefaultWindowListLocked() {
10813        return getDefaultDisplayContentLocked().getWindowList();
10814    }
10815
10816    public DisplayInfo getDefaultDisplayInfoLocked() {
10817        return getDefaultDisplayContentLocked().getDisplayInfo();
10818    }
10819
10820    /**
10821     * Return the list of WindowStates associated on the passed display.
10822     * @param display The screen to return windows from.
10823     * @return The list of WindowStates on the screen, or null if the there is no screen.
10824     */
10825    public WindowList getWindowListLocked(final Display display) {
10826        return getWindowListLocked(display.getDisplayId());
10827    }
10828
10829    /**
10830     * Return the list of WindowStates associated on the passed display.
10831     * @param displayId The screen to return windows from.
10832     * @return The list of WindowStates on the screen, or null if the there is no screen.
10833     */
10834    public WindowList getWindowListLocked(final int displayId) {
10835        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10836        return displayContent != null ? displayContent.getWindowList() : null;
10837    }
10838
10839    public void onDisplayAdded(int displayId) {
10840        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
10841    }
10842
10843    public void handleDisplayAdded(int displayId) {
10844        synchronized (mWindowMap) {
10845            final Display display = mDisplayManager.getDisplay(displayId);
10846            if (display != null) {
10847                createDisplayContentLocked(display);
10848                displayReady(displayId);
10849            }
10850        }
10851    }
10852
10853    public void onDisplayRemoved(int displayId) {
10854        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
10855    }
10856
10857    private void handleDisplayRemovedLocked(int displayId) {
10858        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10859        if (displayContent != null) {
10860            if (displayContent.isAnimating()) {
10861                displayContent.mDeferredRemoval = true;
10862                return;
10863            }
10864            if (DEBUG_DISPLAY) Slog.v(TAG, "Removing display=" + displayContent);
10865            mDisplayContents.delete(displayId);
10866            displayContent.close();
10867            if (displayId == Display.DEFAULT_DISPLAY) {
10868                unregisterPointerEventListener(displayContent.mTapDetector);
10869            }
10870        }
10871        mAnimator.removeDisplayLocked(displayId);
10872    }
10873
10874    public void onDisplayChanged(int displayId) {
10875        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
10876    }
10877
10878    private void handleDisplayChangedLocked(int displayId) {
10879        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10880        if (displayContent != null) {
10881            displayContent.updateDisplayInfo();
10882        }
10883    }
10884
10885    @Override
10886    public Object getWindowManagerLock() {
10887        return mWindowMap;
10888    }
10889
10890    private final class LocalService extends WindowManagerInternal {
10891        @Override
10892        public void requestTraversalFromDisplayManager() {
10893            requestTraversal();
10894        }
10895
10896        @Override
10897        public void setMagnificationSpec(MagnificationSpec spec) {
10898            synchronized (mWindowMap) {
10899                if (mAccessibilityController != null) {
10900                    mAccessibilityController.setMagnificationSpecLocked(spec);
10901                } else {
10902                    throw new IllegalStateException("Magnification callbacks not set!");
10903                }
10904            }
10905            if (Binder.getCallingPid() != android.os.Process.myPid()) {
10906                spec.recycle();
10907            }
10908        }
10909
10910        @Override
10911        public MagnificationSpec getCompatibleMagnificationSpecForWindow(IBinder windowToken) {
10912            synchronized (mWindowMap) {
10913                WindowState windowState = mWindowMap.get(windowToken);
10914                if (windowState == null) {
10915                    return null;
10916                }
10917                MagnificationSpec spec = null;
10918                if (mAccessibilityController != null) {
10919                    spec = mAccessibilityController.getMagnificationSpecForWindowLocked(windowState);
10920                }
10921                if ((spec == null || spec.isNop()) && windowState.mGlobalScale == 1.0f) {
10922                    return null;
10923                }
10924                spec = (spec == null) ? MagnificationSpec.obtain() : MagnificationSpec.obtain(spec);
10925                spec.scale *= windowState.mGlobalScale;
10926                return spec;
10927            }
10928        }
10929
10930        @Override
10931        public void setMagnificationCallbacks(MagnificationCallbacks callbacks) {
10932            synchronized (mWindowMap) {
10933                if (mAccessibilityController == null) {
10934                    mAccessibilityController = new AccessibilityController(
10935                            WindowManagerService.this);
10936                }
10937                mAccessibilityController.setMagnificationCallbacksLocked(callbacks);
10938                if (!mAccessibilityController.hasCallbacksLocked()) {
10939                     mAccessibilityController = null;
10940                }
10941            }
10942        }
10943
10944        @Override
10945        public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
10946            synchronized (mWindowMap) {
10947                if (mAccessibilityController == null) {
10948                    mAccessibilityController = new AccessibilityController(
10949                            WindowManagerService.this);
10950                }
10951                mAccessibilityController.setWindowsForAccessibilityCallback(callback);
10952                if (!mAccessibilityController.hasCallbacksLocked()) {
10953                     mAccessibilityController = null;
10954                }
10955            }
10956        }
10957
10958        @Override
10959        public void setInputFilter(IInputFilter filter) {
10960            mInputManager.setInputFilter(filter);
10961        }
10962
10963        @Override
10964        public IBinder getFocusedWindowToken() {
10965            synchronized (mWindowMap) {
10966                WindowState windowState = getFocusedWindowLocked();
10967                if (windowState != null) {
10968                    return windowState.mClient.asBinder();
10969                }
10970                return null;
10971            }
10972        }
10973
10974        @Override
10975        public boolean isKeyguardLocked() {
10976            return isKeyguardLocked();
10977        }
10978
10979        @Override
10980        public void getWindowFrame(IBinder token, Rect outBounds) {
10981            synchronized (mWindowMap) {
10982                WindowState windowState = mWindowMap.get(token);
10983                if (windowState != null) {
10984                    outBounds.set(windowState.mFrame);
10985                } else {
10986                    outBounds.setEmpty();
10987                }
10988            }
10989        }
10990    }
10991}
10992