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