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