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