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