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