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