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