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