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