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