WindowManagerService.java revision b696de5c10ebcc7bf42d8487fc0e56e0e937754d
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
6550            // Update the configuration based on available input devices, lid switch,
6551            // and platform configuration.
6552            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6553            config.keyboard = Configuration.KEYBOARD_NOKEYS;
6554            config.navigation = Configuration.NAVIGATION_NONAV;
6555
6556            int keyboardPresence = 0;
6557            int navigationPresence = 0;
6558            final InputDevice[] devices = mInputManager.getInputDevices();
6559            final int len = devices.length;
6560            for (int i = 0; i < len; i++) {
6561                InputDevice device = devices[i];
6562                if (!device.isVirtual()) {
6563                    final int sources = device.getSources();
6564                    final int presenceFlag = device.isExternal() ?
6565                            WindowManagerPolicy.PRESENCE_EXTERNAL :
6566                                    WindowManagerPolicy.PRESENCE_INTERNAL;
6567
6568                    if (mIsTouchDevice) {
6569                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
6570                                InputDevice.SOURCE_TOUCHSCREEN) {
6571                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
6572                        }
6573                    } else {
6574                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6575                    }
6576
6577                    if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
6578                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
6579                        navigationPresence |= presenceFlag;
6580                    } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
6581                            && config.navigation == Configuration.NAVIGATION_NONAV) {
6582                        config.navigation = Configuration.NAVIGATION_DPAD;
6583                        navigationPresence |= presenceFlag;
6584                    }
6585
6586                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
6587                        config.keyboard = Configuration.KEYBOARD_QWERTY;
6588                        keyboardPresence |= presenceFlag;
6589                    }
6590                }
6591            }
6592
6593            // Determine whether a hard keyboard is available and enabled.
6594            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6595            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6596                mHardKeyboardAvailable = hardKeyboardAvailable;
6597                mHardKeyboardEnabled = hardKeyboardAvailable;
6598                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6599                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6600            }
6601            if (!mHardKeyboardEnabled) {
6602                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6603            }
6604
6605            // Let the policy update hidden states.
6606            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6607            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6608            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6609            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
6610        }
6611
6612        return true;
6613    }
6614
6615    public boolean isHardKeyboardAvailable() {
6616        synchronized (mWindowMap) {
6617            return mHardKeyboardAvailable;
6618        }
6619    }
6620
6621    public boolean isHardKeyboardEnabled() {
6622        synchronized (mWindowMap) {
6623            return mHardKeyboardEnabled;
6624        }
6625    }
6626
6627    public void setHardKeyboardEnabled(boolean enabled) {
6628        synchronized (mWindowMap) {
6629            if (mHardKeyboardEnabled != enabled) {
6630                mHardKeyboardEnabled = enabled;
6631                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6632            }
6633        }
6634    }
6635
6636    public void setOnHardKeyboardStatusChangeListener(
6637            OnHardKeyboardStatusChangeListener listener) {
6638        synchronized (mWindowMap) {
6639            mHardKeyboardStatusChangeListener = listener;
6640        }
6641    }
6642
6643    void notifyHardKeyboardStatusChange() {
6644        final boolean available, enabled;
6645        final OnHardKeyboardStatusChangeListener listener;
6646        synchronized (mWindowMap) {
6647            listener = mHardKeyboardStatusChangeListener;
6648            available = mHardKeyboardAvailable;
6649            enabled = mHardKeyboardEnabled;
6650        }
6651        if (listener != null) {
6652            listener.onHardKeyboardStatusChange(available, enabled);
6653        }
6654    }
6655
6656    // -------------------------------------------------------------
6657    // Drag and drop
6658    // -------------------------------------------------------------
6659
6660    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
6661            int flags, int width, int height, Surface outSurface) {
6662        if (DEBUG_DRAG) {
6663            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
6664                    + " flags=" + Integer.toHexString(flags) + " win=" + window
6665                    + " asbinder=" + window.asBinder());
6666        }
6667
6668        final int callerPid = Binder.getCallingPid();
6669        final long origId = Binder.clearCallingIdentity();
6670        IBinder token = null;
6671
6672        try {
6673            synchronized (mWindowMap) {
6674                try {
6675                    if (mDragState == null) {
6676                        Surface surface = new Surface(session, callerPid, "drag surface",
6677                                Display.DEFAULT_DISPLAY,
6678                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
6679                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
6680                                + surface + ": CREATE");
6681                        outSurface.copyFrom(surface);
6682                        final IBinder winBinder = window.asBinder();
6683                        token = new Binder();
6684                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
6685                        token = mDragState.mToken = new Binder();
6686
6687                        // 5 second timeout for this window to actually begin the drag
6688                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
6689                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
6690                        mH.sendMessageDelayed(msg, 5000);
6691                    } else {
6692                        Slog.w(TAG, "Drag already in progress");
6693                    }
6694                } catch (Surface.OutOfResourcesException e) {
6695                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
6696                    if (mDragState != null) {
6697                        mDragState.reset();
6698                        mDragState = null;
6699                    }
6700                }
6701            }
6702        } finally {
6703            Binder.restoreCallingIdentity(origId);
6704        }
6705
6706        return token;
6707    }
6708
6709    // -------------------------------------------------------------
6710    // Input Events and Focus Management
6711    // -------------------------------------------------------------
6712
6713    final InputMonitor mInputMonitor = new InputMonitor(this);
6714    private boolean mEventDispatchingEnabled;
6715
6716    public void pauseKeyDispatching(IBinder _token) {
6717        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6718                "pauseKeyDispatching()")) {
6719            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6720        }
6721
6722        synchronized (mWindowMap) {
6723            WindowToken token = mTokenMap.get(_token);
6724            if (token != null) {
6725                mInputMonitor.pauseDispatchingLw(token);
6726            }
6727        }
6728    }
6729
6730    public void resumeKeyDispatching(IBinder _token) {
6731        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6732                "resumeKeyDispatching()")) {
6733            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6734        }
6735
6736        synchronized (mWindowMap) {
6737            WindowToken token = mTokenMap.get(_token);
6738            if (token != null) {
6739                mInputMonitor.resumeDispatchingLw(token);
6740            }
6741        }
6742    }
6743
6744    public void setEventDispatching(boolean enabled) {
6745        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6746                "setEventDispatching()")) {
6747            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6748        }
6749
6750        synchronized (mWindowMap) {
6751            mEventDispatchingEnabled = enabled;
6752            if (mDisplayEnabled) {
6753                mInputMonitor.setEventDispatchingLw(enabled);
6754            }
6755            sendScreenStatusToClientsLocked();
6756        }
6757    }
6758
6759    public IBinder getFocusedWindowToken() {
6760        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
6761                "getFocusedWindowToken()")) {
6762            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
6763        }
6764        synchronized (mWindowMap) {
6765            WindowState windowState = getFocusedWindowLocked();
6766            if (windowState != null) {
6767                return windowState.mClient.asBinder();
6768            }
6769            return null;
6770        }
6771    }
6772
6773    public boolean getWindowFrame(IBinder token, Rect outBounds) {
6774        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
6775                "getWindowFrame()")) {
6776            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
6777        }
6778        synchronized (mWindowMap) {
6779            WindowState windowState = mWindowMap.get(token);
6780            if (windowState != null) {
6781                outBounds.set(windowState.getFrameLw());
6782                return true;
6783            }
6784        }
6785        return false;
6786    }
6787
6788    private WindowState getFocusedWindow() {
6789        synchronized (mWindowMap) {
6790            return getFocusedWindowLocked();
6791        }
6792    }
6793
6794    private WindowState getFocusedWindowLocked() {
6795        return mCurrentFocus;
6796    }
6797
6798    public boolean detectSafeMode() {
6799        if (!mInputMonitor.waitForInputDevicesReady(
6800                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
6801            Slog.w(TAG, "Devices still not ready after waiting "
6802                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
6803                   + " milliseconds before attempting to detect safe mode.");
6804        }
6805
6806        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6807                KeyEvent.KEYCODE_MENU);
6808        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
6809        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
6810                KeyEvent.KEYCODE_DPAD_CENTER);
6811        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
6812                InputManagerService.BTN_MOUSE);
6813        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6814                KeyEvent.KEYCODE_VOLUME_DOWN);
6815        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
6816                || volumeDownState > 0;
6817        try {
6818            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
6819                mSafeMode = true;
6820                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
6821            }
6822        } catch (IllegalArgumentException e) {
6823        }
6824        if (mSafeMode) {
6825            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
6826                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
6827        } else {
6828            Log.i(TAG, "SAFE MODE not enabled");
6829        }
6830        mPolicy.setSafeMode(mSafeMode);
6831        return mSafeMode;
6832    }
6833
6834    public void displayReady() {
6835        synchronized(mWindowMap) {
6836            if (mDisplay != null) {
6837                throw new IllegalStateException("Display already initialized");
6838            }
6839            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
6840            mDisplay = wm.getDefaultDisplay();
6841            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
6842                    PackageManager.FEATURE_TOUCHSCREEN);
6843
6844            synchronized(mDisplaySizeLock) {
6845                // Bootstrap the default logical display from the display manager.
6846                mDisplayManager.getDisplayInfo(Display.DEFAULT_DISPLAY, mDisplayInfo);
6847                mInitialDisplayWidth = mDisplayInfo.logicalWidth;
6848                mInitialDisplayHeight = mDisplayInfo.logicalHeight;
6849                mBaseDisplayWidth = mInitialDisplayWidth;
6850                mBaseDisplayHeight = mInitialDisplayHeight;
6851
6852                mAnimator.setDisplayDimensions(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
6853                        mDisplayInfo.appWidth, mDisplayInfo.appHeight);
6854            }
6855
6856            DisplayDeviceInfo info = new DisplayDeviceInfo();
6857            mDisplayManager.getDefaultExternalDisplayDeviceInfo(info);
6858            mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
6859                    mInitialDisplayWidth, mInitialDisplayHeight,
6860                    info.width, info.height);
6861            mInputManager.setDisplayOrientation(Display.DEFAULT_DISPLAY,
6862                    mDisplay.getRotation(), Surface.ROTATION_0);
6863            mPolicy.setInitialDisplaySize(mDisplay, mInitialDisplayWidth, mInitialDisplayHeight);
6864        }
6865
6866        try {
6867            mActivityManager.updateConfiguration(null);
6868        } catch (RemoteException e) {
6869        }
6870
6871        synchronized (mWindowMap) {
6872            readForcedDisplaySizeLocked();
6873        }
6874    }
6875
6876    public void systemReady() {
6877        mPolicy.systemReady();
6878    }
6879
6880    private void sendScreenStatusToClientsLocked() {
6881        final ArrayList<WindowState> windows = mWindows;
6882        final int count = windows.size();
6883        boolean on = mPowerManager.isScreenOn();
6884        for (int i = count - 1; i >= 0; i--) {
6885            WindowState win = mWindows.get(i);
6886            try {
6887                win.mClient.dispatchScreenState(on);
6888            } catch (RemoteException e) {
6889                // Ignored
6890            }
6891        }
6892    }
6893
6894    // -------------------------------------------------------------
6895    // Async Handler
6896    // -------------------------------------------------------------
6897
6898    final class H extends Handler {
6899        public static final int REPORT_FOCUS_CHANGE = 2;
6900        public static final int REPORT_LOSING_FOCUS = 3;
6901        public static final int DO_TRAVERSAL = 4;
6902        public static final int ADD_STARTING = 5;
6903        public static final int REMOVE_STARTING = 6;
6904        public static final int FINISHED_STARTING = 7;
6905        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
6906        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
6907        public static final int WINDOW_FREEZE_TIMEOUT = 11;
6908        public static final int HOLD_SCREEN_CHANGED = 12;
6909        public static final int APP_TRANSITION_TIMEOUT = 13;
6910        public static final int PERSIST_ANIMATION_SCALE = 14;
6911        public static final int FORCE_GC = 15;
6912        public static final int ENABLE_SCREEN = 16;
6913        public static final int APP_FREEZE_TIMEOUT = 17;
6914        public static final int SEND_NEW_CONFIGURATION = 18;
6915        public static final int REPORT_WINDOWS_CHANGE = 19;
6916        public static final int DRAG_START_TIMEOUT = 20;
6917        public static final int DRAG_END_TIMEOUT = 21;
6918        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
6919        public static final int BOOT_TIMEOUT = 23;
6920        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
6921        public static final int UPDATE_ANIM_PARAMETERS = 25;
6922        public static final int SHOW_STRICT_MODE_VIOLATION = 26;
6923        public static final int DO_ANIMATION_CALLBACK = 27;
6924
6925        public static final int ANIMATOR_WHAT_OFFSET = 100000;
6926        public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
6927        public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 2;
6928
6929        private Session mLastReportedHold;
6930
6931        public H() {
6932        }
6933
6934        @Override
6935        public void handleMessage(Message msg) {
6936            if (DEBUG_WINDOW_TRACE) {
6937                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
6938            }
6939            switch (msg.what) {
6940                case REPORT_FOCUS_CHANGE: {
6941                    WindowState lastFocus;
6942                    WindowState newFocus;
6943
6944                    synchronized(mWindowMap) {
6945                        lastFocus = mLastFocus;
6946                        newFocus = mCurrentFocus;
6947                        if (lastFocus == newFocus) {
6948                            // Focus is not changing, so nothing to do.
6949                            return;
6950                        }
6951                        mLastFocus = newFocus;
6952                        //Slog.i(TAG, "Focus moving from " + lastFocus
6953                        //        + " to " + newFocus);
6954                        if (newFocus != null && lastFocus != null
6955                                && !newFocus.isDisplayedLw()) {
6956                            //Slog.i(TAG, "Delaying loss of focus...");
6957                            mLosingFocus.add(lastFocus);
6958                            lastFocus = null;
6959                        }
6960                    }
6961
6962                    if (lastFocus != newFocus) {
6963                        //System.out.println("Changing focus from " + lastFocus
6964                        //                   + " to " + newFocus);
6965                        if (newFocus != null) {
6966                            try {
6967                                //Slog.i(TAG, "Gaining focus: " + newFocus);
6968                                newFocus.mClient.windowFocusChanged(true, mInTouchMode);
6969                            } catch (RemoteException e) {
6970                                // Ignore if process has died.
6971                            }
6972                            notifyFocusChanged();
6973                        }
6974
6975                        if (lastFocus != null) {
6976                            try {
6977                                //Slog.i(TAG, "Losing focus: " + lastFocus);
6978                                lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
6979                            } catch (RemoteException e) {
6980                                // Ignore if process has died.
6981                            }
6982                        }
6983                    }
6984                } break;
6985
6986                case REPORT_LOSING_FOCUS: {
6987                    ArrayList<WindowState> losers;
6988
6989                    synchronized(mWindowMap) {
6990                        losers = mLosingFocus;
6991                        mLosingFocus = new ArrayList<WindowState>();
6992                    }
6993
6994                    final int N = losers.size();
6995                    for (int i=0; i<N; i++) {
6996                        try {
6997                            //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
6998                            losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
6999                        } catch (RemoteException e) {
7000                             // Ignore if process has died.
7001                        }
7002                    }
7003                } break;
7004
7005                case DO_TRAVERSAL: {
7006                    synchronized(mWindowMap) {
7007                        mTraversalScheduled = false;
7008                        performLayoutAndPlaceSurfacesLocked();
7009                    }
7010                } break;
7011
7012                case ADD_STARTING: {
7013                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7014                    final StartingData sd = wtoken.startingData;
7015
7016                    if (sd == null) {
7017                        // Animation has been canceled... do nothing.
7018                        return;
7019                    }
7020
7021                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
7022                            + wtoken + ": pkg=" + sd.pkg);
7023
7024                    View view = null;
7025                    try {
7026                        view = mPolicy.addStartingWindow(
7027                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
7028                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
7029                    } catch (Exception e) {
7030                        Slog.w(TAG, "Exception when adding starting window", e);
7031                    }
7032
7033                    if (view != null) {
7034                        boolean abort = false;
7035
7036                        synchronized(mWindowMap) {
7037                            if (wtoken.removed || wtoken.startingData == null) {
7038                                // If the window was successfully added, then
7039                                // we need to remove it.
7040                                if (wtoken.startingWindow != null) {
7041                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7042                                            "Aborted starting " + wtoken
7043                                            + ": removed=" + wtoken.removed
7044                                            + " startingData=" + wtoken.startingData);
7045                                    wtoken.startingWindow = null;
7046                                    wtoken.startingData = null;
7047                                    abort = true;
7048                                }
7049                            } else {
7050                                wtoken.startingView = view;
7051                            }
7052                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
7053                                    "Added starting " + wtoken
7054                                    + ": startingWindow="
7055                                    + wtoken.startingWindow + " startingView="
7056                                    + wtoken.startingView);
7057                        }
7058
7059                        if (abort) {
7060                            try {
7061                                mPolicy.removeStartingWindow(wtoken.token, view);
7062                            } catch (Exception e) {
7063                                Slog.w(TAG, "Exception when removing starting window", e);
7064                            }
7065                        }
7066                    }
7067                } break;
7068
7069                case REMOVE_STARTING: {
7070                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7071                    IBinder token = null;
7072                    View view = null;
7073                    synchronized (mWindowMap) {
7074                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
7075                                + wtoken + ": startingWindow="
7076                                + wtoken.startingWindow + " startingView="
7077                                + wtoken.startingView);
7078                        if (wtoken.startingWindow != null) {
7079                            view = wtoken.startingView;
7080                            token = wtoken.token;
7081                            wtoken.startingData = null;
7082                            wtoken.startingView = null;
7083                            wtoken.startingWindow = null;
7084                            wtoken.startingDisplayed = false;
7085                        }
7086                    }
7087                    if (view != null) {
7088                        try {
7089                            mPolicy.removeStartingWindow(token, view);
7090                        } catch (Exception e) {
7091                            Slog.w(TAG, "Exception when removing starting window", e);
7092                        }
7093                    }
7094                } break;
7095
7096                case FINISHED_STARTING: {
7097                    IBinder token = null;
7098                    View view = null;
7099                    while (true) {
7100                        synchronized (mWindowMap) {
7101                            final int N = mFinishedStarting.size();
7102                            if (N <= 0) {
7103                                break;
7104                            }
7105                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7106
7107                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7108                                    "Finished starting " + wtoken
7109                                    + ": startingWindow=" + wtoken.startingWindow
7110                                    + " startingView=" + wtoken.startingView);
7111
7112                            if (wtoken.startingWindow == null) {
7113                                continue;
7114                            }
7115
7116                            view = wtoken.startingView;
7117                            token = wtoken.token;
7118                            wtoken.startingData = null;
7119                            wtoken.startingView = null;
7120                            wtoken.startingWindow = null;
7121                            wtoken.startingDisplayed = false;
7122                        }
7123
7124                        try {
7125                            mPolicy.removeStartingWindow(token, view);
7126                        } catch (Exception e) {
7127                            Slog.w(TAG, "Exception when removing starting window", e);
7128                        }
7129                    }
7130                } break;
7131
7132                case REPORT_APPLICATION_TOKEN_DRAWN: {
7133                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7134
7135                    try {
7136                        if (DEBUG_VISIBILITY) Slog.v(
7137                                TAG, "Reporting drawn in " + wtoken);
7138                        wtoken.appToken.windowsDrawn();
7139                    } catch (RemoteException ex) {
7140                    }
7141                } break;
7142
7143                case REPORT_APPLICATION_TOKEN_WINDOWS: {
7144                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7145
7146                    boolean nowVisible = msg.arg1 != 0;
7147                    boolean nowGone = msg.arg2 != 0;
7148
7149                    try {
7150                        if (DEBUG_VISIBILITY) Slog.v(
7151                                TAG, "Reporting visible in " + wtoken
7152                                + " visible=" + nowVisible
7153                                + " gone=" + nowGone);
7154                        if (nowVisible) {
7155                            wtoken.appToken.windowsVisible();
7156                        } else {
7157                            wtoken.appToken.windowsGone();
7158                        }
7159                    } catch (RemoteException ex) {
7160                    }
7161                } break;
7162
7163                case WINDOW_FREEZE_TIMEOUT: {
7164                    synchronized (mWindowMap) {
7165                        Slog.w(TAG, "Window freeze timeout expired.");
7166                        int i = mWindows.size();
7167                        while (i > 0) {
7168                            i--;
7169                            WindowState w = mWindows.get(i);
7170                            if (w.mOrientationChanging) {
7171                                w.mOrientationChanging = false;
7172                                Slog.w(TAG, "Force clearing orientation change: " + w);
7173                            }
7174                        }
7175                        performLayoutAndPlaceSurfacesLocked();
7176                    }
7177                    break;
7178                }
7179
7180                case HOLD_SCREEN_CHANGED: {
7181                    Session oldHold;
7182                    Session newHold;
7183                    synchronized (mWindowMap) {
7184                        oldHold = mLastReportedHold;
7185                        newHold = (Session)msg.obj;
7186                        mLastReportedHold = newHold;
7187                    }
7188
7189                    if (oldHold != newHold) {
7190                        try {
7191                            if (oldHold != null) {
7192                                mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
7193                                        "window",
7194                                        BatteryStats.WAKE_TYPE_WINDOW);
7195                            }
7196                            if (newHold != null) {
7197                                mBatteryStats.noteStartWakelock(newHold.mUid, -1,
7198                                        "window",
7199                                        BatteryStats.WAKE_TYPE_WINDOW);
7200                            }
7201                        } catch (RemoteException e) {
7202                        }
7203                    }
7204                    break;
7205                }
7206
7207                case APP_TRANSITION_TIMEOUT: {
7208                    synchronized (mWindowMap) {
7209                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
7210                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7211                                    "*** APP TRANSITION TIMEOUT");
7212                            mAppTransitionReady = true;
7213                            mAppTransitionTimeout = true;
7214                            mAnimatingAppTokens.clear();
7215                            mAnimatingAppTokens.addAll(mAppTokens);
7216                            performLayoutAndPlaceSurfacesLocked();
7217                        }
7218                    }
7219                    break;
7220                }
7221
7222                case PERSIST_ANIMATION_SCALE: {
7223                    Settings.System.putFloat(mContext.getContentResolver(),
7224                            Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7225                    Settings.System.putFloat(mContext.getContentResolver(),
7226                            Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7227                    Settings.System.putFloat(mContext.getContentResolver(),
7228                            Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
7229                    break;
7230                }
7231
7232                case FORCE_GC: {
7233                    synchronized (mWindowMap) {
7234                        synchronized (mAnimator) {
7235                            // Since we're holding both mWindowMap and mAnimator we don't need to
7236                            // hold mAnimator.mLayoutToAnim.
7237                            if (mAnimator.mAnimating || mLayoutToAnim.mAnimationScheduled) {
7238                                // If we are animating, don't do the gc now but
7239                                // delay a bit so we don't interrupt the animation.
7240                                mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
7241                                        2000);
7242                                return;
7243                            }
7244                            // If we are currently rotating the display, it will
7245                            // schedule a new message when done.
7246                            if (mDisplayFrozen) {
7247                                return;
7248                            }
7249                        }
7250                    }
7251                    Runtime.getRuntime().gc();
7252                    break;
7253                }
7254
7255                case ENABLE_SCREEN: {
7256                    performEnableScreen();
7257                    break;
7258                }
7259
7260                case APP_FREEZE_TIMEOUT: {
7261                    synchronized (mWindowMap) {
7262                        synchronized (mAnimator) {
7263                            Slog.w(TAG, "App freeze timeout expired.");
7264                            int i = mAppTokens.size();
7265                            while (i > 0) {
7266                                i--;
7267                                AppWindowToken tok = mAppTokens.get(i);
7268                                if (tok.mAppAnimator.freezingScreen) {
7269                                    Slog.w(TAG, "Force clearing freeze: " + tok);
7270                                    unsetAppFreezingScreenLocked(tok, true, true);
7271                                }
7272                            }
7273                        }
7274                    }
7275                    break;
7276                }
7277
7278                case SEND_NEW_CONFIGURATION: {
7279                    removeMessages(SEND_NEW_CONFIGURATION);
7280                    sendNewConfiguration();
7281                    break;
7282                }
7283
7284                case REPORT_WINDOWS_CHANGE: {
7285                    if (mWindowsChanged) {
7286                        synchronized (mWindowMap) {
7287                            mWindowsChanged = false;
7288                        }
7289                        notifyWindowsChanged();
7290                    }
7291                    break;
7292                }
7293
7294                case DRAG_START_TIMEOUT: {
7295                    IBinder win = (IBinder)msg.obj;
7296                    if (DEBUG_DRAG) {
7297                        Slog.w(TAG, "Timeout starting drag by win " + win);
7298                    }
7299                    synchronized (mWindowMap) {
7300                        // !!! TODO: ANR the app that has failed to start the drag in time
7301                        if (mDragState != null) {
7302                            mDragState.unregister();
7303                            mInputMonitor.updateInputWindowsLw(true /*force*/);
7304                            mDragState.reset();
7305                            mDragState = null;
7306                        }
7307                    }
7308                    break;
7309                }
7310
7311                case DRAG_END_TIMEOUT: {
7312                    IBinder win = (IBinder)msg.obj;
7313                    if (DEBUG_DRAG) {
7314                        Slog.w(TAG, "Timeout ending drag to win " + win);
7315                    }
7316                    synchronized (mWindowMap) {
7317                        // !!! TODO: ANR the drag-receiving app
7318                        if (mDragState != null) {
7319                            mDragState.mDragResult = false;
7320                            mDragState.endDragLw();
7321                        }
7322                    }
7323                    break;
7324                }
7325
7326                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
7327                    notifyHardKeyboardStatusChange();
7328                    break;
7329                }
7330
7331                case BOOT_TIMEOUT: {
7332                    performBootTimeout();
7333                    break;
7334                }
7335
7336                case WAITING_FOR_DRAWN_TIMEOUT: {
7337                    Pair<WindowState, IRemoteCallback> pair;
7338                    synchronized (mWindowMap) {
7339                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
7340                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
7341                        if (!mWaitingForDrawn.remove(pair)) {
7342                            return;
7343                        }
7344                    }
7345                    try {
7346                        pair.second.sendResult(null);
7347                    } catch (RemoteException e) {
7348                    }
7349                    break;
7350                }
7351
7352                case UPDATE_ANIM_PARAMETERS: {
7353                    // Used to send multiple changes from the animation side to the layout side.
7354                    synchronized (mWindowMap) {
7355                        if (copyAnimToLayoutParamsLocked()) {
7356                            mH.sendEmptyMessage(CLEAR_PENDING_ACTIONS);
7357                            performLayoutAndPlaceSurfacesLocked();
7358                        }
7359                    }
7360                    break;
7361                }
7362
7363                case SHOW_STRICT_MODE_VIOLATION: {
7364                    showStrictModeViolation(msg.arg1);
7365                    break;
7366                }
7367
7368                // Animation messages. Move to Window{State}Animator
7369                case SET_TRANSPARENT_REGION: {
7370                    Pair<WindowStateAnimator, Region> pair =
7371                                (Pair<WindowStateAnimator, Region>) msg.obj;
7372                    final WindowStateAnimator winAnimator = pair.first;
7373                    winAnimator.setTransparentRegionHint(pair.second);
7374                    break;
7375                }
7376
7377                case CLEAR_PENDING_ACTIONS: {
7378                    mAnimator.clearPendingActions();
7379                    break;
7380                }
7381
7382                case DO_ANIMATION_CALLBACK: {
7383                    try {
7384                        ((IRemoteCallback)msg.obj).sendResult(null);
7385                    } catch (RemoteException e) {
7386                    }
7387                    break;
7388                }
7389            }
7390            if (DEBUG_WINDOW_TRACE) {
7391                Slog.v(TAG, "handleMessage: exit");
7392            }
7393        }
7394    }
7395
7396    // -------------------------------------------------------------
7397    // IWindowManager API
7398    // -------------------------------------------------------------
7399
7400    @Override
7401    public IWindowSession openSession(IInputMethodClient client,
7402            IInputContext inputContext) {
7403        if (client == null) throw new IllegalArgumentException("null client");
7404        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7405        Session session = new Session(this, client, inputContext);
7406        return session;
7407    }
7408
7409    @Override
7410    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7411        synchronized (mWindowMap) {
7412            // The focus for the client is the window immediately below
7413            // where we would place the input method window.
7414            int idx = findDesiredInputMethodWindowIndexLocked(false);
7415            WindowState imFocus;
7416            if (idx > 0) {
7417                imFocus = mWindows.get(idx-1);
7418                if (DEBUG_INPUT_METHOD) {
7419                    Slog.i(TAG, "Desired input method target: " + imFocus);
7420                    Slog.i(TAG, "Current focus: " + this.mCurrentFocus);
7421                    Slog.i(TAG, "Last focus: " + this.mLastFocus);
7422                }
7423                if (imFocus != null) {
7424                    // This may be a starting window, in which case we still want
7425                    // to count it as okay.
7426                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
7427                            && imFocus.mAppToken != null) {
7428                        // The client has definitely started, so it really should
7429                        // have a window in this app token.  Let's look for it.
7430                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
7431                            WindowState w = imFocus.mAppToken.windows.get(i);
7432                            if (w != imFocus) {
7433                                Log.i(TAG, "Switching to real app window: " + w);
7434                                imFocus = w;
7435                                break;
7436                            }
7437                        }
7438                    }
7439                    if (DEBUG_INPUT_METHOD) {
7440                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
7441                        if (imFocus.mSession.mClient != null) {
7442                            Slog.i(TAG, "IM target client binder: "
7443                                    + imFocus.mSession.mClient.asBinder());
7444                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
7445                        }
7446                    }
7447                    if (imFocus.mSession.mClient != null &&
7448                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7449                        return true;
7450                    }
7451
7452                    // Okay, how about this...  what is the current focus?
7453                    // It seems in some cases we may not have moved the IM
7454                    // target window, such as when it was in a pop-up window,
7455                    // so let's also look at the current focus.  (An example:
7456                    // go to Gmail, start searching so the keyboard goes up,
7457                    // press home.  Sometimes the IME won't go down.)
7458                    // Would be nice to fix this more correctly, but it's
7459                    // way at the end of a release, and this should be good enough.
7460                    if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null &&
7461                            mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7462                        return true;
7463                    }
7464                }
7465            }
7466        }
7467        return false;
7468    }
7469
7470    public void getInitialDisplaySize(Point size) {
7471        synchronized(mDisplaySizeLock) {
7472            size.x = mInitialDisplayWidth;
7473            size.y = mInitialDisplayHeight;
7474        }
7475    }
7476
7477    public void setForcedDisplaySize(int longDimen, int shortDimen) {
7478        synchronized(mWindowMap) {
7479            int width, height;
7480            if (mInitialDisplayWidth < mInitialDisplayHeight) {
7481                width = shortDimen < mInitialDisplayWidth
7482                        ? shortDimen : mInitialDisplayWidth;
7483                height = longDimen < mInitialDisplayHeight
7484                        ? longDimen : mInitialDisplayHeight;
7485            } else {
7486                width = longDimen < mInitialDisplayWidth
7487                        ? longDimen : mInitialDisplayWidth;
7488                height = shortDimen < mInitialDisplayHeight
7489                        ? shortDimen : mInitialDisplayHeight;
7490            }
7491            setForcedDisplaySizeLocked(width, height);
7492            Settings.Secure.putString(mContext.getContentResolver(),
7493                    Settings.Secure.DISPLAY_SIZE_FORCED, width + "," + height);
7494        }
7495    }
7496
7497    private void rebuildBlackFrame() {
7498        if (mBlackFrame != null) {
7499            mBlackFrame.kill();
7500            mBlackFrame = null;
7501        }
7502        if (mBaseDisplayWidth < mInitialDisplayWidth
7503                || mBaseDisplayHeight < mInitialDisplayHeight) {
7504            int initW, initH, baseW, baseH;
7505            final boolean rotated = (mRotation == Surface.ROTATION_90
7506                    || mRotation == Surface.ROTATION_270);
7507            if (rotated) {
7508                initW = mInitialDisplayHeight;
7509                initH = mInitialDisplayWidth;
7510                baseW = mBaseDisplayHeight;
7511                baseH = mBaseDisplayWidth;
7512            } else {
7513                initW = mInitialDisplayWidth;
7514                initH = mInitialDisplayHeight;
7515                baseW = mBaseDisplayWidth;
7516                baseH = mBaseDisplayHeight;
7517            }
7518            Rect outer = new Rect(0, 0, initW, initH);
7519            Rect inner = new Rect(0, 0, baseW, baseH);
7520            try {
7521                mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
7522            } catch (Surface.OutOfResourcesException e) {
7523            }
7524        }
7525    }
7526
7527    private void readForcedDisplaySizeLocked() {
7528        final String str = Settings.Secure.getString(mContext.getContentResolver(),
7529                Settings.Secure.DISPLAY_SIZE_FORCED);
7530        if (str == null || str.length() == 0) {
7531            return;
7532        }
7533        final int pos = str.indexOf(',');
7534        if (pos <= 0 || str.lastIndexOf(',') != pos) {
7535            return;
7536        }
7537        int width, height;
7538        try {
7539            width = Integer.parseInt(str.substring(0, pos));
7540            height = Integer.parseInt(str.substring(pos+1));
7541        } catch (NumberFormatException ex) {
7542            return;
7543        }
7544        setForcedDisplaySizeLocked(width, height);
7545    }
7546
7547    private void setForcedDisplaySizeLocked(int width, int height) {
7548        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7549
7550        synchronized(mDisplaySizeLock) {
7551            mBaseDisplayWidth = width;
7552            mBaseDisplayHeight = height;
7553        }
7554        mPolicy.setInitialDisplaySize(mDisplay, mBaseDisplayWidth, mBaseDisplayHeight);
7555
7556        mLayoutNeeded = true;
7557
7558        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7559        mTempConfiguration.setToDefaults();
7560        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7561        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7562            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7563                configChanged = true;
7564            }
7565        }
7566
7567        if (configChanged) {
7568            mWaitingForConfig = true;
7569            startFreezingDisplayLocked(false);
7570            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7571        }
7572
7573        rebuildBlackFrame();
7574
7575        performLayoutAndPlaceSurfacesLocked();
7576    }
7577
7578    public void clearForcedDisplaySize() {
7579        synchronized(mWindowMap) {
7580            setForcedDisplaySizeLocked(mInitialDisplayWidth, mInitialDisplayHeight);
7581            Settings.Secure.putString(mContext.getContentResolver(),
7582                    Settings.Secure.DISPLAY_SIZE_FORCED, "");
7583        }
7584    }
7585
7586    public boolean hasSystemNavBar() {
7587        return mPolicy.hasSystemNavBar();
7588    }
7589
7590    // -------------------------------------------------------------
7591    // Internals
7592    // -------------------------------------------------------------
7593
7594    final WindowState windowForClientLocked(Session session, IWindow client,
7595            boolean throwOnError) {
7596        return windowForClientLocked(session, client.asBinder(), throwOnError);
7597    }
7598
7599    final WindowState windowForClientLocked(Session session, IBinder client,
7600            boolean throwOnError) {
7601        WindowState win = mWindowMap.get(client);
7602        if (localLOGV) Slog.v(
7603            TAG, "Looking up client " + client + ": " + win);
7604        if (win == null) {
7605            RuntimeException ex = new IllegalArgumentException(
7606                    "Requested window " + client + " does not exist");
7607            if (throwOnError) {
7608                throw ex;
7609            }
7610            Slog.w(TAG, "Failed looking up window", ex);
7611            return null;
7612        }
7613        if (session != null && win.mSession != session) {
7614            RuntimeException ex = new IllegalArgumentException(
7615                    "Requested window " + client + " is in session " +
7616                    win.mSession + ", not " + session);
7617            if (throwOnError) {
7618                throw ex;
7619            }
7620            Slog.w(TAG, "Failed looking up window", ex);
7621            return null;
7622        }
7623
7624        return win;
7625    }
7626
7627    final void rebuildAppWindowListLocked() {
7628        int NW = mWindows.size();
7629        int i;
7630        int lastBelow = -1;
7631        int numRemoved = 0;
7632
7633        if (mRebuildTmp.length < NW) {
7634            mRebuildTmp = new WindowState[NW+10];
7635        }
7636
7637        // First remove all existing app windows.
7638        i=0;
7639        while (i < NW) {
7640            WindowState w = mWindows.get(i);
7641            if (w.mAppToken != null) {
7642                WindowState win = mWindows.remove(i);
7643                win.mRebuilding = true;
7644                mRebuildTmp[numRemoved] = win;
7645                mWindowsChanged = true;
7646                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
7647                        "Rebuild removing window: " + win);
7648                NW--;
7649                numRemoved++;
7650                continue;
7651            } else if (lastBelow == i-1) {
7652                if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER
7653                        || w.mAttrs.type == WindowManager.LayoutParams.TYPE_UNIVERSE_BACKGROUND) {
7654                    lastBelow = i;
7655                }
7656            }
7657            i++;
7658        }
7659
7660        // Keep whatever windows were below the app windows still below,
7661        // by skipping them.
7662        lastBelow++;
7663        i = lastBelow;
7664
7665        // First add all of the exiting app tokens...  these are no longer
7666        // in the main app list, but still have windows shown.  We put them
7667        // in the back because now that the animation is over we no longer
7668        // will care about them.
7669        int NT = mExitingAppTokens.size();
7670        for (int j=0; j<NT; j++) {
7671            i = reAddAppWindowsLocked(i, mExitingAppTokens.get(j));
7672        }
7673
7674        // And add in the still active app tokens in Z order.
7675        NT = mAnimatingAppTokens.size();
7676        for (int j=0; j<NT; j++) {
7677            i = reAddAppWindowsLocked(i, mAnimatingAppTokens.get(j));
7678        }
7679
7680        i -= lastBelow;
7681        if (i != numRemoved) {
7682            Slog.w(TAG, "Rebuild removed " + numRemoved
7683                    + " windows but added " + i);
7684            for (i=0; i<numRemoved; i++) {
7685                WindowState ws = mRebuildTmp[i];
7686                if (ws.mRebuilding) {
7687                    StringWriter sw = new StringWriter();
7688                    PrintWriter pw = new PrintWriter(sw);
7689                    ws.dump(pw, "", true);
7690                    pw.flush();
7691                    Slog.w(TAG, "This window was lost: " + ws);
7692                    Slog.w(TAG, sw.toString());
7693                    ws.mWinAnimator.destroySurfaceLocked();
7694                }
7695            }
7696            Slog.w(TAG, "Current app token list:");
7697            dumpAnimatingAppTokensLocked();
7698            Slog.w(TAG, "Final window list:");
7699            dumpWindowsLocked();
7700        }
7701    }
7702
7703    private final void assignLayersLocked() {
7704        int N = mWindows.size();
7705        int curBaseLayer = 0;
7706        int curLayer = 0;
7707        int i;
7708
7709        if (DEBUG_LAYERS) {
7710            RuntimeException here = new RuntimeException("here");
7711            here.fillInStackTrace();
7712            Slog.v(TAG, "Assigning layers", here);
7713        }
7714
7715        for (i=0; i<N; i++) {
7716            final WindowState w = mWindows.get(i);
7717            final WindowStateAnimator winAnimator = w.mWinAnimator;
7718            boolean layerChanged = false;
7719            int oldLayer = w.mLayer;
7720            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
7721                    || (i > 0 && w.mIsWallpaper)) {
7722                curLayer += WINDOW_LAYER_MULTIPLIER;
7723                w.mLayer = curLayer;
7724            } else {
7725                curBaseLayer = curLayer = w.mBaseLayer;
7726                w.mLayer = curLayer;
7727            }
7728            if (w.mLayer != oldLayer) {
7729                layerChanged = true;
7730            }
7731            oldLayer = winAnimator.mAnimLayer;
7732            if (w.mTargetAppToken != null) {
7733                winAnimator.mAnimLayer =
7734                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
7735            } else if (w.mAppToken != null) {
7736                winAnimator.mAnimLayer =
7737                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
7738            } else {
7739                winAnimator.mAnimLayer = w.mLayer;
7740            }
7741            if (w.mIsImWindow) {
7742                winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
7743            } else if (w.mIsWallpaper) {
7744                winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
7745            }
7746            if (winAnimator.mAnimLayer != oldLayer) {
7747                layerChanged = true;
7748            }
7749            if (layerChanged && mAnimator.isDimming(winAnimator)) {
7750                // Force an animation pass just to update the mDimAnimator layer.
7751                updateLayoutToAnimationLocked();
7752            }
7753            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
7754                    + winAnimator.mAnimLayer);
7755            //System.out.println(
7756            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7757        }
7758    }
7759
7760    private boolean mInLayout = false;
7761    private final void performLayoutAndPlaceSurfacesLocked() {
7762        if (mInLayout) {
7763            if (DEBUG) {
7764                throw new RuntimeException("Recursive call!");
7765            }
7766            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
7767                    + Debug.getCallers(3));
7768            return;
7769        }
7770
7771        if (mWaitingForConfig) {
7772            // Our configuration has changed (most likely rotation), but we
7773            // don't yet have the complete configuration to report to
7774            // applications.  Don't do any window layout until we have it.
7775            return;
7776        }
7777
7778        if (mDisplay == null) {
7779            // Not yet initialized, nothing to do.
7780            return;
7781        }
7782
7783        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
7784        mInLayout = true;
7785        boolean recoveringMemory = false;
7786
7787        try {
7788            if (mForceRemoves != null) {
7789                recoveringMemory = true;
7790                // Wait a little bit for things to settle down, and off we go.
7791                for (int i=0; i<mForceRemoves.size(); i++) {
7792                    WindowState ws = mForceRemoves.get(i);
7793                    Slog.i(TAG, "Force removing: " + ws);
7794                    removeWindowInnerLocked(ws.mSession, ws);
7795                }
7796                mForceRemoves = null;
7797                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
7798                Object tmp = new Object();
7799                synchronized (tmp) {
7800                    try {
7801                        tmp.wait(250);
7802                    } catch (InterruptedException e) {
7803                    }
7804                }
7805            }
7806        } catch (RuntimeException e) {
7807            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
7808        }
7809
7810        try {
7811            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
7812
7813            final int N = mPendingRemove.size();
7814            if (N > 0) {
7815                if (mPendingRemoveTmp.length < N) {
7816                    mPendingRemoveTmp = new WindowState[N+10];
7817                }
7818                mPendingRemove.toArray(mPendingRemoveTmp);
7819                mPendingRemove.clear();
7820                for (int i=0; i<N; i++) {
7821                    WindowState w = mPendingRemoveTmp[i];
7822                    removeWindowInnerLocked(w.mSession, w);
7823                }
7824
7825                mInLayout = false;
7826                assignLayersLocked();
7827                mLayoutNeeded = true;
7828                // XXX this recursion seems broken!
7829                Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
7830                performLayoutAndPlaceSurfacesLocked();
7831                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
7832
7833            } else {
7834                mInLayout = false;
7835            }
7836
7837            if (mLayoutNeeded) {
7838                if (++mLayoutRepeatCount < 6) {
7839                    requestTraversalLocked();
7840                } else {
7841                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
7842                    mLayoutRepeatCount = 0;
7843                }
7844            } else {
7845                mLayoutRepeatCount = 0;
7846            }
7847
7848            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
7849                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
7850                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
7851            }
7852        } catch (RuntimeException e) {
7853            mInLayout = false;
7854            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
7855        }
7856
7857        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
7858    }
7859
7860    private final void performLayoutLockedInner(boolean initial, boolean updateInputWindows) {
7861        if (!mLayoutNeeded) {
7862            return;
7863        }
7864
7865        mLayoutNeeded = false;
7866
7867        final int dw = mDisplayInfo.logicalWidth;
7868        final int dh = mDisplayInfo.logicalHeight;
7869
7870        final int NFW = mFakeWindows.size();
7871        for (int i=0; i<NFW; i++) {
7872            mFakeWindows.get(i).layout(dw, dh);
7873        }
7874
7875        final int N = mWindows.size();
7876        int i;
7877
7878        if (DEBUG_LAYOUT) {
7879            Slog.v(TAG, "-------------------------------------");
7880            Slog.v(TAG, "performLayout: needed="
7881                    + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
7882        }
7883
7884        WindowStateAnimator universeBackground = null;
7885
7886        mPolicy.beginLayoutLw(dw, dh, mRotation);
7887        mSystemDecorLayer = mPolicy.getSystemDecorRectLw(mSystemDecorRect);
7888        mScreenRect.set(0, 0, dw, dh);
7889
7890        int seq = mLayoutSeq+1;
7891        if (seq < 0) seq = 0;
7892        mLayoutSeq = seq;
7893
7894        // First perform layout of any root windows (not attached
7895        // to another window).
7896        int topAttached = -1;
7897        for (i = N-1; i >= 0; i--) {
7898            final WindowState win = mWindows.get(i);
7899
7900            // Don't do layout of a window if it is not visible, or
7901            // soon won't be visible, to avoid wasting time and funky
7902            // changes while a window is animating away.
7903            final boolean gone = win.isGoneForLayoutLw();
7904
7905            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
7906                Slog.v(TAG, "1ST PASS " + win
7907                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
7908                        + " mLayoutAttached=" + win.mLayoutAttached);
7909                final AppWindowToken atoken = win.mAppToken;
7910                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
7911                        + win.mViewVisibility + " mRelayoutCalled="
7912                        + win.mRelayoutCalled + " hidden="
7913                        + win.mRootToken.hidden + " hiddenRequested="
7914                        + (atoken != null && atoken.hiddenRequested)
7915                        + " mAttachedHidden=" + win.mAttachedHidden);
7916                else Slog.v(TAG, "  VIS: mViewVisibility="
7917                        + win.mViewVisibility + " mRelayoutCalled="
7918                        + win.mRelayoutCalled + " hidden="
7919                        + win.mRootToken.hidden + " hiddenRequested="
7920                        + (atoken != null && atoken.hiddenRequested)
7921                        + " mAttachedHidden=" + win.mAttachedHidden);
7922            }
7923
7924            // If this view is GONE, then skip it -- keep the current
7925            // frame, and let the caller know so they can ignore it
7926            // if they want.  (We do the normal layout for INVISIBLE
7927            // windows, since that means "perform layout as normal,
7928            // just don't display").
7929            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
7930                    || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
7931                if (!win.mLayoutAttached) {
7932                    if (initial) {
7933                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7934                        win.mContentChanged = false;
7935                    }
7936                    win.mLayoutNeeded = false;
7937                    win.prelayout();
7938                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
7939                    win.mLayoutSeq = seq;
7940                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7941                            + win.mFrame + " mContainingFrame="
7942                            + win.mContainingFrame + " mDisplayFrame="
7943                            + win.mDisplayFrame);
7944                } else {
7945                    if (topAttached < 0) topAttached = i;
7946                }
7947            }
7948            if (win.mViewVisibility == View.VISIBLE
7949                    && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND
7950                    && universeBackground == null) {
7951                universeBackground = win.mWinAnimator;
7952            }
7953        }
7954
7955        if (mAnimator.mUniverseBackground  != universeBackground) {
7956            mFocusMayChange = true;
7957            mAnimator.mUniverseBackground = universeBackground;
7958        }
7959
7960        // Now perform layout of attached windows, which usually
7961        // depend on the position of the window they are attached to.
7962        // XXX does not deal with windows that are attached to windows
7963        // that are themselves attached.
7964        for (i = topAttached; i >= 0; i--) {
7965            final WindowState win = mWindows.get(i);
7966
7967            if (win.mLayoutAttached) {
7968                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
7969                        + " mHaveFrame=" + win.mHaveFrame
7970                        + " mViewVisibility=" + win.mViewVisibility
7971                        + " mRelayoutCalled=" + win.mRelayoutCalled);
7972                // If this view is GONE, then skip it -- keep the current
7973                // frame, and let the caller know so they can ignore it
7974                // if they want.  (We do the normal layout for INVISIBLE
7975                // windows, since that means "perform layout as normal,
7976                // just don't display").
7977                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7978                        || !win.mHaveFrame || win.mLayoutNeeded) {
7979                    if (initial) {
7980                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7981                        win.mContentChanged = false;
7982                    }
7983                    win.mLayoutNeeded = false;
7984                    win.prelayout();
7985                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7986                    win.mLayoutSeq = seq;
7987                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7988                            + win.mFrame + " mContainingFrame="
7989                            + win.mContainingFrame + " mDisplayFrame="
7990                            + win.mDisplayFrame);
7991                }
7992            }
7993        }
7994
7995        // Window frames may have changed.  Tell the input dispatcher about it.
7996        mInputMonitor.setUpdateInputWindowsNeededLw();
7997        if (updateInputWindows) {
7998            mInputMonitor.updateInputWindowsLw(false /*force*/);
7999        }
8000
8001        mPolicy.finishLayoutLw();
8002    }
8003
8004    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
8005        // If the screen is currently frozen or off, then keep
8006        // it frozen/off until this window draws at its new
8007        // orientation.
8008        if (!okToDisplay()) {
8009            if (DEBUG_ORIENTATION) Slog.v(TAG,
8010                    "Changing surface while display frozen: " + w);
8011            w.mOrientationChanging = true;
8012            mInnerFields.mOrientationChangeComplete = false;
8013            if (!mWindowsFreezingScreen) {
8014                mWindowsFreezingScreen = true;
8015                // XXX should probably keep timeout from
8016                // when we first froze the display.
8017                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8018                mH.sendMessageDelayed(mH.obtainMessage(
8019                        H.WINDOW_FREEZE_TIMEOUT), 2000);
8020            }
8021        }
8022    }
8023
8024    /**
8025     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8026     *
8027     * @return bitmap indicating if another pass through layout must be made.
8028     */
8029    public int handleAppTransitionReadyLocked() {
8030        int changes = 0;
8031        int i;
8032        int NN = mOpeningApps.size();
8033        boolean goodToGo = true;
8034        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8035                "Checking " + NN + " opening apps (frozen="
8036                + mDisplayFrozen + " timeout="
8037                + mAppTransitionTimeout + ")...");
8038        if (!mDisplayFrozen && !mAppTransitionTimeout) {
8039            // If the display isn't frozen, wait to do anything until
8040            // all of the apps are ready.  Otherwise just go because
8041            // we'll unfreeze the display when everyone is ready.
8042            for (i=0; i<NN && goodToGo; i++) {
8043                AppWindowToken wtoken = mOpeningApps.get(i);
8044                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8045                        "Check opening app=" + wtoken + ": allDrawn="
8046                        + wtoken.allDrawn + " startingDisplayed="
8047                        + wtoken.startingDisplayed + " startingMoved="
8048                        + wtoken.startingMoved);
8049                if (!wtoken.allDrawn && !wtoken.startingDisplayed
8050                        && !wtoken.startingMoved) {
8051                    goodToGo = false;
8052                }
8053            }
8054        }
8055        if (goodToGo) {
8056            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
8057            int transit = mNextAppTransition;
8058            if (mSkipAppTransitionAnimation) {
8059                transit = WindowManagerPolicy.TRANSIT_UNSET;
8060            }
8061            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
8062            mAppTransitionReady = false;
8063            mAppTransitionRunning = true;
8064            mAppTransitionTimeout = false;
8065            mStartingIconInTransition = false;
8066            mSkipAppTransitionAnimation = false;
8067
8068            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8069
8070            rebuildAppWindowListLocked();
8071
8072            // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
8073            WindowState oldWallpaper =
8074                    mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
8075                        && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
8076                    ? null : mWallpaperTarget;
8077
8078            adjustWallpaperWindowsLocked();
8079            mInnerFields.mWallpaperMayChange = false;
8080
8081            // The top-most window will supply the layout params,
8082            // and we will determine it below.
8083            LayoutParams animLp = null;
8084            int bestAnimLayer = -1;
8085            boolean fullscreenAnim = false;
8086
8087            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8088                    "New wallpaper target=" + mWallpaperTarget
8089                    + ", oldWallpaper=" + oldWallpaper
8090                    + ", lower target=" + mLowerWallpaperTarget
8091                    + ", upper target=" + mUpperWallpaperTarget);
8092            int foundWallpapers = 0;
8093            // Do a first pass through the tokens for two
8094            // things:
8095            // (1) Determine if both the closing and opening
8096            // app token sets are wallpaper targets, in which
8097            // case special animations are needed
8098            // (since the wallpaper needs to stay static
8099            // behind them).
8100            // (2) Find the layout params of the top-most
8101            // application window in the tokens, which is
8102            // what will control the animation theme.
8103            final int NC = mClosingApps.size();
8104            NN = NC + mOpeningApps.size();
8105            for (i=0; i<NN; i++) {
8106                AppWindowToken wtoken;
8107                int mode;
8108                if (i < NC) {
8109                    wtoken = mClosingApps.get(i);
8110                    mode = 1;
8111                } else {
8112                    wtoken = mOpeningApps.get(i-NC);
8113                    mode = 2;
8114                }
8115                if (mLowerWallpaperTarget != null) {
8116                    if (mLowerWallpaperTarget.mAppToken == wtoken
8117                            || mUpperWallpaperTarget.mAppToken == wtoken) {
8118                        foundWallpapers |= mode;
8119                    }
8120                }
8121                if (wtoken.appFullscreen) {
8122                    WindowState ws = wtoken.findMainWindow();
8123                    if (ws != null) {
8124                        animLp = ws.mAttrs;
8125                        bestAnimLayer = ws.mLayer;
8126                        fullscreenAnim = true;
8127                    }
8128                } else if (!fullscreenAnim) {
8129                    WindowState ws = wtoken.findMainWindow();
8130                    if (ws != null) {
8131                        if (ws.mLayer > bestAnimLayer) {
8132                            animLp = ws.mAttrs;
8133                            bestAnimLayer = ws.mLayer;
8134                        }
8135                    }
8136                }
8137            }
8138
8139            if (foundWallpapers == 3) {
8140                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8141                        "Wallpaper animation!");
8142                switch (transit) {
8143                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
8144                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
8145                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
8146                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
8147                        break;
8148                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
8149                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
8150                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
8151                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
8152                        break;
8153                }
8154                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8155                        "New transit: " + transit);
8156            } else if ((oldWallpaper != null) && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
8157                // We are transitioning from an activity with
8158                // a wallpaper to one without.
8159                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
8160                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8161                        "New transit away from wallpaper: " + transit);
8162            } else if (mWallpaperTarget != null) {
8163                // We are transitioning from an activity without
8164                // a wallpaper to now showing the wallpaper
8165                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
8166                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8167                        "New transit into wallpaper: " + transit);
8168            }
8169
8170            // If all closing windows are obscured, then there is
8171            // no need to do an animation.  This is the case, for
8172            // example, when this transition is being done behind
8173            // the lock screen.
8174            if (!mPolicy.allowAppAnimationsLw()) {
8175                animLp = null;
8176            }
8177
8178            AppWindowToken topOpeningApp = null;
8179            int topOpeningLayer = 0;
8180
8181            NN = mOpeningApps.size();
8182            for (i=0; i<NN; i++) {
8183                AppWindowToken wtoken = mOpeningApps.get(i);
8184                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
8185                wtoken.mAppAnimator.clearThumbnail();
8186                wtoken.reportedVisible = false;
8187                wtoken.inPendingTransaction = false;
8188                wtoken.mAppAnimator.animation = null;
8189                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
8190                wtoken.updateReportedVisibilityLocked();
8191                wtoken.waitingToShow = false;
8192                mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked();
8193                if (animLp != null) {
8194                    int layer = -1;
8195                    for (int j=0; j<wtoken.windows.size(); j++) {
8196                        WindowState win = wtoken.windows.get(j);
8197                        if (win.mWinAnimator.mAnimLayer > layer) {
8198                            layer = win.mWinAnimator.mAnimLayer;
8199                        }
8200                    }
8201                    if (topOpeningApp == null || layer > topOpeningLayer) {
8202                        topOpeningApp = wtoken;
8203                        topOpeningLayer = layer;
8204                    }
8205                }
8206            }
8207            NN = mClosingApps.size();
8208            for (i=0; i<NN; i++) {
8209                AppWindowToken wtoken = mClosingApps.get(i);
8210                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8211                        "Now closing app" + wtoken);
8212                wtoken.mAppAnimator.clearThumbnail();
8213                wtoken.inPendingTransaction = false;
8214                wtoken.mAppAnimator.animation = null;
8215                setTokenVisibilityLocked(wtoken, animLp, false,
8216                        transit, false);
8217                wtoken.updateReportedVisibilityLocked();
8218                wtoken.waitingToHide = false;
8219                // Force the allDrawn flag, because we want to start
8220                // this guy's animations regardless of whether it's
8221                // gotten drawn.
8222                wtoken.allDrawn = true;
8223            }
8224
8225            if (mNextAppTransitionThumbnail != null && topOpeningApp != null
8226                    && topOpeningApp.mAppAnimator.animation != null) {
8227                // This thumbnail animation is very special, we need to have
8228                // an extra surface with the thumbnail included with the animation.
8229                Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
8230                        mNextAppTransitionThumbnail.getHeight());
8231                try {
8232                    Surface surface = new Surface(mFxSession, Process.myPid(),
8233                            "thumbnail anim", Display.DEFAULT_DISPLAY,
8234                            dirty.width(), dirty.height(),
8235                            PixelFormat.TRANSLUCENT, Surface.HIDDEN);
8236                    topOpeningApp.mAppAnimator.thumbnail = surface;
8237                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
8238                            + surface + ": CREATE");
8239                    Surface drawSurface = new Surface();
8240                    drawSurface.copyFrom(surface);
8241                    Canvas c = drawSurface.lockCanvas(dirty);
8242                    c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
8243                    drawSurface.unlockCanvasAndPost(c);
8244                    drawSurface.release();
8245                    topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
8246                    Animation anim = createThumbnailAnimationLocked(
8247                            transit, true, true, mNextAppTransitionDelayed);
8248                    topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
8249                    anim.restrictDuration(MAX_ANIMATION_DURATION);
8250                    anim.scaleCurrentDuration(mTransitionAnimationScale);
8251                    topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX;
8252                    topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY;
8253                } catch (Surface.OutOfResourcesException e) {
8254                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
8255                            + " h=" + dirty.height(), e);
8256                    topOpeningApp.mAppAnimator.clearThumbnail();
8257                }
8258            }
8259
8260            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
8261            mNextAppTransitionPackage = null;
8262            mNextAppTransitionThumbnail = null;
8263            scheduleAnimationCallback(mNextAppTransitionCallback);
8264            mNextAppTransitionCallback = null;
8265
8266            mOpeningApps.clear();
8267            mClosingApps.clear();
8268
8269            // This has changed the visibility of windows, so perform
8270            // a new layout to get them all up-to-date.
8271            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
8272                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8273            mLayoutNeeded = true;
8274            if (!moveInputMethodWindowsIfNeededLocked(true)) {
8275                assignLayersLocked();
8276            }
8277            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8278                    false /*updateInputWindows*/);
8279            mFocusMayChange = false;
8280        }
8281
8282        return changes;
8283    }
8284
8285    /**
8286     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8287     *
8288     * @return bitmap indicating if another pass through layout must be made.
8289     */
8290    private int handleAnimatingStoppedAndTransitionLocked() {
8291        int changes = 0;
8292
8293        mAppTransitionRunning = false;
8294        // Restore window app tokens to the ActivityManager views
8295        for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) {
8296            mAnimatingAppTokens.get(i).sendingToBottom = false;
8297        }
8298        mAnimatingAppTokens.clear();
8299        mAnimatingAppTokens.addAll(mAppTokens);
8300        rebuildAppWindowListLocked();
8301
8302        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8303        mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
8304        moveInputMethodWindowsIfNeededLocked(true);
8305        mInnerFields.mWallpaperMayChange = true;
8306        // Since the window list has been rebuilt, focus might
8307        // have to be recomputed since the actual order of windows
8308        // might have changed again.
8309        mFocusMayChange = true;
8310
8311        return changes;
8312    }
8313
8314    /**
8315     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8316     *
8317     * @return bitmap indicating if another pass through layout must be made.
8318     */
8319    private int animateAwayWallpaperLocked() {
8320        int changes = 0;
8321        WindowState oldWallpaper = mWallpaperTarget;
8322        if (mLowerWallpaperTarget != null
8323                && mLowerWallpaperTarget.mAppToken != null) {
8324            if (DEBUG_WALLPAPER) Slog.v(TAG,
8325                    "wallpaperForceHiding changed with lower="
8326                    + mLowerWallpaperTarget);
8327            if (DEBUG_WALLPAPER) Slog.v(TAG,
8328                    "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
8329                    " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
8330            if (mLowerWallpaperTarget.mAppToken.hidden) {
8331                // The lower target has become hidden before we
8332                // actually started the animation...  let's completely
8333                // re-evaluate everything.
8334                mLowerWallpaperTarget = mUpperWallpaperTarget = null;
8335                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8336            }
8337        }
8338        mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8339        if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
8340                + " NEW: " + mWallpaperTarget
8341                + " LOWER: " + mLowerWallpaperTarget);
8342        return changes;
8343    }
8344
8345    private void updateResizingWindows(final WindowState w) {
8346        final WindowStateAnimator winAnimator = w.mWinAnimator;
8347        if (w.mHasSurface && !w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
8348            w.mContentInsetsChanged |=
8349                    !w.mLastContentInsets.equals(w.mContentInsets);
8350            w.mVisibleInsetsChanged |=
8351                    !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8352            boolean configChanged =
8353                w.mConfiguration != mCurConfiguration
8354                && (w.mConfiguration == null
8355                        || mCurConfiguration.diff(w.mConfiguration) != 0);
8356            if (DEBUG_CONFIGURATION && configChanged) {
8357                Slog.v(TAG, "Win " + w + " config changed: "
8358                        + mCurConfiguration);
8359            }
8360            if (localLOGV) Slog.v(TAG, "Resizing " + w
8361                    + ": configChanged=" + configChanged
8362                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8363            w.mLastFrame.set(w.mFrame);
8364            if (w.mContentInsetsChanged
8365                    || w.mVisibleInsetsChanged
8366                    || winAnimator.mSurfaceResized
8367                    || configChanged) {
8368                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8369                    Slog.v(TAG, "Resize reasons: "
8370                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8371                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8372                            + " surfaceResized=" + winAnimator.mSurfaceResized
8373                            + " configChanged=" + configChanged);
8374                }
8375
8376                w.mLastContentInsets.set(w.mContentInsets);
8377                w.mLastVisibleInsets.set(w.mVisibleInsets);
8378                makeWindowFreezingScreenIfNeededLocked(w);
8379                // If the orientation is changing, then we need to
8380                // hold off on unfreezing the display until this
8381                // window has been redrawn; to do that, we need
8382                // to go through the process of getting informed
8383                // by the application when it has finished drawing.
8384                if (w.mOrientationChanging) {
8385                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
8386                            "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
8387                            + w + ", surface " + winAnimator.mSurface);
8388                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8389                    if (w.mAppToken != null) {
8390                        w.mAppToken.allDrawn = false;
8391                    }
8392                }
8393                if (!mResizingWindows.contains(w)) {
8394                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8395                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8396                            + "x" + winAnimator.mSurfaceH);
8397                    mResizingWindows.add(w);
8398                }
8399            } else if (w.mOrientationChanging) {
8400                if (w.isDrawnLw()) {
8401                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8402                            "Orientation not waiting for draw in "
8403                            + w + ", surface " + winAnimator.mSurface);
8404                    w.mOrientationChanging = false;
8405                }
8406            }
8407        }
8408    }
8409
8410    /**
8411     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8412     *
8413     * @param w WindowState this method is applied to.
8414     * @param currentTime The time which animations use for calculating transitions.
8415     * @param innerDw Width of app window.
8416     * @param innerDh Height of app window.
8417     */
8418    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8419                                         final int innerDw, final int innerDh) {
8420        final WindowManager.LayoutParams attrs = w.mAttrs;
8421        final int attrFlags = attrs.flags;
8422        final boolean canBeSeen = w.isDisplayedLw();
8423
8424        if (w.mHasSurface) {
8425            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8426                mInnerFields.mHoldScreen = w.mSession;
8427            }
8428            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8429                    && mInnerFields.mScreenBrightness < 0) {
8430                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8431            }
8432            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8433                    && mInnerFields.mButtonBrightness < 0) {
8434                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8435            }
8436            if (canBeSeen
8437                    && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8438                     || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8439                     || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
8440                mInnerFields.mSyswin = true;
8441            }
8442        }
8443
8444        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8445        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8446            // This window completely covers everything behind it,
8447            // so we want to leave all of them as undimmed (for
8448            // performance reasons).
8449            mInnerFields.mObscured = true;
8450        } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0
8451                && !(w.mAppToken != null && w.mAppToken.hiddenRequested)
8452                && !w.mExiting) {
8453            if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured);
8454            if (!mInnerFields.mDimming) {
8455                //Slog.i(TAG, "DIM BEHIND: " + w);
8456                mInnerFields.mDimming = true;
8457                final WindowStateAnimator winAnimator = w.mWinAnimator;
8458                if (!mAnimator.isDimming(winAnimator)) {
8459                    final int width, height;
8460                    if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
8461                        width = mDisplayInfo.logicalWidth;
8462                        height = mDisplayInfo.logicalHeight;
8463                    } else {
8464                        width = innerDw;
8465                        height = innerDh;
8466                    }
8467                    startDimming(winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount, width, height);
8468                }
8469            }
8470        }
8471    }
8472
8473    private void updateAllDrawnLocked() {
8474        // See if any windows have been drawn, so they (and others
8475        // associated with them) can now be shown.
8476        final ArrayList<AppWindowToken> appTokens = mAnimatingAppTokens;
8477        final int NT = appTokens.size();
8478        for (int i=0; i<NT; i++) {
8479            AppWindowToken wtoken = appTokens.get(i);
8480            if (!wtoken.allDrawn) {
8481                int numInteresting = wtoken.numInterestingWindows;
8482                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8483                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
8484                            "allDrawn: " + wtoken
8485                            + " interesting=" + numInteresting
8486                            + " drawn=" + wtoken.numDrawnWindows);
8487                    wtoken.allDrawn = true;
8488                }
8489            }
8490        }
8491    }
8492
8493    // "Something has changed!  Let's make it correct now."
8494    private final void performLayoutAndPlaceSurfacesLockedInner(
8495            boolean recoveringMemory) {
8496        if (DEBUG_WINDOW_TRACE) {
8497            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8498                    + Debug.getCallers(3));
8499        }
8500        if (mDisplay == null) {
8501            Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
8502            return;
8503        }
8504
8505        final long currentTime = SystemClock.uptimeMillis();
8506        final int dw = mDisplayInfo.logicalWidth;
8507        final int dh = mDisplayInfo.logicalHeight;
8508        final int innerDw = mDisplayInfo.appWidth;
8509        final int innerDh = mDisplayInfo.appHeight;
8510
8511        int i;
8512
8513        if (mFocusMayChange) {
8514            mFocusMayChange = false;
8515            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8516                    false /*updateInputWindows*/);
8517        }
8518
8519        // Initialize state of exiting tokens.
8520        for (i=mExitingTokens.size()-1; i>=0; i--) {
8521            mExitingTokens.get(i).hasVisible = false;
8522        }
8523
8524        // Initialize state of exiting applications.
8525        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8526            mExitingAppTokens.get(i).hasVisible = false;
8527        }
8528
8529        mInnerFields.mHoldScreen = null;
8530        mInnerFields.mScreenBrightness = -1;
8531        mInnerFields.mButtonBrightness = -1;
8532        mTransactionSequence++;
8533
8534        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8535                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8536
8537        Surface.openTransaction();
8538
8539        if (mWatermark != null) {
8540            mWatermark.positionSurface(dw, dh);
8541        }
8542        if (mStrictModeFlash != null) {
8543            mStrictModeFlash.positionSurface(dw, dh);
8544        }
8545
8546        try {
8547            int repeats = 0;
8548
8549            do {
8550                repeats++;
8551                if (repeats > 6) {
8552                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
8553                    mLayoutNeeded = false;
8554                    break;
8555                }
8556
8557                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
8558                    mPendingLayoutChanges);
8559
8560                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
8561                    if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8562                        assignLayersLocked();
8563                        mLayoutNeeded = true;
8564                    }
8565                }
8566
8567                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
8568                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
8569                    if (updateOrientationFromAppTokensLocked(true)) {
8570                        mLayoutNeeded = true;
8571                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8572                    }
8573                }
8574
8575                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8576                    mLayoutNeeded = true;
8577                }
8578
8579                // FIRST LOOP: Perform a layout, if needed.
8580                if (repeats < 4) {
8581                    performLayoutLockedInner(repeats == 1, false /*updateInputWindows*/);
8582                } else {
8583                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
8584                }
8585
8586                // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
8587                // it is animating.
8588                mPendingLayoutChanges = 0;
8589                if (DEBUG_LAYOUT_REPEATS)  debugLayoutRepeats("loop number " + mLayoutRepeatCount,
8590                    mPendingLayoutChanges);
8591                mPolicy.beginAnimationLw(dw, dh);
8592                for (i = mWindows.size() - 1; i >= 0; i--) {
8593                    WindowState w = mWindows.get(i);
8594                    if (w.mHasSurface) {
8595                        mPolicy.animatingWindowLw(w, w.mAttrs);
8596                    }
8597                }
8598                mPendingLayoutChanges |= mPolicy.finishAnimationLw();
8599                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishAnimationLw",
8600                    mPendingLayoutChanges);
8601            } while (mPendingLayoutChanges != 0);
8602
8603            final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
8604
8605            mInnerFields.mObscured = false;
8606            mInnerFields.mDimming = false;
8607            mInnerFields.mSyswin = false;
8608
8609            boolean focusDisplayed = false;
8610            boolean updateAllDrawn = false;
8611            final int N = mWindows.size();
8612            for (i=N-1; i>=0; i--) {
8613                WindowState w = mWindows.get(i);
8614
8615                final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
8616
8617                // Update effect.
8618                w.mObscured = mInnerFields.mObscured;
8619                if (!mInnerFields.mObscured) {
8620                    handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
8621                }
8622
8623                if (obscuredChanged && (mWallpaperTarget == w) && w.isVisibleLw()) {
8624                    // This is the wallpaper target and its obscured state
8625                    // changed... make sure the current wallaper's visibility
8626                    // has been updated accordingly.
8627                    updateWallpaperVisibilityLocked();
8628                }
8629
8630                final WindowStateAnimator winAnimator = w.mWinAnimator;
8631
8632                // If the window has moved due to its containing
8633                // content frame changing, then we'd like to animate
8634                // it.
8635                if (w.mHasSurface && w.shouldAnimateMove()) {
8636                    // Frame has moved, containing content frame
8637                    // has also moved, and we're not currently animating...
8638                    // let's do something.
8639                    Animation a = AnimationUtils.loadAnimation(mContext,
8640                            com.android.internal.R.anim.window_move_from_decor);
8641                    winAnimator.setAnimation(a);
8642                    winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
8643                    winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
8644                    try {
8645                        w.mClient.moved(w.mFrame.left, w.mFrame.top);
8646                    } catch (RemoteException e) {
8647                    }
8648                }
8649
8650                //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
8651                w.mContentChanged = false;
8652
8653                // Moved from updateWindowsAndWallpaperLocked().
8654                if (w.mHasSurface) {
8655                    // Take care of the window being ready to display.
8656                    if (winAnimator.commitFinishDrawingLocked(currentTime)) {
8657                        if ((w.mAttrs.flags
8658                                & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
8659                            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
8660                                    "First draw done in potential wallpaper target " + w);
8661                            mInnerFields.mWallpaperMayChange = true;
8662                            mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
8663                            if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
8664                                debugLayoutRepeats("wallpaper and commitFinishDrawingLocked true",
8665                                    mPendingLayoutChanges);
8666                            }
8667                        }
8668                    }
8669
8670                    winAnimator.setSurfaceBoundaries(recoveringMemory);
8671
8672                    final AppWindowToken atoken = w.mAppToken;
8673                    if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) {
8674                        Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
8675                            + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
8676                            + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
8677                    }
8678                    if (atoken != null
8679                            && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
8680                        if (atoken.lastTransactionSequence != mTransactionSequence) {
8681                            atoken.lastTransactionSequence = mTransactionSequence;
8682                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
8683                            atoken.startingDisplayed = false;
8684                        }
8685                        if ((w.isOnScreen() || winAnimator.mAttrType
8686                                == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
8687                                && !w.mExiting && !w.mDestroying) {
8688                            if (WindowManagerService.DEBUG_VISIBILITY ||
8689                                    WindowManagerService.DEBUG_ORIENTATION) {
8690                                Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
8691                                        + ", isAnimating=" + winAnimator.isAnimating());
8692                                if (!w.isDrawnLw()) {
8693                                    Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
8694                                            + " pv=" + w.mPolicyVisibility
8695                                            + " mDrawState=" + winAnimator.mDrawState
8696                                            + " ah=" + w.mAttachedHidden
8697                                            + " th=" + atoken.hiddenRequested
8698                                            + " a=" + winAnimator.mAnimating);
8699                                }
8700                            }
8701                            if (w != atoken.startingWindow) {
8702                                if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
8703                                    atoken.numInterestingWindows++;
8704                                    if (w.isDrawnLw()) {
8705                                        atoken.numDrawnWindows++;
8706                                        if (WindowManagerService.DEBUG_VISIBILITY ||
8707                                                WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
8708                                                "tokenMayBeDrawn: " + atoken
8709                                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
8710                                                + " mAppFreezing=" + w.mAppFreezing);
8711                                        updateAllDrawn = true;
8712                                    }
8713                                }
8714                            } else if (w.isDrawnLw()) {
8715                                atoken.startingDisplayed = true;
8716                            }
8717                        }
8718                    }
8719                }
8720
8721                if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) {
8722                    focusDisplayed = true;
8723                }
8724
8725                updateResizingWindows(w);
8726            }
8727
8728            if (updateAllDrawn) {
8729                updateAllDrawnLocked();
8730            }
8731
8732            if (focusDisplayed) {
8733                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8734            }
8735
8736            if (!mInnerFields.mDimming && mAnimator.isDimming()) {
8737                stopDimming();
8738            }
8739        } catch (RuntimeException e) {
8740            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
8741        } finally {
8742            Surface.closeTransaction();
8743        }
8744
8745        // If we are ready to perform an app transition, check through
8746        // all of the app tokens to be shown and see if they are ready
8747        // to go.
8748        if (mAppTransitionReady) {
8749            mPendingLayoutChanges |= handleAppTransitionReadyLocked();
8750            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
8751                mPendingLayoutChanges);
8752        }
8753
8754        mInnerFields.mAdjResult = 0;
8755
8756        if (!mAnimator.mAnimating && mAppTransitionRunning) {
8757            // We have finished the animation of an app transition.  To do
8758            // this, we have delayed a lot of operations like showing and
8759            // hiding apps, moving apps in Z-order, etc.  The app token list
8760            // reflects the correct Z-order, but the window list may now
8761            // be out of sync with it.  So here we will just rebuild the
8762            // entire app window list.  Fun!
8763            mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
8764            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
8765                mPendingLayoutChanges);
8766        }
8767
8768        if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 &&
8769                !mAppTransitionReady) {
8770            // At this point, there was a window with a wallpaper that
8771            // was force hiding other windows behind it, but now it
8772            // is going away.  This may be simple -- just animate
8773            // away the wallpaper and its window -- or it may be
8774            // hard -- the wallpaper now needs to be shown behind
8775            // something that was hidden.
8776            mPendingLayoutChanges |= animateAwayWallpaperLocked();
8777            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
8778                mPendingLayoutChanges);
8779        }
8780        mInnerFields.mWallpaperForceHidingChanged = false;
8781
8782        if (mInnerFields.mWallpaperMayChange) {
8783            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
8784                    "Wallpaper may change!  Adjusting");
8785            mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8786        }
8787
8788        if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8789            if (DEBUG_WALLPAPER) Slog.v(TAG,
8790                    "Wallpaper layer changed: assigning layers + relayout");
8791            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8792            assignLayersLocked();
8793        } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
8794            if (DEBUG_WALLPAPER) Slog.v(TAG,
8795                    "Wallpaper visibility changed: relayout");
8796            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8797        }
8798
8799        if (mFocusMayChange) {
8800            mFocusMayChange = false;
8801            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8802                    false /*updateInputWindows*/)) {
8803                mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8804                mInnerFields.mAdjResult = 0;
8805            }
8806        }
8807
8808        if (mLayoutNeeded) {
8809            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8810            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges);
8811        }
8812
8813        if (!mResizingWindows.isEmpty()) {
8814            for (i = mResizingWindows.size() - 1; i >= 0; i--) {
8815                WindowState win = mResizingWindows.get(i);
8816                final WindowStateAnimator winAnimator = win.mWinAnimator;
8817                try {
8818                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8819                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
8820                    int diff = 0;
8821                    boolean configChanged =
8822                        win.mConfiguration != mCurConfiguration
8823                        && (win.mConfiguration == null
8824                                || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0);
8825                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
8826                            && configChanged) {
8827                        Slog.i(TAG, "Sending new config to window " + win + ": "
8828                                + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
8829                                + " / " + mCurConfiguration + " / 0x"
8830                                + Integer.toHexString(diff));
8831                    }
8832                    win.mConfiguration = mCurConfiguration;
8833                    if (DEBUG_ORIENTATION &&
8834                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
8835                            TAG, "Resizing " + win + " WITH DRAW PENDING");
8836                    win.mClient.resized((int)winAnimator.mSurfaceW,
8837                            (int)winAnimator.mSurfaceH,
8838                            win.mLastContentInsets, win.mLastVisibleInsets,
8839                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
8840                            configChanged ? win.mConfiguration : null);
8841                    win.mContentInsetsChanged = false;
8842                    win.mVisibleInsetsChanged = false;
8843                    winAnimator.mSurfaceResized = false;
8844                } catch (RemoteException e) {
8845                    win.mOrientationChanging = false;
8846                }
8847            }
8848            mResizingWindows.clear();
8849        }
8850
8851        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
8852                "With display frozen, orientationChangeComplete="
8853                + mInnerFields.mOrientationChangeComplete);
8854        if (mInnerFields.mOrientationChangeComplete) {
8855            if (mWindowsFreezingScreen) {
8856                mWindowsFreezingScreen = false;
8857                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8858            }
8859            stopFreezingDisplayLocked();
8860        }
8861
8862        // Destroy the surface of any windows that are no longer visible.
8863        boolean wallpaperDestroyed = false;
8864        i = mDestroySurface.size();
8865        if (i > 0) {
8866            do {
8867                i--;
8868                WindowState win = mDestroySurface.get(i);
8869                win.mDestroying = false;
8870                if (mInputMethodWindow == win) {
8871                    mInputMethodWindow = null;
8872                }
8873                if (win == mWallpaperTarget) {
8874                    wallpaperDestroyed = true;
8875                }
8876                win.mWinAnimator.destroySurfaceLocked();
8877            } while (i > 0);
8878            mDestroySurface.clear();
8879        }
8880
8881        // Time to remove any exiting tokens?
8882        for (i=mExitingTokens.size()-1; i>=0; i--) {
8883            WindowToken token = mExitingTokens.get(i);
8884            if (!token.hasVisible) {
8885                mExitingTokens.remove(i);
8886                if (token.windowType == TYPE_WALLPAPER) {
8887                    mWallpaperTokens.remove(token);
8888                    updateLayoutToAnimWallpaperTokens();
8889                }
8890            }
8891        }
8892
8893        // Time to remove any exiting applications?
8894        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8895            AppWindowToken token = mExitingAppTokens.get(i);
8896            if (!token.hasVisible && !mClosingApps.contains(token)) {
8897                // Make sure there is no animation running on this token,
8898                // so any windows associated with it will be removed as
8899                // soon as their animations are complete
8900                token.mAppAnimator.clearAnimation();
8901                token.mAppAnimator.animating = false;
8902                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
8903                        "performLayout: App token exiting now removed" + token);
8904                mAppTokens.remove(token);
8905                mAnimatingAppTokens.remove(token);
8906                mExitingAppTokens.remove(i);
8907            }
8908        }
8909
8910        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
8911            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
8912                try {
8913                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
8914                } catch (RemoteException e) {
8915                }
8916            }
8917            mRelayoutWhileAnimating.clear();
8918        }
8919
8920        if (wallpaperDestroyed) {
8921            mLayoutNeeded |= adjustWallpaperWindowsLocked() != 0;
8922        }
8923        if (mPendingLayoutChanges != 0) {
8924            mLayoutNeeded = true;
8925        }
8926
8927        // Finally update all input windows now that the window changes have stabilized.
8928        mInputMonitor.updateInputWindowsLw(true /*force*/);
8929
8930        setHoldScreenLocked(mInnerFields.mHoldScreen != null);
8931        if (!mDisplayFrozen) {
8932            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
8933                mPowerManager.setScreenBrightnessOverride(-1);
8934            } else {
8935                mPowerManager.setScreenBrightnessOverride((int)
8936                        (mInnerFields.mScreenBrightness * PowerManager.BRIGHTNESS_ON));
8937            }
8938            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
8939                mPowerManager.setButtonBrightnessOverride(-1);
8940            } else {
8941                mPowerManager.setButtonBrightnessOverride((int)
8942                        (mInnerFields.mButtonBrightness * PowerManager.BRIGHTNESS_ON));
8943            }
8944        }
8945        if (mInnerFields.mHoldScreen != mHoldingScreenOn) {
8946            mHoldingScreenOn = mInnerFields.mHoldScreen;
8947            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, mInnerFields.mHoldScreen);
8948            mH.sendMessage(m);
8949        }
8950
8951        if (mTurnOnScreen) {
8952            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
8953            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
8954                    PowerManager.USER_ACTIVITY_EVENT_BUTTON, true);
8955            mTurnOnScreen = false;
8956        }
8957
8958        if (mInnerFields.mUpdateRotation) {
8959            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8960            if (updateRotationUncheckedLocked(false)) {
8961                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8962            } else {
8963                mInnerFields.mUpdateRotation = false;
8964            }
8965        }
8966
8967        if (mInnerFields.mOrientationChangeComplete && !mLayoutNeeded &&
8968                !mInnerFields.mUpdateRotation) {
8969            checkDrawnWindowsLocked();
8970        }
8971
8972        // Check to see if we are now in a state where the screen should
8973        // be enabled, because the window obscured flags have changed.
8974        enableScreenIfNeededLocked();
8975
8976        updateLayoutToAnimationLocked();
8977
8978        if (DEBUG_WINDOW_TRACE) {
8979            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges="
8980                + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded
8981                + " animating=" + mAnimator.mAnimating);
8982        }
8983    }
8984
8985    void checkDrawnWindowsLocked() {
8986        if (mWaitingForDrawn.size() > 0) {
8987            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
8988                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
8989                WindowState win = pair.first;
8990                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
8991                //        + win.mRemoved + " visible=" + win.isVisibleLw()
8992                //        + " shown=" + win.mSurfaceShown);
8993                if (win.mRemoved || !win.isVisibleLw()) {
8994                    // Window has been removed or made invisible; no draw
8995                    // will now happen, so stop waiting.
8996                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
8997                    try {
8998                        pair.second.sendResult(null);
8999                    } catch (RemoteException e) {
9000                    }
9001                    mWaitingForDrawn.remove(pair);
9002                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9003                } else if (win.mWinAnimator.mSurfaceShown) {
9004                    // Window is now drawn (and shown).
9005                    try {
9006                        pair.second.sendResult(null);
9007                    } catch (RemoteException e) {
9008                    }
9009                    mWaitingForDrawn.remove(pair);
9010                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9011                }
9012            }
9013        }
9014    }
9015
9016    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
9017        synchronized (mWindowMap) {
9018            WindowState win = windowForClientLocked(null, token, true);
9019            if (win != null) {
9020                Pair<WindowState, IRemoteCallback> pair =
9021                        new Pair<WindowState, IRemoteCallback>(win, callback);
9022                Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9023                mH.sendMessageDelayed(m, 2000);
9024                mWaitingForDrawn.add(pair);
9025                checkDrawnWindowsLocked();
9026            }
9027        }
9028    }
9029
9030    /**
9031     * Must be called with the main window manager lock held.
9032     */
9033    void setHoldScreenLocked(boolean holding) {
9034        boolean state = mHoldingScreenWakeLock.isHeld();
9035        if (holding != state) {
9036            if (holding) {
9037                mPolicy.screenOnStartedLw();
9038                mHoldingScreenWakeLock.acquire();
9039            } else {
9040                mPolicy.screenOnStoppedLw();
9041                mHoldingScreenWakeLock.release();
9042            }
9043        }
9044    }
9045
9046    void requestTraversalLocked() {
9047        if (!mTraversalScheduled) {
9048            mTraversalScheduled = true;
9049            mH.sendEmptyMessage(H.DO_TRAVERSAL);
9050        }
9051    }
9052
9053    /** Note that Locked in this case is on mLayoutToAnim */
9054    void scheduleAnimationLocked() {
9055        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
9056        if (!layoutToAnim.mAnimationScheduled) {
9057            layoutToAnim.mAnimationScheduled = true;
9058            mChoreographer.postCallback(
9059                    Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
9060        }
9061    }
9062
9063    void updateLayoutToAnimationLocked() {
9064        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
9065        synchronized (layoutToAnim) {
9066            // Copy local params to transfer params.
9067            ArrayList<WindowStateAnimator> winAnimators = layoutToAnim.mWinAnimators;
9068            winAnimators.clear();
9069            int N = mWindows.size();
9070            for (int i = 0; i < N; i++) {
9071                final WindowStateAnimator winAnimator = mWindows.get(i).mWinAnimator;
9072                if (winAnimator.mSurface != null) {
9073                    winAnimators.add(winAnimator);
9074                }
9075            }
9076
9077            layoutToAnim.mWallpaperTarget = mWallpaperTarget;
9078            layoutToAnim.mLowerWallpaperTarget = mLowerWallpaperTarget;
9079            layoutToAnim.mUpperWallpaperTarget = mUpperWallpaperTarget;
9080
9081            final ArrayList<AppWindowAnimParams> paramList = layoutToAnim.mAppWindowAnimParams;
9082            paramList.clear();
9083            N = mAnimatingAppTokens.size();
9084            for (int i = 0; i < N; i++) {
9085                paramList.add(new AppWindowAnimParams(mAnimatingAppTokens.get(i).mAppAnimator));
9086            }
9087
9088            layoutToAnim.mParamsModified = true;
9089            scheduleAnimationLocked();
9090        }
9091    }
9092
9093    void updateLayoutToAnimWallpaperTokens() {
9094        synchronized(mLayoutToAnim) {
9095            mLayoutToAnim.mWallpaperTokens = new ArrayList<WindowToken>(mWallpaperTokens);
9096            mLayoutToAnim.mChanges |= LayoutToAnimatorParams.WALLPAPER_TOKENS_CHANGED;
9097        }
9098    }
9099
9100    void setAnimDimParams(DimAnimator.Parameters params) {
9101        synchronized (mLayoutToAnim) {
9102            mLayoutToAnim.mDimParams = params;
9103            scheduleAnimationLocked();
9104        }
9105    }
9106
9107    void startDimming(final WindowStateAnimator winAnimator, final float target,
9108                      final int width, final int height) {
9109        setAnimDimParams(new DimAnimator.Parameters(winAnimator, width, height, target));
9110    }
9111
9112    void stopDimming() {
9113        setAnimDimParams(null);
9114    }
9115
9116    private boolean copyAnimToLayoutParamsLocked() {
9117        boolean doRequest = false;
9118        final WindowAnimator.AnimatorToLayoutParams animToLayout = mAnimator.mAnimToLayout;
9119        synchronized (animToLayout) {
9120            animToLayout.mUpdateQueued = false;
9121            final int bulkUpdateParams = animToLayout.mBulkUpdateParams;
9122            // TODO(cmautner): As the number of bits grows, use masks of bit groups to
9123            //  eliminate unnecessary tests.
9124            if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
9125                mInnerFields.mUpdateRotation = true;
9126                doRequest = true;
9127            }
9128            if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
9129                mInnerFields.mWallpaperMayChange = true;
9130                doRequest = true;
9131            }
9132            if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
9133                mInnerFields.mWallpaperForceHidingChanged = true;
9134                doRequest = true;
9135            }
9136            if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
9137                mInnerFields.mOrientationChangeComplete = false;
9138            } else {
9139                mInnerFields.mOrientationChangeComplete = true;
9140                if (mWindowsFreezingScreen) {
9141                    doRequest = true;
9142                }
9143            }
9144            if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
9145                mTurnOnScreen = true;
9146            }
9147
9148            mPendingLayoutChanges |= animToLayout.mPendingLayoutChanges;
9149            if (mPendingLayoutChanges != 0) {
9150                doRequest = true;
9151            }
9152
9153            mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper;
9154        }
9155        return doRequest;
9156    }
9157
9158    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
9159                                           boolean secure) {
9160        final Surface surface = winAnimator.mSurface;
9161        boolean leakedSurface = false;
9162        boolean killedApps = false;
9163
9164        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
9165                winAnimator.mSession.mPid, operation);
9166
9167        if (mForceRemoves == null) {
9168            mForceRemoves = new ArrayList<WindowState>();
9169        }
9170
9171        long callingIdentity = Binder.clearCallingIdentity();
9172        try {
9173            // There was some problem...   first, do a sanity check of the
9174            // window list to make sure we haven't left any dangling surfaces
9175            // around.
9176            int N = mWindows.size();
9177            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
9178            for (int i=0; i<N; i++) {
9179                WindowState ws = mWindows.get(i);
9180                WindowStateAnimator wsa = ws.mWinAnimator;
9181                if (wsa.mSurface != null) {
9182                    if (!mSessions.contains(wsa.mSession)) {
9183                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
9184                                + ws + " surface=" + wsa.mSurface
9185                                + " token=" + ws.mToken
9186                                + " pid=" + ws.mSession.mPid
9187                                + " uid=" + ws.mSession.mUid);
9188                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9189                        wsa.mSurface.destroy();
9190                        wsa.mSurfaceShown = false;
9191                        wsa.mSurface = null;
9192                        ws.mHasSurface = false;
9193                        mForceRemoves.add(ws);
9194                        i--;
9195                        N--;
9196                        leakedSurface = true;
9197                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
9198                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
9199                                + ws + " surface=" + wsa.mSurface
9200                                + " token=" + ws.mAppToken);
9201                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9202                        wsa.mSurface.destroy();
9203                        wsa.mSurfaceShown = false;
9204                        wsa.mSurface = null;
9205                        ws.mHasSurface = false;
9206                        leakedSurface = true;
9207                    }
9208                }
9209            }
9210
9211            if (!leakedSurface) {
9212                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
9213                SparseIntArray pidCandidates = new SparseIntArray();
9214                for (int i=0; i<N; i++) {
9215                    WindowStateAnimator wsa = mWindows.get(i).mWinAnimator;
9216                    if (wsa.mSurface != null) {
9217                        pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
9218                    }
9219                }
9220                if (pidCandidates.size() > 0) {
9221                    int[] pids = new int[pidCandidates.size()];
9222                    for (int i=0; i<pids.length; i++) {
9223                        pids[i] = pidCandidates.keyAt(i);
9224                    }
9225                    try {
9226                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
9227                            killedApps = true;
9228                        }
9229                    } catch (RemoteException e) {
9230                    }
9231                }
9232            }
9233
9234            if (leakedSurface || killedApps) {
9235                // We managed to reclaim some memory, so get rid of the trouble
9236                // surface and ask the app to request another one.
9237                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9238                if (surface != null) {
9239                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
9240                            "RECOVER DESTROY", null);
9241                    surface.destroy();
9242                    winAnimator.mSurfaceShown = false;
9243                    winAnimator.mSurface = null;
9244                    winAnimator.mWin.mHasSurface = false;
9245                }
9246
9247                try {
9248                    winAnimator.mWin.mClient.dispatchGetNewSurface();
9249                } catch (RemoteException e) {
9250                }
9251            }
9252        } finally {
9253            Binder.restoreCallingIdentity(callingIdentity);
9254        }
9255
9256        return leakedSurface || killedApps;
9257    }
9258
9259    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9260        WindowState newFocus = computeFocusedWindowLocked();
9261        if (mCurrentFocus != newFocus) {
9262            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
9263            // This check makes sure that we don't already have the focus
9264            // change message pending.
9265            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9266            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9267            if (localLOGV) Slog.v(
9268                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
9269            final WindowState oldFocus = mCurrentFocus;
9270            mCurrentFocus = newFocus;
9271            mAnimator.setCurrentFocus(newFocus);
9272            mLosingFocus.remove(newFocus);
9273            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9274
9275            final WindowState imWindow = mInputMethodWindow;
9276            if (newFocus != imWindow && oldFocus != imWindow) {
9277                if (moveInputMethodWindowsIfNeededLocked(
9278                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
9279                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
9280                    mLayoutNeeded = true;
9281                }
9282                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9283                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
9284                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9285                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9286                    // Client will do the layout, but we need to assign layers
9287                    // for handleNewWindowLocked() below.
9288                    assignLayersLocked();
9289                }
9290            }
9291
9292            if ((focusChanged&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9293                // The change in focus caused us to need to do a layout.  Okay.
9294                mLayoutNeeded = true;
9295                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9296                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
9297                }
9298            }
9299
9300            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9301                // If we defer assigning layers, then the caller is responsible for
9302                // doing this part.
9303                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9304            }
9305
9306            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
9307            return true;
9308        }
9309        return false;
9310    }
9311
9312    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9313        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9314    }
9315
9316    private WindowState computeFocusedWindowLocked() {
9317        WindowState result = null;
9318        WindowState win;
9319
9320        if (mAnimator.mUniverseBackground != null
9321                && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) {
9322            return mAnimator.mUniverseBackground.mWin;
9323        }
9324
9325        int nextAppIndex = mAppTokens.size()-1;
9326        WindowToken nextApp = nextAppIndex >= 0
9327            ? mAppTokens.get(nextAppIndex) : null;
9328
9329        for (int i = mWindows.size() - 1; i >= 0; i--) {
9330            win = mWindows.get(i);
9331
9332            if (localLOGV || DEBUG_FOCUS) Slog.v(
9333                TAG, "Looking for focus: " + i
9334                + " = " + win
9335                + ", flags=" + win.mAttrs.flags
9336                + ", canReceive=" + win.canReceiveKeys());
9337
9338            AppWindowToken thisApp = win.mAppToken;
9339
9340            // If this window's application has been removed, just skip it.
9341            if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
9342                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping app because " + (thisApp.removed
9343                        ? "removed" : "sendingToBottom"));
9344                continue;
9345            }
9346
9347            // If there is a focused app, don't allow focus to go to any
9348            // windows below it.  If this is an application window, step
9349            // through the app tokens until we find its app.
9350            if (thisApp != null && nextApp != null && thisApp != nextApp
9351                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
9352                int origAppIndex = nextAppIndex;
9353                while (nextAppIndex > 0) {
9354                    if (nextApp == mFocusedApp) {
9355                        // Whoops, we are below the focused app...  no focus
9356                        // for you!
9357                        if (localLOGV || DEBUG_FOCUS) Slog.v(
9358                            TAG, "Reached focused app: " + mFocusedApp);
9359                        return null;
9360                    }
9361                    nextAppIndex--;
9362                    nextApp = mAppTokens.get(nextAppIndex);
9363                    if (nextApp == thisApp) {
9364                        break;
9365                    }
9366                }
9367                if (thisApp != nextApp) {
9368                    // Uh oh, the app token doesn't exist!  This shouldn't
9369                    // happen, but if it does we can get totally hosed...
9370                    // so restart at the original app.
9371                    nextAppIndex = origAppIndex;
9372                    nextApp = mAppTokens.get(nextAppIndex);
9373                }
9374            }
9375
9376            // Dispatch to this window if it is wants key events.
9377            if (win.canReceiveKeys()) {
9378                if (DEBUG_FOCUS) Slog.v(
9379                        TAG, "Found focus @ " + i + " = " + win);
9380                result = win;
9381                break;
9382            }
9383        }
9384
9385        return result;
9386    }
9387
9388    private void startFreezingDisplayLocked(boolean inTransaction) {
9389        if (mDisplayFrozen) {
9390            return;
9391        }
9392
9393        if (mDisplay == null || !mPolicy.isScreenOnFully()) {
9394            // No need to freeze the screen before the system is ready or if
9395            // the screen is off.
9396            return;
9397        }
9398
9399        mScreenFrozenLock.acquire();
9400
9401        mDisplayFrozen = true;
9402
9403        mInputMonitor.freezeInputDispatchingLw();
9404
9405        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
9406            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
9407            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
9408            mNextAppTransitionPackage = null;
9409            mNextAppTransitionThumbnail = null;
9410            mAppTransitionReady = true;
9411        }
9412
9413        if (PROFILE_ORIENTATION) {
9414            File file = new File("/data/system/frozen");
9415            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9416        }
9417
9418        if (CUSTOM_SCREEN_ROTATION) {
9419            if (mAnimator.mScreenRotationAnimation != null) {
9420                mAnimator.mScreenRotationAnimation.kill();
9421                mAnimator.mScreenRotationAnimation = null;
9422            }
9423
9424            mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
9425                    mFxSession, inTransaction, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
9426                    mDisplay.getRotation());
9427        }
9428    }
9429
9430    private void stopFreezingDisplayLocked() {
9431        if (!mDisplayFrozen) {
9432            return;
9433        }
9434
9435        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
9436            if (DEBUG_ORIENTATION) Slog.d(TAG,
9437                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
9438                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
9439                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen);
9440            return;
9441        }
9442
9443        mDisplayFrozen = false;
9444        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9445        if (PROFILE_ORIENTATION) {
9446            Debug.stopMethodTracing();
9447        }
9448
9449        boolean updateRotation = false;
9450
9451        if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
9452                && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
9453            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
9454            if (mAnimator.mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9455                    mTransitionAnimationScale, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) {
9456                updateLayoutToAnimationLocked();
9457            } else {
9458                mAnimator.mScreenRotationAnimation.kill();
9459                mAnimator.mScreenRotationAnimation = null;
9460                updateRotation = true;
9461            }
9462        } else {
9463            if (mAnimator.mScreenRotationAnimation != null) {
9464                mAnimator.mScreenRotationAnimation.kill();
9465                mAnimator.mScreenRotationAnimation = null;
9466            }
9467            updateRotation = true;
9468        }
9469
9470        mInputMonitor.thawInputDispatchingLw();
9471
9472        boolean configChanged;
9473
9474        // While the display is frozen we don't re-compute the orientation
9475        // to avoid inconsistent states.  However, something interesting
9476        // could have actually changed during that time so re-evaluate it
9477        // now to catch that.
9478        configChanged = updateOrientationFromAppTokensLocked(false);
9479
9480        // A little kludge: a lot could have happened while the
9481        // display was frozen, so now that we are coming back we
9482        // do a gc so that any remote references the system
9483        // processes holds on others can be released if they are
9484        // no longer needed.
9485        mH.removeMessages(H.FORCE_GC);
9486        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
9487                2000);
9488
9489        mScreenFrozenLock.release();
9490
9491        if (updateRotation) {
9492            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9493            configChanged |= updateRotationUncheckedLocked(false);
9494        }
9495
9496        if (configChanged) {
9497            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9498        }
9499    }
9500
9501    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
9502            DisplayMetrics dm) {
9503        if (index < tokens.length) {
9504            String str = tokens[index];
9505            if (str != null && str.length() > 0) {
9506                try {
9507                    int val = Integer.parseInt(str);
9508                    return val;
9509                } catch (Exception e) {
9510                }
9511            }
9512        }
9513        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
9514            return defDps;
9515        }
9516        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
9517        return val;
9518    }
9519
9520    void createWatermark() {
9521        if (mWatermark != null) {
9522            return;
9523        }
9524
9525        File file = new File("/system/etc/setup.conf");
9526        FileInputStream in = null;
9527        try {
9528            in = new FileInputStream(file);
9529            DataInputStream ind = new DataInputStream(in);
9530            String line = ind.readLine();
9531            if (line != null) {
9532                String[] toks = line.split("%");
9533                if (toks != null && toks.length > 0) {
9534                    mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks);
9535                }
9536            }
9537        } catch (FileNotFoundException e) {
9538        } catch (IOException e) {
9539        } finally {
9540            if (in != null) {
9541                try {
9542                    in.close();
9543                } catch (IOException e) {
9544                }
9545            }
9546        }
9547    }
9548
9549    @Override
9550    public void statusBarVisibilityChanged(int visibility) {
9551        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
9552                != PackageManager.PERMISSION_GRANTED) {
9553            throw new SecurityException("Caller does not hold permission "
9554                    + android.Manifest.permission.STATUS_BAR);
9555        }
9556
9557        synchronized (mWindowMap) {
9558            mLastStatusBarVisibility = visibility;
9559            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
9560            updateStatusBarVisibilityLocked(visibility);
9561        }
9562    }
9563
9564    void updateStatusBarVisibilityLocked(int visibility) {
9565        mInputManager.setSystemUiVisibility(visibility);
9566        final int N = mWindows.size();
9567        for (int i = 0; i < N; i++) {
9568            WindowState ws = mWindows.get(i);
9569            try {
9570                int curValue = ws.mSystemUiVisibility;
9571                int diff = curValue ^ visibility;
9572                // We are only interested in differences of one of the
9573                // clearable flags...
9574                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
9575                // ...if it has actually been cleared.
9576                diff &= ~visibility;
9577                int newValue = (curValue&~diff) | (visibility&diff);
9578                if (newValue != curValue) {
9579                    ws.mSeq++;
9580                    ws.mSystemUiVisibility = newValue;
9581                }
9582                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
9583                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
9584                            visibility, newValue, diff);
9585                }
9586            } catch (RemoteException e) {
9587                // so sorry
9588            }
9589        }
9590    }
9591
9592    @Override
9593    public void reevaluateStatusBarVisibility() {
9594        synchronized (mWindowMap) {
9595            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
9596            updateStatusBarVisibilityLocked(visibility);
9597            performLayoutAndPlaceSurfacesLocked();
9598        }
9599    }
9600
9601    @Override
9602    public FakeWindow addFakeWindow(Looper looper,
9603            InputEventReceiver.Factory inputEventReceiverFactory,
9604            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
9605            boolean hasFocus, boolean touchFullscreen) {
9606        synchronized (mWindowMap) {
9607            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
9608                    name, windowType,
9609                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
9610            int i=0;
9611            while (i<mFakeWindows.size()) {
9612                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
9613                    break;
9614                }
9615            }
9616            mFakeWindows.add(i, fw);
9617            mInputMonitor.updateInputWindowsLw(true);
9618            return fw;
9619        }
9620    }
9621
9622    boolean removeFakeWindowLocked(FakeWindow window) {
9623        synchronized (mWindowMap) {
9624            if (mFakeWindows.remove(window)) {
9625                mInputMonitor.updateInputWindowsLw(true);
9626                return true;
9627            }
9628            return false;
9629        }
9630    }
9631
9632    // It is assumed that this method is called only by InputMethodManagerService.
9633    public void saveLastInputMethodWindowForTransition() {
9634        synchronized (mWindowMap) {
9635            if (mInputMethodWindow != null) {
9636                mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
9637            }
9638        }
9639    }
9640
9641    @Override
9642    public boolean hasNavigationBar() {
9643        return mPolicy.hasNavigationBar();
9644    }
9645
9646    public void lockNow() {
9647        mPolicy.lockNow();
9648    }
9649
9650    void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
9651        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
9652        mPolicy.dump("    ", pw, args);
9653    }
9654
9655    void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
9656        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
9657        if (mTokenMap.size() > 0) {
9658            pw.println("  All tokens:");
9659            Iterator<WindowToken> it = mTokenMap.values().iterator();
9660            while (it.hasNext()) {
9661                WindowToken token = it.next();
9662                pw.print("  Token "); pw.print(token.token);
9663                if (dumpAll) {
9664                    pw.println(':');
9665                    token.dump(pw, "    ");
9666                } else {
9667                    pw.println();
9668                }
9669            }
9670        }
9671        if (mWallpaperTokens.size() > 0) {
9672            pw.println();
9673            pw.println("  Wallpaper tokens:");
9674            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
9675                WindowToken token = mWallpaperTokens.get(i);
9676                pw.print("  Wallpaper #"); pw.print(i);
9677                        pw.print(' '); pw.print(token);
9678                if (dumpAll) {
9679                    pw.println(':');
9680                    token.dump(pw, "    ");
9681                } else {
9682                    pw.println();
9683                }
9684            }
9685        }
9686        if (mAppTokens.size() > 0) {
9687            pw.println();
9688            pw.println("  Application tokens in Z order:");
9689            for (int i=mAppTokens.size()-1; i>=0; i--) {
9690                pw.print("  App #"); pw.print(i); pw.println(": ");
9691                        mAppTokens.get(i).dump(pw, "    ");
9692            }
9693        }
9694        if (mFinishedStarting.size() > 0) {
9695            pw.println();
9696            pw.println("  Finishing start of application tokens:");
9697            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9698                WindowToken token = mFinishedStarting.get(i);
9699                pw.print("  Finished Starting #"); pw.print(i);
9700                        pw.print(' '); pw.print(token);
9701                if (dumpAll) {
9702                    pw.println(':');
9703                    token.dump(pw, "    ");
9704                } else {
9705                    pw.println();
9706                }
9707            }
9708        }
9709        if (mExitingTokens.size() > 0) {
9710            pw.println();
9711            pw.println("  Exiting tokens:");
9712            for (int i=mExitingTokens.size()-1; i>=0; i--) {
9713                WindowToken token = mExitingTokens.get(i);
9714                pw.print("  Exiting #"); pw.print(i);
9715                        pw.print(' '); pw.print(token);
9716                if (dumpAll) {
9717                    pw.println(':');
9718                    token.dump(pw, "    ");
9719                } else {
9720                    pw.println();
9721                }
9722            }
9723        }
9724        if (mExitingAppTokens.size() > 0) {
9725            pw.println();
9726            pw.println("  Exiting application tokens:");
9727            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9728                WindowToken token = mExitingAppTokens.get(i);
9729                pw.print("  Exiting App #"); pw.print(i);
9730                        pw.print(' '); pw.print(token);
9731                if (dumpAll) {
9732                    pw.println(':');
9733                    token.dump(pw, "    ");
9734                } else {
9735                    pw.println();
9736                }
9737            }
9738        }
9739        if (mAppTransitionRunning && mAnimatingAppTokens.size() > 0) {
9740            pw.println();
9741            pw.println("  Application tokens during animation:");
9742            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
9743                WindowToken token = mAnimatingAppTokens.get(i);
9744                pw.print("  App moving to bottom #"); pw.print(i);
9745                        pw.print(' '); pw.print(token);
9746                if (dumpAll) {
9747                    pw.println(':');
9748                    token.dump(pw, "    ");
9749                } else {
9750                    pw.println();
9751                }
9752            }
9753        }
9754        if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
9755            pw.println();
9756            if (mOpeningApps.size() > 0) {
9757                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
9758            }
9759            if (mClosingApps.size() > 0) {
9760                pw.print("  mClosingApps="); pw.println(mClosingApps);
9761            }
9762        }
9763    }
9764
9765    void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
9766        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
9767        if (mSessions.size() > 0) {
9768            Iterator<Session> it = mSessions.iterator();
9769            while (it.hasNext()) {
9770                Session s = it.next();
9771                pw.print("  Session "); pw.print(s); pw.println(':');
9772                s.dump(pw, "    ");
9773            }
9774        }
9775    }
9776
9777    void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
9778            ArrayList<WindowState> windows) {
9779        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
9780        dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
9781    }
9782
9783    void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
9784            ArrayList<WindowState> windows) {
9785        for (int i=mWindows.size()-1; i>=0; i--) {
9786            WindowState w = mWindows.get(i);
9787            if (windows == null || windows.contains(w)) {
9788                pw.print("  Window #"); pw.print(i); pw.print(' ');
9789                        pw.print(w); pw.println(":");
9790                w.dump(pw, "    ", dumpAll || windows != null);
9791            }
9792        }
9793        if (mInputMethodDialogs.size() > 0) {
9794            pw.println();
9795            pw.println("  Input method dialogs:");
9796            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
9797                WindowState w = mInputMethodDialogs.get(i);
9798                if (windows == null || windows.contains(w)) {
9799                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
9800                }
9801            }
9802        }
9803        if (mPendingRemove.size() > 0) {
9804            pw.println();
9805            pw.println("  Remove pending for:");
9806            for (int i=mPendingRemove.size()-1; i>=0; i--) {
9807                WindowState w = mPendingRemove.get(i);
9808                if (windows == null || windows.contains(w)) {
9809                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
9810                            pw.print(w);
9811                    if (dumpAll) {
9812                        pw.println(":");
9813                        w.dump(pw, "    ", true);
9814                    } else {
9815                        pw.println();
9816                    }
9817                }
9818            }
9819        }
9820        if (mForceRemoves != null && mForceRemoves.size() > 0) {
9821            pw.println();
9822            pw.println("  Windows force removing:");
9823            for (int i=mForceRemoves.size()-1; i>=0; i--) {
9824                WindowState w = mForceRemoves.get(i);
9825                pw.print("  Removing #"); pw.print(i); pw.print(' ');
9826                        pw.print(w);
9827                if (dumpAll) {
9828                    pw.println(":");
9829                    w.dump(pw, "    ", true);
9830                } else {
9831                    pw.println();
9832                }
9833            }
9834        }
9835        if (mDestroySurface.size() > 0) {
9836            pw.println();
9837            pw.println("  Windows waiting to destroy their surface:");
9838            for (int i=mDestroySurface.size()-1; i>=0; i--) {
9839                WindowState w = mDestroySurface.get(i);
9840                if (windows == null || windows.contains(w)) {
9841                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
9842                            pw.print(w);
9843                    if (dumpAll) {
9844                        pw.println(":");
9845                        w.dump(pw, "    ", true);
9846                    } else {
9847                        pw.println();
9848                    }
9849                }
9850            }
9851        }
9852        if (mLosingFocus.size() > 0) {
9853            pw.println();
9854            pw.println("  Windows losing focus:");
9855            for (int i=mLosingFocus.size()-1; i>=0; i--) {
9856                WindowState w = mLosingFocus.get(i);
9857                if (windows == null || windows.contains(w)) {
9858                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
9859                            pw.print(w);
9860                    if (dumpAll) {
9861                        pw.println(":");
9862                        w.dump(pw, "    ", true);
9863                    } else {
9864                        pw.println();
9865                    }
9866                }
9867            }
9868        }
9869        if (mResizingWindows.size() > 0) {
9870            pw.println();
9871            pw.println("  Windows waiting to resize:");
9872            for (int i=mResizingWindows.size()-1; i>=0; i--) {
9873                WindowState w = mResizingWindows.get(i);
9874                if (windows == null || windows.contains(w)) {
9875                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
9876                            pw.print(w);
9877                    if (dumpAll) {
9878                        pw.println(":");
9879                        w.dump(pw, "    ", true);
9880                    } else {
9881                        pw.println();
9882                    }
9883                }
9884            }
9885        }
9886        if (mWaitingForDrawn.size() > 0) {
9887            pw.println();
9888            pw.println("  Clients waiting for these windows to be drawn:");
9889            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
9890                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
9891                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
9892                        pw.print(": "); pw.println(pair.second);
9893            }
9894        }
9895        pw.println();
9896        if (mDisplay != null) {
9897            pw.print("  Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
9898                    pw.print(mInitialDisplayHeight);
9899                    if (mInitialDisplayWidth != mBaseDisplayWidth
9900                            || mInitialDisplayHeight != mBaseDisplayHeight) {
9901                        pw.print(" base=");
9902                        pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
9903                    }
9904                    if (mInitialDisplayWidth != mDisplayInfo.logicalWidth
9905                            || mInitialDisplayHeight != mDisplayInfo.logicalHeight) {
9906                        pw.print(" init="); pw.print(mInitialDisplayWidth);
9907                        pw.print("x"); pw.print(mInitialDisplayHeight);
9908                    }
9909                    pw.print(" cur=");
9910                    pw.print(mDisplayInfo.logicalWidth);
9911                    pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
9912                    pw.print(" app=");
9913                    pw.print(mDisplayInfo.appWidth);
9914                    pw.print("x"); pw.print(mDisplayInfo.appHeight);
9915                    pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
9916                    pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
9917                    pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
9918                    pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
9919        } else {
9920            pw.println("  NO DISPLAY");
9921        }
9922        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
9923        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
9924        if (mLastFocus != mCurrentFocus) {
9925            pw.print("  mLastFocus="); pw.println(mLastFocus);
9926        }
9927        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
9928        if (mInputMethodTarget != null) {
9929            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
9930        }
9931        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
9932                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
9933        if (dumpAll) {
9934            pw.print("  mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
9935                    pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
9936                    pw.print(" mScreenRecr="); pw.println(mScreenRect.toShortString());
9937            if (mLastStatusBarVisibility != 0) {
9938                pw.print("  mLastStatusBarVisibility=0x");
9939                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
9940            }
9941            if (mInputMethodWindow != null) {
9942                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
9943            }
9944            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
9945            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
9946                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
9947                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
9948            }
9949            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
9950                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
9951            if (mInputMethodAnimLayerAdjustment != 0 ||
9952                    mWallpaperAnimLayerAdjustment != 0) {
9953                pw.print("  mInputMethodAnimLayerAdjustment=");
9954                        pw.print(mInputMethodAnimLayerAdjustment);
9955                        pw.print("  mWallpaperAnimLayerAdjustment=");
9956                        pw.println(mWallpaperAnimLayerAdjustment);
9957            }
9958            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
9959                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9960            pw.print("  mLayoutNeeded="); pw.print(mLayoutNeeded);
9961                    pw.print("mTransactionSequence="); pw.println(mTransactionSequence);
9962            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
9963                    pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9964                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
9965                    pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
9966            pw.print("  mRotation="); pw.print(mRotation);
9967                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
9968            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
9969                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
9970            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
9971            if (mAnimator.mScreenRotationAnimation != null) {
9972                pw.println("  mScreenRotationAnimation:");
9973                mAnimator.mScreenRotationAnimation.printTo("    ", pw);
9974            }
9975            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9976                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
9977                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
9978            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
9979                    pw.print(" mNextAppTransition=0x");
9980                    pw.print(Integer.toHexString(mNextAppTransition));
9981                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
9982            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
9983                    pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout);
9984            if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) {
9985                pw.print("  mNextAppTransitionType="); pw.println(mNextAppTransitionType);
9986            }
9987            switch (mNextAppTransitionType) {
9988                case ActivityOptions.ANIM_CUSTOM:
9989                    pw.print("  mNextAppTransitionPackage=");
9990                            pw.println(mNextAppTransitionPackage);
9991                    pw.print("  mNextAppTransitionEnter=0x");
9992                            pw.print(Integer.toHexString(mNextAppTransitionEnter));
9993                            pw.print(" mNextAppTransitionExit=0x");
9994                            pw.println(Integer.toHexString(mNextAppTransitionExit));
9995                    break;
9996                case ActivityOptions.ANIM_SCALE_UP:
9997                    pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
9998                            pw.print(" mNextAppTransitionStartY=");
9999                            pw.println(mNextAppTransitionStartY);
10000                    pw.print("  mNextAppTransitionStartWidth=");
10001                            pw.print(mNextAppTransitionStartWidth);
10002                            pw.print(" mNextAppTransitionStartHeight=");
10003                            pw.println(mNextAppTransitionStartHeight);
10004                    break;
10005                case ActivityOptions.ANIM_THUMBNAIL:
10006                case ActivityOptions.ANIM_THUMBNAIL_DELAYED:
10007                    pw.print("  mNextAppTransitionThumbnail=");
10008                            pw.print(mNextAppTransitionThumbnail);
10009                            pw.print(" mNextAppTransitionStartX=");
10010                            pw.print(mNextAppTransitionStartX);
10011                            pw.print(" mNextAppTransitionStartY=");
10012                            pw.println(mNextAppTransitionStartY);
10013                    pw.print("  mNextAppTransitionDelayed="); pw.println(mNextAppTransitionDelayed);
10014                    break;
10015            }
10016            if (mNextAppTransitionCallback != null) {
10017                pw.print("  mNextAppTransitionCallback=");
10018                        pw.println(mNextAppTransitionCallback);
10019            }
10020            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
10021                    pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
10022            pw.println("  Window Animator:");
10023            mAnimator.dump(pw, "    ", dumpAll);
10024        }
10025    }
10026
10027    boolean dumpWindows(PrintWriter pw, String name, String[] args,
10028            int opti, boolean dumpAll) {
10029        ArrayList<WindowState> windows = new ArrayList<WindowState>();
10030        if ("visible".equals(name)) {
10031            synchronized(mWindowMap) {
10032                for (int i=mWindows.size()-1; i>=0; i--) {
10033                    WindowState w = mWindows.get(i);
10034                    if (w.mWinAnimator.mSurfaceShown) {
10035                        windows.add(w);
10036                    }
10037                }
10038            }
10039        } else {
10040            int objectId = 0;
10041            // See if this is an object ID.
10042            try {
10043                objectId = Integer.parseInt(name, 16);
10044                name = null;
10045            } catch (RuntimeException e) {
10046            }
10047            synchronized(mWindowMap) {
10048                for (int i=mWindows.size()-1; i>=0; i--) {
10049                    WindowState w = mWindows.get(i);
10050                    if (name != null) {
10051                        if (w.mAttrs.getTitle().toString().contains(name)) {
10052                            windows.add(w);
10053                        }
10054                    } else if (System.identityHashCode(w) == objectId) {
10055                        windows.add(w);
10056                    }
10057                }
10058            }
10059        }
10060
10061        if (windows.size() <= 0) {
10062            return false;
10063        }
10064
10065        synchronized(mWindowMap) {
10066            dumpWindowsLocked(pw, dumpAll, windows);
10067        }
10068        return true;
10069    }
10070
10071    void dumpLastANRLocked(PrintWriter pw) {
10072        pw.println("WINDOW MANAGER LAST ANR (dumpsys window lastanr)");
10073        if (mLastANRState == null) {
10074            pw.println("  <no ANR has occurred since boot>");
10075        } else {
10076            pw.println(mLastANRState);
10077        }
10078    }
10079
10080    /**
10081     * Saves information about the state of the window manager at
10082     * the time an ANR occurred before anything else in the system changes
10083     * in response.
10084     *
10085     * @param appWindowToken The application that ANR'd, may be null.
10086     * @param windowState The window that ANR'd, may be null.
10087     */
10088    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState) {
10089        StringWriter sw = new StringWriter();
10090        PrintWriter pw = new PrintWriter(sw);
10091        pw.println("  ANR time: " + DateFormat.getInstance().format(new Date()));
10092        if (appWindowToken != null) {
10093            pw.println("  Application at fault: " + appWindowToken.stringName);
10094        }
10095        if (windowState != null) {
10096            pw.println("  Window at fault: " + windowState.mAttrs.getTitle());
10097        }
10098        pw.println();
10099        dumpWindowsNoHeaderLocked(pw, true, null);
10100        pw.close();
10101        mLastANRState = sw.toString();
10102    }
10103
10104    @Override
10105    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
10106        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
10107                != PackageManager.PERMISSION_GRANTED) {
10108            pw.println("Permission Denial: can't dump WindowManager from from pid="
10109                    + Binder.getCallingPid()
10110                    + ", uid=" + Binder.getCallingUid());
10111            return;
10112        }
10113
10114        boolean dumpAll = false;
10115
10116        int opti = 0;
10117        while (opti < args.length) {
10118            String opt = args[opti];
10119            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
10120                break;
10121            }
10122            opti++;
10123            if ("-a".equals(opt)) {
10124                dumpAll = true;
10125            } else if ("-h".equals(opt)) {
10126                pw.println("Window manager dump options:");
10127                pw.println("  [-a] [-h] [cmd] ...");
10128                pw.println("  cmd may be one of:");
10129                pw.println("    l[astanr]: last ANR information");
10130                pw.println("    p[policy]: policy state");
10131                pw.println("    s[essions]: active sessions");
10132                pw.println("    t[okens]: token list");
10133                pw.println("    w[indows]: window list");
10134                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
10135                pw.println("    be a partial substring in a window name, a");
10136                pw.println("    Window hex object identifier, or");
10137                pw.println("    \"all\" for all windows, or");
10138                pw.println("    \"visible\" for the visible windows.");
10139                pw.println("  -a: include all available server state.");
10140                return;
10141            } else {
10142                pw.println("Unknown argument: " + opt + "; use -h for help");
10143            }
10144        }
10145
10146        // Is the caller requesting to dump a particular piece of data?
10147        if (opti < args.length) {
10148            String cmd = args[opti];
10149            opti++;
10150            if ("lastanr".equals(cmd) || "l".equals(cmd)) {
10151                synchronized(mWindowMap) {
10152                    dumpLastANRLocked(pw);
10153                }
10154                return;
10155            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
10156                synchronized(mWindowMap) {
10157                    dumpPolicyLocked(pw, args, true);
10158                }
10159                return;
10160            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
10161                synchronized(mWindowMap) {
10162                    dumpSessionsLocked(pw, true);
10163                }
10164                return;
10165            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
10166                synchronized(mWindowMap) {
10167                    dumpTokensLocked(pw, true);
10168                }
10169                return;
10170            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
10171                synchronized(mWindowMap) {
10172                    dumpWindowsLocked(pw, true, null);
10173                }
10174                return;
10175            } else if ("all".equals(cmd) || "a".equals(cmd)) {
10176                synchronized(mWindowMap) {
10177                    dumpWindowsLocked(pw, true, null);
10178                }
10179                return;
10180            } else {
10181                // Dumping a single name?
10182                if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
10183                    pw.println("Bad window command, or no windows match: " + cmd);
10184                    pw.println("Use -h for help.");
10185                }
10186                return;
10187            }
10188        }
10189
10190        synchronized(mWindowMap) {
10191            pw.println();
10192            if (dumpAll) {
10193                pw.println("-------------------------------------------------------------------------------");
10194            }
10195            dumpLastANRLocked(pw);
10196            pw.println();
10197            if (dumpAll) {
10198                pw.println("-------------------------------------------------------------------------------");
10199            }
10200            dumpPolicyLocked(pw, args, dumpAll);
10201            pw.println();
10202            if (dumpAll) {
10203                pw.println("-------------------------------------------------------------------------------");
10204            }
10205            dumpSessionsLocked(pw, dumpAll);
10206            pw.println();
10207            if (dumpAll) {
10208                pw.println("-------------------------------------------------------------------------------");
10209            }
10210            dumpTokensLocked(pw, dumpAll);
10211            pw.println();
10212            if (dumpAll) {
10213                pw.println("-------------------------------------------------------------------------------");
10214            }
10215            dumpWindowsLocked(pw, dumpAll, null);
10216        }
10217    }
10218
10219    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
10220    public void monitor() {
10221        synchronized (mWindowMap) { }
10222        synchronized (mKeyguardTokenWatcher) { }
10223    }
10224
10225    public interface OnHardKeyboardStatusChangeListener {
10226        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
10227    }
10228
10229    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
10230        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
10231            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
10232                    Integer.toHexString(pendingLayoutChanges));
10233        }
10234    }
10235}
10236