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