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