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