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