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