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