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