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