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