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