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