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