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