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