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