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