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