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