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