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