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