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