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