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