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