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