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