WindowManagerService.java revision 79c6346100b555a8a3d51b3b1c34dbbe99305b9a
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        final int SW_LID = 0x00;
4967        int sw = mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, 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            mInputManager.getInputConfiguration(config);
6287
6288            int orientation = Configuration.ORIENTATION_SQUARE;
6289            if (dw < dh) {
6290                orientation = Configuration.ORIENTATION_PORTRAIT;
6291            } else if (dw > dh) {
6292                orientation = Configuration.ORIENTATION_LANDSCAPE;
6293            }
6294            config.orientation = orientation;
6295        }
6296
6297        // Update real display metrics.
6298        mDisplay.getMetricsWithSize(mRealDisplayMetrics, mCurDisplayWidth, mCurDisplayHeight);
6299
6300        // Update application display metrics.
6301        final DisplayMetrics dm = mDisplayMetrics;
6302        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
6303        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
6304        synchronized(mDisplaySizeLock) {
6305            mAppDisplayWidth = appWidth;
6306            mAppDisplayHeight = appHeight;
6307            mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight,
6308                    mAppDisplayWidth, mAppDisplayHeight);
6309        }
6310        if (false) {
6311            Slog.i(TAG, "Set app display size: " + mAppDisplayWidth
6312                    + " x " + mAppDisplayHeight);
6313        }
6314        mDisplay.getMetricsWithSize(dm, mAppDisplayWidth, mAppDisplayHeight);
6315
6316        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
6317                mCompatDisplayMetrics);
6318
6319        if (config != null) {
6320            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
6321                    / dm.density);
6322            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
6323                    / dm.density);
6324            computeSizeRangesAndScreenLayout(rotated, dw, dh, dm.density, config);
6325
6326            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
6327            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
6328            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
6329
6330            // Determine whether a hard keyboard is available and enabled.
6331            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6332            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6333                mHardKeyboardAvailable = hardKeyboardAvailable;
6334                mHardKeyboardEnabled = hardKeyboardAvailable;
6335
6336                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6337                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6338            }
6339            if (!mHardKeyboardEnabled) {
6340                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6341            }
6342
6343            // Update value of keyboardHidden, hardKeyboardHidden and navigationHidden
6344            // based on whether a hard or soft keyboard is present, whether navigation keys
6345            // are present and the lid switch state.
6346            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6347            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6348            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6349            mPolicy.adjustConfigurationLw(config);
6350        }
6351
6352        return true;
6353    }
6354
6355    public boolean isHardKeyboardAvailable() {
6356        synchronized (mWindowMap) {
6357            return mHardKeyboardAvailable;
6358        }
6359    }
6360
6361    public boolean isHardKeyboardEnabled() {
6362        synchronized (mWindowMap) {
6363            return mHardKeyboardEnabled;
6364        }
6365    }
6366
6367    public void setHardKeyboardEnabled(boolean enabled) {
6368        synchronized (mWindowMap) {
6369            if (mHardKeyboardEnabled != enabled) {
6370                mHardKeyboardEnabled = enabled;
6371                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6372            }
6373        }
6374    }
6375
6376    public void setOnHardKeyboardStatusChangeListener(
6377            OnHardKeyboardStatusChangeListener listener) {
6378        synchronized (mWindowMap) {
6379            mHardKeyboardStatusChangeListener = listener;
6380        }
6381    }
6382
6383    void notifyHardKeyboardStatusChange() {
6384        final boolean available, enabled;
6385        final OnHardKeyboardStatusChangeListener listener;
6386        synchronized (mWindowMap) {
6387            listener = mHardKeyboardStatusChangeListener;
6388            available = mHardKeyboardAvailable;
6389            enabled = mHardKeyboardEnabled;
6390        }
6391        if (listener != null) {
6392            listener.onHardKeyboardStatusChange(available, enabled);
6393        }
6394    }
6395
6396    // -------------------------------------------------------------
6397    // Drag and drop
6398    // -------------------------------------------------------------
6399
6400    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
6401            int flags, int width, int height, Surface outSurface) {
6402        if (DEBUG_DRAG) {
6403            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
6404                    + " flags=" + Integer.toHexString(flags) + " win=" + window
6405                    + " asbinder=" + window.asBinder());
6406        }
6407
6408        final int callerPid = Binder.getCallingPid();
6409        final long origId = Binder.clearCallingIdentity();
6410        IBinder token = null;
6411
6412        try {
6413            synchronized (mWindowMap) {
6414                try {
6415                    if (mDragState == null) {
6416                        Surface surface = new Surface(session, callerPid, "drag surface", 0,
6417                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
6418                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
6419                                + surface + ": CREATE");
6420                        outSurface.copyFrom(surface);
6421                        final IBinder winBinder = window.asBinder();
6422                        token = new Binder();
6423                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
6424                        token = mDragState.mToken = new Binder();
6425
6426                        // 5 second timeout for this window to actually begin the drag
6427                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
6428                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
6429                        mH.sendMessageDelayed(msg, 5000);
6430                    } else {
6431                        Slog.w(TAG, "Drag already in progress");
6432                    }
6433                } catch (Surface.OutOfResourcesException e) {
6434                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
6435                    if (mDragState != null) {
6436                        mDragState.reset();
6437                        mDragState = null;
6438                    }
6439                }
6440            }
6441        } finally {
6442            Binder.restoreCallingIdentity(origId);
6443        }
6444
6445        return token;
6446    }
6447
6448    // -------------------------------------------------------------
6449    // Input Events and Focus Management
6450    // -------------------------------------------------------------
6451
6452    final InputMonitor mInputMonitor = new InputMonitor(this);
6453
6454    public void pauseKeyDispatching(IBinder _token) {
6455        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6456                "pauseKeyDispatching()")) {
6457            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6458        }
6459
6460        synchronized (mWindowMap) {
6461            WindowToken token = mTokenMap.get(_token);
6462            if (token != null) {
6463                mInputMonitor.pauseDispatchingLw(token);
6464            }
6465        }
6466    }
6467
6468    public void resumeKeyDispatching(IBinder _token) {
6469        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6470                "resumeKeyDispatching()")) {
6471            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6472        }
6473
6474        synchronized (mWindowMap) {
6475            WindowToken token = mTokenMap.get(_token);
6476            if (token != null) {
6477                mInputMonitor.resumeDispatchingLw(token);
6478            }
6479        }
6480    }
6481
6482    public void setEventDispatching(boolean enabled) {
6483        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6484                "resumeKeyDispatching()")) {
6485            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6486        }
6487
6488        synchronized (mWindowMap) {
6489            mInputMonitor.setEventDispatchingLw(enabled);
6490        }
6491
6492        sendScreenStatusToClients();
6493    }
6494
6495    private WindowState getFocusedWindow() {
6496        synchronized (mWindowMap) {
6497            return getFocusedWindowLocked();
6498        }
6499    }
6500
6501    private WindowState getFocusedWindowLocked() {
6502        return mCurrentFocus;
6503    }
6504
6505    public boolean detectSafeMode() {
6506        if (!mInputMonitor.waitForInputDevicesReady(
6507                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
6508            Slog.w(TAG, "Devices still not ready after waiting "
6509                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
6510                   + " milliseconds before attempting to detect safe mode.");
6511        }
6512
6513        final int BTN_MOUSE = 0x110;
6514        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6515                KeyEvent.KEYCODE_MENU);
6516        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
6517        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
6518                KeyEvent.KEYCODE_DPAD_CENTER);
6519        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
6520                BTN_MOUSE);
6521        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6522                KeyEvent.KEYCODE_VOLUME_DOWN);
6523        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
6524                || volumeDownState > 0;
6525        try {
6526            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
6527                mSafeMode = true;
6528                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
6529            }
6530        } catch (IllegalArgumentException e) {
6531        }
6532        if (mSafeMode) {
6533            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
6534                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
6535        } else {
6536            Log.i(TAG, "SAFE MODE not enabled");
6537        }
6538        mPolicy.setSafeMode(mSafeMode);
6539        return mSafeMode;
6540    }
6541
6542    public void displayReady() {
6543        synchronized(mWindowMap) {
6544            if (mDisplay != null) {
6545                throw new IllegalStateException("Display already initialized");
6546            }
6547            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
6548            mDisplay = wm.getDefaultDisplay();
6549            synchronized(mDisplaySizeLock) {
6550                mInitialDisplayWidth = mDisplay.getRawWidth();
6551                mInitialDisplayHeight = mDisplay.getRawHeight();
6552                int rot = mDisplay.getRotation();
6553                if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
6554                    // If the screen is currently rotated, we need to swap the
6555                    // initial width and height to get the true natural values.
6556                    int tmp = mInitialDisplayWidth;
6557                    mInitialDisplayWidth = mInitialDisplayHeight;
6558                    mInitialDisplayHeight = tmp;
6559                }
6560                mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth;
6561                mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight;
6562                mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight,
6563                        mAppDisplayWidth, mAppDisplayHeight);
6564            }
6565            mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
6566                    mDisplay.getRawWidth(), mDisplay.getRawHeight(),
6567                    mDisplay.getRawExternalWidth(), mDisplay.getRawExternalHeight());
6568            mPolicy.setInitialDisplaySize(mDisplay, mInitialDisplayWidth, mInitialDisplayHeight);
6569        }
6570
6571        try {
6572            mActivityManager.updateConfiguration(null);
6573        } catch (RemoteException e) {
6574        }
6575
6576        synchronized (mWindowMap) {
6577            readForcedDisplaySizeLocked();
6578        }
6579    }
6580
6581    public void systemReady() {
6582        mPolicy.systemReady();
6583    }
6584
6585    private void sendScreenStatusToClients() {
6586        final ArrayList<WindowState> windows = mWindows;
6587        final int count = windows.size();
6588        boolean on = mPowerManager.isScreenOn();
6589        for (int i = count - 1; i >= 0; i--) {
6590            WindowState win = mWindows.get(i);
6591            try {
6592                win.mClient.dispatchScreenState(on);
6593            } catch (RemoteException e) {
6594                // Ignored
6595            }
6596        }
6597    }
6598
6599    // -------------------------------------------------------------
6600    // Async Handler
6601    // -------------------------------------------------------------
6602
6603    final class H extends Handler {
6604        public static final int REPORT_FOCUS_CHANGE = 2;
6605        public static final int REPORT_LOSING_FOCUS = 3;
6606        public static final int DO_TRAVERSAL = 4;
6607        public static final int ADD_STARTING = 5;
6608        public static final int REMOVE_STARTING = 6;
6609        public static final int FINISHED_STARTING = 7;
6610        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
6611        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
6612        public static final int WINDOW_FREEZE_TIMEOUT = 11;
6613        public static final int HOLD_SCREEN_CHANGED = 12;
6614        public static final int APP_TRANSITION_TIMEOUT = 13;
6615        public static final int PERSIST_ANIMATION_SCALE = 14;
6616        public static final int FORCE_GC = 15;
6617        public static final int ENABLE_SCREEN = 16;
6618        public static final int APP_FREEZE_TIMEOUT = 17;
6619        public static final int SEND_NEW_CONFIGURATION = 18;
6620        public static final int REPORT_WINDOWS_CHANGE = 19;
6621        public static final int DRAG_START_TIMEOUT = 20;
6622        public static final int DRAG_END_TIMEOUT = 21;
6623        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
6624        public static final int BOOT_TIMEOUT = 23;
6625        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
6626        public static final int BULK_UPDATE_PARAMETERS = 25;
6627
6628        public static final int ANIMATOR_WHAT_OFFSET = 100000;
6629        public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
6630        public static final int SET_WALLPAPER_OFFSET = ANIMATOR_WHAT_OFFSET + 2;
6631        public static final int SET_DIM_PARAMETERS = ANIMATOR_WHAT_OFFSET + 3;
6632        public static final int SET_MOVE_ANIMATION = ANIMATOR_WHAT_OFFSET + 4;
6633        public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 5;
6634
6635        private Session mLastReportedHold;
6636
6637        public H() {
6638        }
6639
6640        @Override
6641        public void handleMessage(Message msg) {
6642            if (DEBUG_WINDOW_TRACE) {
6643                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
6644            }
6645            switch (msg.what) {
6646                case REPORT_FOCUS_CHANGE: {
6647                    WindowState lastFocus;
6648                    WindowState newFocus;
6649
6650                    synchronized(mWindowMap) {
6651                        lastFocus = mLastFocus;
6652                        newFocus = mCurrentFocus;
6653                        if (lastFocus == newFocus) {
6654                            // Focus is not changing, so nothing to do.
6655                            return;
6656                        }
6657                        mLastFocus = newFocus;
6658                        //Slog.i(TAG, "Focus moving from " + lastFocus
6659                        //        + " to " + newFocus);
6660                        if (newFocus != null && lastFocus != null
6661                                && !newFocus.isDisplayedLw()) {
6662                            //Slog.i(TAG, "Delaying loss of focus...");
6663                            mLosingFocus.add(lastFocus);
6664                            lastFocus = null;
6665                        }
6666                    }
6667
6668                    if (lastFocus != newFocus) {
6669                        //System.out.println("Changing focus from " + lastFocus
6670                        //                   + " to " + newFocus);
6671                        if (newFocus != null) {
6672                            try {
6673                                //Slog.i(TAG, "Gaining focus: " + newFocus);
6674                                newFocus.mClient.windowFocusChanged(true, mInTouchMode);
6675                            } catch (RemoteException e) {
6676                                // Ignore if process has died.
6677                            }
6678                            notifyFocusChanged();
6679                        }
6680
6681                        if (lastFocus != null) {
6682                            try {
6683                                //Slog.i(TAG, "Losing focus: " + lastFocus);
6684                                lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
6685                            } catch (RemoteException e) {
6686                                // Ignore if process has died.
6687                            }
6688                        }
6689                    }
6690                } break;
6691
6692                case REPORT_LOSING_FOCUS: {
6693                    ArrayList<WindowState> losers;
6694
6695                    synchronized(mWindowMap) {
6696                        losers = mLosingFocus;
6697                        mLosingFocus = new ArrayList<WindowState>();
6698                    }
6699
6700                    final int N = losers.size();
6701                    for (int i=0; i<N; i++) {
6702                        try {
6703                            //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
6704                            losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
6705                        } catch (RemoteException e) {
6706                             // Ignore if process has died.
6707                        }
6708                    }
6709                } break;
6710
6711                case DO_TRAVERSAL: {
6712                    synchronized(mWindowMap) {
6713                        mTraversalScheduled = false;
6714                        performLayoutAndPlaceSurfacesLocked();
6715                    }
6716                } break;
6717
6718                case ADD_STARTING: {
6719                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6720                    final StartingData sd = wtoken.startingData;
6721
6722                    if (sd == null) {
6723                        // Animation has been canceled... do nothing.
6724                        return;
6725                    }
6726
6727                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
6728                            + wtoken + ": pkg=" + sd.pkg);
6729
6730                    View view = null;
6731                    try {
6732                        view = mPolicy.addStartingWindow(
6733                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
6734                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
6735                    } catch (Exception e) {
6736                        Slog.w(TAG, "Exception when adding starting window", e);
6737                    }
6738
6739                    if (view != null) {
6740                        boolean abort = false;
6741
6742                        synchronized(mWindowMap) {
6743                            if (wtoken.removed || wtoken.startingData == null) {
6744                                // If the window was successfully added, then
6745                                // we need to remove it.
6746                                if (wtoken.startingWindow != null) {
6747                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6748                                            "Aborted starting " + wtoken
6749                                            + ": removed=" + wtoken.removed
6750                                            + " startingData=" + wtoken.startingData);
6751                                    wtoken.startingWindow = null;
6752                                    wtoken.startingData = null;
6753                                    abort = true;
6754                                }
6755                            } else {
6756                                wtoken.startingView = view;
6757                            }
6758                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
6759                                    "Added starting " + wtoken
6760                                    + ": startingWindow="
6761                                    + wtoken.startingWindow + " startingView="
6762                                    + wtoken.startingView);
6763                        }
6764
6765                        if (abort) {
6766                            try {
6767                                mPolicy.removeStartingWindow(wtoken.token, view);
6768                            } catch (Exception e) {
6769                                Slog.w(TAG, "Exception when removing starting window", e);
6770                            }
6771                        }
6772                    }
6773                } break;
6774
6775                case REMOVE_STARTING: {
6776                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6777                    IBinder token = null;
6778                    View view = null;
6779                    synchronized (mWindowMap) {
6780                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
6781                                + wtoken + ": startingWindow="
6782                                + wtoken.startingWindow + " startingView="
6783                                + wtoken.startingView);
6784                        if (wtoken.startingWindow != null) {
6785                            view = wtoken.startingView;
6786                            token = wtoken.token;
6787                            wtoken.startingData = null;
6788                            wtoken.startingView = null;
6789                            wtoken.startingWindow = null;
6790                        }
6791                    }
6792                    if (view != null) {
6793                        try {
6794                            mPolicy.removeStartingWindow(token, view);
6795                        } catch (Exception e) {
6796                            Slog.w(TAG, "Exception when removing starting window", e);
6797                        }
6798                    }
6799                } break;
6800
6801                case FINISHED_STARTING: {
6802                    IBinder token = null;
6803                    View view = null;
6804                    while (true) {
6805                        synchronized (mWindowMap) {
6806                            final int N = mFinishedStarting.size();
6807                            if (N <= 0) {
6808                                break;
6809                            }
6810                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
6811
6812                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6813                                    "Finished starting " + wtoken
6814                                    + ": startingWindow=" + wtoken.startingWindow
6815                                    + " startingView=" + wtoken.startingView);
6816
6817                            if (wtoken.startingWindow == null) {
6818                                continue;
6819                            }
6820
6821                            view = wtoken.startingView;
6822                            token = wtoken.token;
6823                            wtoken.startingData = null;
6824                            wtoken.startingView = null;
6825                            wtoken.startingWindow = null;
6826                        }
6827
6828                        try {
6829                            mPolicy.removeStartingWindow(token, view);
6830                        } catch (Exception e) {
6831                            Slog.w(TAG, "Exception when removing starting window", e);
6832                        }
6833                    }
6834                } break;
6835
6836                case REPORT_APPLICATION_TOKEN_DRAWN: {
6837                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6838
6839                    try {
6840                        if (DEBUG_VISIBILITY) Slog.v(
6841                                TAG, "Reporting drawn in " + wtoken);
6842                        wtoken.appToken.windowsDrawn();
6843                    } catch (RemoteException ex) {
6844                    }
6845                } break;
6846
6847                case REPORT_APPLICATION_TOKEN_WINDOWS: {
6848                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6849
6850                    boolean nowVisible = msg.arg1 != 0;
6851                    boolean nowGone = msg.arg2 != 0;
6852
6853                    try {
6854                        if (DEBUG_VISIBILITY) Slog.v(
6855                                TAG, "Reporting visible in " + wtoken
6856                                + " visible=" + nowVisible
6857                                + " gone=" + nowGone);
6858                        if (nowVisible) {
6859                            wtoken.appToken.windowsVisible();
6860                        } else {
6861                            wtoken.appToken.windowsGone();
6862                        }
6863                    } catch (RemoteException ex) {
6864                    }
6865                } break;
6866
6867                case WINDOW_FREEZE_TIMEOUT: {
6868                    synchronized (mWindowMap) {
6869                        Slog.w(TAG, "Window freeze timeout expired.");
6870                        int i = mWindows.size();
6871                        while (i > 0) {
6872                            i--;
6873                            WindowState w = mWindows.get(i);
6874                            if (w.mOrientationChanging) {
6875                                w.mOrientationChanging = false;
6876                                Slog.w(TAG, "Force clearing orientation change: " + w);
6877                            }
6878                        }
6879                        performLayoutAndPlaceSurfacesLocked();
6880                    }
6881                    break;
6882                }
6883
6884                case HOLD_SCREEN_CHANGED: {
6885                    Session oldHold;
6886                    Session newHold;
6887                    synchronized (mWindowMap) {
6888                        oldHold = mLastReportedHold;
6889                        newHold = (Session)msg.obj;
6890                        mLastReportedHold = newHold;
6891                    }
6892
6893                    if (oldHold != newHold) {
6894                        try {
6895                            if (oldHold != null) {
6896                                mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
6897                                        "window",
6898                                        BatteryStats.WAKE_TYPE_WINDOW);
6899                            }
6900                            if (newHold != null) {
6901                                mBatteryStats.noteStartWakelock(newHold.mUid, -1,
6902                                        "window",
6903                                        BatteryStats.WAKE_TYPE_WINDOW);
6904                            }
6905                        } catch (RemoteException e) {
6906                        }
6907                    }
6908                    break;
6909                }
6910
6911                case APP_TRANSITION_TIMEOUT: {
6912                    synchronized (mWindowMap) {
6913                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
6914                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
6915                                    "*** APP TRANSITION TIMEOUT");
6916                            mAppTransitionReady = true;
6917                            mAppTransitionTimeout = true;
6918                            performLayoutAndPlaceSurfacesLocked();
6919                        }
6920                    }
6921                    break;
6922                }
6923
6924                case PERSIST_ANIMATION_SCALE: {
6925                    Settings.System.putFloat(mContext.getContentResolver(),
6926                            Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
6927                    Settings.System.putFloat(mContext.getContentResolver(),
6928                            Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
6929                    Settings.System.putFloat(mContext.getContentResolver(),
6930                            Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
6931                    break;
6932                }
6933
6934                case FORCE_GC: {
6935                    synchronized(mWindowMap) {
6936                        if (mAnimationScheduled) {
6937                            // If we are animating, don't do the gc now but
6938                            // delay a bit so we don't interrupt the animation.
6939                            mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
6940                                    2000);
6941                            return;
6942                        }
6943                        // If we are currently rotating the display, it will
6944                        // schedule a new message when done.
6945                        if (mDisplayFrozen) {
6946                            return;
6947                        }
6948                    }
6949                    Runtime.getRuntime().gc();
6950                    break;
6951                }
6952
6953                case ENABLE_SCREEN: {
6954                    performEnableScreen();
6955                    break;
6956                }
6957
6958                case APP_FREEZE_TIMEOUT: {
6959                    synchronized (mWindowMap) {
6960                        synchronized (mAnimator) {
6961                            Slog.w(TAG, "App freeze timeout expired.");
6962                            int i = mAppTokens.size();
6963                            while (i > 0) {
6964                                i--;
6965                                AppWindowToken tok = mAppTokens.get(i);
6966                                if (tok.mAppAnimator.freezingScreen) {
6967                                    Slog.w(TAG, "Force clearing freeze: " + tok);
6968                                    unsetAppFreezingScreenLocked(tok, true, true);
6969                                }
6970                            }
6971                        }
6972                    }
6973                    break;
6974                }
6975
6976                case SEND_NEW_CONFIGURATION: {
6977                    removeMessages(SEND_NEW_CONFIGURATION);
6978                    sendNewConfiguration();
6979                    break;
6980                }
6981
6982                case REPORT_WINDOWS_CHANGE: {
6983                    if (mWindowsChanged) {
6984                        synchronized (mWindowMap) {
6985                            mWindowsChanged = false;
6986                        }
6987                        notifyWindowsChanged();
6988                    }
6989                    break;
6990                }
6991
6992                case DRAG_START_TIMEOUT: {
6993                    IBinder win = (IBinder)msg.obj;
6994                    if (DEBUG_DRAG) {
6995                        Slog.w(TAG, "Timeout starting drag by win " + win);
6996                    }
6997                    synchronized (mWindowMap) {
6998                        // !!! TODO: ANR the app that has failed to start the drag in time
6999                        if (mDragState != null) {
7000                            mDragState.unregister();
7001                            mInputMonitor.updateInputWindowsLw(true /*force*/);
7002                            mDragState.reset();
7003                            mDragState = null;
7004                        }
7005                    }
7006                    break;
7007                }
7008
7009                case DRAG_END_TIMEOUT: {
7010                    IBinder win = (IBinder)msg.obj;
7011                    if (DEBUG_DRAG) {
7012                        Slog.w(TAG, "Timeout ending drag to win " + win);
7013                    }
7014                    synchronized (mWindowMap) {
7015                        // !!! TODO: ANR the drag-receiving app
7016                        if (mDragState != null) {
7017                            mDragState.mDragResult = false;
7018                            mDragState.endDragLw();
7019                        }
7020                    }
7021                    break;
7022                }
7023
7024                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
7025                    notifyHardKeyboardStatusChange();
7026                    break;
7027                }
7028
7029                case BOOT_TIMEOUT: {
7030                    performBootTimeout();
7031                    break;
7032                }
7033
7034                case WAITING_FOR_DRAWN_TIMEOUT: {
7035                    Pair<WindowState, IRemoteCallback> pair;
7036                    synchronized (mWindowMap) {
7037                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
7038                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
7039                        if (!mWaitingForDrawn.remove(pair)) {
7040                            return;
7041                        }
7042                    }
7043                    try {
7044                        pair.second.sendResult(null);
7045                    } catch (RemoteException e) {
7046                    }
7047                    break;
7048                }
7049
7050                case BULK_UPDATE_PARAMETERS: {
7051                    // Used to send multiple changes from the animation side to the layout side.
7052                    synchronized (mWindowMap) {
7053                        boolean doRequest = false;
7054                        // TODO(cmautner): As the number of bits grows, use masks of bit groups to
7055                        //  eliminate unnecessary tests.
7056                        if ((msg.arg1 & LayoutFields.SET_UPDATE_ROTATION) != 0) {
7057                            mInnerFields.mUpdateRotation = true;
7058                            doRequest = true;
7059                        }
7060                        if ((msg.arg1 & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
7061                            mInnerFields.mWallpaperMayChange = true;
7062                            doRequest = true;
7063                        }
7064                        if ((msg.arg1 & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
7065                            mInnerFields.mWallpaperForceHidingChanged = true;
7066                            doRequest = true;
7067                        }
7068                        if ((msg.arg1 & LayoutFields.CLEAR_ORIENTATION_CHANGE_COMPLETE) != 0) {
7069                            mInnerFields.mOrientationChangeComplete = false;
7070                        } else {
7071                            mInnerFields.mOrientationChangeComplete = true;
7072                            if (mWindowsFreezingScreen) {
7073                                doRequest = true;
7074                            }
7075                        }
7076                        if ((msg.arg1 & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
7077                            mTurnOnScreen = true;
7078                        }
7079
7080                        mPendingLayoutChanges |= msg.arg2;
7081                        if (mPendingLayoutChanges != 0) {
7082                            doRequest = true;
7083                        }
7084
7085                        if (doRequest) {
7086                            mH.sendEmptyMessage(CLEAR_PENDING_ACTIONS);
7087                            performLayoutAndPlaceSurfacesLocked();
7088                        }
7089                    }
7090                    break;
7091                }
7092
7093                // Animation messages. Move to Window{State}Animator
7094                case SET_TRANSPARENT_REGION: {
7095                    Pair<WindowStateAnimator, Region> pair =
7096                                (Pair<WindowStateAnimator, Region>) msg.obj;
7097                    final WindowStateAnimator winAnimator = pair.first;
7098                    winAnimator.setTransparentRegionHint(pair.second);
7099                    break;
7100                }
7101
7102                case SET_WALLPAPER_OFFSET: {
7103                    final WindowStateAnimator winAnimator = (WindowStateAnimator) msg.obj;
7104                    winAnimator.setWallpaperOffset(msg.arg1, msg.arg2);
7105
7106                    scheduleAnimationLocked();
7107                    break;
7108                }
7109
7110                case SET_DIM_PARAMETERS: {
7111                    mAnimator.mDimParams = (DimAnimator.Parameters) msg.obj;
7112
7113                    scheduleAnimationLocked();
7114                    break;
7115                }
7116
7117                case SET_MOVE_ANIMATION: {
7118                    WindowAnimator.SetAnimationParams params =
7119                            (WindowAnimator.SetAnimationParams) msg.obj;
7120                    WindowStateAnimator winAnimator = params.mWinAnimator;
7121                    winAnimator.setAnimation(params.mAnimation);
7122                    winAnimator.mAnimDw = params.mAnimDw;
7123                    winAnimator.mAnimDh = params.mAnimDh;
7124
7125                    scheduleAnimationLocked();
7126                    break;
7127                }
7128
7129                case CLEAR_PENDING_ACTIONS: {
7130                    mAnimator.clearPendingActions();
7131                    break;
7132                }
7133            }
7134            if (DEBUG_WINDOW_TRACE) {
7135                Slog.v(TAG, "handleMessage: exit");
7136            }
7137        }
7138    }
7139
7140    // -------------------------------------------------------------
7141    // IWindowManager API
7142    // -------------------------------------------------------------
7143
7144    @Override
7145    public IWindowSession openSession(IInputMethodClient client,
7146            IInputContext inputContext) {
7147        if (client == null) throw new IllegalArgumentException("null client");
7148        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7149        Session session = new Session(this, client, inputContext);
7150        return session;
7151    }
7152
7153    @Override
7154    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7155        synchronized (mWindowMap) {
7156            // The focus for the client is the window immediately below
7157            // where we would place the input method window.
7158            int idx = findDesiredInputMethodWindowIndexLocked(false);
7159            WindowState imFocus;
7160            if (idx > 0) {
7161                imFocus = mWindows.get(idx-1);
7162                //Log.i(TAG, "Desired input method target: " + imFocus);
7163                //Log.i(TAG, "Current focus: " + this.mCurrentFocus);
7164                //Log.i(TAG, "Last focus: " + this.mLastFocus);
7165                if (imFocus != null) {
7166                    // This may be a starting window, in which case we still want
7167                    // to count it as okay.
7168                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
7169                            && imFocus.mAppToken != null) {
7170                        // The client has definitely started, so it really should
7171                        // have a window in this app token.  Let's look for it.
7172                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
7173                            WindowState w = imFocus.mAppToken.windows.get(i);
7174                            if (w != imFocus) {
7175                                //Log.i(TAG, "Switching to real app window: " + w);
7176                                imFocus = w;
7177                                break;
7178                            }
7179                        }
7180                    }
7181                    //Log.i(TAG, "IM target client: " + imFocus.mSession.mClient);
7182                    //if (imFocus.mSession.mClient != null) {
7183                    //    Log.i(TAG, "IM target client binder: " + imFocus.mSession.mClient.asBinder());
7184                    //    Log.i(TAG, "Requesting client binder: " + client.asBinder());
7185                    //}
7186                    if (imFocus.mSession.mClient != null &&
7187                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7188                        return true;
7189                    }
7190
7191                    // Okay, how about this...  what is the current focus?
7192                    // It seems in some cases we may not have moved the IM
7193                    // target window, such as when it was in a pop-up window,
7194                    // so let's also look at the current focus.  (An example:
7195                    // go to Gmail, start searching so the keyboard goes up,
7196                    // press home.  Sometimes the IME won't go down.)
7197                    // Would be nice to fix this more correctly, but it's
7198                    // way at the end of a release, and this should be good enough.
7199                    if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null &&
7200                            mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7201                        return true;
7202                    }
7203                }
7204            }
7205        }
7206        return false;
7207    }
7208
7209    public void getDisplaySize(Point size) {
7210        synchronized(mDisplaySizeLock) {
7211            size.x = mAppDisplayWidth;
7212            size.y = mAppDisplayHeight;
7213        }
7214    }
7215
7216    public void getRealDisplaySize(Point size) {
7217        synchronized(mDisplaySizeLock) {
7218            size.x = mCurDisplayWidth;
7219            size.y = mCurDisplayHeight;
7220        }
7221    }
7222
7223    public void getInitialDisplaySize(Point size) {
7224        synchronized(mDisplaySizeLock) {
7225            size.x = mInitialDisplayWidth;
7226            size.y = mInitialDisplayHeight;
7227        }
7228    }
7229
7230    public int getMaximumSizeDimension() {
7231        synchronized(mDisplaySizeLock) {
7232            // Do this based on the raw screen size, until we are smarter.
7233            return mBaseDisplayWidth > mBaseDisplayHeight
7234                    ? mBaseDisplayWidth : mBaseDisplayHeight;
7235        }
7236    }
7237
7238    public void getCurrentSizeRange(Point smallestSize, Point largestSize) {
7239        synchronized(mDisplaySizeLock) {
7240            smallestSize.x = mSmallestDisplayWidth;
7241            smallestSize.y = mSmallestDisplayHeight;
7242            largestSize.x = mLargestDisplayWidth;
7243            largestSize.y = mLargestDisplayHeight;
7244        }
7245    }
7246
7247    public void setForcedDisplaySize(int longDimen, int shortDimen) {
7248        synchronized(mWindowMap) {
7249            int width, height;
7250            if (mInitialDisplayWidth < mInitialDisplayHeight) {
7251                width = shortDimen < mInitialDisplayWidth
7252                        ? shortDimen : mInitialDisplayWidth;
7253                height = longDimen < mInitialDisplayHeight
7254                        ? longDimen : mInitialDisplayHeight;
7255            } else {
7256                width = longDimen < mInitialDisplayWidth
7257                        ? longDimen : mInitialDisplayWidth;
7258                height = shortDimen < mInitialDisplayHeight
7259                        ? shortDimen : mInitialDisplayHeight;
7260            }
7261            setForcedDisplaySizeLocked(width, height);
7262            Settings.Secure.putString(mContext.getContentResolver(),
7263                    Settings.Secure.DISPLAY_SIZE_FORCED, width + "," + height);
7264        }
7265    }
7266
7267    private void rebuildBlackFrame() {
7268        if (mBlackFrame != null) {
7269            mBlackFrame.kill();
7270            mBlackFrame = null;
7271        }
7272        if (mBaseDisplayWidth < mInitialDisplayWidth
7273                || mBaseDisplayHeight < mInitialDisplayHeight) {
7274            int initW, initH, baseW, baseH;
7275            final boolean rotated = (mRotation == Surface.ROTATION_90
7276                    || mRotation == Surface.ROTATION_270);
7277            if (rotated) {
7278                initW = mInitialDisplayHeight;
7279                initH = mInitialDisplayWidth;
7280                baseW = mBaseDisplayHeight;
7281                baseH = mBaseDisplayWidth;
7282            } else {
7283                initW = mInitialDisplayWidth;
7284                initH = mInitialDisplayHeight;
7285                baseW = mBaseDisplayWidth;
7286                baseH = mBaseDisplayHeight;
7287            }
7288            Rect outer = new Rect(0, 0, initW, initH);
7289            Rect inner = new Rect(0, 0, baseW, baseH);
7290            try {
7291                mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
7292            } catch (Surface.OutOfResourcesException e) {
7293            }
7294        }
7295    }
7296
7297    private void readForcedDisplaySizeLocked() {
7298        final String str = Settings.Secure.getString(mContext.getContentResolver(),
7299                Settings.Secure.DISPLAY_SIZE_FORCED);
7300        if (str == null || str.length() == 0) {
7301            return;
7302        }
7303        final int pos = str.indexOf(',');
7304        if (pos <= 0 || str.lastIndexOf(',') != pos) {
7305            return;
7306        }
7307        int width, height;
7308        try {
7309            width = Integer.parseInt(str.substring(0, pos));
7310            height = Integer.parseInt(str.substring(pos+1));
7311        } catch (NumberFormatException ex) {
7312            return;
7313        }
7314        setForcedDisplaySizeLocked(width, height);
7315    }
7316
7317    private void setForcedDisplaySizeLocked(int width, int height) {
7318        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7319
7320        synchronized(mDisplaySizeLock) {
7321            mBaseDisplayWidth = width;
7322            mBaseDisplayHeight = height;
7323        }
7324        mPolicy.setInitialDisplaySize(mDisplay, mBaseDisplayWidth, mBaseDisplayHeight);
7325
7326        mLayoutNeeded = true;
7327
7328        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7329        mTempConfiguration.setToDefaults();
7330        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7331        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7332            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7333                configChanged = true;
7334            }
7335        }
7336
7337        if (configChanged) {
7338            mWaitingForConfig = true;
7339            startFreezingDisplayLocked(false);
7340            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7341        }
7342
7343        rebuildBlackFrame();
7344
7345        performLayoutAndPlaceSurfacesLocked();
7346    }
7347
7348    public void clearForcedDisplaySize() {
7349        synchronized(mWindowMap) {
7350            setForcedDisplaySizeLocked(mInitialDisplayWidth, mInitialDisplayHeight);
7351            Settings.Secure.putString(mContext.getContentResolver(),
7352                    Settings.Secure.DISPLAY_SIZE_FORCED, "");
7353        }
7354    }
7355
7356    public boolean hasSystemNavBar() {
7357        return mPolicy.hasSystemNavBar();
7358    }
7359
7360    // -------------------------------------------------------------
7361    // Internals
7362    // -------------------------------------------------------------
7363
7364    final WindowState windowForClientLocked(Session session, IWindow client,
7365            boolean throwOnError) {
7366        return windowForClientLocked(session, client.asBinder(), throwOnError);
7367    }
7368
7369    final WindowState windowForClientLocked(Session session, IBinder client,
7370            boolean throwOnError) {
7371        WindowState win = mWindowMap.get(client);
7372        if (localLOGV) Slog.v(
7373            TAG, "Looking up client " + client + ": " + win);
7374        if (win == null) {
7375            RuntimeException ex = new IllegalArgumentException(
7376                    "Requested window " + client + " does not exist");
7377            if (throwOnError) {
7378                throw ex;
7379            }
7380            Slog.w(TAG, "Failed looking up window", ex);
7381            return null;
7382        }
7383        if (session != null && win.mSession != session) {
7384            RuntimeException ex = new IllegalArgumentException(
7385                    "Requested window " + client + " is in session " +
7386                    win.mSession + ", not " + session);
7387            if (throwOnError) {
7388                throw ex;
7389            }
7390            Slog.w(TAG, "Failed looking up window", ex);
7391            return null;
7392        }
7393
7394        return win;
7395    }
7396
7397    final void rebuildAppWindowListLocked() {
7398        int NW = mWindows.size();
7399        int i;
7400        int lastWallpaper = -1;
7401        int numRemoved = 0;
7402
7403        if (mRebuildTmp.length < NW) {
7404            mRebuildTmp = new WindowState[NW+10];
7405        }
7406
7407        // First remove all existing app windows.
7408        i=0;
7409        while (i < NW) {
7410            WindowState w = mWindows.get(i);
7411            if (w.mAppToken != null) {
7412                WindowState win = mWindows.remove(i);
7413                win.mRebuilding = true;
7414                mRebuildTmp[numRemoved] = win;
7415                mWindowsChanged = true;
7416                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
7417                        "Rebuild removing window: " + win);
7418                NW--;
7419                numRemoved++;
7420                continue;
7421            } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER
7422                    && lastWallpaper == i-1) {
7423                lastWallpaper = i;
7424            }
7425            i++;
7426        }
7427
7428        // The wallpaper window(s) typically live at the bottom of the stack,
7429        // so skip them before adding app tokens.
7430        lastWallpaper++;
7431        i = lastWallpaper;
7432
7433        // First add all of the exiting app tokens...  these are no longer
7434        // in the main app list, but still have windows shown.  We put them
7435        // in the back because now that the animation is over we no longer
7436        // will care about them.
7437        int NT = mExitingAppTokens.size();
7438        for (int j=0; j<NT; j++) {
7439            i = reAddAppWindowsLocked(i, mExitingAppTokens.get(j));
7440        }
7441
7442        // And add in the still active app tokens in Z order.
7443        NT = mAppTokens.size();
7444        for (int j=0; j<NT; j++) {
7445            i = reAddAppWindowsLocked(i, mAppTokens.get(j));
7446        }
7447
7448        i -= lastWallpaper;
7449        if (i != numRemoved) {
7450            Slog.w(TAG, "Rebuild removed " + numRemoved
7451                    + " windows but added " + i);
7452            for (i=0; i<numRemoved; i++) {
7453                WindowState ws = mRebuildTmp[i];
7454                if (ws.mRebuilding) {
7455                    StringWriter sw = new StringWriter();
7456                    PrintWriter pw = new PrintWriter(sw);
7457                    ws.dump(pw, "", true);
7458                    pw.flush();
7459                    Slog.w(TAG, "This window was lost: " + ws);
7460                    Slog.w(TAG, sw.toString());
7461                    ws.mWinAnimator.destroySurfaceLocked();
7462                }
7463            }
7464            Slog.w(TAG, "Current app token list:");
7465            dumpAppTokensLocked();
7466            Slog.w(TAG, "Final window list:");
7467            dumpWindowsLocked();
7468        }
7469    }
7470
7471    private final void assignLayersLocked() {
7472        int N = mWindows.size();
7473        int curBaseLayer = 0;
7474        int curLayer = 0;
7475        int i;
7476
7477        if (DEBUG_LAYERS) {
7478            RuntimeException here = new RuntimeException("here");
7479            here.fillInStackTrace();
7480            Slog.v(TAG, "Assigning layers", here);
7481        }
7482
7483        for (i=0; i<N; i++) {
7484            WindowState w = mWindows.get(i);
7485            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
7486                    || (i > 0 && w.mIsWallpaper)) {
7487                curLayer += WINDOW_LAYER_MULTIPLIER;
7488                w.mLayer = curLayer;
7489            } else {
7490                curBaseLayer = curLayer = w.mBaseLayer;
7491                w.mLayer = curLayer;
7492            }
7493            if (w.mTargetAppToken != null) {
7494                w.mWinAnimator.mAnimLayer =
7495                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
7496            } else if (w.mAppToken != null) {
7497                w.mWinAnimator.mAnimLayer =
7498                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
7499            } else {
7500                w.mWinAnimator.mAnimLayer = w.mLayer;
7501            }
7502            if (w.mIsImWindow) {
7503                w.mWinAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
7504            } else if (w.mIsWallpaper) {
7505                w.mWinAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
7506            }
7507            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
7508                    + w.mWinAnimator.mAnimLayer);
7509            //System.out.println(
7510            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7511        }
7512    }
7513
7514    private boolean mInLayout = false;
7515    private final void performLayoutAndPlaceSurfacesLocked() {
7516        if (mInLayout) {
7517            if (DEBUG) {
7518                throw new RuntimeException("Recursive call!");
7519            }
7520            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
7521            return;
7522        }
7523
7524        if (mWaitingForConfig) {
7525            // Our configuration has changed (most likely rotation), but we
7526            // don't yet have the complete configuration to report to
7527            // applications.  Don't do any window layout until we have it.
7528            return;
7529        }
7530
7531        if (mDisplay == null) {
7532            // Not yet initialized, nothing to do.
7533            return;
7534        }
7535
7536        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
7537        mInLayout = true;
7538        boolean recoveringMemory = false;
7539
7540        try {
7541            if (mForceRemoves != null) {
7542                recoveringMemory = true;
7543                // Wait a little bit for things to settle down, and off we go.
7544                for (int i=0; i<mForceRemoves.size(); i++) {
7545                    WindowState ws = mForceRemoves.get(i);
7546                    Slog.i(TAG, "Force removing: " + ws);
7547                    removeWindowInnerLocked(ws.mSession, ws);
7548                }
7549                mForceRemoves = null;
7550                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
7551                Object tmp = new Object();
7552                synchronized (tmp) {
7553                    try {
7554                        tmp.wait(250);
7555                    } catch (InterruptedException e) {
7556                    }
7557                }
7558            }
7559        } catch (RuntimeException e) {
7560            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
7561        }
7562
7563        try {
7564            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
7565
7566            final int N = mPendingRemove.size();
7567            if (N > 0) {
7568                if (mPendingRemoveTmp.length < N) {
7569                    mPendingRemoveTmp = new WindowState[N+10];
7570                }
7571                mPendingRemove.toArray(mPendingRemoveTmp);
7572                mPendingRemove.clear();
7573                for (int i=0; i<N; i++) {
7574                    WindowState w = mPendingRemoveTmp[i];
7575                    removeWindowInnerLocked(w.mSession, w);
7576                }
7577
7578                mInLayout = false;
7579                assignLayersLocked();
7580                mLayoutNeeded = true;
7581                // XXX this recursion seems broken!
7582                Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
7583                performLayoutAndPlaceSurfacesLocked();
7584                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
7585
7586            } else {
7587                mInLayout = false;
7588            }
7589
7590            if (mLayoutNeeded) {
7591                if (++mLayoutRepeatCount < 6) {
7592                    requestTraversalLocked();
7593                } else {
7594                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
7595                    mLayoutRepeatCount = 0;
7596                }
7597            } else {
7598                mLayoutRepeatCount = 0;
7599            }
7600
7601            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
7602                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
7603                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
7604            }
7605        } catch (RuntimeException e) {
7606            mInLayout = false;
7607            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
7608        }
7609
7610        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
7611    }
7612
7613    private final void performLayoutLockedInner(boolean initial, boolean updateInputWindows) {
7614        if (!mLayoutNeeded) {
7615            return;
7616        }
7617
7618        mLayoutNeeded = false;
7619
7620        final int dw = mCurDisplayWidth;
7621        final int dh = mCurDisplayHeight;
7622
7623        final int NFW = mFakeWindows.size();
7624        for (int i=0; i<NFW; i++) {
7625            mFakeWindows.get(i).layout(dw, dh);
7626        }
7627
7628        final int N = mWindows.size();
7629        int i;
7630
7631        if (DEBUG_LAYOUT) {
7632            Slog.v(TAG, "-------------------------------------");
7633            Slog.v(TAG, "performLayout: needed="
7634                    + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
7635        }
7636
7637        mPolicy.beginLayoutLw(dw, dh, mRotation);
7638
7639        int seq = mLayoutSeq+1;
7640        if (seq < 0) seq = 0;
7641        mLayoutSeq = seq;
7642
7643        // First perform layout of any root windows (not attached
7644        // to another window).
7645        int topAttached = -1;
7646        for (i = N-1; i >= 0; i--) {
7647            final WindowState win = mWindows.get(i);
7648
7649            // Don't do layout of a window if it is not visible, or
7650            // soon won't be visible, to avoid wasting time and funky
7651            // changes while a window is animating away.
7652            final boolean gone = win.isGoneForLayoutLw();
7653
7654            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
7655                Slog.v(TAG, "1ST PASS " + win
7656                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
7657                        + " mLayoutAttached=" + win.mLayoutAttached);
7658                final AppWindowToken atoken = win.mAppToken;
7659                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
7660                        + win.mViewVisibility + " mRelayoutCalled="
7661                        + win.mRelayoutCalled + " hidden="
7662                        + win.mRootToken.hidden + " hiddenRequested="
7663                        + (atoken != null && atoken.hiddenRequested)
7664                        + " mAttachedHidden=" + win.mAttachedHidden);
7665                else Slog.v(TAG, "  VIS: mViewVisibility="
7666                        + win.mViewVisibility + " mRelayoutCalled="
7667                        + win.mRelayoutCalled + " hidden="
7668                        + win.mRootToken.hidden + " hiddenRequested="
7669                        + (atoken != null && atoken.hiddenRequested)
7670                        + " mAttachedHidden=" + win.mAttachedHidden);
7671            }
7672
7673            // If this view is GONE, then skip it -- keep the current
7674            // frame, and let the caller know so they can ignore it
7675            // if they want.  (We do the normal layout for INVISIBLE
7676            // windows, since that means "perform layout as normal,
7677            // just don't display").
7678            if (!gone || !win.mHaveFrame || win.mLayoutNeeded) {
7679                if (!win.mLayoutAttached) {
7680                    if (initial) {
7681                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7682                        win.mContentChanged = false;
7683                    }
7684                    win.mLayoutNeeded = false;
7685                    win.prelayout();
7686                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
7687                    win.mLayoutSeq = seq;
7688                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7689                            + win.mFrame + " mContainingFrame="
7690                            + win.mContainingFrame + " mDisplayFrame="
7691                            + win.mDisplayFrame);
7692                } else {
7693                    if (topAttached < 0) topAttached = i;
7694                }
7695            }
7696        }
7697
7698        // Now perform layout of attached windows, which usually
7699        // depend on the position of the window they are attached to.
7700        // XXX does not deal with windows that are attached to windows
7701        // that are themselves attached.
7702        for (i = topAttached; i >= 0; i--) {
7703            final WindowState win = mWindows.get(i);
7704
7705            if (win.mLayoutAttached) {
7706                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
7707                        + " mHaveFrame=" + win.mHaveFrame
7708                        + " mViewVisibility=" + win.mViewVisibility
7709                        + " mRelayoutCalled=" + win.mRelayoutCalled);
7710                // If this view is GONE, then skip it -- keep the current
7711                // frame, and let the caller know so they can ignore it
7712                // if they want.  (We do the normal layout for INVISIBLE
7713                // windows, since that means "perform layout as normal,
7714                // just don't display").
7715                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7716                        || !win.mHaveFrame || win.mLayoutNeeded) {
7717                    if (initial) {
7718                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7719                        win.mContentChanged = false;
7720                    }
7721                    win.mLayoutNeeded = false;
7722                    win.prelayout();
7723                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7724                    win.mLayoutSeq = seq;
7725                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7726                            + win.mFrame + " mContainingFrame="
7727                            + win.mContainingFrame + " mDisplayFrame="
7728                            + win.mDisplayFrame);
7729                }
7730            }
7731        }
7732
7733        // Window frames may have changed.  Tell the input dispatcher about it.
7734        mInputMonitor.setUpdateInputWindowsNeededLw();
7735        if (updateInputWindows) {
7736            mInputMonitor.updateInputWindowsLw(false /*force*/);
7737        }
7738
7739        mPolicy.finishLayoutLw();
7740    }
7741
7742    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
7743        // If the screen is currently frozen or off, then keep
7744        // it frozen/off until this window draws at its new
7745        // orientation.
7746        if (!okToDisplay()) {
7747            if (DEBUG_ORIENTATION) Slog.v(TAG,
7748                    "Changing surface while display frozen: " + w);
7749            w.mOrientationChanging = true;
7750            mInnerFields.mOrientationChangeComplete = false;
7751            if (!mWindowsFreezingScreen) {
7752                mWindowsFreezingScreen = true;
7753                // XXX should probably keep timeout from
7754                // when we first froze the display.
7755                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
7756                mH.sendMessageDelayed(mH.obtainMessage(
7757                        H.WINDOW_FREEZE_TIMEOUT), 2000);
7758            }
7759        }
7760    }
7761
7762    /**
7763     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
7764     *
7765     * @return bitmap indicating if another pass through layout must be made.
7766     */
7767    public int handleAppTransitionReadyLocked() {
7768        int changes = 0;
7769        int i;
7770        int NN = mOpeningApps.size();
7771        boolean goodToGo = true;
7772        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7773                "Checking " + NN + " opening apps (frozen="
7774                + mDisplayFrozen + " timeout="
7775                + mAppTransitionTimeout + ")...");
7776        if (!mDisplayFrozen && !mAppTransitionTimeout) {
7777            // If the display isn't frozen, wait to do anything until
7778            // all of the apps are ready.  Otherwise just go because
7779            // we'll unfreeze the display when everyone is ready.
7780            for (i=0; i<NN && goodToGo; i++) {
7781                AppWindowToken wtoken = mOpeningApps.get(i);
7782                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7783                        "Check opening app" + wtoken + ": allDrawn="
7784                        + wtoken.allDrawn + " startingDisplayed="
7785                        + wtoken.startingDisplayed + " startingMoved="
7786                        + wtoken.startingMoved);
7787                if (!wtoken.allDrawn && !wtoken.startingDisplayed
7788                        && !wtoken.startingMoved) {
7789                    goodToGo = false;
7790                }
7791            }
7792        }
7793        if (goodToGo) {
7794            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
7795            int transit = mNextAppTransition;
7796            if (mSkipAppTransitionAnimation) {
7797                transit = WindowManagerPolicy.TRANSIT_UNSET;
7798            }
7799            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
7800            mAppTransitionReady = false;
7801            mAppTransitionRunning = true;
7802            mAppTransitionTimeout = false;
7803            mStartingIconInTransition = false;
7804            mSkipAppTransitionAnimation = false;
7805
7806            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
7807
7808            // If there are applications waiting to come to the
7809            // top of the stack, now is the time to move their windows.
7810            // (Note that we don't do apps going to the bottom
7811            // here -- we want to keep their windows in the old
7812            // Z-order until the animation completes.)
7813            if (mToTopApps.size() > 0) {
7814                NN = mAppTokens.size();
7815                for (i=0; i<NN; i++) {
7816                    AppWindowToken wtoken = mAppTokens.get(i);
7817                    if (wtoken.sendingToTop) {
7818                        wtoken.sendingToTop = false;
7819                        moveAppWindowsLocked(wtoken, NN, false);
7820                    }
7821                }
7822                mToTopApps.clear();
7823            }
7824
7825            WindowState oldWallpaper = mWallpaperTarget;
7826
7827            adjustWallpaperWindowsLocked();
7828            mInnerFields.mWallpaperMayChange = false;
7829
7830            // The top-most window will supply the layout params,
7831            // and we will determine it below.
7832            LayoutParams animLp = null;
7833            int bestAnimLayer = -1;
7834            boolean fullscreenAnim = false;
7835
7836            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7837                    "New wallpaper target=" + mWallpaperTarget
7838                    + ", lower target=" + mLowerWallpaperTarget
7839                    + ", upper target=" + mUpperWallpaperTarget);
7840            int foundWallpapers = 0;
7841            // Do a first pass through the tokens for two
7842            // things:
7843            // (1) Determine if both the closing and opening
7844            // app token sets are wallpaper targets, in which
7845            // case special animations are needed
7846            // (since the wallpaper needs to stay static
7847            // behind them).
7848            // (2) Find the layout params of the top-most
7849            // application window in the tokens, which is
7850            // what will control the animation theme.
7851            final int NC = mClosingApps.size();
7852            NN = NC + mOpeningApps.size();
7853            for (i=0; i<NN; i++) {
7854                AppWindowToken wtoken;
7855                int mode;
7856                if (i < NC) {
7857                    wtoken = mClosingApps.get(i);
7858                    mode = 1;
7859                } else {
7860                    wtoken = mOpeningApps.get(i-NC);
7861                    mode = 2;
7862                }
7863                if (mLowerWallpaperTarget != null) {
7864                    if (mLowerWallpaperTarget.mAppToken == wtoken
7865                            || mUpperWallpaperTarget.mAppToken == wtoken) {
7866                        foundWallpapers |= mode;
7867                    }
7868                }
7869                if (wtoken.appFullscreen) {
7870                    WindowState ws = wtoken.findMainWindow();
7871                    if (ws != null) {
7872                        animLp = ws.mAttrs;
7873                        bestAnimLayer = ws.mLayer;
7874                        fullscreenAnim = true;
7875                    }
7876                } else if (!fullscreenAnim) {
7877                    WindowState ws = wtoken.findMainWindow();
7878                    if (ws != null) {
7879                        if (ws.mLayer > bestAnimLayer) {
7880                            animLp = ws.mAttrs;
7881                            bestAnimLayer = ws.mLayer;
7882                        }
7883                    }
7884                }
7885            }
7886
7887            if (foundWallpapers == 3) {
7888                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7889                        "Wallpaper animation!");
7890                switch (transit) {
7891                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
7892                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
7893                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
7894                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
7895                        break;
7896                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
7897                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
7898                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
7899                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
7900                        break;
7901                }
7902                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7903                        "New transit: " + transit);
7904            } else if (oldWallpaper != null) {
7905                // We are transitioning from an activity with
7906                // a wallpaper to one without.
7907                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
7908                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7909                        "New transit away from wallpaper: " + transit);
7910            } else if (mWallpaperTarget != null) {
7911                // We are transitioning from an activity without
7912                // a wallpaper to now showing the wallpaper
7913                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
7914                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7915                        "New transit into wallpaper: " + transit);
7916            }
7917
7918            // If all closing windows are obscured, then there is
7919            // no need to do an animation.  This is the case, for
7920            // example, when this transition is being done behind
7921            // the lock screen.
7922            if (!mPolicy.allowAppAnimationsLw()) {
7923                animLp = null;
7924            }
7925
7926            AppWindowToken topOpeningApp = null;
7927            int topOpeningLayer = 0;
7928
7929            // TODO(cmautner): Move to animation side.
7930            NN = mOpeningApps.size();
7931            for (i=0; i<NN; i++) {
7932                AppWindowToken wtoken = mOpeningApps.get(i);
7933                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
7934                wtoken.mAppAnimator.clearThumbnail();
7935                wtoken.reportedVisible = false;
7936                wtoken.inPendingTransaction = false;
7937                wtoken.mAppAnimator.animation = null;
7938                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
7939                wtoken.updateReportedVisibilityLocked();
7940                wtoken.waitingToShow = false;
7941                mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked();
7942                if (animLp != null) {
7943                    int layer = -1;
7944                    for (int j=0; j<wtoken.windows.size(); j++) {
7945                        WindowState win = wtoken.windows.get(j);
7946                        if (win.mWinAnimator.mAnimLayer > layer) {
7947                            layer = win.mWinAnimator.mAnimLayer;
7948                        }
7949                    }
7950                    if (topOpeningApp == null || layer > topOpeningLayer) {
7951                        topOpeningApp = wtoken;
7952                        topOpeningLayer = layer;
7953                    }
7954                }
7955            }
7956            NN = mClosingApps.size();
7957            for (i=0; i<NN; i++) {
7958                AppWindowToken wtoken = mClosingApps.get(i);
7959                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7960                        "Now closing app" + wtoken);
7961                wtoken.mAppAnimator.clearThumbnail();
7962                wtoken.inPendingTransaction = false;
7963                wtoken.mAppAnimator.animation = null;
7964                setTokenVisibilityLocked(wtoken, animLp, false,
7965                        transit, false);
7966                wtoken.updateReportedVisibilityLocked();
7967                wtoken.waitingToHide = false;
7968                // Force the allDrawn flag, because we want to start
7969                // this guy's animations regardless of whether it's
7970                // gotten drawn.
7971                wtoken.allDrawn = true;
7972            }
7973
7974            if (mNextAppTransitionThumbnail != null && topOpeningApp != null
7975                    && topOpeningApp.mAppAnimator.animation != null) {
7976                // This thumbnail animation is very special, we need to have
7977                // an extra surface with the thumbnail included with the animation.
7978                Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
7979                        mNextAppTransitionThumbnail.getHeight());
7980                try {
7981                    Surface surface = new Surface(mFxSession, Process.myPid(),
7982                            "thumbnail anim", 0, dirty.width(), dirty.height(),
7983                            PixelFormat.TRANSLUCENT, Surface.HIDDEN);
7984                    topOpeningApp.mAppAnimator.thumbnail = surface;
7985                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
7986                            + surface + ": CREATE");
7987                    Surface drawSurface = new Surface();
7988                    drawSurface.copyFrom(surface);
7989                    Canvas c = drawSurface.lockCanvas(dirty);
7990                    c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
7991                    drawSurface.unlockCanvasAndPost(c);
7992                    drawSurface.release();
7993                    topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
7994                    Animation anim = createThumbnailAnimationLocked(transit, true, true);
7995                    topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
7996                    anim.restrictDuration(MAX_ANIMATION_DURATION);
7997                    anim.scaleCurrentDuration(mTransitionAnimationScale);
7998                    topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX;
7999                    topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY;
8000                } catch (Surface.OutOfResourcesException e) {
8001                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
8002                            + " h=" + dirty.height(), e);
8003                    topOpeningApp.mAppAnimator.clearThumbnail();
8004                }
8005            }
8006
8007            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
8008            mNextAppTransitionPackage = null;
8009            mNextAppTransitionThumbnail = null;
8010            if (mNextAppTransitionCallback != null) {
8011                try {
8012                    mNextAppTransitionCallback.sendResult(null);
8013                } catch (RemoteException e) {
8014                }
8015            }
8016
8017            mOpeningApps.clear();
8018            mClosingApps.clear();
8019
8020            // This has changed the visibility of windows, so perform
8021            // a new layout to get them all up-to-date.
8022            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
8023                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8024            mLayoutNeeded = true;
8025            if (!moveInputMethodWindowsIfNeededLocked(true)) {
8026                assignLayersLocked();
8027            }
8028            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8029                    false /*updateInputWindows*/);
8030            mFocusMayChange = false;
8031        }
8032
8033        return changes;
8034    }
8035
8036    /**
8037     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8038     *
8039     * @return bitmap indicating if another pass through layout must be made.
8040     */
8041    private int handleAnimatingStoppedAndTransitionLocked() {
8042        int changes = 0;
8043
8044        mAppTransitionRunning = false;
8045        // Clear information about apps that were moving.
8046        mToBottomApps.clear();
8047
8048        rebuildAppWindowListLocked();
8049        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8050        mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
8051        moveInputMethodWindowsIfNeededLocked(false);
8052        mInnerFields.mWallpaperMayChange = true;
8053        // Since the window list has been rebuilt, focus might
8054        // have to be recomputed since the actual order of windows
8055        // might have changed again.
8056        mFocusMayChange = true;
8057
8058        return changes;
8059    }
8060
8061    /**
8062     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8063     *
8064     * @return bitmap indicating if another pass through layout must be made.
8065     */
8066    private int animateAwayWallpaperLocked() {
8067        int changes = 0;
8068        WindowState oldWallpaper = mWallpaperTarget;
8069        if (mLowerWallpaperTarget != null
8070                && mLowerWallpaperTarget.mAppToken != null) {
8071            if (DEBUG_WALLPAPER) Slog.v(TAG,
8072                    "wallpaperForceHiding changed with lower="
8073                    + mLowerWallpaperTarget);
8074            if (DEBUG_WALLPAPER) Slog.v(TAG,
8075                    "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
8076                    " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
8077            if (mLowerWallpaperTarget.mAppToken.hidden) {
8078                // The lower target has become hidden before we
8079                // actually started the animation...  let's completely
8080                // re-evaluate everything.
8081                mLowerWallpaperTarget = mUpperWallpaperTarget = null;
8082                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8083            }
8084        }
8085        mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8086        if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
8087                + " NEW: " + mWallpaperTarget
8088                + " LOWER: " + mLowerWallpaperTarget);
8089        return changes;
8090    }
8091
8092    private void updateResizingWindows(final WindowState w) {
8093        final WindowStateAnimator winAnimator = w.mWinAnimator;
8094        if (w.mHasSurface && !w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
8095            w.mContentInsetsChanged |=
8096                !w.mLastContentInsets.equals(w.mContentInsets);
8097            w.mVisibleInsetsChanged |=
8098                !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8099            boolean configChanged =
8100                w.mConfiguration != mCurConfiguration
8101                && (w.mConfiguration == null
8102                        || mCurConfiguration.diff(w.mConfiguration) != 0);
8103            if (DEBUG_CONFIGURATION && configChanged) {
8104                Slog.v(TAG, "Win " + w + " config changed: "
8105                        + mCurConfiguration);
8106            }
8107            if (localLOGV) Slog.v(TAG, "Resizing " + w
8108                    + ": configChanged=" + configChanged
8109                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8110            w.mLastFrame.set(w.mFrame);
8111            if (w.mContentInsetsChanged
8112                    || w.mVisibleInsetsChanged
8113                    || winAnimator.mSurfaceResized
8114                    || configChanged) {
8115                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8116                    Slog.v(TAG, "Resize reasons: "
8117                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8118                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8119                            + " surfaceResized=" + winAnimator.mSurfaceResized
8120                            + " configChanged=" + configChanged);
8121                }
8122
8123                w.mLastContentInsets.set(w.mContentInsets);
8124                w.mLastVisibleInsets.set(w.mVisibleInsets);
8125                makeWindowFreezingScreenIfNeededLocked(w);
8126                // If the orientation is changing, then we need to
8127                // hold off on unfreezing the display until this
8128                // window has been redrawn; to do that, we need
8129                // to go through the process of getting informed
8130                // by the application when it has finished drawing.
8131                if (w.mOrientationChanging) {
8132                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8133                            "Orientation start waiting for draw in "
8134                            + w + ", surface " + winAnimator.mSurface);
8135                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8136                    if (w.mAppToken != null) {
8137                        w.mAppToken.allDrawn = false;
8138                    }
8139                }
8140                if (!mResizingWindows.contains(w)) {
8141                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8142                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8143                            + "x" + winAnimator.mSurfaceH);
8144                    mResizingWindows.add(w);
8145                }
8146            } else if (w.mOrientationChanging) {
8147                if (w.isDrawnLw()) {
8148                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8149                            "Orientation not waiting for draw in "
8150                            + w + ", surface " + winAnimator.mSurface);
8151                    w.mOrientationChanging = false;
8152                }
8153            }
8154        }
8155    }
8156
8157    /**
8158     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8159     *
8160     * @param w WindowState this method is applied to.
8161     * @param currentTime The time which animations use for calculating transitions.
8162     * @param innerDw Width of app window.
8163     * @param innerDh Height of app window.
8164     */
8165    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8166                                         final int innerDw, final int innerDh) {
8167        final WindowManager.LayoutParams attrs = w.mAttrs;
8168        final int attrFlags = attrs.flags;
8169        final boolean canBeSeen = w.isDisplayedLw();
8170
8171        if (w.mHasSurface) {
8172            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8173                mInnerFields.mHoldScreen = w.mSession;
8174            }
8175            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8176                    && mInnerFields.mScreenBrightness < 0) {
8177                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8178            }
8179            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8180                    && mInnerFields.mButtonBrightness < 0) {
8181                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8182            }
8183            if (canBeSeen
8184                    && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8185                     || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8186                     || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
8187                mInnerFields.mSyswin = true;
8188            }
8189        }
8190
8191        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8192        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8193            // This window completely covers everything behind it,
8194            // so we want to leave all of them as undimmed (for
8195            // performance reasons).
8196            mInnerFields.mObscured = true;
8197        } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0
8198                && !(w.mAppToken != null && w.mAppToken.hiddenRequested)) {
8199            if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured);
8200            if (!mInnerFields.mDimming) {
8201                //Slog.i(TAG, "DIM BEHIND: " + w);
8202                mInnerFields.mDimming = true;
8203                if (!mAnimator.isDimming()) {
8204                    final int width, height;
8205                    if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
8206                        width = mCurDisplayWidth;
8207                        height = mCurDisplayHeight;
8208                    } else {
8209                        width = innerDw;
8210                        height = innerDh;
8211                    }
8212                    mAnimator.startDimming(w.mWinAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount,
8213                            width, height);
8214                }
8215            }
8216        }
8217    }
8218
8219    // "Something has changed!  Let's make it correct now."
8220    private final void performLayoutAndPlaceSurfacesLockedInner(
8221            boolean recoveringMemory) {
8222        if (DEBUG_WINDOW_TRACE) {
8223            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8224                    + Debug.getCallers(3));
8225        }
8226        if (mDisplay == null) {
8227            Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
8228            return;
8229        }
8230
8231        final long currentTime = SystemClock.uptimeMillis();
8232        final int dw = mCurDisplayWidth;
8233        final int dh = mCurDisplayHeight;
8234        final int innerDw = mAppDisplayWidth;
8235        final int innerDh = mAppDisplayHeight;
8236
8237        int i;
8238
8239        if (mFocusMayChange) {
8240            mFocusMayChange = false;
8241            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8242                    false /*updateInputWindows*/);
8243        }
8244
8245        // Initialize state of exiting tokens.
8246        for (i=mExitingTokens.size()-1; i>=0; i--) {
8247            mExitingTokens.get(i).hasVisible = false;
8248        }
8249
8250        // Initialize state of exiting applications.
8251        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8252            mExitingAppTokens.get(i).hasVisible = false;
8253        }
8254
8255        mInnerFields.mHoldScreen = null;
8256        mInnerFields.mScreenBrightness = -1;
8257        mInnerFields.mButtonBrightness = -1;
8258
8259        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8260                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8261
8262        Surface.openTransaction();
8263
8264        if (mWatermark != null) {
8265            mWatermark.positionSurface(dw, dh);
8266        }
8267        if (mStrictModeFlash != null) {
8268            mStrictModeFlash.positionSurface(dw, dh);
8269        }
8270
8271        try {
8272            int repeats = 0;
8273
8274            do {
8275                repeats++;
8276                if (repeats > 6) {
8277                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
8278                    mLayoutNeeded = false;
8279                    break;
8280                }
8281
8282                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
8283                    mPendingLayoutChanges);
8284
8285                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
8286                    if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8287                        assignLayersLocked();
8288                        mLayoutNeeded = true;
8289                    }
8290                }
8291
8292                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
8293                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
8294                    if (updateOrientationFromAppTokensLocked(true)) {
8295                        mLayoutNeeded = true;
8296                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8297                    }
8298                }
8299
8300                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8301                    mLayoutNeeded = true;
8302                }
8303
8304                // FIRST LOOP: Perform a layout, if needed.
8305                if (repeats < 4) {
8306                    performLayoutLockedInner(repeats == 1, false /*updateInputWindows*/);
8307                } else {
8308                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
8309                }
8310
8311                // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
8312                // it is animating.
8313                mPendingLayoutChanges = 0;
8314                if (DEBUG_LAYOUT_REPEATS)  debugLayoutRepeats("loop number " + mLayoutRepeatCount,
8315                    mPendingLayoutChanges);
8316                mPolicy.beginAnimationLw(dw, dh);
8317                for (i = mWindows.size() - 1; i >= 0; i--) {
8318                    WindowState w = mWindows.get(i);
8319                    if (w.mHasSurface) {
8320                        mPolicy.animatingWindowLw(w, w.mAttrs);
8321                    }
8322                }
8323                mPendingLayoutChanges |= mPolicy.finishAnimationLw();
8324                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishAnimationLw",
8325                    mPendingLayoutChanges);
8326            } while (mPendingLayoutChanges != 0);
8327
8328            final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
8329
8330            mInnerFields.mObscured = false;
8331            mInnerFields.mDimming = false;
8332            mInnerFields.mSyswin = false;
8333
8334            boolean focusDisplayed = false;
8335            final int N = mWindows.size();
8336            for (i=N-1; i>=0; i--) {
8337                WindowState w = mWindows.get(i);
8338
8339                final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
8340
8341                // Update effect.
8342                w.mObscured = mInnerFields.mObscured;
8343                if (!mInnerFields.mObscured) {
8344                    handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
8345                }
8346
8347                if (obscuredChanged && mWallpaperTarget == w) {
8348                    // This is the wallpaper target and its obscured state
8349                    // changed... make sure the current wallaper's visibility
8350                    // has been updated accordingly.
8351                    updateWallpaperVisibilityLocked();
8352                }
8353
8354                final WindowStateAnimator winAnimator = w.mWinAnimator;
8355
8356                // If the window has moved due to its containing
8357                // content frame changing, then we'd like to animate
8358                // it.
8359                if (w.mHasSurface && w.shouldAnimateMove()) {
8360                    // Frame has moved, containing content frame
8361                    // has also moved, and we're not currently animating...
8362                    // let's do something.
8363                    Animation a = AnimationUtils.loadAnimation(mContext,
8364                            com.android.internal.R.anim.window_move_from_decor);
8365                    winAnimator.setAnimation(a);
8366                    winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
8367                    winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
8368                } else {
8369                    winAnimator.mAnimDw = innerDw;
8370                    winAnimator.mAnimDh = innerDh;
8371                }
8372
8373                //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
8374                w.mContentChanged = false;
8375
8376                // Moved from updateWindowsAndWallpaperLocked().
8377                if (w.mHasSurface) {
8378                    // Take care of the window being ready to display.
8379                    if (winAnimator.commitFinishDrawingLocked(currentTime)) {
8380                        if ((w.mAttrs.flags
8381                                & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
8382                            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
8383                                    "First draw done in potential wallpaper target " + w);
8384                            mInnerFields.mWallpaperMayChange = true;
8385                            mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
8386                            if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
8387                                debugLayoutRepeats("updateWindowsAndWallpaperLocked 1",
8388                                    mPendingLayoutChanges);
8389                            }
8390                        }
8391                    }
8392
8393                    winAnimator.setSurfaceBoundaries(recoveringMemory);
8394                }
8395
8396                if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) {
8397                    focusDisplayed = true;
8398                }
8399
8400                updateResizingWindows(w);
8401            }
8402
8403            if (focusDisplayed) {
8404                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8405            }
8406
8407            if (!mInnerFields.mDimming && mAnimator.isDimming()) {
8408                mAnimator.stopDimming();
8409            }
8410        } catch (RuntimeException e) {
8411            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
8412        } finally {
8413            Surface.closeTransaction();
8414        }
8415
8416        // If we are ready to perform an app transition, check through
8417        // all of the app tokens to be shown and see if they are ready
8418        // to go.
8419        if (mAppTransitionReady) {
8420            mPendingLayoutChanges |= handleAppTransitionReadyLocked();
8421            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
8422                mPendingLayoutChanges);
8423        }
8424
8425        mInnerFields.mAdjResult = 0;
8426
8427        if (!mAnimator.mAnimating && mAppTransitionRunning) {
8428            // We have finished the animation of an app transition.  To do
8429            // this, we have delayed a lot of operations like showing and
8430            // hiding apps, moving apps in Z-order, etc.  The app token list
8431            // reflects the correct Z-order, but the window list may now
8432            // be out of sync with it.  So here we will just rebuild the
8433            // entire app window list.  Fun!
8434            mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
8435            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
8436                mPendingLayoutChanges);
8437        }
8438
8439        if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 &&
8440                !mAppTransitionReady) {
8441            // At this point, there was a window with a wallpaper that
8442            // was force hiding other windows behind it, but now it
8443            // is going away.  This may be simple -- just animate
8444            // away the wallpaper and its window -- or it may be
8445            // hard -- the wallpaper now needs to be shown behind
8446            // something that was hidden.
8447            mPendingLayoutChanges |= animateAwayWallpaperLocked();
8448            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
8449                mPendingLayoutChanges);
8450        }
8451        mInnerFields.mWallpaperForceHidingChanged = false;
8452
8453        if (mInnerFields.mWallpaperMayChange) {
8454            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
8455                    "Wallpaper may change!  Adjusting");
8456            mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8457        }
8458
8459        if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8460            if (DEBUG_WALLPAPER) Slog.v(TAG,
8461                    "Wallpaper layer changed: assigning layers + relayout");
8462            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8463            assignLayersLocked();
8464        } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
8465            if (DEBUG_WALLPAPER) Slog.v(TAG,
8466                    "Wallpaper visibility changed: relayout");
8467            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8468        }
8469
8470        if (mFocusMayChange) {
8471            mFocusMayChange = false;
8472            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8473                    false /*updateInputWindows*/)) {
8474                mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8475                mInnerFields.mAdjResult = 0;
8476            }
8477        }
8478
8479        if (mLayoutNeeded) {
8480            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8481            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges);
8482        }
8483
8484        if (!mResizingWindows.isEmpty()) {
8485            for (i = mResizingWindows.size() - 1; i >= 0; i--) {
8486                WindowState win = mResizingWindows.get(i);
8487                final WindowStateAnimator winAnimator = win.mWinAnimator;
8488                try {
8489                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8490                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
8491                    int diff = 0;
8492                    boolean configChanged =
8493                        win.mConfiguration != mCurConfiguration
8494                        && (win.mConfiguration == null
8495                                || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0);
8496                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
8497                            && configChanged) {
8498                        Slog.i(TAG, "Sending new config to window " + win + ": "
8499                                + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
8500                                + " / " + mCurConfiguration + " / 0x"
8501                                + Integer.toHexString(diff));
8502                    }
8503                    win.mConfiguration = mCurConfiguration;
8504                    if (DEBUG_ORIENTATION &&
8505                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
8506                            TAG, "Resizing " + win + " WITH DRAW PENDING");
8507                    win.mClient.resized((int)winAnimator.mSurfaceW,
8508                            (int)winAnimator.mSurfaceH,
8509                            win.mLastContentInsets, win.mLastVisibleInsets,
8510                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
8511                            configChanged ? win.mConfiguration : null);
8512                    win.mContentInsetsChanged = false;
8513                    win.mVisibleInsetsChanged = false;
8514                    winAnimator.mSurfaceResized = false;
8515                } catch (RemoteException e) {
8516                    win.mOrientationChanging = false;
8517                }
8518            }
8519            mResizingWindows.clear();
8520        }
8521
8522        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
8523                "With display frozen, orientationChangeComplete="
8524                + mInnerFields.mOrientationChangeComplete);
8525        if (mInnerFields.mOrientationChangeComplete) {
8526            if (mWindowsFreezingScreen) {
8527                mWindowsFreezingScreen = false;
8528                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8529            }
8530            stopFreezingDisplayLocked();
8531        }
8532
8533        // Destroy the surface of any windows that are no longer visible.
8534        boolean wallpaperDestroyed = false;
8535        i = mDestroySurface.size();
8536        if (i > 0) {
8537            do {
8538                i--;
8539                WindowState win = mDestroySurface.get(i);
8540                win.mDestroying = false;
8541                if (mInputMethodWindow == win) {
8542                    mInputMethodWindow = null;
8543                }
8544                if (win == mWallpaperTarget) {
8545                    wallpaperDestroyed = true;
8546                }
8547                win.mWinAnimator.destroySurfaceLocked();
8548            } while (i > 0);
8549            mDestroySurface.clear();
8550        }
8551
8552        // Time to remove any exiting tokens?
8553        for (i=mExitingTokens.size()-1; i>=0; i--) {
8554            WindowToken token = mExitingTokens.get(i);
8555            if (!token.hasVisible) {
8556                mExitingTokens.remove(i);
8557                if (token.windowType == TYPE_WALLPAPER) {
8558                    mWallpaperTokens.remove(token);
8559                }
8560            }
8561        }
8562
8563        // Time to remove any exiting applications?
8564        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8565            AppWindowToken token = mExitingAppTokens.get(i);
8566            if (!token.hasVisible && !mClosingApps.contains(token)) {
8567                // Make sure there is no animation running on this token,
8568                // so any windows associated with it will be removed as
8569                // soon as their animations are complete
8570                token.mAppAnimator.clearAnimation();
8571                token.mAppAnimator.animating = false;
8572                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
8573                        "performLayout: App token exiting now removed" + token);
8574                mAppTokens.remove(token);
8575                mExitingAppTokens.remove(i);
8576            }
8577        }
8578
8579        if (!mAnimator.mAnimating && mAppTransitionRunning) {
8580            // We have finished the animation of an app transition.  To do
8581            // this, we have delayed a lot of operations like showing and
8582            // hiding apps, moving apps in Z-order, etc.  The app token list
8583            // reflects the correct Z-order, but the window list may now
8584            // be out of sync with it.  So here we will just rebuild the
8585            // entire app window list.  Fun!
8586            mAppTransitionRunning = false;
8587            mLayoutNeeded = true;
8588            rebuildAppWindowListLocked();
8589            assignLayersLocked();
8590            // Clear information about apps that were moving.
8591            mToBottomApps.clear();
8592        }
8593
8594        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
8595            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
8596                try {
8597                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
8598                } catch (RemoteException e) {
8599                }
8600            }
8601            mRelayoutWhileAnimating.clear();
8602        }
8603
8604        if (wallpaperDestroyed) {
8605            mLayoutNeeded |= adjustWallpaperWindowsLocked() != 0;
8606        }
8607        if (mPendingLayoutChanges != 0) {
8608            mLayoutNeeded = true;
8609        }
8610
8611        // Finally update all input windows now that the window changes have stabilized.
8612        mInputMonitor.updateInputWindowsLw(true /*force*/);
8613
8614        setHoldScreenLocked(mInnerFields.mHoldScreen != null);
8615        if (!mDisplayFrozen) {
8616            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
8617                mPowerManager.setScreenBrightnessOverride(-1);
8618            } else {
8619                mPowerManager.setScreenBrightnessOverride((int)
8620                        (mInnerFields.mScreenBrightness * Power.BRIGHTNESS_ON));
8621            }
8622            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
8623                mPowerManager.setButtonBrightnessOverride(-1);
8624            } else {
8625                mPowerManager.setButtonBrightnessOverride((int)
8626                        (mInnerFields.mButtonBrightness * Power.BRIGHTNESS_ON));
8627            }
8628        }
8629        if (mInnerFields.mHoldScreen != mHoldingScreenOn) {
8630            mHoldingScreenOn = mInnerFields.mHoldScreen;
8631            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, mInnerFields.mHoldScreen);
8632            mH.sendMessage(m);
8633        }
8634
8635        if (mTurnOnScreen) {
8636            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
8637            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
8638                    LocalPowerManager.BUTTON_EVENT, true);
8639            mTurnOnScreen = false;
8640        }
8641
8642        if (mInnerFields.mUpdateRotation) {
8643            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8644            if (updateRotationUncheckedLocked(false)) {
8645                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8646            } else {
8647                mInnerFields.mUpdateRotation = false;
8648            }
8649        }
8650
8651        if (mInnerFields.mOrientationChangeComplete && !mLayoutNeeded &&
8652                !mInnerFields.mUpdateRotation) {
8653            checkDrawnWindowsLocked();
8654        }
8655
8656        // Check to see if we are now in a state where the screen should
8657        // be enabled, because the window obscured flags have changed.
8658        enableScreenIfNeededLocked();
8659
8660        scheduleAnimationLocked();
8661
8662        if (DEBUG_WINDOW_TRACE) {
8663            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges="
8664                + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded
8665                + " animating=" + mAnimator.mAnimating);
8666        }
8667    }
8668
8669    void checkDrawnWindowsLocked() {
8670        if (mWaitingForDrawn.size() > 0) {
8671            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
8672                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
8673                WindowState win = pair.first;
8674                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
8675                //        + win.mRemoved + " visible=" + win.isVisibleLw()
8676                //        + " shown=" + win.mSurfaceShown);
8677                if (win.mRemoved || !win.isVisibleLw()) {
8678                    // Window has been removed or made invisible; no draw
8679                    // will now happen, so stop waiting.
8680                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
8681                    try {
8682                        pair.second.sendResult(null);
8683                    } catch (RemoteException e) {
8684                    }
8685                    mWaitingForDrawn.remove(pair);
8686                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8687                } else if (win.mWinAnimator.mSurfaceShown) {
8688                    // Window is now drawn (and shown).
8689                    try {
8690                        pair.second.sendResult(null);
8691                    } catch (RemoteException e) {
8692                    }
8693                    mWaitingForDrawn.remove(pair);
8694                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8695                }
8696            }
8697        }
8698    }
8699
8700    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
8701        synchronized (mWindowMap) {
8702            WindowState win = windowForClientLocked(null, token, true);
8703            if (win != null) {
8704                Pair<WindowState, IRemoteCallback> pair =
8705                        new Pair<WindowState, IRemoteCallback>(win, callback);
8706                Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8707                mH.sendMessageDelayed(m, 2000);
8708                mWaitingForDrawn.add(pair);
8709                checkDrawnWindowsLocked();
8710            }
8711        }
8712    }
8713
8714    /**
8715     * Must be called with the main window manager lock held.
8716     */
8717    void setHoldScreenLocked(boolean holding) {
8718        boolean state = mHoldingScreenWakeLock.isHeld();
8719        if (holding != state) {
8720            if (holding) {
8721                mPolicy.screenOnStartedLw();
8722                mHoldingScreenWakeLock.acquire();
8723            } else {
8724                mPolicy.screenOnStoppedLw();
8725                mHoldingScreenWakeLock.release();
8726            }
8727        }
8728    }
8729
8730    void requestTraversalLocked() {
8731        if (!mTraversalScheduled) {
8732            mTraversalScheduled = true;
8733            mH.sendEmptyMessage(H.DO_TRAVERSAL);
8734        }
8735    }
8736
8737    void scheduleAnimationLocked() {
8738        if (!mAnimationScheduled) {
8739            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationRunnable, null);
8740            mAnimationScheduled = true;
8741        }
8742    }
8743
8744    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
8745                                           boolean secure) {
8746        final Surface surface = winAnimator.mSurface;
8747        boolean leakedSurface = false;
8748        boolean killedApps = false;
8749
8750        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
8751                winAnimator.mSession.mPid, operation);
8752
8753        if (mForceRemoves == null) {
8754            mForceRemoves = new ArrayList<WindowState>();
8755        }
8756
8757        long callingIdentity = Binder.clearCallingIdentity();
8758        try {
8759            // There was some problem...   first, do a sanity check of the
8760            // window list to make sure we haven't left any dangling surfaces
8761            // around.
8762            int N = mWindows.size();
8763            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
8764            for (int i=0; i<N; i++) {
8765                WindowState ws = mWindows.get(i);
8766                WindowStateAnimator wsa = ws.mWinAnimator;
8767                if (wsa.mSurface != null) {
8768                    if (!mSessions.contains(wsa.mSession)) {
8769                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8770                                + ws + " surface=" + wsa.mSurface
8771                                + " token=" + ws.mToken
8772                                + " pid=" + ws.mSession.mPid
8773                                + " uid=" + ws.mSession.mUid);
8774                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8775                        wsa.mSurface.destroy();
8776                        wsa.mSurfaceShown = false;
8777                        wsa.mSurface = null;
8778                        ws.mHasSurface = false;
8779                        mForceRemoves.add(ws);
8780                        i--;
8781                        N--;
8782                        leakedSurface = true;
8783                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
8784                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
8785                                + ws + " surface=" + wsa.mSurface
8786                                + " token=" + ws.mAppToken);
8787                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8788                        wsa.mSurface.destroy();
8789                        wsa.mSurfaceShown = false;
8790                        wsa.mSurface = null;
8791                        ws.mHasSurface = false;
8792                        leakedSurface = true;
8793                    }
8794                }
8795            }
8796
8797            if (!leakedSurface) {
8798                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
8799                SparseIntArray pidCandidates = new SparseIntArray();
8800                for (int i=0; i<N; i++) {
8801                    WindowStateAnimator wsa = mWindows.get(i).mWinAnimator;
8802                    if (wsa.mSurface != null) {
8803                        pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
8804                    }
8805                }
8806                if (pidCandidates.size() > 0) {
8807                    int[] pids = new int[pidCandidates.size()];
8808                    for (int i=0; i<pids.length; i++) {
8809                        pids[i] = pidCandidates.keyAt(i);
8810                    }
8811                    try {
8812                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
8813                            killedApps = true;
8814                        }
8815                    } catch (RemoteException e) {
8816                    }
8817                }
8818            }
8819
8820            if (leakedSurface || killedApps) {
8821                // We managed to reclaim some memory, so get rid of the trouble
8822                // surface and ask the app to request another one.
8823                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8824                if (surface != null) {
8825                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
8826                            "RECOVER DESTROY", null);
8827                    surface.destroy();
8828                    winAnimator.mSurfaceShown = false;
8829                    winAnimator.mSurface = null;
8830                    winAnimator.mWin.mHasSurface = false;
8831                }
8832
8833                try {
8834                    winAnimator.mWin.mClient.dispatchGetNewSurface();
8835                } catch (RemoteException e) {
8836                }
8837            }
8838        } finally {
8839            Binder.restoreCallingIdentity(callingIdentity);
8840        }
8841
8842        return leakedSurface || killedApps;
8843    }
8844
8845    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
8846        WindowState newFocus = computeFocusedWindowLocked();
8847        if (mCurrentFocus != newFocus) {
8848            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
8849            // This check makes sure that we don't already have the focus
8850            // change message pending.
8851            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
8852            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
8853            if (localLOGV) Slog.v(
8854                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
8855            final WindowState oldFocus = mCurrentFocus;
8856            mCurrentFocus = newFocus;
8857            mAnimator.setCurrentFocus(newFocus);
8858            mLosingFocus.remove(newFocus);
8859            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
8860
8861            final WindowState imWindow = mInputMethodWindow;
8862            if (newFocus != imWindow && oldFocus != imWindow) {
8863                if (moveInputMethodWindowsIfNeededLocked(
8864                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
8865                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
8866                    mLayoutNeeded = true;
8867                }
8868                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8869                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
8870                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
8871                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
8872                    // Client will do the layout, but we need to assign layers
8873                    // for handleNewWindowLocked() below.
8874                    assignLayersLocked();
8875                }
8876            }
8877
8878            if ((focusChanged&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8879                // The change in focus caused us to need to do a layout.  Okay.
8880                mLayoutNeeded = true;
8881                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8882                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
8883                }
8884            }
8885
8886            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
8887                // If we defer assigning layers, then the caller is responsible for
8888                // doing this part.
8889                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
8890            }
8891
8892            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
8893            return true;
8894        }
8895        return false;
8896    }
8897
8898    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
8899        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
8900    }
8901
8902    private WindowState computeFocusedWindowLocked() {
8903        WindowState result = null;
8904        WindowState win;
8905
8906        int nextAppIndex = mAppTokens.size()-1;
8907        WindowToken nextApp = nextAppIndex >= 0
8908            ? mAppTokens.get(nextAppIndex) : null;
8909
8910        for (int i = mWindows.size() - 1; i >= 0; i--) {
8911            win = mWindows.get(i);
8912
8913            if (localLOGV || DEBUG_FOCUS) Slog.v(
8914                TAG, "Looking for focus: " + i
8915                + " = " + win
8916                + ", flags=" + win.mAttrs.flags
8917                + ", canReceive=" + win.canReceiveKeys());
8918
8919            AppWindowToken thisApp = win.mAppToken;
8920
8921            // If this window's application has been removed, just skip it.
8922            if (thisApp != null && thisApp.removed) {
8923                continue;
8924            }
8925
8926            // If there is a focused app, don't allow focus to go to any
8927            // windows below it.  If this is an application window, step
8928            // through the app tokens until we find its app.
8929            if (thisApp != null && nextApp != null && thisApp != nextApp
8930                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
8931                int origAppIndex = nextAppIndex;
8932                while (nextAppIndex > 0) {
8933                    if (nextApp == mFocusedApp) {
8934                        // Whoops, we are below the focused app...  no focus
8935                        // for you!
8936                        if (localLOGV || DEBUG_FOCUS) Slog.v(
8937                            TAG, "Reached focused app: " + mFocusedApp);
8938                        return null;
8939                    }
8940                    nextAppIndex--;
8941                    nextApp = mAppTokens.get(nextAppIndex);
8942                    if (nextApp == thisApp) {
8943                        break;
8944                    }
8945                }
8946                if (thisApp != nextApp) {
8947                    // Uh oh, the app token doesn't exist!  This shouldn't
8948                    // happen, but if it does we can get totally hosed...
8949                    // so restart at the original app.
8950                    nextAppIndex = origAppIndex;
8951                    nextApp = mAppTokens.get(nextAppIndex);
8952                }
8953            }
8954
8955            // Dispatch to this window if it is wants key events.
8956            if (win.canReceiveKeys()) {
8957                if (DEBUG_FOCUS) Slog.v(
8958                        TAG, "Found focus @ " + i + " = " + win);
8959                result = win;
8960                break;
8961            }
8962        }
8963
8964        return result;
8965    }
8966
8967    private void startFreezingDisplayLocked(boolean inTransaction) {
8968        if (mDisplayFrozen) {
8969            return;
8970        }
8971
8972        if (mDisplay == null || !mPolicy.isScreenOnFully()) {
8973            // No need to freeze the screen before the system is ready or if
8974            // the screen is off.
8975            return;
8976        }
8977
8978        mScreenFrozenLock.acquire();
8979
8980        mDisplayFrozen = true;
8981
8982        mInputMonitor.freezeInputDispatchingLw();
8983
8984        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
8985            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
8986            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
8987            mNextAppTransitionPackage = null;
8988            mNextAppTransitionThumbnail = null;
8989            mAppTransitionReady = true;
8990        }
8991
8992        if (PROFILE_ORIENTATION) {
8993            File file = new File("/data/system/frozen");
8994            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
8995        }
8996
8997        if (CUSTOM_SCREEN_ROTATION) {
8998            if (mAnimator.mScreenRotationAnimation != null) {
8999                mAnimator.mScreenRotationAnimation.kill();
9000                mAnimator.mScreenRotationAnimation = null;
9001            }
9002
9003            mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
9004                    mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight,
9005                    mDisplay.getRotation());
9006
9007            if (!mAnimator.mScreenRotationAnimation.hasScreenshot()) {
9008                Surface.freezeDisplay(0);
9009            }
9010        } else {
9011            Surface.freezeDisplay(0);
9012        }
9013    }
9014
9015    private void stopFreezingDisplayLocked() {
9016        if (!mDisplayFrozen) {
9017            return;
9018        }
9019
9020        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
9021            if (DEBUG_ORIENTATION) Slog.d(TAG,
9022                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
9023                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
9024                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen);
9025            return;
9026        }
9027
9028        mDisplayFrozen = false;
9029        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9030        if (PROFILE_ORIENTATION) {
9031            Debug.stopMethodTracing();
9032        }
9033
9034        boolean updateRotation = false;
9035
9036        if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
9037                && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
9038            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
9039            if (mAnimator.mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9040                    mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
9041                scheduleAnimationLocked();
9042            } else {
9043                mAnimator.mScreenRotationAnimation.kill();
9044                mAnimator.mScreenRotationAnimation = null;
9045                updateRotation = true;
9046            }
9047        } else {
9048            if (mAnimator.mScreenRotationAnimation != null) {
9049                mAnimator.mScreenRotationAnimation.kill();
9050                mAnimator.mScreenRotationAnimation = null;
9051            }
9052            updateRotation = true;
9053        }
9054        Surface.unfreezeDisplay(0);
9055
9056        mInputMonitor.thawInputDispatchingLw();
9057
9058        boolean configChanged;
9059
9060        // While the display is frozen we don't re-compute the orientation
9061        // to avoid inconsistent states.  However, something interesting
9062        // could have actually changed during that time so re-evaluate it
9063        // now to catch that.
9064        configChanged = updateOrientationFromAppTokensLocked(false);
9065
9066        // A little kludge: a lot could have happened while the
9067        // display was frozen, so now that we are coming back we
9068        // do a gc so that any remote references the system
9069        // processes holds on others can be released if they are
9070        // no longer needed.
9071        mH.removeMessages(H.FORCE_GC);
9072        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
9073                2000);
9074
9075        mScreenFrozenLock.release();
9076
9077        if (updateRotation) {
9078            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9079            configChanged |= updateRotationUncheckedLocked(false);
9080        }
9081
9082        if (configChanged) {
9083            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9084        }
9085    }
9086
9087    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
9088            DisplayMetrics dm) {
9089        if (index < tokens.length) {
9090            String str = tokens[index];
9091            if (str != null && str.length() > 0) {
9092                try {
9093                    int val = Integer.parseInt(str);
9094                    return val;
9095                } catch (Exception e) {
9096                }
9097            }
9098        }
9099        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
9100            return defDps;
9101        }
9102        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
9103        return val;
9104    }
9105
9106    void createWatermark() {
9107        if (mWatermark != null) {
9108            return;
9109        }
9110
9111        File file = new File("/system/etc/setup.conf");
9112        FileInputStream in = null;
9113        try {
9114            in = new FileInputStream(file);
9115            DataInputStream ind = new DataInputStream(in);
9116            String line = ind.readLine();
9117            if (line != null) {
9118                String[] toks = line.split("%");
9119                if (toks != null && toks.length > 0) {
9120                    mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks);
9121                }
9122            }
9123        } catch (FileNotFoundException e) {
9124        } catch (IOException e) {
9125        } finally {
9126            if (in != null) {
9127                try {
9128                    in.close();
9129                } catch (IOException e) {
9130                }
9131            }
9132        }
9133    }
9134
9135    @Override
9136    public void statusBarVisibilityChanged(int visibility) {
9137        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
9138                != PackageManager.PERMISSION_GRANTED) {
9139            throw new SecurityException("Caller does not hold permission "
9140                    + android.Manifest.permission.STATUS_BAR);
9141        }
9142
9143        synchronized (mWindowMap) {
9144            mLastStatusBarVisibility = visibility;
9145            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
9146            updateStatusBarVisibilityLocked(visibility);
9147        }
9148    }
9149
9150    void updateStatusBarVisibilityLocked(int visibility) {
9151        mInputManager.setSystemUiVisibility(visibility);
9152        final int N = mWindows.size();
9153        for (int i = 0; i < N; i++) {
9154            WindowState ws = mWindows.get(i);
9155            try {
9156                int curValue = ws.mSystemUiVisibility;
9157                int diff = curValue ^ visibility;
9158                // We are only interested in differences of one of the
9159                // clearable flags...
9160                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
9161                // ...if it has actually been cleared.
9162                diff &= ~visibility;
9163                int newValue = (curValue&~diff) | (visibility&diff);
9164                if (newValue != curValue) {
9165                    ws.mSeq++;
9166                    ws.mSystemUiVisibility = newValue;
9167                }
9168                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
9169                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
9170                            visibility, newValue, diff);
9171                }
9172            } catch (RemoteException e) {
9173                // so sorry
9174            }
9175        }
9176    }
9177
9178    @Override
9179    public void reevaluateStatusBarVisibility() {
9180        synchronized (mWindowMap) {
9181            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
9182            updateStatusBarVisibilityLocked(visibility);
9183            performLayoutAndPlaceSurfacesLocked();
9184        }
9185    }
9186
9187    @Override
9188    public FakeWindow addFakeWindow(Looper looper,
9189            InputEventReceiver.Factory inputEventReceiverFactory,
9190            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
9191            boolean hasFocus, boolean touchFullscreen) {
9192        synchronized (mWindowMap) {
9193            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
9194                    name, windowType,
9195                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
9196            int i=0;
9197            while (i<mFakeWindows.size()) {
9198                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
9199                    break;
9200                }
9201            }
9202            mFakeWindows.add(i, fw);
9203            mInputMonitor.updateInputWindowsLw(true);
9204            return fw;
9205        }
9206    }
9207
9208    boolean removeFakeWindowLocked(FakeWindow window) {
9209        synchronized (mWindowMap) {
9210            if (mFakeWindows.remove(window)) {
9211                mInputMonitor.updateInputWindowsLw(true);
9212                return true;
9213            }
9214            return false;
9215        }
9216    }
9217
9218    @Override
9219    public boolean hasNavigationBar() {
9220        return mPolicy.hasNavigationBar();
9221    }
9222
9223    public void lockNow() {
9224        mPolicy.lockNow();
9225    }
9226
9227    void dumpPolicyLocked(FileDescriptor fd, PrintWriter pw, String[] args, boolean dumpAll) {
9228        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
9229        mPolicy.dump("    ", fd, pw, args);
9230    }
9231
9232    void dumpTokensLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9233        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
9234        if (mTokenMap.size() > 0) {
9235            pw.println("  All tokens:");
9236            Iterator<WindowToken> it = mTokenMap.values().iterator();
9237            while (it.hasNext()) {
9238                WindowToken token = it.next();
9239                pw.print("  Token "); pw.print(token.token);
9240                if (dumpAll) {
9241                    pw.println(':');
9242                    token.dump(pw, "    ");
9243                } else {
9244                    pw.println();
9245                }
9246            }
9247        }
9248        if (mWallpaperTokens.size() > 0) {
9249            pw.println();
9250            pw.println("  Wallpaper tokens:");
9251            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
9252                WindowToken token = mWallpaperTokens.get(i);
9253                pw.print("  Wallpaper #"); pw.print(i);
9254                        pw.print(' '); pw.print(token);
9255                if (dumpAll) {
9256                    pw.println(':');
9257                    token.dump(pw, "    ");
9258                } else {
9259                    pw.println();
9260                }
9261            }
9262        }
9263        if (mAppTokens.size() > 0) {
9264            pw.println();
9265            pw.println("  Application tokens in Z order:");
9266            for (int i=mAppTokens.size()-1; i>=0; i--) {
9267                pw.print("  App #"); pw.print(i); pw.println(": ");
9268                        mAppTokens.get(i).dump(pw, "    ");
9269            }
9270        }
9271        if (mFinishedStarting.size() > 0) {
9272            pw.println();
9273            pw.println("  Finishing start of application tokens:");
9274            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9275                WindowToken token = mFinishedStarting.get(i);
9276                pw.print("  Finished Starting #"); pw.print(i);
9277                        pw.print(' '); pw.print(token);
9278                if (dumpAll) {
9279                    pw.println(':');
9280                    token.dump(pw, "    ");
9281                } else {
9282                    pw.println();
9283                }
9284            }
9285        }
9286        if (mExitingTokens.size() > 0) {
9287            pw.println();
9288            pw.println("  Exiting tokens:");
9289            for (int i=mExitingTokens.size()-1; i>=0; i--) {
9290                WindowToken token = mExitingTokens.get(i);
9291                pw.print("  Exiting #"); pw.print(i);
9292                        pw.print(' '); pw.print(token);
9293                if (dumpAll) {
9294                    pw.println(':');
9295                    token.dump(pw, "    ");
9296                } else {
9297                    pw.println();
9298                }
9299            }
9300        }
9301        if (mExitingAppTokens.size() > 0) {
9302            pw.println();
9303            pw.println("  Exiting application tokens:");
9304            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9305                WindowToken token = mExitingAppTokens.get(i);
9306                pw.print("  Exiting App #"); pw.print(i);
9307                        pw.print(' '); pw.print(token);
9308                if (dumpAll) {
9309                    pw.println(':');
9310                    token.dump(pw, "    ");
9311                } else {
9312                    pw.println();
9313                }
9314            }
9315        }
9316        pw.println();
9317        if (mOpeningApps.size() > 0) {
9318            pw.print("  mOpeningApps="); pw.println(mOpeningApps);
9319        }
9320        if (mClosingApps.size() > 0) {
9321            pw.print("  mClosingApps="); pw.println(mClosingApps);
9322        }
9323        if (mToTopApps.size() > 0) {
9324            pw.print("  mToTopApps="); pw.println(mToTopApps);
9325        }
9326        if (mToBottomApps.size() > 0) {
9327            pw.print("  mToBottomApps="); pw.println(mToBottomApps);
9328        }
9329    }
9330
9331    void dumpSessionsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9332        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
9333        if (mSessions.size() > 0) {
9334            Iterator<Session> it = mSessions.iterator();
9335            while (it.hasNext()) {
9336                Session s = it.next();
9337                pw.print("  Session "); pw.print(s); pw.println(':');
9338                s.dump(pw, "    ");
9339            }
9340        }
9341    }
9342
9343    void dumpWindowsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
9344            ArrayList<WindowState> windows) {
9345        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
9346        for (int i=mWindows.size()-1; i>=0; i--) {
9347            WindowState w = mWindows.get(i);
9348            if (windows == null || windows.contains(w)) {
9349                pw.print("  Window #"); pw.print(i); pw.print(' ');
9350                        pw.print(w); pw.println(":");
9351                w.dump(pw, "    ", dumpAll || windows != null);
9352            }
9353        }
9354        if (mInputMethodDialogs.size() > 0) {
9355            pw.println();
9356            pw.println("  Input method dialogs:");
9357            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
9358                WindowState w = mInputMethodDialogs.get(i);
9359                if (windows == null || windows.contains(w)) {
9360                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
9361                }
9362            }
9363        }
9364        if (mPendingRemove.size() > 0) {
9365            pw.println();
9366            pw.println("  Remove pending for:");
9367            for (int i=mPendingRemove.size()-1; i>=0; i--) {
9368                WindowState w = mPendingRemove.get(i);
9369                if (windows == null || windows.contains(w)) {
9370                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
9371                            pw.print(w);
9372                    if (dumpAll) {
9373                        pw.println(":");
9374                        w.dump(pw, "    ", true);
9375                    } else {
9376                        pw.println();
9377                    }
9378                }
9379            }
9380        }
9381        if (mForceRemoves != null && mForceRemoves.size() > 0) {
9382            pw.println();
9383            pw.println("  Windows force removing:");
9384            for (int i=mForceRemoves.size()-1; i>=0; i--) {
9385                WindowState w = mForceRemoves.get(i);
9386                pw.print("  Removing #"); pw.print(i); pw.print(' ');
9387                        pw.print(w);
9388                if (dumpAll) {
9389                    pw.println(":");
9390                    w.dump(pw, "    ", true);
9391                } else {
9392                    pw.println();
9393                }
9394            }
9395        }
9396        if (mDestroySurface.size() > 0) {
9397            pw.println();
9398            pw.println("  Windows waiting to destroy their surface:");
9399            for (int i=mDestroySurface.size()-1; i>=0; i--) {
9400                WindowState w = mDestroySurface.get(i);
9401                if (windows == null || windows.contains(w)) {
9402                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
9403                            pw.print(w);
9404                    if (dumpAll) {
9405                        pw.println(":");
9406                        w.dump(pw, "    ", true);
9407                    } else {
9408                        pw.println();
9409                    }
9410                }
9411            }
9412        }
9413        if (mLosingFocus.size() > 0) {
9414            pw.println();
9415            pw.println("  Windows losing focus:");
9416            for (int i=mLosingFocus.size()-1; i>=0; i--) {
9417                WindowState w = mLosingFocus.get(i);
9418                if (windows == null || windows.contains(w)) {
9419                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
9420                            pw.print(w);
9421                    if (dumpAll) {
9422                        pw.println(":");
9423                        w.dump(pw, "    ", true);
9424                    } else {
9425                        pw.println();
9426                    }
9427                }
9428            }
9429        }
9430        if (mResizingWindows.size() > 0) {
9431            pw.println();
9432            pw.println("  Windows waiting to resize:");
9433            for (int i=mResizingWindows.size()-1; i>=0; i--) {
9434                WindowState w = mResizingWindows.get(i);
9435                if (windows == null || windows.contains(w)) {
9436                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
9437                            pw.print(w);
9438                    if (dumpAll) {
9439                        pw.println(":");
9440                        w.dump(pw, "    ", true);
9441                    } else {
9442                        pw.println();
9443                    }
9444                }
9445            }
9446        }
9447        if (mWaitingForDrawn.size() > 0) {
9448            pw.println();
9449            pw.println("  Clients waiting for these windows to be drawn:");
9450            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
9451                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
9452                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
9453                        pw.print(": "); pw.println(pair.second);
9454            }
9455        }
9456        pw.println();
9457        if (mDisplay != null) {
9458            pw.print("  Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
9459                    pw.print(mInitialDisplayHeight);
9460                    if (mInitialDisplayWidth != mBaseDisplayWidth
9461                            || mInitialDisplayHeight != mBaseDisplayHeight) {
9462                        pw.print(" base=");
9463                        pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
9464                    }
9465                    final int rawWidth = mDisplay.getRawWidth();
9466                    final int rawHeight = mDisplay.getRawHeight();
9467                    if (rawWidth != mCurDisplayWidth || rawHeight != mCurDisplayHeight) {
9468                        pw.print(" raw="); pw.print(rawWidth); pw.print("x"); pw.print(rawHeight);
9469                    }
9470                    pw.print(" cur=");
9471                    pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
9472                    pw.print(" app=");
9473                    pw.print(mAppDisplayWidth); pw.print("x"); pw.print(mAppDisplayHeight);
9474                    pw.print(" rng="); pw.print(mSmallestDisplayWidth);
9475                    pw.print("x"); pw.print(mSmallestDisplayHeight);
9476                    pw.print("-"); pw.print(mLargestDisplayWidth);
9477                    pw.print("x"); pw.println(mLargestDisplayHeight);
9478        } else {
9479            pw.println("  NO DISPLAY");
9480        }
9481        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
9482        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
9483        if (mLastFocus != mCurrentFocus) {
9484            pw.print("  mLastFocus="); pw.println(mLastFocus);
9485        }
9486        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
9487        if (mInputMethodTarget != null) {
9488            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
9489        }
9490        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
9491                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
9492        if (dumpAll) {
9493            if (mLastStatusBarVisibility != 0) {
9494                pw.print("  mLastStatusBarVisibility=0x");
9495                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
9496            }
9497            if (mInputMethodWindow != null) {
9498                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
9499            }
9500            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
9501            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
9502                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
9503                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
9504            }
9505            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
9506                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
9507            if (mInputMethodAnimLayerAdjustment != 0 ||
9508                    mWallpaperAnimLayerAdjustment != 0) {
9509                pw.print("  mInputMethodAnimLayerAdjustment=");
9510                        pw.print(mInputMethodAnimLayerAdjustment);
9511                        pw.print("  mWallpaperAnimLayerAdjustment=");
9512                        pw.println(mWallpaperAnimLayerAdjustment);
9513            }
9514            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
9515                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9516            pw.print("  mLayoutNeeded="); pw.println(mLayoutNeeded);
9517            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
9518                    pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9519                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
9520                    pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
9521            pw.print("  mRotation="); pw.print(mRotation);
9522                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
9523            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
9524                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
9525            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
9526            if (mAnimator.mScreenRotationAnimation != null) {
9527                pw.println("  mScreenRotationAnimation:");
9528                mAnimator.mScreenRotationAnimation.printTo("    ", pw);
9529            }
9530            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9531                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
9532                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
9533            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
9534                    pw.print("  mNextAppTransition=0x");
9535                    pw.print(Integer.toHexString(mNextAppTransition));
9536                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
9537            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
9538                    pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout);
9539            if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) {
9540                pw.print("  mNextAppTransitionType="); pw.println(mNextAppTransitionType);
9541            }
9542            switch (mNextAppTransitionType) {
9543                case ActivityOptions.ANIM_CUSTOM:
9544                    pw.print("  mNextAppTransitionPackage=");
9545                            pw.print(mNextAppTransitionPackage);
9546                            pw.print(" mNextAppTransitionEnter=0x");
9547                            pw.print(Integer.toHexString(mNextAppTransitionEnter));
9548                            pw.print(" mNextAppTransitionExit=0x");
9549                            pw.print(Integer.toHexString(mNextAppTransitionExit));
9550                    break;
9551                case ActivityOptions.ANIM_SCALE_UP:
9552                    pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
9553                            pw.print(" mNextAppTransitionStartY=");
9554                            pw.println(mNextAppTransitionStartY);
9555                    pw.print("  mNextAppTransitionStartWidth=");
9556                            pw.print(mNextAppTransitionStartWidth);
9557                            pw.print(" mNextAppTransitionStartHeight=");
9558                            pw.println(mNextAppTransitionStartHeight);
9559                    break;
9560                case ActivityOptions.ANIM_THUMBNAIL:
9561                    pw.print("  mNextAppTransitionThumbnail=");
9562                            pw.print(mNextAppTransitionThumbnail);
9563                            pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
9564                            pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY);
9565                    break;
9566            }
9567            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9568                    pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9569        }
9570    }
9571
9572    boolean dumpWindows(FileDescriptor fd, PrintWriter pw, String name, String[] args,
9573            int opti, boolean dumpAll) {
9574        ArrayList<WindowState> windows = new ArrayList<WindowState>();
9575        if ("visible".equals(name)) {
9576            synchronized(mWindowMap) {
9577                for (int i=mWindows.size()-1; i>=0; i--) {
9578                    WindowState w = mWindows.get(i);
9579                    if (w.mWinAnimator.mSurfaceShown) {
9580                        windows.add(w);
9581                    }
9582                }
9583            }
9584        } else {
9585            int objectId = 0;
9586            // See if this is an object ID.
9587            try {
9588                objectId = Integer.parseInt(name, 16);
9589                name = null;
9590            } catch (RuntimeException e) {
9591            }
9592            synchronized(mWindowMap) {
9593                for (int i=mWindows.size()-1; i>=0; i--) {
9594                    WindowState w = mWindows.get(i);
9595                    if (name != null) {
9596                        if (w.mAttrs.getTitle().toString().contains(name)) {
9597                            windows.add(w);
9598                        }
9599                    } else if (System.identityHashCode(w) == objectId) {
9600                        windows.add(w);
9601                    }
9602                }
9603            }
9604        }
9605
9606        if (windows.size() <= 0) {
9607            return false;
9608        }
9609
9610        synchronized(mWindowMap) {
9611            dumpWindowsLocked(fd, pw, dumpAll, windows);
9612        }
9613        return true;
9614    }
9615
9616    @Override
9617    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9618        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
9619                != PackageManager.PERMISSION_GRANTED) {
9620            pw.println("Permission Denial: can't dump WindowManager from from pid="
9621                    + Binder.getCallingPid()
9622                    + ", uid=" + Binder.getCallingUid());
9623            return;
9624        }
9625
9626        boolean dumpAll = false;
9627
9628        int opti = 0;
9629        while (opti < args.length) {
9630            String opt = args[opti];
9631            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9632                break;
9633            }
9634            opti++;
9635            if ("-a".equals(opt)) {
9636                dumpAll = true;
9637            } else if ("-h".equals(opt)) {
9638                pw.println("Window manager dump options:");
9639                pw.println("  [-a] [-h] [cmd] ...");
9640                pw.println("  cmd may be one of:");
9641                pw.println("    p[policy]: policy state");
9642                pw.println("    s[essions]: active sessions");
9643                pw.println("    t[okens]: token list");
9644                pw.println("    w[indows]: window list");
9645                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
9646                pw.println("    be a partial substring in a window name, a");
9647                pw.println("    Window hex object identifier, or");
9648                pw.println("    \"all\" for all windows, or");
9649                pw.println("    \"visible\" for the visible windows.");
9650                pw.println("  -a: include all available server state.");
9651                return;
9652            } else {
9653                pw.println("Unknown argument: " + opt + "; use -h for help");
9654            }
9655        }
9656
9657        // Is the caller requesting to dump a particular piece of data?
9658        if (opti < args.length) {
9659            String cmd = args[opti];
9660            opti++;
9661            if ("policy".equals(cmd) || "p".equals(cmd)) {
9662                synchronized(mWindowMap) {
9663                    dumpPolicyLocked(fd, pw, args, true);
9664                }
9665                return;
9666            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
9667                synchronized(mWindowMap) {
9668                    dumpSessionsLocked(fd, pw, true);
9669                }
9670                return;
9671            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
9672                synchronized(mWindowMap) {
9673                    dumpTokensLocked(fd, pw, true);
9674                }
9675                return;
9676            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
9677                synchronized(mWindowMap) {
9678                    dumpWindowsLocked(fd, pw, true, null);
9679                }
9680                return;
9681            } else if ("all".equals(cmd) || "a".equals(cmd)) {
9682                synchronized(mWindowMap) {
9683                    dumpWindowsLocked(fd, pw, true, null);
9684                }
9685                return;
9686            } else {
9687                // Dumping a single name?
9688                if (!dumpWindows(fd, pw, cmd, args, opti, dumpAll)) {
9689                    pw.println("Bad window command, or no windows match: " + cmd);
9690                    pw.println("Use -h for help.");
9691                }
9692                return;
9693            }
9694        }
9695
9696        synchronized(mWindowMap) {
9697            if (dumpAll) {
9698                pw.println("-------------------------------------------------------------------------------");
9699            }
9700            dumpPolicyLocked(fd, pw, args, dumpAll);
9701            pw.println();
9702            if (dumpAll) {
9703                pw.println("-------------------------------------------------------------------------------");
9704            }
9705            dumpSessionsLocked(fd, pw, dumpAll);
9706            pw.println();
9707            if (dumpAll) {
9708                pw.println("-------------------------------------------------------------------------------");
9709            }
9710            dumpTokensLocked(fd, pw, dumpAll);
9711            pw.println();
9712            if (dumpAll) {
9713                pw.println("-------------------------------------------------------------------------------");
9714            }
9715            dumpWindowsLocked(fd, pw, dumpAll, null);
9716        }
9717    }
9718
9719    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
9720    public void monitor() {
9721        synchronized (mWindowMap) { }
9722        synchronized (mKeyguardTokenWatcher) { }
9723    }
9724
9725    public interface OnHardKeyboardStatusChangeListener {
9726        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
9727    }
9728
9729    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
9730        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
9731            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
9732                    Integer.toHexString(pendingLayoutChanges));
9733        }
9734    }
9735
9736    void bulkSetParameters(final int bulkUpdateParams, int pendingLayoutChanges) {
9737        mH.sendMessage(mH.obtainMessage(H.BULK_UPDATE_PARAMETERS, bulkUpdateParams,
9738                pendingLayoutChanges));
9739    }
9740}
9741