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