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