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