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