WindowManagerService.java revision 19d9a8f47625319406f593d4ec71de0c8df1fcfe
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.clearAllDrawn();
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 flag 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.clearAllDrawn();
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                wtoken.setVisibleBeforeClientHidden();
4427            } else if (visible) {
4428                if (!mAppTransition.isTransitionSet() && mAppTransition.isReady()) {
4429                    // Add the app mOpeningApps if transition is unset but ready. This means
4430                    // we're doing a screen freeze, and the unfreeze will wait for all opening
4431                    // apps to be ready.
4432                    mOpeningApps.add(wtoken);
4433                }
4434                wtoken.startingMoved = false;
4435                // If the token is currently hidden (should be the common case), or has been
4436                // stopped, then we need to set up to wait for its windows to be ready.
4437                if (wtoken.hidden || wtoken.mAppStopped) {
4438                    wtoken.clearAllDrawn();
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        final int imeHeight = mPolicy.getInputMethodWindowVisibleHeightLw();
7539        final boolean imeHeightChanged = imeVisible &&
7540                imeHeight != displayContent.mDividerControllerLocked.getImeHeightAdjustedFor();
7541
7542        // The divider could be adjusted for IME position, or be thinner than usual,
7543        // or both. There are three possible cases:
7544        // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
7545        // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
7546        // - If IME is not visible, divider is not moved and is normal width.
7547
7548        if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
7549            final ArrayList<TaskStack> stacks = displayContent.getStacks();
7550            for (int i = stacks.size() - 1; i >= 0; --i) {
7551                final TaskStack stack = stacks.get(i);
7552                final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
7553                if (stack.isVisibleLocked() && (imeOnBottom || isDockedOnBottom)) {
7554                    stack.setAdjustedForIme(imeWin, imeOnBottom && imeHeightChanged);
7555                } else {
7556                    stack.resetAdjustedForIme(false);
7557                }
7558            }
7559            displayContent.mDividerControllerLocked.setAdjustedForIme(
7560                    imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight);
7561        } else {
7562            final ArrayList<TaskStack> stacks = displayContent.getStacks();
7563            for (int i = stacks.size() - 1; i >= 0; --i) {
7564                final TaskStack stack = stacks.get(i);
7565                stack.resetAdjustedForIme(!dockVisible);
7566            }
7567            displayContent.mDividerControllerLocked.setAdjustedForIme(
7568                    false /*ime*/, false /*divider*/, dockVisible /*animate*/, imeWin, imeHeight);
7569        }
7570    }
7571
7572    // -------------------------------------------------------------
7573    // Drag and drop
7574    // -------------------------------------------------------------
7575
7576    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
7577            int flags, int width, int height, Surface outSurface) {
7578        if (DEBUG_DRAG) {
7579            Slog.d(TAG_WM, "prepare drag surface: w=" + width + " h=" + height
7580                    + " flags=" + Integer.toHexString(flags) + " win=" + window
7581                    + " asbinder=" + window.asBinder());
7582        }
7583
7584        final int callerPid = Binder.getCallingPid();
7585        final int callerUid = Binder.getCallingUid();
7586        final long origId = Binder.clearCallingIdentity();
7587        IBinder token = null;
7588
7589        try {
7590            synchronized (mWindowMap) {
7591                try {
7592                    if (mDragState == null) {
7593                        // TODO(multi-display): support other displays
7594                        final DisplayContent displayContent = getDefaultDisplayContentLocked();
7595                        final Display display = displayContent.getDisplay();
7596
7597                        SurfaceControl surface = new SurfaceControl(session, "drag surface",
7598                                width, height, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
7599                        surface.setLayerStack(display.getLayerStack());
7600                        float alpha = 1;
7601                        if ((flags & View.DRAG_FLAG_OPAQUE) == 0) {
7602                            alpha = DRAG_SHADOW_ALPHA_TRANSPARENT;
7603                        }
7604                        surface.setAlpha(alpha);
7605
7606                        if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, "  DRAG "
7607                                + surface + ": CREATE");
7608                        outSurface.copyFrom(surface);
7609                        final IBinder winBinder = window.asBinder();
7610                        token = new Binder();
7611                        mDragState = new DragState(this, token, surface, flags, winBinder);
7612                        mDragState.mPid = callerPid;
7613                        mDragState.mUid = callerUid;
7614                        mDragState.mOriginalAlpha = alpha;
7615                        token = mDragState.mToken = new Binder();
7616
7617                        // 5 second timeout for this window to actually begin the drag
7618                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
7619                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
7620                        mH.sendMessageDelayed(msg, 5000);
7621                    } else {
7622                        Slog.w(TAG_WM, "Drag already in progress");
7623                    }
7624                } catch (OutOfResourcesException e) {
7625                    Slog.e(TAG_WM, "Can't allocate drag surface w=" + width + " h=" + height, e);
7626                    if (mDragState != null) {
7627                        mDragState.reset();
7628                        mDragState = null;
7629                    }
7630                }
7631            }
7632        } finally {
7633            Binder.restoreCallingIdentity(origId);
7634        }
7635
7636        return token;
7637    }
7638
7639    // -------------------------------------------------------------
7640    // Input Events and Focus Management
7641    // -------------------------------------------------------------
7642
7643    final InputMonitor mInputMonitor = new InputMonitor(this);
7644    private boolean mEventDispatchingEnabled;
7645
7646    @Override
7647    public void pauseKeyDispatching(IBinder _token) {
7648        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7649                "pauseKeyDispatching()")) {
7650            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7651        }
7652
7653        synchronized (mWindowMap) {
7654            WindowToken token = mTokenMap.get(_token);
7655            if (token != null) {
7656                mInputMonitor.pauseDispatchingLw(token);
7657            }
7658        }
7659    }
7660
7661    @Override
7662    public void resumeKeyDispatching(IBinder _token) {
7663        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7664                "resumeKeyDispatching()")) {
7665            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7666        }
7667
7668        synchronized (mWindowMap) {
7669            WindowToken token = mTokenMap.get(_token);
7670            if (token != null) {
7671                mInputMonitor.resumeDispatchingLw(token);
7672            }
7673        }
7674    }
7675
7676    @Override
7677    public void setEventDispatching(boolean enabled) {
7678        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
7679                "setEventDispatching()")) {
7680            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
7681        }
7682
7683        synchronized (mWindowMap) {
7684            mEventDispatchingEnabled = enabled;
7685            if (mDisplayEnabled) {
7686                mInputMonitor.setEventDispatchingLw(enabled);
7687            }
7688        }
7689    }
7690
7691    private WindowState getFocusedWindow() {
7692        synchronized (mWindowMap) {
7693            return getFocusedWindowLocked();
7694        }
7695    }
7696
7697    private WindowState getFocusedWindowLocked() {
7698        return mCurrentFocus;
7699    }
7700
7701    TaskStack getImeTargetStackLocked() {
7702        // Don't use WindowState.getStack() because it returns home stack for system windows.
7703        Task imeTask = mInputMethodTarget != null ? mInputMethodTarget.getTask() : null;
7704        return imeTask != null ? imeTask.mStack : null;
7705    }
7706
7707    private void showAuditSafeModeNotification() {
7708        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
7709                new Intent(Intent.ACTION_VIEW,
7710                           Uri.parse("https://support.google.com/nexus/answer/2852139")), 0);
7711
7712        String title = mContext.getString(R.string.audit_safemode_notification);
7713
7714        Notification notification = new Notification.Builder(mContext)
7715                .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
7716                .setWhen(0)
7717                .setOngoing(true)
7718                .setTicker(title)
7719                .setLocalOnly(true)
7720                .setPriority(Notification.PRIORITY_HIGH)
7721                .setVisibility(Notification.VISIBILITY_PUBLIC)
7722                .setColor(mContext.getColor(
7723                        com.android.internal.R.color.system_notification_accent_color))
7724                .setContentTitle(title)
7725                .setContentText(mContext.getString(R.string.audit_safemode_notification_details))
7726                .setContentIntent(pendingIntent)
7727                .build();
7728
7729        NotificationManager notificationManager = (NotificationManager) mContext
7730                .getSystemService(Context.NOTIFICATION_SERVICE);
7731
7732        notificationManager.notifyAsUser(null, R.string.audit_safemode_notification, notification,
7733                UserHandle.ALL);
7734    }
7735
7736    public boolean detectSafeMode() {
7737        if (!mInputMonitor.waitForInputDevicesReady(
7738                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
7739            Slog.w(TAG_WM, "Devices still not ready after waiting "
7740                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
7741                   + " milliseconds before attempting to detect safe mode.");
7742        }
7743
7744        if (Settings.Global.getInt(
7745                mContext.getContentResolver(), Settings.Global.SAFE_BOOT_DISALLOWED, 0) != 0) {
7746            return false;
7747        }
7748
7749        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
7750                KeyEvent.KEYCODE_MENU);
7751        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
7752        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
7753                KeyEvent.KEYCODE_DPAD_CENTER);
7754        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
7755                InputManagerService.BTN_MOUSE);
7756        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
7757                KeyEvent.KEYCODE_VOLUME_DOWN);
7758        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
7759                || volumeDownState > 0;
7760        try {
7761            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0
7762                    || SystemProperties.getInt(ShutdownThread.RO_SAFEMODE_PROPERTY, 0) != 0) {
7763                int auditSafeMode = SystemProperties.getInt(ShutdownThread.AUDIT_SAFEMODE_PROPERTY, 0);
7764
7765                if (auditSafeMode == 0) {
7766                    mSafeMode = true;
7767                    SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
7768                } else {
7769                    // stay in safe mode until we have updated to a newer build
7770                    int buildDate = SystemProperties.getInt(PROPERTY_BUILD_DATE_UTC, 0);
7771
7772                    if (auditSafeMode >= buildDate) {
7773                        mSafeMode = true;
7774                        showAuditSafeModeNotification();
7775                    } else {
7776                        SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
7777                        SystemProperties.set(ShutdownThread.AUDIT_SAFEMODE_PROPERTY, "");
7778                    }
7779                }
7780            }
7781        } catch (IllegalArgumentException e) {
7782        }
7783        if (mSafeMode) {
7784            Log.i(TAG_WM, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
7785                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
7786            SystemProperties.set(ShutdownThread.RO_SAFEMODE_PROPERTY, "1");
7787        } else {
7788            Log.i(TAG_WM, "SAFE MODE not enabled");
7789        }
7790        mPolicy.setSafeMode(mSafeMode);
7791        return mSafeMode;
7792    }
7793
7794    public void displayReady() {
7795        for (Display display : mDisplays) {
7796            displayReady(display.getDisplayId());
7797        }
7798
7799        synchronized(mWindowMap) {
7800            final DisplayContent displayContent = getDefaultDisplayContentLocked();
7801            readForcedDisplayPropertiesLocked(displayContent);
7802            mDisplayReady = true;
7803        }
7804
7805        try {
7806            mActivityManager.updateConfiguration(null);
7807        } catch (RemoteException e) {
7808        }
7809
7810        synchronized(mWindowMap) {
7811            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
7812                    PackageManager.FEATURE_TOUCHSCREEN);
7813            configureDisplayPolicyLocked(getDefaultDisplayContentLocked());
7814        }
7815
7816        try {
7817            mActivityManager.updateConfiguration(null);
7818        } catch (RemoteException e) {
7819        }
7820
7821        updateCircularDisplayMaskIfNeeded();
7822    }
7823
7824    private void displayReady(int displayId) {
7825        synchronized(mWindowMap) {
7826            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7827            if (displayContent != null) {
7828                mAnimator.addDisplayLocked(displayId);
7829                displayContent.initializeDisplayBaseInfo();
7830                if (displayContent.mTapDetector != null) {
7831                    displayContent.mTapDetector.init();
7832                }
7833            }
7834        }
7835    }
7836
7837    public void systemReady() {
7838        mPolicy.systemReady();
7839    }
7840
7841    // -------------------------------------------------------------
7842    // Async Handler
7843    // -------------------------------------------------------------
7844
7845    final class H extends Handler {
7846        public static final int REPORT_FOCUS_CHANGE = 2;
7847        public static final int REPORT_LOSING_FOCUS = 3;
7848        public static final int DO_TRAVERSAL = 4;
7849        public static final int ADD_STARTING = 5;
7850        public static final int REMOVE_STARTING = 6;
7851        public static final int FINISHED_STARTING = 7;
7852        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
7853        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
7854        public static final int WINDOW_FREEZE_TIMEOUT = 11;
7855
7856        public static final int APP_TRANSITION_TIMEOUT = 13;
7857        public static final int PERSIST_ANIMATION_SCALE = 14;
7858        public static final int FORCE_GC = 15;
7859        public static final int ENABLE_SCREEN = 16;
7860        public static final int APP_FREEZE_TIMEOUT = 17;
7861        public static final int SEND_NEW_CONFIGURATION = 18;
7862        public static final int REPORT_WINDOWS_CHANGE = 19;
7863        public static final int DRAG_START_TIMEOUT = 20;
7864        public static final int DRAG_END_TIMEOUT = 21;
7865        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
7866        public static final int BOOT_TIMEOUT = 23;
7867        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
7868        public static final int SHOW_STRICT_MODE_VIOLATION = 25;
7869        public static final int DO_ANIMATION_CALLBACK = 26;
7870
7871        public static final int DO_DISPLAY_ADDED = 27;
7872        public static final int DO_DISPLAY_REMOVED = 28;
7873        public static final int DO_DISPLAY_CHANGED = 29;
7874
7875        public static final int CLIENT_FREEZE_TIMEOUT = 30;
7876        public static final int TAP_OUTSIDE_TASK = 31;
7877        public static final int NOTIFY_ACTIVITY_DRAWN = 32;
7878
7879        public static final int ALL_WINDOWS_DRAWN = 33;
7880
7881        public static final int NEW_ANIMATOR_SCALE = 34;
7882
7883        public static final int SHOW_CIRCULAR_DISPLAY_MASK = 35;
7884        public static final int SHOW_EMULATOR_DISPLAY_OVERLAY = 36;
7885
7886        public static final int CHECK_IF_BOOT_ANIMATION_FINISHED = 37;
7887        public static final int RESET_ANR_MESSAGE = 38;
7888        public static final int WALLPAPER_DRAW_PENDING_TIMEOUT = 39;
7889
7890        public static final int FINISH_TASK_POSITIONING = 40;
7891
7892        public static final int UPDATE_DOCKED_STACK_DIVIDER = 41;
7893
7894        public static final int RESIZE_STACK = 42;
7895        public static final int RESIZE_TASK = 43;
7896
7897        public static final int TWO_FINGER_SCROLL_START = 44;
7898
7899        public static final int WINDOW_REPLACEMENT_TIMEOUT = 46;
7900
7901        public static final int NOTIFY_APP_TRANSITION_STARTING = 47;
7902        public static final int NOTIFY_APP_TRANSITION_CANCELLED = 48;
7903        public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
7904        public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
7905        public static final int UPDATE_ANIMATION_SCALE = 51;
7906        public static final int WINDOW_REMOVE_TIMEOUT = 52;
7907
7908        public static final int NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED = 53;
7909
7910        /**
7911         * Used to denote that an integer field in a message will not be used.
7912         */
7913        public static final int UNUSED = 0;
7914
7915        @Override
7916        public void handleMessage(Message msg) {
7917            if (DEBUG_WINDOW_TRACE) {
7918                Slog.v(TAG_WM, "handleMessage: entry what=" + msg.what);
7919            }
7920            switch (msg.what) {
7921                case REPORT_FOCUS_CHANGE: {
7922                    WindowState lastFocus;
7923                    WindowState newFocus;
7924
7925                    AccessibilityController accessibilityController = null;
7926
7927                    synchronized(mWindowMap) {
7928                        // TODO(multidisplay): Accessibility supported only of default desiplay.
7929                        if (mAccessibilityController != null && getDefaultDisplayContentLocked()
7930                                .getDisplayId() == Display.DEFAULT_DISPLAY) {
7931                            accessibilityController = mAccessibilityController;
7932                        }
7933
7934                        lastFocus = mLastFocus;
7935                        newFocus = mCurrentFocus;
7936                        if (lastFocus == newFocus) {
7937                            // Focus is not changing, so nothing to do.
7938                            return;
7939                        }
7940                        mLastFocus = newFocus;
7941                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Focus moving from " + lastFocus +
7942                                " to " + newFocus);
7943                        if (newFocus != null && lastFocus != null
7944                                && !newFocus.isDisplayedLw()) {
7945                            //Slog.i(TAG_WM, "Delaying loss of focus...");
7946                            mLosingFocus.add(lastFocus);
7947                            lastFocus = null;
7948                        }
7949                    }
7950
7951                    // First notify the accessibility manager for the change so it has
7952                    // the windows before the newly focused one starts firing eventgs.
7953                    if (accessibilityController != null) {
7954                        accessibilityController.onWindowFocusChangedNotLocked();
7955                    }
7956
7957                    //System.out.println("Changing focus from " + lastFocus
7958                    //                   + " to " + newFocus);
7959                    if (newFocus != null) {
7960                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Gaining focus: " + newFocus);
7961                        newFocus.reportFocusChangedSerialized(true, mInTouchMode);
7962                        notifyFocusChanged();
7963                    }
7964
7965                    if (lastFocus != null) {
7966                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Losing focus: " + lastFocus);
7967                        lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
7968                    }
7969                } break;
7970
7971                case REPORT_LOSING_FOCUS: {
7972                    ArrayList<WindowState> losers;
7973
7974                    synchronized(mWindowMap) {
7975                        losers = mLosingFocus;
7976                        mLosingFocus = new ArrayList<WindowState>();
7977                    }
7978
7979                    final int N = losers.size();
7980                    for (int i=0; i<N; i++) {
7981                        if (DEBUG_FOCUS_LIGHT) Slog.i(TAG_WM, "Losing delayed focus: " +
7982                                losers.get(i));
7983                        losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
7984                    }
7985                } break;
7986
7987                case DO_TRAVERSAL: {
7988                    synchronized(mWindowMap) {
7989                        mWindowPlacerLocked.performSurfacePlacement();
7990                    }
7991                } break;
7992
7993                case ADD_STARTING: {
7994                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7995                    final StartingData sd = wtoken.startingData;
7996
7997                    if (sd == null) {
7998                        // Animation has been canceled... do nothing.
7999                        return;
8000                    }
8001
8002                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Add starting "
8003                            + wtoken + ": pkg=" + sd.pkg);
8004
8005                    View view = null;
8006                    try {
8007                        final Configuration overrideConfig = wtoken != null && wtoken.mTask != null
8008                                ? wtoken.mTask.mOverrideConfig : null;
8009                        view = mPolicy.addStartingWindow(wtoken.token, sd.pkg, sd.theme,
8010                            sd.compatInfo, sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.logo,
8011                            sd.windowFlags, overrideConfig);
8012                    } catch (Exception e) {
8013                        Slog.w(TAG_WM, "Exception when adding starting window", e);
8014                    }
8015
8016                    if (view != null) {
8017                        boolean abort = false;
8018
8019                        synchronized(mWindowMap) {
8020                            if (wtoken.removed || wtoken.startingData == null) {
8021                                // If the window was successfully added, then
8022                                // we need to remove it.
8023                                if (wtoken.startingWindow != null) {
8024                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
8025                                            "Aborted starting " + wtoken
8026                                            + ": removed=" + wtoken.removed
8027                                            + " startingData=" + wtoken.startingData);
8028                                    wtoken.startingWindow = null;
8029                                    wtoken.startingData = null;
8030                                    abort = true;
8031                                }
8032                            } else {
8033                                wtoken.startingView = view;
8034                            }
8035                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG_WM,
8036                                    "Added starting " + wtoken
8037                                    + ": startingWindow="
8038                                    + wtoken.startingWindow + " startingView="
8039                                    + wtoken.startingView);
8040                        }
8041
8042                        if (abort) {
8043                            try {
8044                                mPolicy.removeStartingWindow(wtoken.token, view);
8045                            } catch (Exception e) {
8046                                Slog.w(TAG_WM, "Exception when removing starting window", e);
8047                            }
8048                        }
8049                    }
8050                } break;
8051
8052                case REMOVE_STARTING: {
8053                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
8054                    IBinder token = null;
8055                    View view = null;
8056                    synchronized (mWindowMap) {
8057                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Remove starting "
8058                                + wtoken + ": startingWindow="
8059                                + wtoken.startingWindow + " startingView="
8060                                + wtoken.startingView);
8061                        if (wtoken.startingWindow != null) {
8062                            view = wtoken.startingView;
8063                            token = wtoken.token;
8064                            wtoken.startingData = null;
8065                            wtoken.startingView = null;
8066                            wtoken.startingWindow = null;
8067                            wtoken.startingDisplayed = false;
8068                        }
8069                    }
8070                    if (view != null) {
8071                        try {
8072                            mPolicy.removeStartingWindow(token, view);
8073                        } catch (Exception e) {
8074                            Slog.w(TAG_WM, "Exception when removing starting window", e);
8075                        }
8076                    }
8077                } break;
8078
8079                case FINISHED_STARTING: {
8080                    IBinder token = null;
8081                    View view = null;
8082                    while (true) {
8083                        synchronized (mWindowMap) {
8084                            final int N = mFinishedStarting.size();
8085                            if (N <= 0) {
8086                                break;
8087                            }
8088                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
8089
8090                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
8091                                    "Finished starting " + wtoken
8092                                    + ": startingWindow=" + wtoken.startingWindow
8093                                    + " startingView=" + wtoken.startingView);
8094
8095                            if (wtoken.startingWindow == null) {
8096                                continue;
8097                            }
8098
8099                            view = wtoken.startingView;
8100                            token = wtoken.token;
8101                            wtoken.startingData = null;
8102                            wtoken.startingView = null;
8103                            wtoken.startingWindow = null;
8104                            wtoken.startingDisplayed = false;
8105                        }
8106
8107                        try {
8108                            mPolicy.removeStartingWindow(token, view);
8109                        } catch (Exception e) {
8110                            Slog.w(TAG_WM, "Exception when removing starting window", e);
8111                        }
8112                    }
8113                } break;
8114
8115                case REPORT_APPLICATION_TOKEN_DRAWN: {
8116                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
8117
8118                    try {
8119                        if (DEBUG_VISIBILITY) Slog.v(
8120                                TAG_WM, "Reporting drawn in " + wtoken);
8121                        wtoken.appToken.windowsDrawn();
8122                    } catch (RemoteException ex) {
8123                    }
8124                } break;
8125
8126                case REPORT_APPLICATION_TOKEN_WINDOWS: {
8127                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
8128
8129                    boolean nowVisible = msg.arg1 != 0;
8130                    boolean nowGone = msg.arg2 != 0;
8131
8132                    try {
8133                        if (DEBUG_VISIBILITY) Slog.v(
8134                                TAG_WM, "Reporting visible in " + wtoken
8135                                + " visible=" + nowVisible
8136                                + " gone=" + nowGone);
8137                        if (nowVisible) {
8138                            wtoken.appToken.windowsVisible();
8139                        } else {
8140                            wtoken.appToken.windowsGone();
8141                        }
8142                    } catch (RemoteException ex) {
8143                    }
8144                } break;
8145
8146                case WINDOW_FREEZE_TIMEOUT: {
8147                    // TODO(multidisplay): Can non-default displays rotate?
8148                    synchronized (mWindowMap) {
8149                        Slog.w(TAG_WM, "Window freeze timeout expired.");
8150                        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
8151                        final WindowList windows = getDefaultWindowListLocked();
8152                        int i = windows.size();
8153                        while (i > 0) {
8154                            i--;
8155                            WindowState w = windows.get(i);
8156                            if (w.mOrientationChanging) {
8157                                w.mOrientationChanging = false;
8158                                w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
8159                                        - mDisplayFreezeTime);
8160                                Slog.w(TAG_WM, "Force clearing orientation change: " + w);
8161                            }
8162                        }
8163                        mWindowPlacerLocked.performSurfacePlacement();
8164                    }
8165                    break;
8166                }
8167
8168                case APP_TRANSITION_TIMEOUT: {
8169                    synchronized (mWindowMap) {
8170                        if (mAppTransition.isTransitionSet() || !mOpeningApps.isEmpty()
8171                                    || !mClosingApps.isEmpty()) {
8172                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "*** APP TRANSITION TIMEOUT."
8173                                    + " isTransitionSet()=" + mAppTransition.isTransitionSet()
8174                                    + " mOpeningApps.size()=" + mOpeningApps.size()
8175                                    + " mClosingApps.size()=" + mClosingApps.size());
8176                            mAppTransition.setTimeout();
8177                            mWindowPlacerLocked.performSurfacePlacement();
8178                        }
8179                    }
8180                    break;
8181                }
8182
8183                case PERSIST_ANIMATION_SCALE: {
8184                    Settings.Global.putFloat(mContext.getContentResolver(),
8185                            Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScaleSetting);
8186                    Settings.Global.putFloat(mContext.getContentResolver(),
8187                            Settings.Global.TRANSITION_ANIMATION_SCALE,
8188                            mTransitionAnimationScaleSetting);
8189                    Settings.Global.putFloat(mContext.getContentResolver(),
8190                            Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScaleSetting);
8191                    break;
8192                }
8193
8194                case UPDATE_ANIMATION_SCALE: {
8195                    @UpdateAnimationScaleMode
8196                    final int mode = msg.arg1;
8197                    switch (mode) {
8198                        case WINDOW_ANIMATION_SCALE: {
8199                            mWindowAnimationScaleSetting = Settings.Global.getFloat(
8200                                    mContext.getContentResolver(),
8201                                    Settings.Global.WINDOW_ANIMATION_SCALE,
8202                                    mWindowAnimationScaleSetting);
8203                            break;
8204                        }
8205                        case TRANSITION_ANIMATION_SCALE: {
8206                            mTransitionAnimationScaleSetting = Settings.Global.getFloat(
8207                                    mContext.getContentResolver(),
8208                                    Settings.Global.TRANSITION_ANIMATION_SCALE,
8209                                    mTransitionAnimationScaleSetting);
8210                            break;
8211                        }
8212                        case ANIMATION_DURATION_SCALE: {
8213                            mAnimatorDurationScaleSetting = Settings.Global.getFloat(
8214                                    mContext.getContentResolver(),
8215                                    Settings.Global.ANIMATOR_DURATION_SCALE,
8216                                    mAnimatorDurationScaleSetting);
8217                            dispatchNewAnimatorScaleLocked(null);
8218                            break;
8219                        }
8220                    }
8221                    break;
8222                }
8223
8224                case FORCE_GC: {
8225                    synchronized (mWindowMap) {
8226                        // Since we're holding both mWindowMap and mAnimator we don't need to
8227                        // hold mAnimator.mLayoutToAnim.
8228                        if (mAnimator.isAnimating() || mAnimationScheduled) {
8229                            // If we are animating, don't do the gc now but
8230                            // delay a bit so we don't interrupt the animation.
8231                            sendEmptyMessageDelayed(H.FORCE_GC, 2000);
8232                            return;
8233                        }
8234                        // If we are currently rotating the display, it will
8235                        // schedule a new message when done.
8236                        if (mDisplayFrozen) {
8237                            return;
8238                        }
8239                    }
8240                    Runtime.getRuntime().gc();
8241                    break;
8242                }
8243
8244                case ENABLE_SCREEN: {
8245                    performEnableScreen();
8246                    break;
8247                }
8248
8249                case APP_FREEZE_TIMEOUT: {
8250                    synchronized (mWindowMap) {
8251                        Slog.w(TAG_WM, "App freeze timeout expired.");
8252                        mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
8253                        final int numStacks = mStackIdToStack.size();
8254                        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
8255                            final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
8256                            final ArrayList<Task> tasks = stack.getTasks();
8257                            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
8258                                AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
8259                                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
8260                                    AppWindowToken tok = tokens.get(tokenNdx);
8261                                    if (tok.mAppAnimator.freezingScreen) {
8262                                        Slog.w(TAG_WM, "Force clearing freeze: " + tok);
8263                                        unsetAppFreezingScreenLocked(tok, true, true);
8264                                    }
8265                                }
8266                            }
8267                        }
8268                    }
8269                    break;
8270                }
8271
8272                case CLIENT_FREEZE_TIMEOUT: {
8273                    synchronized (mWindowMap) {
8274                        if (mClientFreezingScreen) {
8275                            mClientFreezingScreen = false;
8276                            mLastFinishedFreezeSource = "client-timeout";
8277                            stopFreezingDisplayLocked();
8278                        }
8279                    }
8280                    break;
8281                }
8282
8283                case SEND_NEW_CONFIGURATION: {
8284                    removeMessages(SEND_NEW_CONFIGURATION);
8285                    sendNewConfiguration();
8286                    break;
8287                }
8288
8289                case REPORT_WINDOWS_CHANGE: {
8290                    if (mWindowsChanged) {
8291                        synchronized (mWindowMap) {
8292                            mWindowsChanged = false;
8293                        }
8294                        notifyWindowsChanged();
8295                    }
8296                    break;
8297                }
8298
8299                case DRAG_START_TIMEOUT: {
8300                    IBinder win = (IBinder)msg.obj;
8301                    if (DEBUG_DRAG) {
8302                        Slog.w(TAG_WM, "Timeout starting drag by win " + win);
8303                    }
8304                    synchronized (mWindowMap) {
8305                        // !!! TODO: ANR the app that has failed to start the drag in time
8306                        if (mDragState != null) {
8307                            mDragState.unregister();
8308                            mInputMonitor.updateInputWindowsLw(true /*force*/);
8309                            mDragState.reset();
8310                            mDragState = null;
8311                        }
8312                    }
8313                    break;
8314                }
8315
8316                case DRAG_END_TIMEOUT: {
8317                    IBinder win = (IBinder)msg.obj;
8318                    if (DEBUG_DRAG) {
8319                        Slog.w(TAG_WM, "Timeout ending drag to win " + win);
8320                    }
8321                    synchronized (mWindowMap) {
8322                        // !!! TODO: ANR the drag-receiving app
8323                        if (mDragState != null) {
8324                            mDragState.mDragResult = false;
8325                            mDragState.endDragLw();
8326                        }
8327                    }
8328                    break;
8329                }
8330
8331                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
8332                    notifyHardKeyboardStatusChange();
8333                    break;
8334                }
8335
8336                case BOOT_TIMEOUT: {
8337                    performBootTimeout();
8338                    break;
8339                }
8340
8341                case WAITING_FOR_DRAWN_TIMEOUT: {
8342                    Runnable callback = null;
8343                    synchronized (mWindowMap) {
8344                        Slog.w(TAG_WM, "Timeout waiting for drawn: undrawn=" + mWaitingForDrawn);
8345                        mWaitingForDrawn.clear();
8346                        callback = mWaitingForDrawnCallback;
8347                        mWaitingForDrawnCallback = null;
8348                    }
8349                    if (callback != null) {
8350                        callback.run();
8351                    }
8352                    break;
8353                }
8354
8355                case SHOW_STRICT_MODE_VIOLATION: {
8356                    showStrictModeViolation(msg.arg1, msg.arg2);
8357                    break;
8358                }
8359
8360                case SHOW_CIRCULAR_DISPLAY_MASK: {
8361                    showCircularMask(msg.arg1 == 1);
8362                    break;
8363                }
8364
8365                case SHOW_EMULATOR_DISPLAY_OVERLAY: {
8366                    showEmulatorDisplayOverlay();
8367                    break;
8368                }
8369
8370                case DO_ANIMATION_CALLBACK: {
8371                    try {
8372                        ((IRemoteCallback)msg.obj).sendResult(null);
8373                    } catch (RemoteException e) {
8374                    }
8375                    break;
8376                }
8377
8378                case DO_DISPLAY_ADDED:
8379                    handleDisplayAdded(msg.arg1);
8380                    break;
8381
8382                case DO_DISPLAY_REMOVED:
8383                    synchronized (mWindowMap) {
8384                        handleDisplayRemovedLocked(msg.arg1);
8385                    }
8386                    break;
8387
8388                case DO_DISPLAY_CHANGED:
8389                    synchronized (mWindowMap) {
8390                        handleDisplayChangedLocked(msg.arg1);
8391                    }
8392                    break;
8393
8394                case TWO_FINGER_SCROLL_START: {
8395                    startScrollingTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
8396                }
8397                break;
8398
8399                case TAP_OUTSIDE_TASK: {
8400                    handleTapOutsideTask((DisplayContent)msg.obj, msg.arg1, msg.arg2);
8401                }
8402                break;
8403
8404                case FINISH_TASK_POSITIONING: {
8405                    finishPositioning();
8406                }
8407                break;
8408
8409                case NOTIFY_ACTIVITY_DRAWN:
8410                    try {
8411                        mActivityManager.notifyActivityDrawn((IBinder) msg.obj);
8412                    } catch (RemoteException e) {
8413                    }
8414                    break;
8415                case ALL_WINDOWS_DRAWN: {
8416                    Runnable callback;
8417                    synchronized (mWindowMap) {
8418                        callback = mWaitingForDrawnCallback;
8419                        mWaitingForDrawnCallback = null;
8420                    }
8421                    if (callback != null) {
8422                        callback.run();
8423                    }
8424                }
8425                case NEW_ANIMATOR_SCALE: {
8426                    float scale = getCurrentAnimatorScale();
8427                    ValueAnimator.setDurationScale(scale);
8428                    Session session = (Session)msg.obj;
8429                    if (session != null) {
8430                        try {
8431                            session.mCallback.onAnimatorScaleChanged(scale);
8432                        } catch (RemoteException e) {
8433                        }
8434                    } else {
8435                        ArrayList<IWindowSessionCallback> callbacks
8436                                = new ArrayList<IWindowSessionCallback>();
8437                        synchronized (mWindowMap) {
8438                            for (int i=0; i<mSessions.size(); i++) {
8439                                callbacks.add(mSessions.valueAt(i).mCallback);
8440                            }
8441
8442                        }
8443                        for (int i=0; i<callbacks.size(); i++) {
8444                            try {
8445                                callbacks.get(i).onAnimatorScaleChanged(scale);
8446                            } catch (RemoteException e) {
8447                            }
8448                        }
8449                    }
8450                }
8451                break;
8452                case CHECK_IF_BOOT_ANIMATION_FINISHED: {
8453                    final boolean bootAnimationComplete;
8454                    synchronized (mWindowMap) {
8455                        if (DEBUG_BOOT) Slog.i(TAG_WM, "CHECK_IF_BOOT_ANIMATION_FINISHED:");
8456                        bootAnimationComplete = checkBootAnimationCompleteLocked();
8457                    }
8458                    if (bootAnimationComplete) {
8459                        performEnableScreen();
8460                    }
8461                }
8462                break;
8463                case RESET_ANR_MESSAGE: {
8464                    synchronized (mWindowMap) {
8465                        mLastANRState = null;
8466                    }
8467                }
8468                break;
8469                case WALLPAPER_DRAW_PENDING_TIMEOUT: {
8470                    synchronized (mWindowMap) {
8471                        if (mWallpaperControllerLocked.processWallpaperDrawPendingTimeout()) {
8472                            mWindowPlacerLocked.performSurfacePlacement();
8473                        }
8474                    }
8475                }
8476                case UPDATE_DOCKED_STACK_DIVIDER: {
8477                    synchronized (mWindowMap) {
8478                        final DisplayContent displayContent = getDefaultDisplayContentLocked();
8479                        displayContent.getDockedDividerController().reevaluateVisibility(false);
8480                        adjustForImeIfNeeded(displayContent);
8481                    }
8482                }
8483                break;
8484                case RESIZE_TASK: {
8485                    try {
8486                        mActivityManager.resizeTask(msg.arg1, (Rect) msg.obj, msg.arg2);
8487                    } catch (RemoteException e) {
8488                        // This will not happen since we are in the same process.
8489                    }
8490                }
8491                break;
8492                case RESIZE_STACK: {
8493                    try {
8494                        mActivityManager.resizeStack(
8495                                msg.arg1, (Rect) msg.obj, msg.arg2 == 1, false, false, -1);
8496                    } catch (RemoteException e) {
8497                        // This will not happen since we are in the same process.
8498                    }
8499                }
8500                break;
8501                case WINDOW_REPLACEMENT_TIMEOUT: {
8502                    final AppWindowToken token = (AppWindowToken) msg.obj;
8503                    synchronized (mWindowMap) {
8504                        token.clearTimedoutReplacesLocked();
8505                    }
8506                }
8507                case NOTIFY_APP_TRANSITION_STARTING: {
8508                    mAmInternal.notifyAppTransitionStarting(msg.arg1);
8509                }
8510                break;
8511                case NOTIFY_APP_TRANSITION_CANCELLED: {
8512                    mAmInternal.notifyAppTransitionCancelled();
8513                }
8514                break;
8515                case NOTIFY_APP_TRANSITION_FINISHED: {
8516                    mAmInternal.notifyAppTransitionFinished();
8517                }
8518                break;
8519                case NOTIFY_STARTING_WINDOW_DRAWN: {
8520                    mAmInternal.notifyStartingWindowDrawn();
8521                }
8522                break;
8523                case WINDOW_REMOVE_TIMEOUT: {
8524                    final WindowState window = (WindowState) msg.obj;
8525                    synchronized(mWindowMap) {
8526                        // It's counterintuitive that we check that "mWindowRemovalAllowed"
8527                        // is false. But in fact if it's true, it means a remove has already
8528                        // been requested and we better just not do anything.
8529                        if (!window.mRemoved && !window.mWindowRemovalAllowed) {
8530                            removeWindowLocked(window);
8531                        }
8532                    }
8533                }
8534                break;
8535                case NOTIFY_DOCKED_STACK_MINIMIZED_CHANGED: {
8536                    mAmInternal.notifyDockedStackMinimizedChanged(msg.arg1 == 1);
8537                }
8538                break;
8539            }
8540            if (DEBUG_WINDOW_TRACE) {
8541                Slog.v(TAG_WM, "handleMessage: exit");
8542            }
8543        }
8544    }
8545
8546    void destroyPreservedSurfaceLocked() {
8547        for (int i = mDestroyPreservedSurface.size() - 1; i >= 0 ; i--) {
8548            final WindowState w = mDestroyPreservedSurface.get(i);
8549            w.mWinAnimator.destroyPreservedSurfaceLocked();
8550        }
8551        mDestroyPreservedSurface.clear();
8552    }
8553    // -------------------------------------------------------------
8554    // IWindowManager API
8555    // -------------------------------------------------------------
8556
8557    @Override
8558    public IWindowSession openSession(IWindowSessionCallback callback, IInputMethodClient client,
8559            IInputContext inputContext) {
8560        if (client == null) throw new IllegalArgumentException("null client");
8561        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
8562        Session session = new Session(this, callback, client, inputContext);
8563        return session;
8564    }
8565
8566    @Override
8567    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
8568        synchronized (mWindowMap) {
8569            // The focus for the client is the window immediately below
8570            // where we would place the input method window.
8571            int idx = findDesiredInputMethodWindowIndexLocked(false);
8572            if (idx > 0) {
8573                // TODO(multidisplay): IMEs are only supported on the default display.
8574                WindowState imFocus = getDefaultWindowListLocked().get(idx-1);
8575                if (DEBUG_INPUT_METHOD) {
8576                    Slog.i(TAG_WM, "Desired input method target: " + imFocus);
8577                    Slog.i(TAG_WM, "Current focus: " + mCurrentFocus);
8578                    Slog.i(TAG_WM, "Last focus: " + mLastFocus);
8579                }
8580                if (imFocus != null) {
8581                    // This may be a starting window, in which case we still want
8582                    // to count it as okay.
8583                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
8584                            && imFocus.mAppToken != null) {
8585                        // The client has definitely started, so it really should
8586                        // have a window in this app token.  Let's look for it.
8587                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
8588                            WindowState w = imFocus.mAppToken.windows.get(i);
8589                            if (w != imFocus) {
8590                                Log.i(TAG_WM, "Switching to real app window: " + w);
8591                                imFocus = w;
8592                                break;
8593                            }
8594                        }
8595                    }
8596                    if (DEBUG_INPUT_METHOD) {
8597                        Slog.i(TAG_WM, "IM target client: " + imFocus.mSession.mClient);
8598                        if (imFocus.mSession.mClient != null) {
8599                            Slog.i(TAG_WM, "IM target client binder: "
8600                                    + imFocus.mSession.mClient.asBinder());
8601                            Slog.i(TAG_WM, "Requesting client binder: " + client.asBinder());
8602                        }
8603                    }
8604                    if (imFocus.mSession.mClient != null &&
8605                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
8606                        return true;
8607                    }
8608                }
8609            }
8610
8611            // Okay, how about this...  what is the current focus?
8612            // It seems in some cases we may not have moved the IM
8613            // target window, such as when it was in a pop-up window,
8614            // so let's also look at the current focus.  (An example:
8615            // go to Gmail, start searching so the keyboard goes up,
8616            // press home.  Sometimes the IME won't go down.)
8617            // Would be nice to fix this more correctly, but it's
8618            // way at the end of a release, and this should be good enough.
8619            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
8620                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
8621                return true;
8622            }
8623        }
8624        return false;
8625    }
8626
8627    @Override
8628    public void getInitialDisplaySize(int displayId, Point size) {
8629        synchronized (mWindowMap) {
8630            final DisplayContent displayContent = getDisplayContentLocked(displayId);
8631            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
8632                size.x = displayContent.mInitialDisplayWidth;
8633                size.y = displayContent.mInitialDisplayHeight;
8634            }
8635        }
8636    }
8637
8638    @Override
8639    public void getBaseDisplaySize(int displayId, Point size) {
8640        synchronized (mWindowMap) {
8641            final DisplayContent displayContent = getDisplayContentLocked(displayId);
8642            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
8643                size.x = displayContent.mBaseDisplayWidth;
8644                size.y = displayContent.mBaseDisplayHeight;
8645            }
8646        }
8647    }
8648
8649    @Override
8650    public void setForcedDisplaySize(int displayId, int width, int height) {
8651        if (mContext.checkCallingOrSelfPermission(
8652                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
8653                PackageManager.PERMISSION_GRANTED) {
8654            throw new SecurityException("Must hold permission " +
8655                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
8656        }
8657        if (displayId != Display.DEFAULT_DISPLAY) {
8658            throw new IllegalArgumentException("Can only set the default display");
8659        }
8660        final long ident = Binder.clearCallingIdentity();
8661        try {
8662            synchronized(mWindowMap) {
8663                // Set some sort of reasonable bounds on the size of the display that we
8664                // will try to emulate.
8665                final int MIN_WIDTH = 200;
8666                final int MIN_HEIGHT = 200;
8667                final int MAX_SCALE = 2;
8668                final DisplayContent displayContent = getDisplayContentLocked(displayId);
8669                if (displayContent != null) {
8670                    width = Math.min(Math.max(width, MIN_WIDTH),
8671                            displayContent.mInitialDisplayWidth * MAX_SCALE);
8672                    height = Math.min(Math.max(height, MIN_HEIGHT),
8673                            displayContent.mInitialDisplayHeight * MAX_SCALE);
8674                    setForcedDisplaySizeLocked(displayContent, width, height);
8675                    Settings.Global.putString(mContext.getContentResolver(),
8676                            Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
8677                }
8678            }
8679        } finally {
8680            Binder.restoreCallingIdentity(ident);
8681        }
8682    }
8683
8684    @Override
8685    public void setForcedDisplayScalingMode(int displayId, int mode) {
8686        if (mContext.checkCallingOrSelfPermission(
8687                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
8688                PackageManager.PERMISSION_GRANTED) {
8689            throw new SecurityException("Must hold permission " +
8690                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
8691        }
8692        if (displayId != Display.DEFAULT_DISPLAY) {
8693            throw new IllegalArgumentException("Can only set the default display");
8694        }
8695        final long ident = Binder.clearCallingIdentity();
8696        try {
8697            synchronized(mWindowMap) {
8698                final DisplayContent displayContent = getDisplayContentLocked(displayId);
8699                if (displayContent != null) {
8700                    if (mode < 0 || mode > 1) {
8701                        mode = 0;
8702                    }
8703                    setForcedDisplayScalingModeLocked(displayContent, mode);
8704                    Settings.Global.putInt(mContext.getContentResolver(),
8705                            Settings.Global.DISPLAY_SCALING_FORCE, mode);
8706                }
8707            }
8708        } finally {
8709            Binder.restoreCallingIdentity(ident);
8710        }
8711    }
8712
8713    private void setForcedDisplayScalingModeLocked(DisplayContent displayContent, int mode) {
8714        Slog.i(TAG_WM, "Using display scaling mode: " + (mode == 0 ? "auto" : "off"));
8715        displayContent.mDisplayScalingDisabled = (mode != 0);
8716        reconfigureDisplayLocked(displayContent);
8717    }
8718
8719    private void readForcedDisplayPropertiesLocked(final DisplayContent displayContent) {
8720        // Display size.
8721        String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
8722                Settings.Global.DISPLAY_SIZE_FORCED);
8723        if (sizeStr == null || sizeStr.length() == 0) {
8724            sizeStr = SystemProperties.get(SIZE_OVERRIDE, null);
8725        }
8726        if (sizeStr != null && sizeStr.length() > 0) {
8727            final int pos = sizeStr.indexOf(',');
8728            if (pos > 0 && sizeStr.lastIndexOf(',') == pos) {
8729                int width, height;
8730                try {
8731                    width = Integer.parseInt(sizeStr.substring(0, pos));
8732                    height = Integer.parseInt(sizeStr.substring(pos+1));
8733                    if (displayContent.mBaseDisplayWidth != width
8734                            || displayContent.mBaseDisplayHeight != height) {
8735                        Slog.i(TAG_WM, "FORCED DISPLAY SIZE: " + width + "x" + height);
8736                        displayContent.mBaseDisplayWidth = width;
8737                        displayContent.mBaseDisplayHeight = height;
8738                    }
8739                } catch (NumberFormatException ex) {
8740                }
8741            }
8742        }
8743
8744        // Display density.
8745        final int density = getForcedDisplayDensityForUserLocked(mCurrentUserId);
8746        if (density != 0) {
8747            displayContent.mBaseDisplayDensity = density;
8748        }
8749
8750        // Display scaling mode.
8751        int mode = Settings.Global.getInt(mContext.getContentResolver(),
8752                Settings.Global.DISPLAY_SCALING_FORCE, 0);
8753        if (mode != 0) {
8754            Slog.i(TAG_WM, "FORCED DISPLAY SCALING DISABLED");
8755            displayContent.mDisplayScalingDisabled = true;
8756        }
8757    }
8758
8759    // displayContent must not be null
8760    private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
8761        Slog.i(TAG_WM, "Using new display size: " + width + "x" + height);
8762        displayContent.mBaseDisplayWidth = width;
8763        displayContent.mBaseDisplayHeight = height;
8764        reconfigureDisplayLocked(displayContent);
8765    }
8766
8767    @Override
8768    public void clearForcedDisplaySize(int displayId) {
8769        if (mContext.checkCallingOrSelfPermission(
8770                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
8771                PackageManager.PERMISSION_GRANTED) {
8772            throw new SecurityException("Must hold permission " +
8773                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
8774        }
8775        if (displayId != Display.DEFAULT_DISPLAY) {
8776            throw new IllegalArgumentException("Can only set the default display");
8777        }
8778        final long ident = Binder.clearCallingIdentity();
8779        try {
8780            synchronized(mWindowMap) {
8781                final DisplayContent displayContent = getDisplayContentLocked(displayId);
8782                if (displayContent != null) {
8783                    setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
8784                            displayContent.mInitialDisplayHeight);
8785                    Settings.Global.putString(mContext.getContentResolver(),
8786                            Settings.Global.DISPLAY_SIZE_FORCED, "");
8787                }
8788            }
8789        } finally {
8790            Binder.restoreCallingIdentity(ident);
8791        }
8792    }
8793
8794    @Override
8795    public int getInitialDisplayDensity(int displayId) {
8796        synchronized (mWindowMap) {
8797            final DisplayContent displayContent = getDisplayContentLocked(displayId);
8798            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
8799                return displayContent.mInitialDisplayDensity;
8800            }
8801        }
8802        return -1;
8803    }
8804
8805    @Override
8806    public int getBaseDisplayDensity(int displayId) {
8807        synchronized (mWindowMap) {
8808            final DisplayContent displayContent = getDisplayContentLocked(displayId);
8809            if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
8810                return displayContent.mBaseDisplayDensity;
8811            }
8812        }
8813        return -1;
8814    }
8815
8816    @Override
8817    public void setForcedDisplayDensity(int displayId, int density) {
8818        if (mContext.checkCallingOrSelfPermission(
8819                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
8820                PackageManager.PERMISSION_GRANTED) {
8821            throw new SecurityException("Must hold permission " +
8822                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
8823        }
8824        if (displayId != Display.DEFAULT_DISPLAY) {
8825            throw new IllegalArgumentException("Can only set the default display");
8826        }
8827        final long ident = Binder.clearCallingIdentity();
8828        try {
8829            synchronized(mWindowMap) {
8830                final DisplayContent displayContent = getDisplayContentLocked(displayId);
8831                if (displayContent != null) {
8832                    setForcedDisplayDensityLocked(displayContent, density);
8833                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
8834                            Settings.Secure.DISPLAY_DENSITY_FORCED,
8835                            Integer.toString(density), mCurrentUserId);
8836                }
8837            }
8838        } finally {
8839            Binder.restoreCallingIdentity(ident);
8840        }
8841    }
8842
8843    @Override
8844    public void clearForcedDisplayDensity(int displayId) {
8845        if (mContext.checkCallingOrSelfPermission(
8846                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
8847                PackageManager.PERMISSION_GRANTED) {
8848            throw new SecurityException("Must hold permission " +
8849                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
8850        }
8851        if (displayId != Display.DEFAULT_DISPLAY) {
8852            throw new IllegalArgumentException("Can only set the default display");
8853        }
8854        final long ident = Binder.clearCallingIdentity();
8855        try {
8856            synchronized(mWindowMap) {
8857                final DisplayContent displayContent = getDisplayContentLocked(displayId);
8858                if (displayContent != null) {
8859                    setForcedDisplayDensityLocked(displayContent,
8860                            displayContent.mInitialDisplayDensity);
8861                    Settings.Secure.putStringForUser(mContext.getContentResolver(),
8862                            Settings.Secure.DISPLAY_DENSITY_FORCED, "", mCurrentUserId);
8863                }
8864            }
8865        } finally {
8866            Binder.restoreCallingIdentity(ident);
8867        }
8868    }
8869
8870    /**
8871     * @param userId the ID of the user
8872     * @return the forced display density for the specified user, if set, or
8873     *         {@code 0} if not set
8874     */
8875    private int getForcedDisplayDensityForUserLocked(int userId) {
8876        String densityStr = Settings.Secure.getStringForUser(mContext.getContentResolver(),
8877                Settings.Secure.DISPLAY_DENSITY_FORCED, userId);
8878        if (densityStr == null || densityStr.length() == 0) {
8879            densityStr = SystemProperties.get(DENSITY_OVERRIDE, null);
8880        }
8881        if (densityStr != null && densityStr.length() > 0) {
8882            try {
8883                return Integer.parseInt(densityStr);
8884            } catch (NumberFormatException ex) {
8885            }
8886        }
8887        return 0;
8888    }
8889
8890    /**
8891     * Forces the given display to the use the specified density.
8892     *
8893     * @param displayContent the display to modify
8894     * @param density the density in DPI to use
8895     */
8896    private void setForcedDisplayDensityLocked(@NonNull DisplayContent displayContent,
8897            int density) {
8898        displayContent.mBaseDisplayDensity = density;
8899        reconfigureDisplayLocked(displayContent);
8900    }
8901
8902    // displayContent must not be null
8903    private void reconfigureDisplayLocked(DisplayContent displayContent) {
8904        // TODO: Multidisplay: for now only use with default display.
8905        if (!mDisplayReady) {
8906            return;
8907        }
8908        configureDisplayPolicyLocked(displayContent);
8909        displayContent.layoutNeeded = true;
8910
8911        boolean configChanged = updateOrientationFromAppTokensLocked(false);
8912        mTempConfiguration.setToDefaults();
8913        mTempConfiguration.updateFrom(mCurConfiguration);
8914        computeScreenConfigurationLocked(mTempConfiguration);
8915        configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0;
8916
8917        if (configChanged) {
8918            mWaitingForConfig = true;
8919            startFreezingDisplayLocked(false, 0, 0);
8920            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8921            if (!mReconfigureOnConfigurationChanged.contains(displayContent)) {
8922                mReconfigureOnConfigurationChanged.add(displayContent);
8923            }
8924        }
8925
8926        mWindowPlacerLocked.performSurfacePlacement();
8927    }
8928
8929    private void configureDisplayPolicyLocked(DisplayContent displayContent) {
8930        mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
8931                displayContent.mBaseDisplayWidth,
8932                displayContent.mBaseDisplayHeight,
8933                displayContent.mBaseDisplayDensity);
8934
8935        DisplayInfo displayInfo = displayContent.getDisplayInfo();
8936        mPolicy.setDisplayOverscan(displayContent.getDisplay(),
8937                displayInfo.overscanLeft, displayInfo.overscanTop,
8938                displayInfo.overscanRight, displayInfo.overscanBottom);
8939    }
8940
8941    @Override
8942    public void setOverscan(int displayId, int left, int top, int right, int bottom) {
8943        if (mContext.checkCallingOrSelfPermission(
8944                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
8945                PackageManager.PERMISSION_GRANTED) {
8946            throw new SecurityException("Must hold permission " +
8947                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
8948        }
8949        final long ident = Binder.clearCallingIdentity();
8950        try {
8951            synchronized(mWindowMap) {
8952                DisplayContent displayContent = getDisplayContentLocked(displayId);
8953                if (displayContent != null) {
8954                    setOverscanLocked(displayContent, left, top, right, bottom);
8955                }
8956            }
8957        } finally {
8958            Binder.restoreCallingIdentity(ident);
8959        }
8960    }
8961
8962    private void setOverscanLocked(DisplayContent displayContent,
8963            int left, int top, int right, int bottom) {
8964        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
8965        displayInfo.overscanLeft = left;
8966        displayInfo.overscanTop = top;
8967        displayInfo.overscanRight = right;
8968        displayInfo.overscanBottom = bottom;
8969
8970        mDisplaySettings.setOverscanLocked(displayInfo.uniqueId, displayInfo.name, left, top,
8971                right, bottom);
8972        mDisplaySettings.writeSettingsLocked();
8973
8974        reconfigureDisplayLocked(displayContent);
8975    }
8976
8977    // -------------------------------------------------------------
8978    // Internals
8979    // -------------------------------------------------------------
8980
8981    final WindowState windowForClientLocked(Session session, IWindow client,
8982            boolean throwOnError) {
8983        return windowForClientLocked(session, client.asBinder(), throwOnError);
8984    }
8985
8986    final WindowState windowForClientLocked(Session session, IBinder client,
8987            boolean throwOnError) {
8988        WindowState win = mWindowMap.get(client);
8989        if (localLOGV) Slog.v(
8990            TAG_WM, "Looking up client " + client + ": " + win);
8991        if (win == null) {
8992            RuntimeException ex = new IllegalArgumentException(
8993                    "Requested window " + client + " does not exist");
8994            if (throwOnError) {
8995                throw ex;
8996            }
8997            Slog.w(TAG_WM, "Failed looking up window", ex);
8998            return null;
8999        }
9000        if (session != null && win.mSession != session) {
9001            RuntimeException ex = new IllegalArgumentException(
9002                    "Requested window " + client + " is in session " +
9003                    win.mSession + ", not " + session);
9004            if (throwOnError) {
9005                throw ex;
9006            }
9007            Slog.w(TAG_WM, "Failed looking up window", ex);
9008            return null;
9009        }
9010
9011        return win;
9012    }
9013
9014    final void rebuildAppWindowListLocked() {
9015        rebuildAppWindowListLocked(getDefaultDisplayContentLocked());
9016    }
9017
9018    private void rebuildAppWindowListLocked(final DisplayContent displayContent) {
9019        final WindowList windows = displayContent.getWindowList();
9020        int NW = windows.size();
9021        int i;
9022        int lastBelow = -1;
9023        int numRemoved = 0;
9024
9025        if (mRebuildTmp.length < NW) {
9026            mRebuildTmp = new WindowState[NW+10];
9027        }
9028
9029        // First remove all existing app windows.
9030        i=0;
9031        while (i < NW) {
9032            WindowState w = windows.get(i);
9033            if (w.mAppToken != null) {
9034                WindowState win = windows.remove(i);
9035                win.mRebuilding = true;
9036                mRebuildTmp[numRemoved] = win;
9037                mWindowsChanged = true;
9038                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Rebuild removing window: " + win);
9039                NW--;
9040                numRemoved++;
9041                continue;
9042            } else if (lastBelow == i-1) {
9043                if (w.mAttrs.type == TYPE_WALLPAPER) {
9044                    lastBelow = i;
9045                }
9046            }
9047            i++;
9048        }
9049
9050        // Keep whatever windows were below the app windows still below,
9051        // by skipping them.
9052        lastBelow++;
9053        i = lastBelow;
9054
9055        // First add all of the exiting app tokens...  these are no longer
9056        // in the main app list, but still have windows shown.  We put them
9057        // in the back because now that the animation is over we no longer
9058        // will care about them.
9059        final ArrayList<TaskStack> stacks = displayContent.getStacks();
9060        final int numStacks = stacks.size();
9061        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
9062            AppTokenList exitingAppTokens = stacks.get(stackNdx).mExitingAppTokens;
9063            int NT = exitingAppTokens.size();
9064            for (int j = 0; j < NT; j++) {
9065                i = reAddAppWindowsLocked(displayContent, i, exitingAppTokens.get(j));
9066            }
9067        }
9068
9069        // And add in the still active app tokens in Z order.
9070        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
9071            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
9072            final int numTasks = tasks.size();
9073            for (int taskNdx = 0; taskNdx < numTasks; ++taskNdx) {
9074                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
9075                final int numTokens = tokens.size();
9076                for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
9077                    final AppWindowToken wtoken = tokens.get(tokenNdx);
9078                    if (wtoken.mIsExiting && !wtoken.waitingForReplacement()) {
9079                        continue;
9080                    }
9081                    i = reAddAppWindowsLocked(displayContent, i, wtoken);
9082                }
9083            }
9084        }
9085
9086        i -= lastBelow;
9087        if (i != numRemoved) {
9088            displayContent.layoutNeeded = true;
9089            Slog.w(TAG_WM, "On display=" + displayContent.getDisplayId() + " Rebuild removed "
9090                    + numRemoved + " windows but added " + i + " rebuildAppWindowListLocked() "
9091                    + " callers=" + Debug.getCallers(10));
9092            for (i = 0; i < numRemoved; i++) {
9093                WindowState ws = mRebuildTmp[i];
9094                if (ws.mRebuilding) {
9095                    StringWriter sw = new StringWriter();
9096                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
9097                    ws.dump(pw, "", true);
9098                    pw.flush();
9099                    Slog.w(TAG_WM, "This window was lost: " + ws);
9100                    Slog.w(TAG_WM, sw.toString());
9101                    ws.mWinAnimator.destroySurfaceLocked();
9102                }
9103            }
9104            Slog.w(TAG_WM, "Current app token list:");
9105            dumpAppTokensLocked();
9106            Slog.w(TAG_WM, "Final window list:");
9107            dumpWindowsLocked();
9108        }
9109        Arrays.fill(mRebuildTmp, null);
9110    }
9111
9112    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
9113        // If the screen is currently frozen or off, then keep
9114        // it frozen/off until this window draws at its new
9115        // orientation.
9116        if (!okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
9117            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Changing surface while display frozen: " + w);
9118            w.mOrientationChanging = true;
9119            w.mLastFreezeDuration = 0;
9120            mWindowPlacerLocked.mOrientationChangeComplete = false;
9121            if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
9122                mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
9123                // XXX should probably keep timeout from
9124                // when we first froze the display.
9125                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
9126                mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT,
9127                        WINDOW_FREEZE_TIMEOUT_DURATION);
9128            }
9129        }
9130    }
9131
9132    /**
9133     * @return bitmap indicating if another pass through layout must be made.
9134     */
9135    int handleAnimatingStoppedAndTransitionLocked() {
9136        int changes = 0;
9137
9138        mAppTransition.setIdle();
9139
9140        for (int i = mNoAnimationNotifyOnTransitionFinished.size() - 1; i >= 0; i--) {
9141            final IBinder token = mNoAnimationNotifyOnTransitionFinished.get(i);
9142            mAppTransition.notifyAppTransitionFinishedLocked(token);
9143        }
9144        mNoAnimationNotifyOnTransitionFinished.clear();
9145
9146        mWallpaperControllerLocked.hideDeferredWallpapersIfNeeded();
9147
9148        // Restore window app tokens to the ActivityManager views
9149        ArrayList<TaskStack> stacks = getDefaultDisplayContentLocked().getStacks();
9150        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
9151            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
9152            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
9153                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
9154                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
9155                    tokens.get(tokenNdx).sendingToBottom = false;
9156                }
9157            }
9158        }
9159        rebuildAppWindowListLocked();
9160
9161        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
9162        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG_WM,
9163                "Wallpaper layer changed: assigning layers + relayout");
9164        moveInputMethodWindowsIfNeededLocked(true);
9165        mWindowPlacerLocked.mWallpaperMayChange = true;
9166        // Since the window list has been rebuilt, focus might
9167        // have to be recomputed since the actual order of windows
9168        // might have changed again.
9169        mFocusMayChange = true;
9170
9171        return changes;
9172    }
9173
9174    void updateResizingWindows(final WindowState w) {
9175        final WindowStateAnimator winAnimator = w.mWinAnimator;
9176        if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq && !w.isGoneForLayoutLw()) {
9177            w.setInsetsChanged();
9178            boolean configChanged = w.isConfigChanged();
9179            if (DEBUG_CONFIGURATION && configChanged) {
9180                Slog.v(TAG_WM, "Win " + w + " config changed: "
9181                        + mCurConfiguration);
9182            }
9183            final boolean dragResizingChanged = w.isDragResizeChanged()
9184                    && !w.isDragResizingChangeReported();
9185            if (localLOGV) Slog.v(TAG_WM, "Resizing " + w
9186                    + ": configChanged=" + configChanged
9187                    + " dragResizingChanged=" + dragResizingChanged
9188                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
9189            w.mLastFrame.set(w.mFrame);
9190            if (w.mContentInsetsChanged
9191                    || w.mVisibleInsetsChanged
9192                    || winAnimator.mSurfaceResized
9193                    || w.mOutsetsChanged
9194                    || configChanged
9195                    || dragResizingChanged
9196                    || w.mResizedWhileNotDragResizing) {
9197                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
9198                    Slog.v(TAG_WM, "Resize reasons for w=" + w + ": "
9199                            + " contentInsetsChanged=" + w.mContentInsetsChanged
9200                            + " " + w.mContentInsets.toShortString()
9201                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
9202                            + " " + w.mVisibleInsets.toShortString()
9203                            + " stableInsetsChanged=" + w.mStableInsetsChanged
9204                            + " " + w.mStableInsets.toShortString()
9205                            + " outsetsChanged=" + w.mOutsetsChanged
9206                            + " " + w.mOutsets.toShortString()
9207                            + " surfaceResized=" + winAnimator.mSurfaceResized
9208                            + " configChanged=" + configChanged
9209                            + " dragResizingChanged=" + dragResizingChanged
9210                            + " resizedWhileNotDragResizing=" + w.mResizedWhileNotDragResizing);
9211                }
9212
9213                // If it's a dead window left on screen, and the configuration changed,
9214                // there is nothing we can do about it. Remove the window now.
9215                if (w.mAppToken != null && w.mAppDied) {
9216                    w.mAppToken.removeAllDeadWindows();
9217                    return;
9218                }
9219
9220                w.mLastOverscanInsets.set(w.mOverscanInsets);
9221                w.mLastContentInsets.set(w.mContentInsets);
9222                w.mLastVisibleInsets.set(w.mVisibleInsets);
9223                w.mLastStableInsets.set(w.mStableInsets);
9224                w.mLastOutsets.set(w.mOutsets);
9225                makeWindowFreezingScreenIfNeededLocked(w);
9226                // If the orientation is changing, or we're starting or ending
9227                // a drag resizing action, then we need to hold off on unfreezing
9228                // the display until this window has been redrawn; to do that,
9229                // we need to go through the process of getting informed by the
9230                // application when it has finished drawing.
9231                if (w.mOrientationChanging || dragResizingChanged
9232                        || w.mResizedWhileNotDragResizing) {
9233                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) {
9234                        Slog.v(TAG_WM, "Orientation or resize start waiting for draw"
9235                                + ", mDrawState=DRAW_PENDING in " + w
9236                                + ", surfaceController " + winAnimator.mSurfaceController);
9237                    }
9238                    winAnimator.mDrawState = DRAW_PENDING;
9239                    if (w.mAppToken != null) {
9240                        w.mAppToken.clearAllDrawn();
9241                    }
9242                }
9243                if (!mResizingWindows.contains(w)) {
9244                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG_WM,
9245                            "Resizing window " + w);
9246                    mResizingWindows.add(w);
9247                }
9248            } else if (w.mOrientationChanging) {
9249                if (w.isDrawnLw()) {
9250                    if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
9251                            "Orientation not waiting for draw in "
9252                            + w + ", surfaceController " + winAnimator.mSurfaceController);
9253                    w.mOrientationChanging = false;
9254                    w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
9255                            - mDisplayFreezeTime);
9256                }
9257            }
9258        }
9259    }
9260
9261    void checkDrawnWindowsLocked() {
9262        if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
9263            return;
9264        }
9265        for (int j = mWaitingForDrawn.size() - 1; j >= 0; j--) {
9266            WindowState win = mWaitingForDrawn.get(j);
9267            if (DEBUG_SCREEN_ON) Slog.i(TAG_WM, "Waiting for drawn " + win +
9268                    ": removed=" + win.mRemoved + " visible=" + win.isVisibleLw() +
9269                    " mHasSurface=" + win.mHasSurface +
9270                    " drawState=" + win.mWinAnimator.mDrawState);
9271            if (win.mRemoved || !win.mHasSurface || !win.mPolicyVisibility) {
9272                // Window has been removed or hidden; no draw will now happen, so stop waiting.
9273                if (DEBUG_SCREEN_ON) Slog.w(TAG_WM, "Aborted waiting for drawn: " + win);
9274                mWaitingForDrawn.remove(win);
9275            } else if (win.hasDrawnLw()) {
9276                // Window is now drawn (and shown).
9277                if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "Window drawn win=" + win);
9278                mWaitingForDrawn.remove(win);
9279            }
9280        }
9281        if (mWaitingForDrawn.isEmpty()) {
9282            if (DEBUG_SCREEN_ON) Slog.d(TAG_WM, "All windows drawn!");
9283            mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
9284            mH.sendEmptyMessage(H.ALL_WINDOWS_DRAWN);
9285        }
9286    }
9287
9288    void setHoldScreenLocked(final Session newHoldScreen) {
9289        final boolean hold = newHoldScreen != null;
9290
9291        if (hold && mHoldingScreenOn != newHoldScreen) {
9292            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
9293        }
9294        mHoldingScreenOn = newHoldScreen;
9295
9296        final boolean state = mHoldingScreenWakeLock.isHeld();
9297        if (hold != state) {
9298            if (hold) {
9299                if (DEBUG_KEEP_SCREEN_ON) {
9300                    Slog.d(TAG_KEEP_SCREEN_ON, "Acquiring screen wakelock due to " +
9301                            mWindowPlacerLocked.mHoldScreenWindow);
9302                }
9303                mLastWakeLockHoldingWindow = mWindowPlacerLocked.mHoldScreenWindow;
9304                mLastWakeLockObscuringWindow = null;
9305                mHoldingScreenWakeLock.acquire();
9306                mPolicy.keepScreenOnStartedLw();
9307            } else {
9308                if (DEBUG_KEEP_SCREEN_ON) {
9309                    Slog.d(TAG_KEEP_SCREEN_ON, "Releasing screen wakelock, obscured by " +
9310                            mWindowPlacerLocked.mObsuringWindow);
9311                }
9312                mLastWakeLockHoldingWindow = null;
9313                mLastWakeLockObscuringWindow = mWindowPlacerLocked.mObsuringWindow;
9314                mPolicy.keepScreenOnStoppedLw();
9315                mHoldingScreenWakeLock.release();
9316            }
9317        }
9318    }
9319
9320    void requestTraversal() {
9321        synchronized (mWindowMap) {
9322            mWindowPlacerLocked.requestTraversal();
9323        }
9324    }
9325
9326    /** Note that Locked in this case is on mLayoutToAnim */
9327    void scheduleAnimationLocked() {
9328        if (!mAnimationScheduled) {
9329            mAnimationScheduled = true;
9330            mChoreographer.postFrameCallback(mAnimator.mAnimationFrameCallback);
9331        }
9332    }
9333
9334    boolean needsLayout() {
9335        final int numDisplays = mDisplayContents.size();
9336        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9337            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
9338            if (displayContent.layoutNeeded) {
9339                return true;
9340            }
9341        }
9342        return false;
9343    }
9344
9345    /** If a window that has an animation specifying a colored background and the current wallpaper
9346     * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to
9347     * suddenly disappear. */
9348    int adjustAnimationBackground(WindowStateAnimator winAnimator) {
9349        WindowList windows = winAnimator.mWin.getWindowList();
9350        for (int i = windows.size() - 1; i >= 0; --i) {
9351            WindowState testWin = windows.get(i);
9352            if (testWin.mIsWallpaper && testWin.isVisibleNow()) {
9353                return testWin.mWinAnimator.mAnimLayer;
9354            }
9355        }
9356        return winAnimator.mAnimLayer;
9357    }
9358
9359    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
9360                                           boolean secure) {
9361        final WindowSurfaceController surfaceController = winAnimator.mSurfaceController;
9362        boolean leakedSurface = false;
9363        boolean killedApps = false;
9364
9365        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
9366                winAnimator.mSession.mPid, operation);
9367
9368        final long callingIdentity = Binder.clearCallingIdentity();
9369        try {
9370            // There was some problem...   first, do a sanity check of the window list to make sure
9371            // we haven't left any dangling surfaces around.
9372
9373            Slog.i(TAG_WM, "Out of memory for surface!  Looking for leaks...");
9374            final int numDisplays = mDisplayContents.size();
9375            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9376                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
9377                final int numWindows = windows.size();
9378                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
9379                    final WindowState ws = windows.get(winNdx);
9380                    final WindowStateAnimator wsa = ws.mWinAnimator;
9381                    if (wsa.mSurfaceController == null) {
9382                        continue;
9383                    }
9384                    if (!mSessions.contains(wsa.mSession)) {
9385                        Slog.w(TAG_WM, "LEAKED SURFACE (session doesn't exist): "
9386                                + ws + " surface=" + wsa.mSurfaceController
9387                                + " token=" + ws.mToken
9388                                + " pid=" + ws.mSession.mPid
9389                                + " uid=" + ws.mSession.mUid);
9390                        wsa.destroySurface();
9391                        mForceRemoves.add(ws);
9392                        leakedSurface = true;
9393                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
9394                        Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
9395                                + ws + " surface=" + wsa.mSurfaceController
9396                                + " token=" + ws.mAppToken
9397                                + " saved=" + ws.hasSavedSurface());
9398                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", false);
9399                        wsa.destroySurface();
9400                        leakedSurface = true;
9401                    }
9402                }
9403            }
9404
9405            if (!leakedSurface) {
9406                Slog.w(TAG_WM, "No leaked surfaces; killing applicatons!");
9407                SparseIntArray pidCandidates = new SparseIntArray();
9408                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9409                    final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
9410                    final int numWindows = windows.size();
9411                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
9412                        final WindowState ws = windows.get(winNdx);
9413                        if (mForceRemoves.contains(ws)) {
9414                            continue;
9415                        }
9416                        WindowStateAnimator wsa = ws.mWinAnimator;
9417                        if (wsa.mSurfaceController != null) {
9418                            pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
9419                        }
9420                    }
9421                    if (pidCandidates.size() > 0) {
9422                        int[] pids = new int[pidCandidates.size()];
9423                        for (int i=0; i<pids.length; i++) {
9424                            pids[i] = pidCandidates.keyAt(i);
9425                        }
9426                        try {
9427                            if (mActivityManager.killPids(pids, "Free memory", secure)) {
9428                                killedApps = true;
9429                            }
9430                        } catch (RemoteException e) {
9431                        }
9432                    }
9433                }
9434            }
9435
9436            if (leakedSurface || killedApps) {
9437                // We managed to reclaim some memory, so get rid of the trouble
9438                // surface and ask the app to request another one.
9439                Slog.w(TAG_WM, "Looks like we have reclaimed some memory, clearing surface for retry.");
9440                if (surfaceController != null) {
9441                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
9442                            "RECOVER DESTROY", false);
9443                    winAnimator.destroySurface();
9444                    scheduleRemoveStartingWindowLocked(winAnimator.mWin.mAppToken);
9445                }
9446
9447                try {
9448                    winAnimator.mWin.mClient.dispatchGetNewSurface();
9449                } catch (RemoteException e) {
9450                }
9451            }
9452        } finally {
9453            Binder.restoreCallingIdentity(callingIdentity);
9454        }
9455
9456        return leakedSurface || killedApps;
9457    }
9458
9459    boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9460        WindowState newFocus = computeFocusedWindowLocked();
9461        if (mCurrentFocus != newFocus) {
9462            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
9463            // This check makes sure that we don't already have the focus
9464            // change message pending.
9465            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9466            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9467            // TODO(multidisplay): Focused windows on default display only.
9468            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9469            final boolean imWindowChanged = moveInputMethodWindowsIfNeededLocked(
9470                    mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS
9471                            && mode != UPDATE_FOCUS_WILL_PLACE_SURFACES);
9472            if (imWindowChanged) {
9473                displayContent.layoutNeeded = true;
9474                newFocus = computeFocusedWindowLocked();
9475            }
9476
9477            if (DEBUG_FOCUS_LIGHT || localLOGV) Slog.v(TAG_WM, "Changing focus from " +
9478                    mCurrentFocus + " to " + newFocus + " Callers=" + Debug.getCallers(4));
9479            final WindowState oldFocus = mCurrentFocus;
9480            mCurrentFocus = newFocus;
9481            mLosingFocus.remove(newFocus);
9482
9483            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9484
9485            if (imWindowChanged && oldFocus != mInputMethodWindow) {
9486                // Focus of the input method window changed. Perform layout if needed.
9487                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9488                    mWindowPlacerLocked.performLayoutLockedInner(displayContent, true /*initial*/,
9489                            updateInputWindows);
9490                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9491                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9492                    // Client will do the layout, but we need to assign layers
9493                    // for handleNewWindowLocked() below.
9494                    mLayersController.assignLayersLocked(displayContent.getWindowList());
9495                }
9496            }
9497
9498            if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9499                // The change in focus caused us to need to do a layout.  Okay.
9500                displayContent.layoutNeeded = true;
9501                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9502                    mWindowPlacerLocked.performLayoutLockedInner(displayContent, true /*initial*/,
9503                            updateInputWindows);
9504                }
9505            }
9506
9507            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9508                // If we defer assigning layers, then the caller is responsible for
9509                // doing this part.
9510                mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9511            }
9512
9513            adjustForImeIfNeeded(displayContent);
9514
9515            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
9516            return true;
9517        }
9518        return false;
9519    }
9520
9521    private WindowState computeFocusedWindowLocked() {
9522        final int displayCount = mDisplayContents.size();
9523        for (int i = 0; i < displayCount; i++) {
9524            final DisplayContent displayContent = mDisplayContents.valueAt(i);
9525            WindowState win = findFocusedWindowLocked(displayContent);
9526            if (win != null) {
9527                return win;
9528            }
9529        }
9530        return null;
9531    }
9532
9533    WindowState findFocusedWindowLocked(DisplayContent displayContent) {
9534        final WindowList windows = displayContent.getWindowList();
9535        for (int i = windows.size() - 1; i >= 0; i--) {
9536            final WindowState win = windows.get(i);
9537
9538            if (localLOGV || DEBUG_FOCUS) Slog.v(
9539                TAG_WM, "Looking for focus: " + i
9540                + " = " + win
9541                + ", flags=" + win.mAttrs.flags
9542                + ", canReceive=" + win.canReceiveKeys());
9543
9544            if (!win.canReceiveKeys()) {
9545                continue;
9546            }
9547
9548            AppWindowToken wtoken = win.mAppToken;
9549
9550            // If this window's application has been removed, just skip it.
9551            if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) {
9552                if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because "
9553                        + (wtoken.removed ? "removed" : "sendingToBottom"));
9554                continue;
9555            }
9556
9557            // Descend through all of the app tokens and find the first that either matches
9558            // win.mAppToken (return win) or mFocusedApp (return null).
9559            if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING &&
9560                    mFocusedApp != null) {
9561                ArrayList<Task> tasks = displayContent.getTasks();
9562                for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
9563                    AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
9564                    int tokenNdx = tokens.size() - 1;
9565                    for ( ; tokenNdx >= 0; --tokenNdx) {
9566                        final AppWindowToken token = tokens.get(tokenNdx);
9567                        if (wtoken == token) {
9568                            break;
9569                        }
9570                        if (mFocusedApp == token && token.windowsAreFocusable()) {
9571                            // Whoops, we are below the focused app whose windows are focusable...
9572                            // No focus for you!!!
9573                            if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM,
9574                                    "findFocusedWindow: Reached focused app=" + mFocusedApp);
9575                            return null;
9576                        }
9577                    }
9578                    if (tokenNdx >= 0) {
9579                        // Early exit from loop, must have found the matching token.
9580                        break;
9581                    }
9582                }
9583            }
9584
9585            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ " + i +
9586                        " = " + win);
9587            return win;
9588        }
9589
9590        if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows.");
9591        return null;
9592    }
9593
9594    private void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
9595        if (mDisplayFrozen) {
9596            return;
9597        }
9598
9599        if (!mDisplayReady || !mPolicy.isScreenOn()) {
9600            // No need to freeze the screen before the system is ready or if
9601            // the screen is off.
9602            return;
9603        }
9604
9605        if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
9606                "startFreezingDisplayLocked: inTransaction=" + inTransaction
9607                + " exitAnim=" + exitAnim + " enterAnim=" + enterAnim
9608                + " called by " + Debug.getCallers(8));
9609        mScreenFrozenLock.acquire();
9610
9611        mDisplayFrozen = true;
9612        mDisplayFreezeTime = SystemClock.elapsedRealtime();
9613        mLastFinishedFreezeSource = null;
9614
9615        mInputMonitor.freezeInputDispatchingLw();
9616
9617        // Clear the last input window -- that is just used for
9618        // clean transitions between IMEs, and if we are freezing
9619        // the screen then the whole world is changing behind the scenes.
9620        mPolicy.setLastInputMethodWindowLw(null, null);
9621
9622        if (mAppTransition.isTransitionSet()) {
9623            mAppTransition.freeze();
9624        }
9625
9626        if (PROFILE_ORIENTATION) {
9627            File file = new File("/data/system/frozen");
9628            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9629        }
9630
9631        if (CUSTOM_SCREEN_ROTATION) {
9632            mExitAnimId = exitAnim;
9633            mEnterAnimId = enterAnim;
9634            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9635            final int displayId = displayContent.getDisplayId();
9636            ScreenRotationAnimation screenRotationAnimation =
9637                    mAnimator.getScreenRotationAnimationLocked(displayId);
9638            if (screenRotationAnimation != null) {
9639                screenRotationAnimation.kill();
9640            }
9641
9642            // Check whether the current screen contains any secure content.
9643            boolean isSecure = false;
9644            final WindowList windows = getDefaultWindowListLocked();
9645            final int N = windows.size();
9646            for (int i = 0; i < N; i++) {
9647                WindowState ws = windows.get(i);
9648                if (ws.isOnScreen() && (ws.mAttrs.flags & FLAG_SECURE) != 0) {
9649                    isSecure = true;
9650                    break;
9651                }
9652            }
9653
9654            // TODO(multidisplay): rotation on main screen only.
9655            displayContent.updateDisplayInfo();
9656            screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
9657                    mFxSession, inTransaction, mPolicy.isDefaultOrientationForced(), isSecure);
9658            mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9659        }
9660    }
9661
9662    void stopFreezingDisplayLocked() {
9663        if (!mDisplayFrozen) {
9664            return;
9665        }
9666
9667        if (mWaitingForConfig || mAppsFreezingScreen > 0
9668                || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
9669                || mClientFreezingScreen || !mOpeningApps.isEmpty()) {
9670            if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
9671                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
9672                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
9673                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
9674                + ", mClientFreezingScreen=" + mClientFreezingScreen
9675                + ", mOpeningApps.size()=" + mOpeningApps.size());
9676            return;
9677        }
9678
9679        if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
9680                "stopFreezingDisplayLocked: Unfreezing now");
9681
9682        mDisplayFrozen = false;
9683        mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
9684        StringBuilder sb = new StringBuilder(128);
9685        sb.append("Screen frozen for ");
9686        TimeUtils.formatDuration(mLastDisplayFreezeDuration, sb);
9687        if (mLastFinishedFreezeSource != null) {
9688            sb.append(" due to ");
9689            sb.append(mLastFinishedFreezeSource);
9690        }
9691        Slog.i(TAG_WM, sb.toString());
9692        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9693        mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
9694        if (PROFILE_ORIENTATION) {
9695            Debug.stopMethodTracing();
9696        }
9697
9698        boolean updateRotation = false;
9699
9700        final DisplayContent displayContent = getDefaultDisplayContentLocked();
9701        final int displayId = displayContent.getDisplayId();
9702        ScreenRotationAnimation screenRotationAnimation =
9703                mAnimator.getScreenRotationAnimationLocked(displayId);
9704        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
9705                && screenRotationAnimation.hasScreenshot()) {
9706            if (DEBUG_ORIENTATION) Slog.i(TAG_WM, "**** Dismissing screen rotation animation");
9707            // TODO(multidisplay): rotation on main screen only.
9708            DisplayInfo displayInfo = displayContent.getDisplayInfo();
9709            // Get rotation animation again, with new top window
9710            boolean isDimming = displayContent.isDimming();
9711            if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
9712                mExitAnimId = mEnterAnimId = 0;
9713            }
9714            if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9715                    getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
9716                        displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
9717                scheduleAnimationLocked();
9718            } else {
9719                screenRotationAnimation.kill();
9720                mAnimator.setScreenRotationAnimationLocked(displayId, null);
9721                updateRotation = true;
9722            }
9723        } else {
9724            if (screenRotationAnimation != null) {
9725                screenRotationAnimation.kill();
9726                mAnimator.setScreenRotationAnimationLocked(displayId, null);
9727            }
9728            updateRotation = true;
9729        }
9730
9731        mInputMonitor.thawInputDispatchingLw();
9732
9733        boolean configChanged;
9734
9735        // While the display is frozen we don't re-compute the orientation
9736        // to avoid inconsistent states.  However, something interesting
9737        // could have actually changed during that time so re-evaluate it
9738        // now to catch that.
9739        configChanged = updateOrientationFromAppTokensLocked(false);
9740
9741        // A little kludge: a lot could have happened while the
9742        // display was frozen, so now that we are coming back we
9743        // do a gc so that any remote references the system
9744        // processes holds on others can be released if they are
9745        // no longer needed.
9746        mH.removeMessages(H.FORCE_GC);
9747        mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);
9748
9749        mScreenFrozenLock.release();
9750
9751        if (updateRotation) {
9752            if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation");
9753            configChanged |= updateRotationUncheckedLocked(false);
9754        }
9755
9756        if (configChanged) {
9757            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9758        }
9759    }
9760
9761    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
9762            DisplayMetrics dm) {
9763        if (index < tokens.length) {
9764            String str = tokens[index];
9765            if (str != null && str.length() > 0) {
9766                try {
9767                    int val = Integer.parseInt(str);
9768                    return val;
9769                } catch (Exception e) {
9770                }
9771            }
9772        }
9773        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
9774            return defDps;
9775        }
9776        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
9777        return val;
9778    }
9779
9780    void createWatermarkInTransaction() {
9781        if (mWatermark != null) {
9782            return;
9783        }
9784
9785        File file = new File("/system/etc/setup.conf");
9786        FileInputStream in = null;
9787        DataInputStream ind = null;
9788        try {
9789            in = new FileInputStream(file);
9790            ind = new DataInputStream(in);
9791            String line = ind.readLine();
9792            if (line != null) {
9793                String[] toks = line.split("%");
9794                if (toks != null && toks.length > 0) {
9795                    mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
9796                            mRealDisplayMetrics, mFxSession, toks);
9797                }
9798            }
9799        } catch (FileNotFoundException e) {
9800        } catch (IOException e) {
9801        } finally {
9802            if (ind != null) {
9803                try {
9804                    ind.close();
9805                } catch (IOException e) {
9806                }
9807            } else if (in != null) {
9808                try {
9809                    in.close();
9810                } catch (IOException e) {
9811                }
9812            }
9813        }
9814    }
9815
9816    @Override
9817    public void statusBarVisibilityChanged(int visibility) {
9818        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
9819                != PackageManager.PERMISSION_GRANTED) {
9820            throw new SecurityException("Caller does not hold permission "
9821                    + android.Manifest.permission.STATUS_BAR);
9822        }
9823
9824        synchronized (mWindowMap) {
9825            mLastStatusBarVisibility = visibility;
9826            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
9827            updateStatusBarVisibilityLocked(visibility);
9828        }
9829    }
9830
9831    // TOOD(multidisplay): StatusBar on multiple screens?
9832    boolean updateStatusBarVisibilityLocked(int visibility) {
9833        if (mLastDispatchedSystemUiVisibility == visibility) {
9834            return false;
9835        }
9836        final int globalDiff = (visibility ^ mLastDispatchedSystemUiVisibility)
9837                // We are only interested in differences of one of the
9838                // clearable flags...
9839                & View.SYSTEM_UI_CLEARABLE_FLAGS
9840                // ...if it has actually been cleared.
9841                & ~visibility;
9842
9843        mLastDispatchedSystemUiVisibility = visibility;
9844        mInputManager.setSystemUiVisibility(visibility);
9845        final WindowList windows = getDefaultWindowListLocked();
9846        final int N = windows.size();
9847        for (int i = 0; i < N; i++) {
9848            WindowState ws = windows.get(i);
9849            try {
9850                int curValue = ws.mSystemUiVisibility;
9851                int diff = (curValue ^ visibility) & globalDiff;
9852                int newValue = (curValue&~diff) | (visibility&diff);
9853                if (newValue != curValue) {
9854                    ws.mSeq++;
9855                    ws.mSystemUiVisibility = newValue;
9856                }
9857                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
9858                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
9859                            visibility, newValue, diff);
9860                }
9861            } catch (RemoteException e) {
9862                // so sorry
9863            }
9864        }
9865        return true;
9866    }
9867
9868    @Override
9869    public void reevaluateStatusBarVisibility() {
9870        synchronized (mWindowMap) {
9871            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
9872            if (updateStatusBarVisibilityLocked(visibility)) {
9873                mWindowPlacerLocked.requestTraversal();
9874            }
9875        }
9876    }
9877
9878    private static final class HideNavInputConsumer extends InputConsumerImpl
9879            implements WindowManagerPolicy.InputConsumer {
9880        private final InputEventReceiver mInputEventReceiver;
9881
9882        HideNavInputConsumer(WindowManagerService service, Looper looper,
9883                             InputEventReceiver.Factory inputEventReceiverFactory) {
9884            super(service, "input consumer", null);
9885            mInputEventReceiver = inputEventReceiverFactory.createInputEventReceiver(
9886                    mClientChannel, looper);
9887        }
9888
9889        @Override
9890        public void dismiss() {
9891            if (mService.removeInputConsumer()) {
9892                synchronized (mService.mWindowMap) {
9893                    mInputEventReceiver.dispose();
9894                    disposeChannelsLw();
9895                }
9896            }
9897        }
9898    }
9899
9900    @Override
9901    public WindowManagerPolicy.InputConsumer addInputConsumer(Looper looper,
9902            InputEventReceiver.Factory inputEventReceiverFactory) {
9903        synchronized (mWindowMap) {
9904            HideNavInputConsumer inputConsumerImpl = new HideNavInputConsumer(
9905                    this, looper, inputEventReceiverFactory);
9906            mInputConsumer = inputConsumerImpl;
9907            mInputMonitor.updateInputWindowsLw(true);
9908            return inputConsumerImpl;
9909        }
9910    }
9911
9912    boolean removeInputConsumer() {
9913        synchronized (mWindowMap) {
9914            if (mInputConsumer != null) {
9915                mInputConsumer = null;
9916                mInputMonitor.updateInputWindowsLw(true);
9917                return true;
9918            }
9919            return false;
9920        }
9921    }
9922
9923    public void createWallpaperInputConsumer(InputChannel inputChannel) {
9924        synchronized (mWindowMap) {
9925            mWallpaperInputConsumer = new InputConsumerImpl(this, "wallpaper input", inputChannel);
9926            mWallpaperInputConsumer.mWindowHandle.hasWallpaper = true;
9927            mInputMonitor.updateInputWindowsLw(true);
9928        }
9929    }
9930
9931    public void removeWallpaperInputConsumer() {
9932        synchronized (mWindowMap) {
9933            if (mWallpaperInputConsumer != null) {
9934                mWallpaperInputConsumer.disposeChannelsLw();
9935                mWallpaperInputConsumer = null;
9936                mInputMonitor.updateInputWindowsLw(true);
9937            }
9938        }
9939    }
9940
9941    @Override
9942    public boolean hasNavigationBar() {
9943        return mPolicy.hasNavigationBar();
9944    }
9945
9946    @Override
9947    public void lockNow(Bundle options) {
9948        mPolicy.lockNow(options);
9949    }
9950
9951    public void showRecentApps(boolean fromHome) {
9952        mPolicy.showRecentApps(fromHome);
9953    }
9954
9955    @Override
9956    public boolean isSafeModeEnabled() {
9957        return mSafeMode;
9958    }
9959
9960    @Override
9961    public boolean clearWindowContentFrameStats(IBinder token) {
9962        if (!checkCallingPermission(Manifest.permission.FRAME_STATS,
9963                "clearWindowContentFrameStats()")) {
9964            throw new SecurityException("Requires FRAME_STATS permission");
9965        }
9966        synchronized (mWindowMap) {
9967            WindowState windowState = mWindowMap.get(token);
9968            if (windowState == null) {
9969                return false;
9970            }
9971            WindowSurfaceController surfaceController = windowState.mWinAnimator.mSurfaceController;
9972            if (surfaceController == null) {
9973                return false;
9974            }
9975            return surfaceController.clearWindowContentFrameStats();
9976        }
9977    }
9978
9979    @Override
9980    public WindowContentFrameStats getWindowContentFrameStats(IBinder token) {
9981        if (!checkCallingPermission(Manifest.permission.FRAME_STATS,
9982                "getWindowContentFrameStats()")) {
9983            throw new SecurityException("Requires FRAME_STATS permission");
9984        }
9985        synchronized (mWindowMap) {
9986            WindowState windowState = mWindowMap.get(token);
9987            if (windowState == null) {
9988                return null;
9989            }
9990            WindowSurfaceController surfaceController = windowState.mWinAnimator.mSurfaceController;
9991            if (surfaceController == null) {
9992                return null;
9993            }
9994            if (mTempWindowRenderStats == null) {
9995                mTempWindowRenderStats = new WindowContentFrameStats();
9996            }
9997            WindowContentFrameStats stats = mTempWindowRenderStats;
9998            if (!surfaceController.getWindowContentFrameStats(stats)) {
9999                return null;
10000            }
10001            return stats;
10002        }
10003    }
10004
10005    public void notifyAppRelaunching(IBinder token) {
10006        synchronized (mWindowMap) {
10007            AppWindowToken appWindow = findAppWindowToken(token);
10008            if (appWindow != null) {
10009                appWindow.startRelaunching();
10010            }
10011        }
10012    }
10013
10014    public void notifyAppRelaunchingFinished(IBinder token) {
10015        synchronized (mWindowMap) {
10016            AppWindowToken appWindow = findAppWindowToken(token);
10017            if (appWindow != null) {
10018                appWindow.finishRelaunching();
10019            }
10020        }
10021    }
10022
10023    @Override
10024    public int getDockedDividerInsetsLw() {
10025        return getDefaultDisplayContentLocked().getDockedDividerController().getContentInsets();
10026    }
10027
10028    void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
10029        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
10030        mPolicy.dump("    ", pw, args);
10031    }
10032
10033    void dumpAnimatorLocked(PrintWriter pw, String[] args, boolean dumpAll) {
10034        pw.println("WINDOW MANAGER ANIMATOR STATE (dumpsys window animator)");
10035        mAnimator.dumpLocked(pw, "    ", dumpAll);
10036    }
10037
10038    void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
10039        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
10040        if (!mTokenMap.isEmpty()) {
10041            pw.println("  All tokens:");
10042            Iterator<WindowToken> it = mTokenMap.values().iterator();
10043            while (it.hasNext()) {
10044                WindowToken token = it.next();
10045                pw.print("  "); pw.print(token);
10046                if (dumpAll) {
10047                    pw.println(':');
10048                    token.dump(pw, "    ");
10049                } else {
10050                    pw.println();
10051                }
10052            }
10053        }
10054        mWallpaperControllerLocked.dumpTokens(pw, "  ", dumpAll);
10055        if (!mFinishedStarting.isEmpty()) {
10056            pw.println();
10057            pw.println("  Finishing start of application tokens:");
10058            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
10059                WindowToken token = mFinishedStarting.get(i);
10060                pw.print("  Finished Starting #"); pw.print(i);
10061                        pw.print(' '); pw.print(token);
10062                if (dumpAll) {
10063                    pw.println(':');
10064                    token.dump(pw, "    ");
10065                } else {
10066                    pw.println();
10067                }
10068            }
10069        }
10070        if (!mOpeningApps.isEmpty() || !mClosingApps.isEmpty()) {
10071            pw.println();
10072            if (mOpeningApps.size() > 0) {
10073                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
10074            }
10075            if (mClosingApps.size() > 0) {
10076                pw.print("  mClosingApps="); pw.println(mClosingApps);
10077            }
10078        }
10079    }
10080
10081    void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
10082        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
10083        for (int i=0; i<mSessions.size(); i++) {
10084            Session s = mSessions.valueAt(i);
10085            pw.print("  Session "); pw.print(s); pw.println(':');
10086            s.dump(pw, "    ");
10087        }
10088    }
10089
10090    void dumpDisplayContentsLocked(PrintWriter pw, boolean dumpAll) {
10091        pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)");
10092        if (mDisplayReady) {
10093            final int numDisplays = mDisplayContents.size();
10094            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10095                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
10096                displayContent.dump("  ", pw);
10097            }
10098        } else {
10099            pw.println("  NO DISPLAY");
10100        }
10101    }
10102
10103    void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
10104            ArrayList<WindowState> windows) {
10105        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
10106        dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
10107    }
10108
10109    void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
10110            ArrayList<WindowState> windows) {
10111        final int numDisplays = mDisplayContents.size();
10112        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10113            final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
10114            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10115                final WindowState w = windowList.get(winNdx);
10116                if (windows == null || windows.contains(w)) {
10117                    pw.print("  Window #"); pw.print(winNdx); pw.print(' ');
10118                            pw.print(w); pw.println(":");
10119                    w.dump(pw, "    ", dumpAll || windows != null);
10120                }
10121            }
10122        }
10123        if (mInputMethodDialogs.size() > 0) {
10124            pw.println();
10125            pw.println("  Input method dialogs:");
10126            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
10127                WindowState w = mInputMethodDialogs.get(i);
10128                if (windows == null || windows.contains(w)) {
10129                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
10130                }
10131            }
10132        }
10133        if (mPendingRemove.size() > 0) {
10134            pw.println();
10135            pw.println("  Remove pending for:");
10136            for (int i=mPendingRemove.size()-1; i>=0; i--) {
10137                WindowState w = mPendingRemove.get(i);
10138                if (windows == null || windows.contains(w)) {
10139                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
10140                            pw.print(w);
10141                    if (dumpAll) {
10142                        pw.println(":");
10143                        w.dump(pw, "    ", true);
10144                    } else {
10145                        pw.println();
10146                    }
10147                }
10148            }
10149        }
10150        if (mForceRemoves != null && mForceRemoves.size() > 0) {
10151            pw.println();
10152            pw.println("  Windows force removing:");
10153            for (int i=mForceRemoves.size()-1; i>=0; i--) {
10154                WindowState w = mForceRemoves.get(i);
10155                pw.print("  Removing #"); pw.print(i); pw.print(' ');
10156                        pw.print(w);
10157                if (dumpAll) {
10158                    pw.println(":");
10159                    w.dump(pw, "    ", true);
10160                } else {
10161                    pw.println();
10162                }
10163            }
10164        }
10165        if (mDestroySurface.size() > 0) {
10166            pw.println();
10167            pw.println("  Windows waiting to destroy their surface:");
10168            for (int i=mDestroySurface.size()-1; i>=0; i--) {
10169                WindowState w = mDestroySurface.get(i);
10170                if (windows == null || windows.contains(w)) {
10171                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
10172                            pw.print(w);
10173                    if (dumpAll) {
10174                        pw.println(":");
10175                        w.dump(pw, "    ", true);
10176                    } else {
10177                        pw.println();
10178                    }
10179                }
10180            }
10181        }
10182        if (mLosingFocus.size() > 0) {
10183            pw.println();
10184            pw.println("  Windows losing focus:");
10185            for (int i=mLosingFocus.size()-1; i>=0; i--) {
10186                WindowState w = mLosingFocus.get(i);
10187                if (windows == null || windows.contains(w)) {
10188                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
10189                            pw.print(w);
10190                    if (dumpAll) {
10191                        pw.println(":");
10192                        w.dump(pw, "    ", true);
10193                    } else {
10194                        pw.println();
10195                    }
10196                }
10197            }
10198        }
10199        if (mResizingWindows.size() > 0) {
10200            pw.println();
10201            pw.println("  Windows waiting to resize:");
10202            for (int i=mResizingWindows.size()-1; i>=0; i--) {
10203                WindowState w = mResizingWindows.get(i);
10204                if (windows == null || windows.contains(w)) {
10205                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
10206                            pw.print(w);
10207                    if (dumpAll) {
10208                        pw.println(":");
10209                        w.dump(pw, "    ", true);
10210                    } else {
10211                        pw.println();
10212                    }
10213                }
10214            }
10215        }
10216        if (mWaitingForDrawn.size() > 0) {
10217            pw.println();
10218            pw.println("  Clients waiting for these windows to be drawn:");
10219            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
10220                WindowState win = mWaitingForDrawn.get(i);
10221                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(win);
10222            }
10223        }
10224        pw.println();
10225        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
10226        pw.print("  mHasPermanentDpad="); pw.println(mHasPermanentDpad);
10227        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
10228        if (mLastFocus != mCurrentFocus) {
10229            pw.print("  mLastFocus="); pw.println(mLastFocus);
10230        }
10231        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
10232        if (mInputMethodTarget != null) {
10233            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
10234        }
10235        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
10236                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
10237        pw.print("  mLastDisplayFreezeDuration=");
10238                TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
10239                if ( mLastFinishedFreezeSource != null) {
10240                    pw.print(" due to ");
10241                    pw.print(mLastFinishedFreezeSource);
10242                }
10243                pw.println();
10244        pw.print("  mLastWakeLockHoldingWindow=");pw.print(mLastWakeLockHoldingWindow);
10245                pw.print(" mLastWakeLockObscuringWindow="); pw.print(mLastWakeLockObscuringWindow);
10246                pw.println();
10247
10248        mInputMonitor.dump(pw, "  ");
10249
10250        if (dumpAll) {
10251            pw.print("  mSystemDecorLayer="); pw.print(mSystemDecorLayer);
10252                    pw.print(" mScreenRect="); pw.println(mScreenRect.toShortString());
10253            if (mLastStatusBarVisibility != 0) {
10254                pw.print("  mLastStatusBarVisibility=0x");
10255                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
10256            }
10257            if (mInputMethodWindow != null) {
10258                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
10259            }
10260            mWindowPlacerLocked.dump(pw, "  ");
10261            mWallpaperControllerLocked.dump(pw, "  ");
10262            mLayersController.dump(pw, "  ");
10263            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
10264                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
10265            if (needsLayout()) {
10266                pw.print("  layoutNeeded on displays=");
10267                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10268                    final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
10269                    if (displayContent.layoutNeeded) {
10270                        pw.print(displayContent.getDisplayId());
10271                    }
10272                }
10273                pw.println();
10274            }
10275            pw.print("  mTransactionSequence="); pw.println(mTransactionSequence);
10276            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
10277                    pw.print(" windows="); pw.print(mWindowsFreezingScreen);
10278                    pw.print(" client="); pw.print(mClientFreezingScreen);
10279                    pw.print(" apps="); pw.print(mAppsFreezingScreen);
10280                    pw.print(" waitingForConfig="); pw.println(mWaitingForConfig);
10281            pw.print("  mRotation="); pw.print(mRotation);
10282                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
10283            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
10284                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
10285            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
10286            pw.print("  Animation settings: disabled="); pw.print(mAnimationsDisabled);
10287                    pw.print(" window="); pw.print(mWindowAnimationScaleSetting);
10288                    pw.print(" transition="); pw.print(mTransitionAnimationScaleSetting);
10289                    pw.print(" animator="); pw.println(mAnimatorDurationScaleSetting);
10290            pw.print(" mSkipAppTransitionAnimation=");pw.println(mSkipAppTransitionAnimation);
10291            pw.println("  mLayoutToAnim:");
10292            mAppTransition.dump(pw, "    ");
10293        }
10294    }
10295
10296    boolean dumpWindows(PrintWriter pw, String name, String[] args,
10297            int opti, boolean dumpAll) {
10298        WindowList windows = new WindowList();
10299        if ("apps".equals(name) || "visible".equals(name) || "visible-apps".equals(name)) {
10300            final boolean appsOnly = name.contains("apps");
10301            final boolean visibleOnly = name.contains("visible");
10302            synchronized(mWindowMap) {
10303                if (appsOnly) {
10304                    dumpDisplayContentsLocked(pw, true);
10305                }
10306
10307                final int numDisplays = mDisplayContents.size();
10308                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10309                    final WindowList windowList =
10310                            mDisplayContents.valueAt(displayNdx).getWindowList();
10311                    for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10312                        final WindowState w = windowList.get(winNdx);
10313                        if ((!visibleOnly || w.mWinAnimator.getShown())
10314                                && (!appsOnly || w.mAppToken != null)) {
10315                            windows.add(w);
10316                        }
10317                    }
10318                }
10319            }
10320        } else {
10321            int objectId = 0;
10322            // See if this is an object ID.
10323            try {
10324                objectId = Integer.parseInt(name, 16);
10325                name = null;
10326            } catch (RuntimeException e) {
10327            }
10328            synchronized(mWindowMap) {
10329                final int numDisplays = mDisplayContents.size();
10330                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10331                    final WindowList windowList =
10332                            mDisplayContents.valueAt(displayNdx).getWindowList();
10333                    for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10334                        final WindowState w = windowList.get(winNdx);
10335                        if (name != null) {
10336                            if (w.mAttrs.getTitle().toString().contains(name)) {
10337                                windows.add(w);
10338                            }
10339                        } else if (System.identityHashCode(w) == objectId) {
10340                            windows.add(w);
10341                        }
10342                    }
10343                }
10344            }
10345        }
10346
10347        if (windows.size() <= 0) {
10348            return false;
10349        }
10350
10351        synchronized(mWindowMap) {
10352            dumpWindowsLocked(pw, dumpAll, windows);
10353        }
10354        return true;
10355    }
10356
10357    void dumpLastANRLocked(PrintWriter pw) {
10358        pw.println("WINDOW MANAGER LAST ANR (dumpsys window lastanr)");
10359        if (mLastANRState == null) {
10360            pw.println("  <no ANR has occurred since boot>");
10361        } else {
10362            pw.println(mLastANRState);
10363        }
10364    }
10365
10366    /**
10367     * Saves information about the state of the window manager at
10368     * the time an ANR occurred before anything else in the system changes
10369     * in response.
10370     *
10371     * @param appWindowToken The application that ANR'd, may be null.
10372     * @param windowState The window that ANR'd, may be null.
10373     * @param reason The reason for the ANR, may be null.
10374     */
10375    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState,
10376            String reason) {
10377        StringWriter sw = new StringWriter();
10378        PrintWriter pw = new FastPrintWriter(sw, false, 1024);
10379        pw.println("  ANR time: " + DateFormat.getInstance().format(new Date()));
10380        if (appWindowToken != null) {
10381            pw.println("  Application at fault: " + appWindowToken.stringName);
10382        }
10383        if (windowState != null) {
10384            pw.println("  Window at fault: " + windowState.mAttrs.getTitle());
10385        }
10386        if (reason != null) {
10387            pw.println("  Reason: " + reason);
10388        }
10389        pw.println();
10390        dumpWindowsNoHeaderLocked(pw, true, null);
10391        pw.println();
10392        pw.println("Last ANR continued");
10393        dumpDisplayContentsLocked(pw, true);
10394        pw.close();
10395        mLastANRState = sw.toString();
10396
10397        mH.removeMessages(H.RESET_ANR_MESSAGE);
10398        mH.sendEmptyMessageDelayed(H.RESET_ANR_MESSAGE, LAST_ANR_LIFETIME_DURATION_MSECS);
10399    }
10400
10401    @Override
10402    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
10403        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
10404                != PackageManager.PERMISSION_GRANTED) {
10405            pw.println("Permission Denial: can't dump WindowManager from from pid="
10406                    + Binder.getCallingPid()
10407                    + ", uid=" + Binder.getCallingUid());
10408            return;
10409        }
10410
10411        boolean dumpAll = false;
10412
10413        int opti = 0;
10414        while (opti < args.length) {
10415            String opt = args[opti];
10416            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
10417                break;
10418            }
10419            opti++;
10420            if ("-a".equals(opt)) {
10421                dumpAll = true;
10422            } else if ("-h".equals(opt)) {
10423                pw.println("Window manager dump options:");
10424                pw.println("  [-a] [-h] [cmd] ...");
10425                pw.println("  cmd may be one of:");
10426                pw.println("    l[astanr]: last ANR information");
10427                pw.println("    p[policy]: policy state");
10428                pw.println("    a[animator]: animator state");
10429                pw.println("    s[essions]: active sessions");
10430                pw.println("    surfaces: active surfaces (debugging enabled only)");
10431                pw.println("    d[isplays]: active display contents");
10432                pw.println("    t[okens]: token list");
10433                pw.println("    w[indows]: window list");
10434                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
10435                pw.println("    be a partial substring in a window name, a");
10436                pw.println("    Window hex object identifier, or");
10437                pw.println("    \"all\" for all windows, or");
10438                pw.println("    \"visible\" for the visible windows.");
10439                pw.println("    \"visible-apps\" for the visible app windows.");
10440                pw.println("  -a: include all available server state.");
10441                return;
10442            } else {
10443                pw.println("Unknown argument: " + opt + "; use -h for help");
10444            }
10445        }
10446
10447        // Is the caller requesting to dump a particular piece of data?
10448        if (opti < args.length) {
10449            String cmd = args[opti];
10450            opti++;
10451            if ("lastanr".equals(cmd) || "l".equals(cmd)) {
10452                synchronized(mWindowMap) {
10453                    dumpLastANRLocked(pw);
10454                }
10455                return;
10456            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
10457                synchronized(mWindowMap) {
10458                    dumpPolicyLocked(pw, args, true);
10459                }
10460                return;
10461            } else if ("animator".equals(cmd) || "a".equals(cmd)) {
10462                synchronized(mWindowMap) {
10463                    dumpAnimatorLocked(pw, args, true);
10464                }
10465                return;
10466            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
10467                synchronized(mWindowMap) {
10468                    dumpSessionsLocked(pw, true);
10469                }
10470                return;
10471            } else if ("surfaces".equals(cmd)) {
10472                synchronized(mWindowMap) {
10473                    WindowSurfaceController.SurfaceTrace.dumpAllSurfaces(pw, null);
10474                }
10475                return;
10476            } else if ("displays".equals(cmd) || "d".equals(cmd)) {
10477                synchronized(mWindowMap) {
10478                    dumpDisplayContentsLocked(pw, true);
10479                }
10480                return;
10481            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
10482                synchronized(mWindowMap) {
10483                    dumpTokensLocked(pw, true);
10484                }
10485                return;
10486            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
10487                synchronized(mWindowMap) {
10488                    dumpWindowsLocked(pw, true, null);
10489                }
10490                return;
10491            } else if ("all".equals(cmd) || "a".equals(cmd)) {
10492                synchronized(mWindowMap) {
10493                    dumpWindowsLocked(pw, true, null);
10494                }
10495                return;
10496            } else {
10497                // Dumping a single name?
10498                if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
10499                    pw.println("Bad window command, or no windows match: " + cmd);
10500                    pw.println("Use -h for help.");
10501                }
10502                return;
10503            }
10504        }
10505
10506        synchronized(mWindowMap) {
10507            pw.println();
10508            if (dumpAll) {
10509                pw.println("-------------------------------------------------------------------------------");
10510            }
10511            dumpLastANRLocked(pw);
10512            pw.println();
10513            if (dumpAll) {
10514                pw.println("-------------------------------------------------------------------------------");
10515            }
10516            dumpPolicyLocked(pw, args, dumpAll);
10517            pw.println();
10518            if (dumpAll) {
10519                pw.println("-------------------------------------------------------------------------------");
10520            }
10521            dumpAnimatorLocked(pw, args, dumpAll);
10522            pw.println();
10523            if (dumpAll) {
10524                pw.println("-------------------------------------------------------------------------------");
10525            }
10526            dumpSessionsLocked(pw, dumpAll);
10527            pw.println();
10528            if (dumpAll) {
10529                pw.println("-------------------------------------------------------------------------------");
10530            }
10531            WindowSurfaceController.SurfaceTrace.dumpAllSurfaces(pw, dumpAll ?
10532                    "-------------------------------------------------------------------------------"
10533                    : null);
10534            pw.println();
10535            if (dumpAll) {
10536                pw.println("-------------------------------------------------------------------------------");
10537            }
10538            dumpDisplayContentsLocked(pw, dumpAll);
10539            pw.println();
10540            if (dumpAll) {
10541                pw.println("-------------------------------------------------------------------------------");
10542            }
10543            dumpTokensLocked(pw, dumpAll);
10544            pw.println();
10545            if (dumpAll) {
10546                pw.println("-------------------------------------------------------------------------------");
10547            }
10548            dumpWindowsLocked(pw, dumpAll, null);
10549        }
10550    }
10551
10552    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
10553    @Override
10554    public void monitor() {
10555        synchronized (mWindowMap) { }
10556    }
10557
10558    private DisplayContent newDisplayContentLocked(final Display display) {
10559        DisplayContent displayContent = new DisplayContent(display, this);
10560        final int displayId = display.getDisplayId();
10561        if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
10562        mDisplayContents.put(displayId, displayContent);
10563
10564        DisplayInfo displayInfo = displayContent.getDisplayInfo();
10565        final Rect rect = new Rect();
10566        mDisplaySettings.getOverscanLocked(displayInfo.name, displayInfo.uniqueId, rect);
10567        displayInfo.overscanLeft = rect.left;
10568        displayInfo.overscanTop = rect.top;
10569        displayInfo.overscanRight = rect.right;
10570        displayInfo.overscanBottom = rect.bottom;
10571        mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(displayId, displayInfo);
10572        configureDisplayPolicyLocked(displayContent);
10573
10574        // TODO: Create an input channel for each display with touch capability.
10575        if (displayId == Display.DEFAULT_DISPLAY) {
10576            displayContent.mTapDetector = new TaskTapPointerEventListener(this, displayContent);
10577            registerPointerEventListener(displayContent.mTapDetector);
10578            registerPointerEventListener(mMousePositionTracker);
10579        }
10580
10581        return displayContent;
10582    }
10583
10584    public void createDisplayContentLocked(final Display display) {
10585        if (display == null) {
10586            throw new IllegalArgumentException("getDisplayContent: display must not be null");
10587        }
10588        getDisplayContentLocked(display.getDisplayId());
10589    }
10590
10591    /**
10592     * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
10593     * there is a Display for the displayId.
10594     * @param displayId The display the caller is interested in.
10595     * @return The DisplayContent associated with displayId or null if there is no Display for it.
10596     */
10597    public DisplayContent getDisplayContentLocked(final int displayId) {
10598        DisplayContent displayContent = mDisplayContents.get(displayId);
10599        if (displayContent == null) {
10600            final Display display = mDisplayManager.getDisplay(displayId);
10601            if (display != null) {
10602                displayContent = newDisplayContentLocked(display);
10603            }
10604        }
10605        return displayContent;
10606    }
10607
10608    // There is an inherent assumption that this will never return null.
10609    public DisplayContent getDefaultDisplayContentLocked() {
10610        return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
10611    }
10612
10613    public WindowList getDefaultWindowListLocked() {
10614        return getDefaultDisplayContentLocked().getWindowList();
10615    }
10616
10617    public DisplayInfo getDefaultDisplayInfoLocked() {
10618        return getDefaultDisplayContentLocked().getDisplayInfo();
10619    }
10620
10621    /**
10622     * Return the list of WindowStates associated on the passed display.
10623     * @param display The screen to return windows from.
10624     * @return The list of WindowStates on the screen, or null if the there is no screen.
10625     */
10626    public WindowList getWindowListLocked(final Display display) {
10627        return getWindowListLocked(display.getDisplayId());
10628    }
10629
10630    /**
10631     * Return the list of WindowStates associated on the passed display.
10632     * @param displayId The screen to return windows from.
10633     * @return The list of WindowStates on the screen, or null if the there is no screen.
10634     */
10635    public WindowList getWindowListLocked(final int displayId) {
10636        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10637        return displayContent != null ? displayContent.getWindowList() : null;
10638    }
10639
10640    public void onDisplayAdded(int displayId) {
10641        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
10642    }
10643
10644    public void handleDisplayAdded(int displayId) {
10645        synchronized (mWindowMap) {
10646            final Display display = mDisplayManager.getDisplay(displayId);
10647            if (display != null) {
10648                createDisplayContentLocked(display);
10649                displayReady(displayId);
10650            }
10651            mWindowPlacerLocked.requestTraversal();
10652        }
10653    }
10654
10655    public void onDisplayRemoved(int displayId) {
10656        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
10657    }
10658
10659    private void handleDisplayRemovedLocked(int displayId) {
10660        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10661        if (displayContent != null) {
10662            if (displayContent.isAnimating()) {
10663                displayContent.mDeferredRemoval = true;
10664                return;
10665            }
10666            if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + displayContent);
10667            mDisplayContents.delete(displayId);
10668            displayContent.close();
10669            if (displayId == Display.DEFAULT_DISPLAY) {
10670                unregisterPointerEventListener(displayContent.mTapDetector);
10671                unregisterPointerEventListener(mMousePositionTracker);
10672            }
10673        }
10674        mAnimator.removeDisplayLocked(displayId);
10675        mWindowPlacerLocked.requestTraversal();
10676    }
10677
10678    public void onDisplayChanged(int displayId) {
10679        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
10680    }
10681
10682    private void handleDisplayChangedLocked(int displayId) {
10683        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10684        if (displayContent != null) {
10685            displayContent.updateDisplayInfo();
10686        }
10687        mWindowPlacerLocked.requestTraversal();
10688    }
10689
10690    @Override
10691    public Object getWindowManagerLock() {
10692        return mWindowMap;
10693    }
10694
10695    /**
10696     * Hint to a token that its activity will relaunch, which will trigger removal and addition of
10697     * a window.
10698     * @param token Application token for which the activity will be relaunched.
10699     */
10700    public void setReplacingWindow(IBinder token, boolean animate) {
10701        AppWindowToken appWindowToken = null;
10702        synchronized (mWindowMap) {
10703            appWindowToken = findAppWindowToken(token);
10704            if (appWindowToken == null || !appWindowToken.isVisible()) {
10705                Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
10706                        + token);
10707                return;
10708            }
10709            appWindowToken.setReplacingWindows(animate);
10710        }
10711    }
10712
10713    /**
10714     * Hint to a token that its windows will be replaced across activity relaunch.
10715     * The windows would otherwise be removed  shortly following this as the
10716     * activity is torn down.
10717     * @param token Application token for which the activity will be relaunched.
10718     * @param childrenOnly Whether to mark only child windows for replacement
10719     *                     (for the case where main windows are being preserved/
10720     *                     reused rather than replaced).
10721     *
10722     */
10723    public void setReplacingWindows(IBinder token, boolean childrenOnly) {
10724        AppWindowToken appWindowToken = null;
10725        synchronized (mWindowMap) {
10726            appWindowToken = findAppWindowToken(token);
10727            if (appWindowToken == null || !appWindowToken.isVisible()) {
10728                Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
10729                        + token);
10730                return;
10731            }
10732
10733            if (childrenOnly) {
10734                appWindowToken.setReplacingChildren();
10735            } else {
10736                appWindowToken.setReplacingWindows(false /* animate */);
10737            }
10738
10739            scheduleClearReplacingWindowIfNeeded(token, true /* replacing */);
10740        }
10741    }
10742
10743    /**
10744     * If we're replacing the window, schedule a timer to clear the replaced window
10745     * after a timeout, in case the replacing window is not coming.
10746     *
10747     * If we're not replacing the window, clear the replace window settings of the app.
10748     *
10749     * @param token Application token for the activity whose window might be replaced.
10750     * @param replacing Whether the window is being replaced or not.
10751     */
10752    public void scheduleClearReplacingWindowIfNeeded(IBinder token, boolean replacing) {
10753        AppWindowToken appWindowToken = null;
10754        synchronized (mWindowMap) {
10755            appWindowToken = findAppWindowToken(token);
10756            if (appWindowToken == null) {
10757                Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token "
10758                        + token);
10759                return;
10760            }
10761            if (replacing) {
10762                mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT);
10763                mH.sendMessageDelayed(
10764                        mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken),
10765                        WINDOW_REPLACEMENT_TIMEOUT_DURATION);
10766            } else {
10767                appWindowToken.resetReplacingWindows();
10768            }
10769        }
10770    }
10771
10772    @Override
10773    public int getDockedStackSide() {
10774        synchronized (mWindowMap) {
10775            final TaskStack dockedStack = getDefaultDisplayContentLocked()
10776                    .getDockedStackVisibleForUserLocked();
10777            return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide();
10778        }
10779    }
10780
10781    @Override
10782    public void setDockedStackResizing(boolean resizing) {
10783        synchronized (mWindowMap) {
10784            getDefaultDisplayContentLocked().getDockedDividerController().setResizing(resizing);
10785            requestTraversal();
10786        }
10787    }
10788
10789    @Override
10790    public void setDockedStackDividerTouchRegion(Rect touchRegion) {
10791        synchronized (mWindowMap) {
10792            getDefaultDisplayContentLocked().getDockedDividerController()
10793                    .setTouchRegion(touchRegion);
10794            setFocusTaskRegionLocked();
10795        }
10796    }
10797
10798    @Override
10799    public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
10800        synchronized (mWindowMap) {
10801            getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer(
10802                    visible, targetStackId, alpha);
10803        }
10804    }
10805
10806    public void animateResizePinnedStack(final Rect bounds, final int animationDuration) {
10807        synchronized (mWindowMap) {
10808            final TaskStack stack = mStackIdToStack.get(PINNED_STACK_ID);
10809            if (stack == null) {
10810                Slog.w(TAG, "animateResizePinnedStack: stackId " + PINNED_STACK_ID + " not found.");
10811                return;
10812            }
10813            final Rect originalBounds = new Rect();
10814            stack.getBounds(originalBounds);
10815            UiThread.getHandler().post(new Runnable() {
10816                @Override
10817                public void run() {
10818                    mBoundsAnimationController.animateBounds(
10819                            stack, originalBounds, bounds, animationDuration);
10820                }
10821            });
10822        }
10823    }
10824
10825    public void setTaskResizeable(int taskId, int resizeMode) {
10826        synchronized (mWindowMap) {
10827            final Task task = mTaskIdToTask.get(taskId);
10828            if (task != null) {
10829                task.setResizeable(resizeMode);
10830            }
10831        }
10832    }
10833
10834    public void setForceResizableTasks(boolean forceResizableTasks) {
10835        synchronized (mWindowMap) {
10836            mForceResizableTasks = forceResizableTasks;
10837        }
10838    }
10839
10840    static int dipToPixel(int dip, DisplayMetrics displayMetrics) {
10841        return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics);
10842    }
10843
10844    @Override
10845    public void registerDockedStackListener(IDockedStackListener listener) {
10846        if (!checkCallingPermission(android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS,
10847                "registerDockedStackListener()")) {
10848            return;
10849        }
10850        // TODO(multi-display): The listener is registered on the default display only.
10851        getDefaultDisplayContentLocked().mDividerControllerLocked.registerDockedStackListener(
10852                listener);
10853    }
10854
10855    @Override
10856    public void requestAppKeyboardShortcuts(IResultReceiver receiver, int deviceId) {
10857        try {
10858            WindowState focusedWindow = getFocusedWindow();
10859            if (focusedWindow != null && focusedWindow.mClient != null) {
10860                getFocusedWindow().mClient.requestAppKeyboardShortcuts(receiver, deviceId);
10861            }
10862        } catch (RemoteException e) {
10863        }
10864    }
10865
10866    @Override
10867    public void getStableInsets(Rect outInsets) throws RemoteException {
10868        synchronized (mWindowMap) {
10869            getStableInsetsLocked(outInsets);
10870        }
10871    }
10872
10873    void getStableInsetsLocked(Rect outInsets) {
10874        final DisplayInfo di = getDefaultDisplayInfoLocked();
10875        mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets);
10876    }
10877
10878    private void getNonDecorInsetsLocked(Rect outInsets) {
10879        final DisplayInfo di = getDefaultDisplayInfoLocked();
10880        mPolicy.getNonDecorInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight, outInsets);
10881    }
10882
10883    /**
10884     * Intersects the specified {@code inOutBounds} with the display frame that excludes the stable
10885     * inset areas.
10886     *
10887     * @param inOutBounds The inOutBounds to subtract the stable inset areas from.
10888     */
10889    public void subtractStableInsets(Rect inOutBounds) {
10890        synchronized (mWindowMap) {
10891            getStableInsetsLocked(mTmpRect2);
10892            final DisplayInfo di = getDefaultDisplayInfoLocked();
10893            mTmpRect.set(0, 0, di.logicalWidth, di.logicalHeight);
10894            mTmpRect.inset(mTmpRect2);
10895            inOutBounds.intersect(mTmpRect);
10896        }
10897    }
10898
10899    /**
10900     * Intersects the specified {@code inOutBounds} with the display frame that excludes
10901     * areas that could never be removed in Honeycomb. See
10902     * {@link WindowManagerPolicy#getNonDecorInsetsLw}.
10903     *
10904     * @param inOutBounds The inOutBounds to subtract the inset areas from.
10905     */
10906    public void subtractNonDecorInsets(Rect inOutBounds) {
10907        synchronized (mWindowMap) {
10908            getNonDecorInsetsLocked(mTmpRect2);
10909            final DisplayInfo di = getDefaultDisplayInfoLocked();
10910            mTmpRect.set(0, 0, di.logicalWidth, di.logicalHeight);
10911            mTmpRect.inset(mTmpRect2);
10912            inOutBounds.intersect(mTmpRect);
10913        }
10914    }
10915
10916    private MousePositionTracker mMousePositionTracker = new MousePositionTracker();
10917
10918    private static class MousePositionTracker implements PointerEventListener {
10919        private boolean mLatestEventWasMouse;
10920        private float mLatestMouseX;
10921        private float mLatestMouseY;
10922
10923        void updatePosition(float x, float y) {
10924            synchronized (this) {
10925                mLatestEventWasMouse = true;
10926                mLatestMouseX = x;
10927                mLatestMouseY = y;
10928            }
10929        }
10930
10931        @Override
10932        public void onPointerEvent(MotionEvent motionEvent) {
10933            if (motionEvent.isFromSource(InputDevice.SOURCE_MOUSE)) {
10934                updatePosition(motionEvent.getRawX(), motionEvent.getRawY());
10935            } else {
10936                synchronized (this) {
10937                    mLatestEventWasMouse = false;
10938                }
10939            }
10940        }
10941    };
10942
10943    void updatePointerIcon(IWindow client) {
10944        float mouseX, mouseY;
10945
10946        synchronized(mMousePositionTracker) {
10947            if (!mMousePositionTracker.mLatestEventWasMouse) {
10948                return;
10949            }
10950            mouseX = mMousePositionTracker.mLatestMouseX;
10951            mouseY = mMousePositionTracker.mLatestMouseY;
10952        }
10953
10954        synchronized (mWindowMap) {
10955            if (mDragState != null) {
10956                // Drag cursor overrides the app cursor.
10957                return;
10958            }
10959            WindowState callingWin = windowForClientLocked(null, client, false);
10960            if (callingWin == null) {
10961                Slog.w(TAG_WM, "Bad requesting window " + client);
10962                return;
10963            }
10964            final DisplayContent displayContent = callingWin.getDisplayContent();
10965            if (displayContent == null) {
10966                return;
10967            }
10968            WindowState windowUnderPointer =
10969                    displayContent.getTouchableWinAtPointLocked(mouseX, mouseY);
10970            if (windowUnderPointer != callingWin) {
10971                return;
10972            }
10973            try {
10974                windowUnderPointer.mClient.updatePointerIcon(
10975                        windowUnderPointer.translateToWindowX(mouseX),
10976                        windowUnderPointer.translateToWindowY(mouseY));
10977            } catch (RemoteException e) {
10978                Slog.w(TAG_WM, "unable to update pointer icon");
10979            }
10980        }
10981    }
10982
10983    void restorePointerIconLocked(DisplayContent displayContent, float latestX, float latestY) {
10984        // Mouse position tracker has not been getting updates while dragging, update it now.
10985        mMousePositionTracker.updatePosition(latestX, latestY);
10986
10987        WindowState windowUnderPointer =
10988                displayContent.getTouchableWinAtPointLocked(latestX, latestY);
10989        if (windowUnderPointer != null) {
10990            try {
10991                windowUnderPointer.mClient.updatePointerIcon(
10992                        windowUnderPointer.translateToWindowX(latestX),
10993                        windowUnderPointer.translateToWindowY(latestY));
10994            } catch (RemoteException e) {
10995                Slog.w(TAG_WM, "unable to restore pointer icon");
10996            }
10997        } else {
10998            InputManager.getInstance().setPointerIconShape(PointerIcon.STYLE_DEFAULT);
10999        }
11000    }
11001
11002    public void registerShortcutKey(long shortcutCode, IShortcutService shortcutKeyReceiver)
11003            throws RemoteException {
11004        if (!checkCallingPermission(Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS,
11005                "registerShortcutKey")) {
11006            throw new SecurityException(
11007                    "Requires REGISTER_WINDOW_MANAGER_LISTENERS permission");
11008        }
11009        mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver);
11010    }
11011
11012    private final class LocalService extends WindowManagerInternal {
11013        @Override
11014        public void requestTraversalFromDisplayManager() {
11015            requestTraversal();
11016        }
11017
11018        @Override
11019        public void setMagnificationSpec(MagnificationSpec spec) {
11020            synchronized (mWindowMap) {
11021                if (mAccessibilityController != null) {
11022                    mAccessibilityController.setMagnificationSpecLocked(spec);
11023                } else {
11024                    throw new IllegalStateException("Magnification callbacks not set!");
11025                }
11026            }
11027            if (Binder.getCallingPid() != android.os.Process.myPid()) {
11028                spec.recycle();
11029            }
11030        }
11031
11032        @Override
11033        public void getMagnificationRegion(@NonNull Region magnificationRegion) {
11034            synchronized (mWindowMap) {
11035                if (mAccessibilityController != null) {
11036                    mAccessibilityController.getMagnificationRegionLocked(magnificationRegion);
11037                } else {
11038                    throw new IllegalStateException("Magnification callbacks not set!");
11039                }
11040            }
11041        }
11042
11043        @Override
11044        public MagnificationSpec getCompatibleMagnificationSpecForWindow(IBinder windowToken) {
11045            synchronized (mWindowMap) {
11046                WindowState windowState = mWindowMap.get(windowToken);
11047                if (windowState == null) {
11048                    return null;
11049                }
11050                MagnificationSpec spec = null;
11051                if (mAccessibilityController != null) {
11052                    spec = mAccessibilityController.getMagnificationSpecForWindowLocked(windowState);
11053                }
11054                if ((spec == null || spec.isNop()) && windowState.mGlobalScale == 1.0f) {
11055                    return null;
11056                }
11057                spec = (spec == null) ? MagnificationSpec.obtain() : MagnificationSpec.obtain(spec);
11058                spec.scale *= windowState.mGlobalScale;
11059                return spec;
11060            }
11061        }
11062
11063        @Override
11064        public void setMagnificationCallbacks(@Nullable MagnificationCallbacks callbacks) {
11065            synchronized (mWindowMap) {
11066                if (mAccessibilityController == null) {
11067                    mAccessibilityController = new AccessibilityController(
11068                            WindowManagerService.this);
11069                }
11070                mAccessibilityController.setMagnificationCallbacksLocked(callbacks);
11071                if (!mAccessibilityController.hasCallbacksLocked()) {
11072                    mAccessibilityController = null;
11073                }
11074            }
11075        }
11076
11077        @Override
11078        public void setWindowsForAccessibilityCallback(WindowsForAccessibilityCallback callback) {
11079            synchronized (mWindowMap) {
11080                if (mAccessibilityController == null) {
11081                    mAccessibilityController = new AccessibilityController(
11082                            WindowManagerService.this);
11083                }
11084                mAccessibilityController.setWindowsForAccessibilityCallback(callback);
11085                if (!mAccessibilityController.hasCallbacksLocked()) {
11086                    mAccessibilityController = null;
11087                }
11088            }
11089        }
11090
11091        @Override
11092        public void setInputFilter(IInputFilter filter) {
11093            mInputManager.setInputFilter(filter);
11094        }
11095
11096        @Override
11097        public IBinder getFocusedWindowToken() {
11098            synchronized (mWindowMap) {
11099                WindowState windowState = getFocusedWindowLocked();
11100                if (windowState != null) {
11101                    return windowState.mClient.asBinder();
11102                }
11103                return null;
11104            }
11105        }
11106
11107        @Override
11108        public boolean isKeyguardLocked() {
11109            return WindowManagerService.this.isKeyguardLocked();
11110        }
11111
11112        @Override
11113        public void showGlobalActions() {
11114            WindowManagerService.this.showGlobalActions();
11115        }
11116
11117        @Override
11118        public void getWindowFrame(IBinder token, Rect outBounds) {
11119            synchronized (mWindowMap) {
11120                WindowState windowState = mWindowMap.get(token);
11121                if (windowState != null) {
11122                    outBounds.set(windowState.mFrame);
11123                } else {
11124                    outBounds.setEmpty();
11125                }
11126            }
11127        }
11128
11129        @Override
11130        public void waitForAllWindowsDrawn(Runnable callback, long timeout) {
11131            boolean allWindowsDrawn = false;
11132            synchronized (mWindowMap) {
11133                mWaitingForDrawnCallback = callback;
11134                final WindowList windows = getDefaultWindowListLocked();
11135                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
11136                    final WindowState win = windows.get(winNdx);
11137                    final boolean isForceHiding = mPolicy.isForceHiding(win.mAttrs);
11138                    if (win.isVisibleLw()
11139                            && (win.mAppToken != null || isForceHiding)) {
11140                        win.mWinAnimator.mDrawState = DRAW_PENDING;
11141                        // Force add to mResizingWindows.
11142                        win.mLastContentInsets.set(-1, -1, -1, -1);
11143                        mWaitingForDrawn.add(win);
11144
11145                        // No need to wait for the windows below Keyguard.
11146                        if (isForceHiding) {
11147                            break;
11148                        }
11149                    }
11150                }
11151                mWindowPlacerLocked.requestTraversal();
11152                mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT);
11153                if (mWaitingForDrawn.isEmpty()) {
11154                    allWindowsDrawn = true;
11155                } else {
11156                    mH.sendEmptyMessageDelayed(H.WAITING_FOR_DRAWN_TIMEOUT, timeout);
11157                    checkDrawnWindowsLocked();
11158                }
11159            }
11160            if (allWindowsDrawn) {
11161                callback.run();
11162            }
11163        }
11164
11165        @Override
11166        public void addWindowToken(IBinder token, int type) {
11167            WindowManagerService.this.addWindowToken(token, type);
11168        }
11169
11170        @Override
11171        public void removeWindowToken(IBinder token, boolean removeWindows) {
11172            synchronized(mWindowMap) {
11173                if (removeWindows) {
11174                    WindowToken wtoken = mTokenMap.remove(token);
11175                    if (wtoken != null) {
11176                        wtoken.removeAllWindows();
11177                    }
11178                }
11179                WindowManagerService.this.removeWindowToken(token);
11180            }
11181        }
11182
11183        @Override
11184        public void registerAppTransitionListener(AppTransitionListener listener) {
11185            synchronized (mWindowMap) {
11186                mAppTransition.registerListenerLocked(listener);
11187            }
11188        }
11189
11190        @Override
11191        public int getInputMethodWindowVisibleHeight() {
11192            synchronized (mWindowMap) {
11193                return mPolicy.getInputMethodWindowVisibleHeightLw();
11194            }
11195        }
11196
11197        @Override
11198        public void saveLastInputMethodWindowForTransition() {
11199            synchronized (mWindowMap) {
11200                if (mInputMethodWindow != null) {
11201                    mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
11202                }
11203            }
11204        }
11205
11206        @Override
11207        public boolean isHardKeyboardAvailable() {
11208            synchronized (mWindowMap) {
11209                return mHardKeyboardAvailable;
11210            }
11211        }
11212
11213        @Override
11214        public void setOnHardKeyboardStatusChangeListener(
11215                OnHardKeyboardStatusChangeListener listener) {
11216            synchronized (mWindowMap) {
11217                mHardKeyboardStatusChangeListener = listener;
11218            }
11219        }
11220
11221        @Override
11222        public boolean isStackVisible(int stackId) {
11223            synchronized (mWindowMap) {
11224                return WindowManagerService.this.isStackVisibleLocked(stackId);
11225            }
11226        }
11227
11228        @Override
11229        public boolean isDockedDividerResizing() {
11230            synchronized (mWindowMap) {
11231                return getDefaultDisplayContentLocked().getDockedDividerController().isResizing();
11232            }
11233        }
11234    }
11235}
11236