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