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