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