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