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