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