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