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