WindowManagerService.java revision be4f5bb7fc08ca25d67525fdd97d15f73d150891
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
5585        // We need to update our screen size information to match the new
5586        // rotation.  Note that this is redundant with the later call to
5587        // sendNewConfiguration() that must be called after this function
5588        // returns...  however we need to do the screen size part of that
5589        // before then so we have the correct size to use when initializiation
5590        // the rotation animation for the new rotation.
5591        computeScreenConfigurationLocked(null);
5592
5593        if (!inTransaction) {
5594            if (SHOW_TRANSACTIONS)  Slog.i(TAG,
5595                    ">>> OPEN TRANSACTION setRotationUnchecked");
5596            Surface.openTransaction();
5597        }
5598        try {
5599            // NOTE: We disable the rotation in the emulator because
5600            //       it doesn't support hardware OpenGL emulation yet.
5601            if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
5602                    && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
5603                if (mAnimator.mScreenRotationAnimation.setRotation(rotation, mFxSession,
5604                        MAX_ANIMATION_DURATION, mTransitionAnimationScale,
5605                        mCurDisplayWidth, mCurDisplayHeight)) {
5606                    scheduleAnimationLocked();
5607                }
5608            }
5609            Surface.setOrientation(0, rotation);
5610        } finally {
5611            if (!inTransaction) {
5612                Surface.closeTransaction();
5613                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5614                        "<<< CLOSE TRANSACTION setRotationUnchecked");
5615            }
5616        }
5617
5618        rebuildBlackFrame();
5619
5620        for (int i=mWindows.size()-1; i>=0; i--) {
5621            WindowState w = mWindows.get(i);
5622            if (w.mHasSurface) {
5623                if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
5624                w.mOrientationChanging = true;
5625                mInnerFields.mOrientationChangeComplete = false;
5626            }
5627        }
5628        for (int i=mRotationWatchers.size()-1; i>=0; i--) {
5629            try {
5630                mRotationWatchers.get(i).onRotationChanged(rotation);
5631            } catch (RemoteException e) {
5632            }
5633        }
5634        return true;
5635    }
5636
5637    public int getRotation() {
5638        return mRotation;
5639    }
5640
5641    public int watchRotation(IRotationWatcher watcher) {
5642        final IBinder watcherBinder = watcher.asBinder();
5643        IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
5644            public void binderDied() {
5645                synchronized (mWindowMap) {
5646                    for (int i=0; i<mRotationWatchers.size(); i++) {
5647                        if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
5648                            IRotationWatcher removed = mRotationWatchers.remove(i);
5649                            if (removed != null) {
5650                                removed.asBinder().unlinkToDeath(this, 0);
5651                            }
5652                            i--;
5653                        }
5654                    }
5655                }
5656            }
5657        };
5658
5659        synchronized (mWindowMap) {
5660            try {
5661                watcher.asBinder().linkToDeath(dr, 0);
5662                mRotationWatchers.add(watcher);
5663            } catch (RemoteException e) {
5664                // Client died, no cleanup needed.
5665            }
5666
5667            return mRotation;
5668        }
5669    }
5670
5671    /**
5672     * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
5673     * theme attribute) on devices that feature a physical options menu key attempt to position
5674     * their menu panel window along the edge of the screen nearest the physical menu key.
5675     * This lowers the travel distance between invoking the menu panel and selecting
5676     * a menu option.
5677     *
5678     * This method helps control where that menu is placed. Its current implementation makes
5679     * assumptions about the menu key and its relationship to the screen based on whether
5680     * the device's natural orientation is portrait (width < height) or landscape.
5681     *
5682     * The menu key is assumed to be located along the bottom edge of natural-portrait
5683     * devices and along the right edge of natural-landscape devices. If these assumptions
5684     * do not hold for the target device, this method should be changed to reflect that.
5685     *
5686     * @return A {@link Gravity} value for placing the options menu window
5687     */
5688    public int getPreferredOptionsPanelGravity() {
5689        synchronized (mWindowMap) {
5690            final int rotation = getRotation();
5691
5692            if (mInitialDisplayWidth < mInitialDisplayHeight) {
5693                // On devices with a natural orientation of portrait
5694                switch (rotation) {
5695                    default:
5696                    case Surface.ROTATION_0:
5697                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5698                    case Surface.ROTATION_90:
5699                        return Gravity.RIGHT | Gravity.BOTTOM;
5700                    case Surface.ROTATION_180:
5701                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5702                    case Surface.ROTATION_270:
5703                        return Gravity.LEFT | Gravity.BOTTOM;
5704                }
5705            } else {
5706                // On devices with a natural orientation of landscape
5707                switch (rotation) {
5708                    default:
5709                    case Surface.ROTATION_0:
5710                        return Gravity.RIGHT | Gravity.BOTTOM;
5711                    case Surface.ROTATION_90:
5712                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5713                    case Surface.ROTATION_180:
5714                        return Gravity.LEFT | Gravity.BOTTOM;
5715                    case Surface.ROTATION_270:
5716                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5717                }
5718            }
5719        }
5720    }
5721
5722    /**
5723     * Starts the view server on the specified port.
5724     *
5725     * @param port The port to listener to.
5726     *
5727     * @return True if the server was successfully started, false otherwise.
5728     *
5729     * @see com.android.server.wm.ViewServer
5730     * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
5731     */
5732    public boolean startViewServer(int port) {
5733        if (isSystemSecure()) {
5734            return false;
5735        }
5736
5737        if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
5738            return false;
5739        }
5740
5741        if (port < 1024) {
5742            return false;
5743        }
5744
5745        if (mViewServer != null) {
5746            if (!mViewServer.isRunning()) {
5747                try {
5748                    return mViewServer.start();
5749                } catch (IOException e) {
5750                    Slog.w(TAG, "View server did not start");
5751                }
5752            }
5753            return false;
5754        }
5755
5756        try {
5757            mViewServer = new ViewServer(this, port);
5758            return mViewServer.start();
5759        } catch (IOException e) {
5760            Slog.w(TAG, "View server did not start");
5761        }
5762        return false;
5763    }
5764
5765    private boolean isSystemSecure() {
5766        return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
5767                "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
5768    }
5769
5770    /**
5771     * Stops the view server if it exists.
5772     *
5773     * @return True if the server stopped, false if it wasn't started or
5774     *         couldn't be stopped.
5775     *
5776     * @see com.android.server.wm.ViewServer
5777     */
5778    public boolean stopViewServer() {
5779        if (isSystemSecure()) {
5780            return false;
5781        }
5782
5783        if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
5784            return false;
5785        }
5786
5787        if (mViewServer != null) {
5788            return mViewServer.stop();
5789        }
5790        return false;
5791    }
5792
5793    /**
5794     * Indicates whether the view server is running.
5795     *
5796     * @return True if the server is running, false otherwise.
5797     *
5798     * @see com.android.server.wm.ViewServer
5799     */
5800    public boolean isViewServerRunning() {
5801        if (isSystemSecure()) {
5802            return false;
5803        }
5804
5805        if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
5806            return false;
5807        }
5808
5809        return mViewServer != null && mViewServer.isRunning();
5810    }
5811
5812    /**
5813     * Lists all availble windows in the system. The listing is written in the
5814     * specified Socket's output stream with the following syntax:
5815     * windowHashCodeInHexadecimal windowName
5816     * Each line of the ouput represents a different window.
5817     *
5818     * @param client The remote client to send the listing to.
5819     * @return False if an error occured, true otherwise.
5820     */
5821    boolean viewServerListWindows(Socket client) {
5822        if (isSystemSecure()) {
5823            return false;
5824        }
5825
5826        boolean result = true;
5827
5828        WindowState[] windows;
5829        synchronized (mWindowMap) {
5830            //noinspection unchecked
5831            windows = mWindows.toArray(new WindowState[mWindows.size()]);
5832        }
5833
5834        BufferedWriter out = null;
5835
5836        // Any uncaught exception will crash the system process
5837        try {
5838            OutputStream clientStream = client.getOutputStream();
5839            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
5840
5841            final int count = windows.length;
5842            for (int i = 0; i < count; i++) {
5843                final WindowState w = windows[i];
5844                out.write(Integer.toHexString(System.identityHashCode(w)));
5845                out.write(' ');
5846                out.append(w.mAttrs.getTitle());
5847                out.write('\n');
5848            }
5849
5850            out.write("DONE.\n");
5851            out.flush();
5852        } catch (Exception e) {
5853            result = false;
5854        } finally {
5855            if (out != null) {
5856                try {
5857                    out.close();
5858                } catch (IOException e) {
5859                    result = false;
5860                }
5861            }
5862        }
5863
5864        return result;
5865    }
5866
5867    /**
5868     * Returns the focused window in the following format:
5869     * windowHashCodeInHexadecimal windowName
5870     *
5871     * @param client The remote client to send the listing to.
5872     * @return False if an error occurred, true otherwise.
5873     */
5874    boolean viewServerGetFocusedWindow(Socket client) {
5875        if (isSystemSecure()) {
5876            return false;
5877        }
5878
5879        boolean result = true;
5880
5881        WindowState focusedWindow = getFocusedWindow();
5882
5883        BufferedWriter out = null;
5884
5885        // Any uncaught exception will crash the system process
5886        try {
5887            OutputStream clientStream = client.getOutputStream();
5888            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
5889
5890            if(focusedWindow != null) {
5891                out.write(Integer.toHexString(System.identityHashCode(focusedWindow)));
5892                out.write(' ');
5893                out.append(focusedWindow.mAttrs.getTitle());
5894            }
5895            out.write('\n');
5896            out.flush();
5897        } catch (Exception e) {
5898            result = false;
5899        } finally {
5900            if (out != null) {
5901                try {
5902                    out.close();
5903                } catch (IOException e) {
5904                    result = false;
5905                }
5906            }
5907        }
5908
5909        return result;
5910    }
5911
5912    /**
5913     * Sends a command to a target window. The result of the command, if any, will be
5914     * written in the output stream of the specified socket.
5915     *
5916     * The parameters must follow this syntax:
5917     * windowHashcode extra
5918     *
5919     * Where XX is the length in characeters of the windowTitle.
5920     *
5921     * The first parameter is the target window. The window with the specified hashcode
5922     * will be the target. If no target can be found, nothing happens. The extra parameters
5923     * will be delivered to the target window and as parameters to the command itself.
5924     *
5925     * @param client The remote client to sent the result, if any, to.
5926     * @param command The command to execute.
5927     * @param parameters The command parameters.
5928     *
5929     * @return True if the command was successfully delivered, false otherwise. This does
5930     *         not indicate whether the command itself was successful.
5931     */
5932    boolean viewServerWindowCommand(Socket client, String command, String parameters) {
5933        if (isSystemSecure()) {
5934            return false;
5935        }
5936
5937        boolean success = true;
5938        Parcel data = null;
5939        Parcel reply = null;
5940
5941        BufferedWriter out = null;
5942
5943        // Any uncaught exception will crash the system process
5944        try {
5945            // Find the hashcode of the window
5946            int index = parameters.indexOf(' ');
5947            if (index == -1) {
5948                index = parameters.length();
5949            }
5950            final String code = parameters.substring(0, index);
5951            int hashCode = (int) Long.parseLong(code, 16);
5952
5953            // Extract the command's parameter after the window description
5954            if (index < parameters.length()) {
5955                parameters = parameters.substring(index + 1);
5956            } else {
5957                parameters = "";
5958            }
5959
5960            final WindowState window = findWindow(hashCode);
5961            if (window == null) {
5962                return false;
5963            }
5964
5965            data = Parcel.obtain();
5966            data.writeInterfaceToken("android.view.IWindow");
5967            data.writeString(command);
5968            data.writeString(parameters);
5969            data.writeInt(1);
5970            ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
5971
5972            reply = Parcel.obtain();
5973
5974            final IBinder binder = window.mClient.asBinder();
5975            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
5976            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
5977
5978            reply.readException();
5979
5980            if (!client.isOutputShutdown()) {
5981                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
5982                out.write("DONE\n");
5983                out.flush();
5984            }
5985
5986        } catch (Exception e) {
5987            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
5988            success = false;
5989        } finally {
5990            if (data != null) {
5991                data.recycle();
5992            }
5993            if (reply != null) {
5994                reply.recycle();
5995            }
5996            if (out != null) {
5997                try {
5998                    out.close();
5999                } catch (IOException e) {
6000
6001                }
6002            }
6003        }
6004
6005        return success;
6006    }
6007
6008    public void addWindowChangeListener(WindowChangeListener listener) {
6009        synchronized(mWindowMap) {
6010            mWindowChangeListeners.add(listener);
6011        }
6012    }
6013
6014    public void removeWindowChangeListener(WindowChangeListener listener) {
6015        synchronized(mWindowMap) {
6016            mWindowChangeListeners.remove(listener);
6017        }
6018    }
6019
6020    private void notifyWindowsChanged() {
6021        WindowChangeListener[] windowChangeListeners;
6022        synchronized(mWindowMap) {
6023            if(mWindowChangeListeners.isEmpty()) {
6024                return;
6025            }
6026            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6027            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6028        }
6029        int N = windowChangeListeners.length;
6030        for(int i = 0; i < N; i++) {
6031            windowChangeListeners[i].windowsChanged();
6032        }
6033    }
6034
6035    private void notifyFocusChanged() {
6036        WindowChangeListener[] windowChangeListeners;
6037        synchronized(mWindowMap) {
6038            if(mWindowChangeListeners.isEmpty()) {
6039                return;
6040            }
6041            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6042            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6043        }
6044        int N = windowChangeListeners.length;
6045        for(int i = 0; i < N; i++) {
6046            windowChangeListeners[i].focusChanged();
6047        }
6048    }
6049
6050    private WindowState findWindow(int hashCode) {
6051        if (hashCode == -1) {
6052            return getFocusedWindow();
6053        }
6054
6055        synchronized (mWindowMap) {
6056            final ArrayList<WindowState> windows = mWindows;
6057            final int count = windows.size();
6058
6059            for (int i = 0; i < count; i++) {
6060                WindowState w = windows.get(i);
6061                if (System.identityHashCode(w) == hashCode) {
6062                    return w;
6063                }
6064            }
6065        }
6066
6067        return null;
6068    }
6069
6070    /*
6071     * Instruct the Activity Manager to fetch the current configuration and broadcast
6072     * that to config-changed listeners if appropriate.
6073     */
6074    void sendNewConfiguration() {
6075        try {
6076            mActivityManager.updateConfiguration(null);
6077        } catch (RemoteException e) {
6078        }
6079    }
6080
6081    public Configuration computeNewConfiguration() {
6082        synchronized (mWindowMap) {
6083            Configuration config = computeNewConfigurationLocked();
6084            if (config == null && mWaitingForConfig) {
6085                // Nothing changed but we are waiting for something... stop that!
6086                mWaitingForConfig = false;
6087                performLayoutAndPlaceSurfacesLocked();
6088            }
6089            return config;
6090        }
6091    }
6092
6093    Configuration computeNewConfigurationLocked() {
6094        Configuration config = new Configuration();
6095        config.fontScale = 0;
6096        if (!computeScreenConfigurationLocked(config)) {
6097            return null;
6098        }
6099        return config;
6100    }
6101
6102    private void adjustDisplaySizeRanges(int rotation, int dw, int dh) {
6103        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
6104        if (width < mSmallestDisplayWidth) {
6105            mSmallestDisplayWidth = width;
6106        }
6107        if (width > mLargestDisplayWidth) {
6108            mLargestDisplayWidth = width;
6109        }
6110        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation);
6111        if (height < mSmallestDisplayHeight) {
6112            mSmallestDisplayHeight = height;
6113        }
6114        if (height > mLargestDisplayHeight) {
6115            mLargestDisplayHeight = height;
6116        }
6117    }
6118
6119    private int reduceConfigLayout(int curLayout, int rotation, float density,
6120            int dw, int dh) {
6121        // Get the app screen size at this rotation.
6122        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6123        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6124
6125        // Compute the screen layout size class for this rotation.
6126        int screenLayoutSize;
6127        boolean screenLayoutLong;
6128        boolean screenLayoutCompatNeeded;
6129        int longSize = w;
6130        int shortSize = h;
6131        if (longSize < shortSize) {
6132            int tmp = longSize;
6133            longSize = shortSize;
6134            shortSize = tmp;
6135        }
6136        longSize = (int)(longSize/density);
6137        shortSize = (int)(shortSize/density);
6138
6139        // These semi-magic numbers define our compatibility modes for
6140        // applications with different screens.  These are guarantees to
6141        // app developers about the space they can expect for a particular
6142        // configuration.  DO NOT CHANGE!
6143        if (longSize < 470) {
6144            // This is shorter than an HVGA normal density screen (which
6145            // is 480 pixels on its long side).
6146            screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_SMALL;
6147            screenLayoutLong = false;
6148            screenLayoutCompatNeeded = false;
6149        } else {
6150            // What size is this screen screen?
6151            if (longSize >= 960 && shortSize >= 720) {
6152                // 1.5xVGA or larger screens at medium density are the point
6153                // at which we consider it to be an extra large screen.
6154                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_XLARGE;
6155            } else if (longSize >= 640 && shortSize >= 480) {
6156                // VGA or larger screens at medium density are the point
6157                // at which we consider it to be a large screen.
6158                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_LARGE;
6159            } else {
6160                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_NORMAL;
6161            }
6162
6163            // If this screen is wider than normal HVGA, or taller
6164            // than FWVGA, then for old apps we want to run in size
6165            // compatibility mode.
6166            if (shortSize > 321 || longSize > 570) {
6167                screenLayoutCompatNeeded = true;
6168            } else {
6169                screenLayoutCompatNeeded = false;
6170            }
6171
6172            // Is this a long screen?
6173            if (((longSize*3)/5) >= (shortSize-1)) {
6174                // Anything wider than WVGA (5:3) is considering to be long.
6175                screenLayoutLong = true;
6176            } else {
6177                screenLayoutLong = false;
6178            }
6179        }
6180
6181        // Now reduce the last screenLayout to not be better than what we
6182        // have found.
6183        if (!screenLayoutLong) {
6184            curLayout = (curLayout&~Configuration.SCREENLAYOUT_LONG_MASK)
6185                    | Configuration.SCREENLAYOUT_LONG_NO;
6186        }
6187        if (screenLayoutCompatNeeded) {
6188            curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
6189        }
6190        int curSize = curLayout&Configuration.SCREENLAYOUT_SIZE_MASK;
6191        if (screenLayoutSize < curSize) {
6192            curLayout = (curLayout&~Configuration.SCREENLAYOUT_SIZE_MASK)
6193                    | screenLayoutSize;
6194        }
6195        return curLayout;
6196    }
6197
6198    private void computeSizeRangesAndScreenLayout(boolean rotated, int dw, int dh,
6199            float density, Configuration outConfig) {
6200        // We need to determine the smallest width that will occur under normal
6201        // operation.  To this, start with the base screen size and compute the
6202        // width under the different possible rotations.  We need to un-rotate
6203        // the current screen dimensions before doing this.
6204        int unrotDw, unrotDh;
6205        if (rotated) {
6206            unrotDw = dh;
6207            unrotDh = dw;
6208        } else {
6209            unrotDw = dw;
6210            unrotDh = dh;
6211        }
6212        mSmallestDisplayWidth = 1<<30;
6213        mSmallestDisplayHeight = 1<<30;
6214        mLargestDisplayWidth = 0;
6215        mLargestDisplayHeight = 0;
6216        adjustDisplaySizeRanges(Surface.ROTATION_0, unrotDw, unrotDh);
6217        adjustDisplaySizeRanges(Surface.ROTATION_90, unrotDh, unrotDw);
6218        adjustDisplaySizeRanges(Surface.ROTATION_180, unrotDw, unrotDh);
6219        adjustDisplaySizeRanges(Surface.ROTATION_270, unrotDh, unrotDw);
6220        int sl = Configuration.SCREENLAYOUT_SIZE_XLARGE
6221                | Configuration.SCREENLAYOUT_LONG_YES;
6222        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
6223        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
6224        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
6225        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
6226        outConfig.smallestScreenWidthDp = (int)(mSmallestDisplayWidth / density);
6227        outConfig.screenLayout = sl;
6228    }
6229
6230    private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
6231            int dw, int dh) {
6232        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6233        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6234        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
6235        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
6236        if (curSize == 0 || size < curSize) {
6237            curSize = size;
6238        }
6239        return curSize;
6240    }
6241
6242    private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
6243        mTmpDisplayMetrics.setTo(dm);
6244        dm = mTmpDisplayMetrics;
6245        int unrotDw, unrotDh;
6246        if (rotated) {
6247            unrotDw = dh;
6248            unrotDh = dw;
6249        } else {
6250            unrotDw = dw;
6251            unrotDh = dh;
6252        }
6253        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, dm, unrotDw, unrotDh);
6254        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, dm, unrotDh, unrotDw);
6255        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, dm, unrotDw, unrotDh);
6256        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, dm, unrotDh, unrotDw);
6257        return sw;
6258    }
6259
6260    boolean computeScreenConfigurationLocked(Configuration config) {
6261        if (mDisplay == null) {
6262            return false;
6263        }
6264
6265        // Use the effective "visual" dimensions based on current rotation
6266        final boolean rotated = (mRotation == Surface.ROTATION_90
6267                || mRotation == Surface.ROTATION_270);
6268        final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
6269        final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
6270
6271        synchronized(mDisplaySizeLock) {
6272            if (mAltOrientation) {
6273                mCurDisplayWidth = realdw;
6274                mCurDisplayHeight = realdh;
6275                if (realdw > realdh) {
6276                    // Turn landscape into portrait.
6277                    int maxw = (int)(realdh/1.3f);
6278                    if (maxw < realdw) {
6279                        mCurDisplayWidth = maxw;
6280                    }
6281                } else {
6282                    // Turn portrait into landscape.
6283                    int maxh = (int)(realdw/1.3f);
6284                    if (maxh < realdh) {
6285                        mCurDisplayHeight = maxh;
6286                    }
6287                }
6288            } else {
6289                mCurDisplayWidth = realdw;
6290                mCurDisplayHeight = realdh;
6291            }
6292        }
6293
6294        final int dw = mCurDisplayWidth;
6295        final int dh = mCurDisplayHeight;
6296
6297        if (config != null) {
6298            int orientation = Configuration.ORIENTATION_SQUARE;
6299            if (dw < dh) {
6300                orientation = Configuration.ORIENTATION_PORTRAIT;
6301            } else if (dw > dh) {
6302                orientation = Configuration.ORIENTATION_LANDSCAPE;
6303            }
6304            config.orientation = orientation;
6305        }
6306
6307        // Update real display metrics.
6308        mDisplay.getMetricsWithSize(mRealDisplayMetrics, mCurDisplayWidth, mCurDisplayHeight);
6309
6310        // Update application display metrics.
6311        final DisplayMetrics dm = mDisplayMetrics;
6312        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
6313        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
6314        synchronized(mDisplaySizeLock) {
6315            mAppDisplayWidth = appWidth;
6316            mAppDisplayHeight = appHeight;
6317            mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight,
6318                    mAppDisplayWidth, mAppDisplayHeight);
6319        }
6320        if (false) {
6321            Slog.i(TAG, "Set app display size: " + mAppDisplayWidth
6322                    + " x " + mAppDisplayHeight);
6323        }
6324        mDisplay.getMetricsWithSize(dm, mAppDisplayWidth, mAppDisplayHeight);
6325
6326        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
6327                mCompatDisplayMetrics);
6328
6329        if (config != null) {
6330            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
6331                    / dm.density);
6332            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
6333                    / dm.density);
6334            computeSizeRangesAndScreenLayout(rotated, dw, dh, dm.density, config);
6335
6336            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
6337            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
6338            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
6339
6340            // Update the configuration based on available input devices, lid switch,
6341            // and platform configuration.
6342            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6343            config.keyboard = Configuration.KEYBOARD_NOKEYS;
6344            config.navigation = Configuration.NAVIGATION_NONAV;
6345
6346            int keyboardPresence = 0;
6347            int navigationPresence = 0;
6348            for (InputDevice device : mInputManager.getInputDevices()) {
6349                if (!device.isVirtual()) {
6350                    final int sources = device.getSources();
6351                    final int presenceFlag = device.isExternal() ?
6352                            WindowManagerPolicy.PRESENCE_EXTERNAL :
6353                                    WindowManagerPolicy.PRESENCE_INTERNAL;
6354
6355                    if ((sources & InputDevice.SOURCE_TOUCHSCREEN) != 0) {
6356                        config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
6357                    }
6358
6359                    if ((sources & InputDevice.SOURCE_TRACKBALL) != 0) {
6360                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
6361                        navigationPresence |= presenceFlag;
6362                    } else if ((sources & InputDevice.SOURCE_DPAD) != 0
6363                            && config.navigation == Configuration.NAVIGATION_NONAV) {
6364                        config.navigation = Configuration.NAVIGATION_DPAD;
6365                        navigationPresence |= presenceFlag;
6366                    }
6367
6368                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
6369                        config.keyboard = Configuration.KEYBOARD_QWERTY;
6370                        keyboardPresence |= presenceFlag;
6371                    }
6372                }
6373            }
6374
6375            // Determine whether a hard keyboard is available and enabled.
6376            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6377            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6378                mHardKeyboardAvailable = hardKeyboardAvailable;
6379                mHardKeyboardEnabled = hardKeyboardAvailable;
6380                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6381                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6382            }
6383            if (!mHardKeyboardEnabled) {
6384                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6385            }
6386
6387            // Let the policy update hidden states.
6388            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6389            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6390            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6391            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
6392        }
6393
6394        return true;
6395    }
6396
6397    public boolean isHardKeyboardAvailable() {
6398        synchronized (mWindowMap) {
6399            return mHardKeyboardAvailable;
6400        }
6401    }
6402
6403    public boolean isHardKeyboardEnabled() {
6404        synchronized (mWindowMap) {
6405            return mHardKeyboardEnabled;
6406        }
6407    }
6408
6409    public void setHardKeyboardEnabled(boolean enabled) {
6410        synchronized (mWindowMap) {
6411            if (mHardKeyboardEnabled != enabled) {
6412                mHardKeyboardEnabled = enabled;
6413                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6414            }
6415        }
6416    }
6417
6418    public void setOnHardKeyboardStatusChangeListener(
6419            OnHardKeyboardStatusChangeListener listener) {
6420        synchronized (mWindowMap) {
6421            mHardKeyboardStatusChangeListener = listener;
6422        }
6423    }
6424
6425    void notifyHardKeyboardStatusChange() {
6426        final boolean available, enabled;
6427        final OnHardKeyboardStatusChangeListener listener;
6428        synchronized (mWindowMap) {
6429            listener = mHardKeyboardStatusChangeListener;
6430            available = mHardKeyboardAvailable;
6431            enabled = mHardKeyboardEnabled;
6432        }
6433        if (listener != null) {
6434            listener.onHardKeyboardStatusChange(available, enabled);
6435        }
6436    }
6437
6438    // -------------------------------------------------------------
6439    // Drag and drop
6440    // -------------------------------------------------------------
6441
6442    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
6443            int flags, int width, int height, Surface outSurface) {
6444        if (DEBUG_DRAG) {
6445            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
6446                    + " flags=" + Integer.toHexString(flags) + " win=" + window
6447                    + " asbinder=" + window.asBinder());
6448        }
6449
6450        final int callerPid = Binder.getCallingPid();
6451        final long origId = Binder.clearCallingIdentity();
6452        IBinder token = null;
6453
6454        try {
6455            synchronized (mWindowMap) {
6456                try {
6457                    if (mDragState == null) {
6458                        Surface surface = new Surface(session, callerPid, "drag surface", 0,
6459                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
6460                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
6461                                + surface + ": CREATE");
6462                        outSurface.copyFrom(surface);
6463                        final IBinder winBinder = window.asBinder();
6464                        token = new Binder();
6465                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
6466                        token = mDragState.mToken = new Binder();
6467
6468                        // 5 second timeout for this window to actually begin the drag
6469                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
6470                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
6471                        mH.sendMessageDelayed(msg, 5000);
6472                    } else {
6473                        Slog.w(TAG, "Drag already in progress");
6474                    }
6475                } catch (Surface.OutOfResourcesException e) {
6476                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
6477                    if (mDragState != null) {
6478                        mDragState.reset();
6479                        mDragState = null;
6480                    }
6481                }
6482            }
6483        } finally {
6484            Binder.restoreCallingIdentity(origId);
6485        }
6486
6487        return token;
6488    }
6489
6490    // -------------------------------------------------------------
6491    // Input Events and Focus Management
6492    // -------------------------------------------------------------
6493
6494    final InputMonitor mInputMonitor = new InputMonitor(this);
6495
6496    public void pauseKeyDispatching(IBinder _token) {
6497        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6498                "pauseKeyDispatching()")) {
6499            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6500        }
6501
6502        synchronized (mWindowMap) {
6503            WindowToken token = mTokenMap.get(_token);
6504            if (token != null) {
6505                mInputMonitor.pauseDispatchingLw(token);
6506            }
6507        }
6508    }
6509
6510    public void resumeKeyDispatching(IBinder _token) {
6511        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6512                "resumeKeyDispatching()")) {
6513            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6514        }
6515
6516        synchronized (mWindowMap) {
6517            WindowToken token = mTokenMap.get(_token);
6518            if (token != null) {
6519                mInputMonitor.resumeDispatchingLw(token);
6520            }
6521        }
6522    }
6523
6524    public void setEventDispatching(boolean enabled) {
6525        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6526                "resumeKeyDispatching()")) {
6527            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6528        }
6529
6530        synchronized (mWindowMap) {
6531            mInputMonitor.setEventDispatchingLw(enabled);
6532        }
6533
6534        sendScreenStatusToClients();
6535    }
6536
6537    private WindowState getFocusedWindow() {
6538        synchronized (mWindowMap) {
6539            return getFocusedWindowLocked();
6540        }
6541    }
6542
6543    private WindowState getFocusedWindowLocked() {
6544        return mCurrentFocus;
6545    }
6546
6547    public boolean detectSafeMode() {
6548        if (!mInputMonitor.waitForInputDevicesReady(
6549                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
6550            Slog.w(TAG, "Devices still not ready after waiting "
6551                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
6552                   + " milliseconds before attempting to detect safe mode.");
6553        }
6554
6555        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6556                KeyEvent.KEYCODE_MENU);
6557        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
6558        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
6559                KeyEvent.KEYCODE_DPAD_CENTER);
6560        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
6561                InputManagerService.BTN_MOUSE);
6562        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6563                KeyEvent.KEYCODE_VOLUME_DOWN);
6564        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
6565                || volumeDownState > 0;
6566        try {
6567            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
6568                mSafeMode = true;
6569                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
6570            }
6571        } catch (IllegalArgumentException e) {
6572        }
6573        if (mSafeMode) {
6574            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
6575                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
6576        } else {
6577            Log.i(TAG, "SAFE MODE not enabled");
6578        }
6579        mPolicy.setSafeMode(mSafeMode);
6580        return mSafeMode;
6581    }
6582
6583    public void displayReady() {
6584        synchronized(mWindowMap) {
6585            if (mDisplay != null) {
6586                throw new IllegalStateException("Display already initialized");
6587            }
6588            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
6589            mDisplay = wm.getDefaultDisplay();
6590            synchronized(mDisplaySizeLock) {
6591                mInitialDisplayWidth = mDisplay.getRawWidth();
6592                mInitialDisplayHeight = mDisplay.getRawHeight();
6593                int rot = mDisplay.getRotation();
6594                if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
6595                    // If the screen is currently rotated, we need to swap the
6596                    // initial width and height to get the true natural values.
6597                    int tmp = mInitialDisplayWidth;
6598                    mInitialDisplayWidth = mInitialDisplayHeight;
6599                    mInitialDisplayHeight = tmp;
6600                }
6601                mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth;
6602                mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight;
6603                mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight,
6604                        mAppDisplayWidth, mAppDisplayHeight);
6605            }
6606            mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
6607                    mDisplay.getRawWidth(), mDisplay.getRawHeight(),
6608                    mDisplay.getRawExternalWidth(), mDisplay.getRawExternalHeight());
6609            mPolicy.setInitialDisplaySize(mDisplay, mInitialDisplayWidth, mInitialDisplayHeight);
6610        }
6611
6612        try {
6613            mActivityManager.updateConfiguration(null);
6614        } catch (RemoteException e) {
6615        }
6616
6617        synchronized (mWindowMap) {
6618            readForcedDisplaySizeLocked();
6619        }
6620    }
6621
6622    public void systemReady() {
6623        mPolicy.systemReady();
6624    }
6625
6626    private void sendScreenStatusToClients() {
6627        final ArrayList<WindowState> windows = mWindows;
6628        final int count = windows.size();
6629        boolean on = mPowerManager.isScreenOn();
6630        for (int i = count - 1; i >= 0; i--) {
6631            WindowState win = mWindows.get(i);
6632            try {
6633                win.mClient.dispatchScreenState(on);
6634            } catch (RemoteException e) {
6635                // Ignored
6636            }
6637        }
6638    }
6639
6640    // -------------------------------------------------------------
6641    // Async Handler
6642    // -------------------------------------------------------------
6643
6644    final class H extends Handler {
6645        public static final int REPORT_FOCUS_CHANGE = 2;
6646        public static final int REPORT_LOSING_FOCUS = 3;
6647        public static final int DO_TRAVERSAL = 4;
6648        public static final int ADD_STARTING = 5;
6649        public static final int REMOVE_STARTING = 6;
6650        public static final int FINISHED_STARTING = 7;
6651        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
6652        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
6653        public static final int WINDOW_FREEZE_TIMEOUT = 11;
6654        public static final int HOLD_SCREEN_CHANGED = 12;
6655        public static final int APP_TRANSITION_TIMEOUT = 13;
6656        public static final int PERSIST_ANIMATION_SCALE = 14;
6657        public static final int FORCE_GC = 15;
6658        public static final int ENABLE_SCREEN = 16;
6659        public static final int APP_FREEZE_TIMEOUT = 17;
6660        public static final int SEND_NEW_CONFIGURATION = 18;
6661        public static final int REPORT_WINDOWS_CHANGE = 19;
6662        public static final int DRAG_START_TIMEOUT = 20;
6663        public static final int DRAG_END_TIMEOUT = 21;
6664        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
6665        public static final int BOOT_TIMEOUT = 23;
6666        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
6667        public static final int BULK_UPDATE_PARAMETERS = 25;
6668
6669        public static final int ANIMATOR_WHAT_OFFSET = 100000;
6670        public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
6671        public static final int SET_WALLPAPER_OFFSET = ANIMATOR_WHAT_OFFSET + 2;
6672        public static final int SET_DIM_PARAMETERS = ANIMATOR_WHAT_OFFSET + 3;
6673        public static final int SET_MOVE_ANIMATION = ANIMATOR_WHAT_OFFSET + 4;
6674        public static final int CLEAR_PENDING_ACTIONS = ANIMATOR_WHAT_OFFSET + 5;
6675
6676        private Session mLastReportedHold;
6677
6678        public H() {
6679        }
6680
6681        @Override
6682        public void handleMessage(Message msg) {
6683            if (DEBUG_WINDOW_TRACE) {
6684                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
6685            }
6686            switch (msg.what) {
6687                case REPORT_FOCUS_CHANGE: {
6688                    WindowState lastFocus;
6689                    WindowState newFocus;
6690
6691                    synchronized(mWindowMap) {
6692                        lastFocus = mLastFocus;
6693                        newFocus = mCurrentFocus;
6694                        if (lastFocus == newFocus) {
6695                            // Focus is not changing, so nothing to do.
6696                            return;
6697                        }
6698                        mLastFocus = newFocus;
6699                        //Slog.i(TAG, "Focus moving from " + lastFocus
6700                        //        + " to " + newFocus);
6701                        if (newFocus != null && lastFocus != null
6702                                && !newFocus.isDisplayedLw()) {
6703                            //Slog.i(TAG, "Delaying loss of focus...");
6704                            mLosingFocus.add(lastFocus);
6705                            lastFocus = null;
6706                        }
6707                    }
6708
6709                    if (lastFocus != newFocus) {
6710                        //System.out.println("Changing focus from " + lastFocus
6711                        //                   + " to " + newFocus);
6712                        if (newFocus != null) {
6713                            try {
6714                                //Slog.i(TAG, "Gaining focus: " + newFocus);
6715                                newFocus.mClient.windowFocusChanged(true, mInTouchMode);
6716                            } catch (RemoteException e) {
6717                                // Ignore if process has died.
6718                            }
6719                            notifyFocusChanged();
6720                        }
6721
6722                        if (lastFocus != null) {
6723                            try {
6724                                //Slog.i(TAG, "Losing focus: " + lastFocus);
6725                                lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
6726                            } catch (RemoteException e) {
6727                                // Ignore if process has died.
6728                            }
6729                        }
6730                    }
6731                } break;
6732
6733                case REPORT_LOSING_FOCUS: {
6734                    ArrayList<WindowState> losers;
6735
6736                    synchronized(mWindowMap) {
6737                        losers = mLosingFocus;
6738                        mLosingFocus = new ArrayList<WindowState>();
6739                    }
6740
6741                    final int N = losers.size();
6742                    for (int i=0; i<N; i++) {
6743                        try {
6744                            //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
6745                            losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
6746                        } catch (RemoteException e) {
6747                             // Ignore if process has died.
6748                        }
6749                    }
6750                } break;
6751
6752                case DO_TRAVERSAL: {
6753                    synchronized(mWindowMap) {
6754                        mTraversalScheduled = false;
6755                        performLayoutAndPlaceSurfacesLocked();
6756                    }
6757                } break;
6758
6759                case ADD_STARTING: {
6760                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6761                    final StartingData sd = wtoken.startingData;
6762
6763                    if (sd == null) {
6764                        // Animation has been canceled... do nothing.
6765                        return;
6766                    }
6767
6768                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
6769                            + wtoken + ": pkg=" + sd.pkg);
6770
6771                    View view = null;
6772                    try {
6773                        view = mPolicy.addStartingWindow(
6774                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
6775                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
6776                    } catch (Exception e) {
6777                        Slog.w(TAG, "Exception when adding starting window", e);
6778                    }
6779
6780                    if (view != null) {
6781                        boolean abort = false;
6782
6783                        synchronized(mWindowMap) {
6784                            if (wtoken.removed || wtoken.startingData == null) {
6785                                // If the window was successfully added, then
6786                                // we need to remove it.
6787                                if (wtoken.startingWindow != null) {
6788                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6789                                            "Aborted starting " + wtoken
6790                                            + ": removed=" + wtoken.removed
6791                                            + " startingData=" + wtoken.startingData);
6792                                    wtoken.startingWindow = null;
6793                                    wtoken.startingData = null;
6794                                    abort = true;
6795                                }
6796                            } else {
6797                                wtoken.startingView = view;
6798                            }
6799                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
6800                                    "Added starting " + wtoken
6801                                    + ": startingWindow="
6802                                    + wtoken.startingWindow + " startingView="
6803                                    + wtoken.startingView);
6804                        }
6805
6806                        if (abort) {
6807                            try {
6808                                mPolicy.removeStartingWindow(wtoken.token, view);
6809                            } catch (Exception e) {
6810                                Slog.w(TAG, "Exception when removing starting window", e);
6811                            }
6812                        }
6813                    }
6814                } break;
6815
6816                case REMOVE_STARTING: {
6817                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6818                    IBinder token = null;
6819                    View view = null;
6820                    synchronized (mWindowMap) {
6821                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
6822                                + wtoken + ": startingWindow="
6823                                + wtoken.startingWindow + " startingView="
6824                                + wtoken.startingView);
6825                        if (wtoken.startingWindow != null) {
6826                            view = wtoken.startingView;
6827                            token = wtoken.token;
6828                            wtoken.startingData = null;
6829                            wtoken.startingView = null;
6830                            wtoken.startingWindow = null;
6831                        }
6832                    }
6833                    if (view != null) {
6834                        try {
6835                            mPolicy.removeStartingWindow(token, view);
6836                        } catch (Exception e) {
6837                            Slog.w(TAG, "Exception when removing starting window", e);
6838                        }
6839                    }
6840                } break;
6841
6842                case FINISHED_STARTING: {
6843                    IBinder token = null;
6844                    View view = null;
6845                    while (true) {
6846                        synchronized (mWindowMap) {
6847                            final int N = mFinishedStarting.size();
6848                            if (N <= 0) {
6849                                break;
6850                            }
6851                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
6852
6853                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6854                                    "Finished starting " + wtoken
6855                                    + ": startingWindow=" + wtoken.startingWindow
6856                                    + " startingView=" + wtoken.startingView);
6857
6858                            if (wtoken.startingWindow == null) {
6859                                continue;
6860                            }
6861
6862                            view = wtoken.startingView;
6863                            token = wtoken.token;
6864                            wtoken.startingData = null;
6865                            wtoken.startingView = null;
6866                            wtoken.startingWindow = null;
6867                        }
6868
6869                        try {
6870                            mPolicy.removeStartingWindow(token, view);
6871                        } catch (Exception e) {
6872                            Slog.w(TAG, "Exception when removing starting window", e);
6873                        }
6874                    }
6875                } break;
6876
6877                case REPORT_APPLICATION_TOKEN_DRAWN: {
6878                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6879
6880                    try {
6881                        if (DEBUG_VISIBILITY) Slog.v(
6882                                TAG, "Reporting drawn in " + wtoken);
6883                        wtoken.appToken.windowsDrawn();
6884                    } catch (RemoteException ex) {
6885                    }
6886                } break;
6887
6888                case REPORT_APPLICATION_TOKEN_WINDOWS: {
6889                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6890
6891                    boolean nowVisible = msg.arg1 != 0;
6892                    boolean nowGone = msg.arg2 != 0;
6893
6894                    try {
6895                        if (DEBUG_VISIBILITY) Slog.v(
6896                                TAG, "Reporting visible in " + wtoken
6897                                + " visible=" + nowVisible
6898                                + " gone=" + nowGone);
6899                        if (nowVisible) {
6900                            wtoken.appToken.windowsVisible();
6901                        } else {
6902                            wtoken.appToken.windowsGone();
6903                        }
6904                    } catch (RemoteException ex) {
6905                    }
6906                } break;
6907
6908                case WINDOW_FREEZE_TIMEOUT: {
6909                    synchronized (mWindowMap) {
6910                        Slog.w(TAG, "Window freeze timeout expired.");
6911                        int i = mWindows.size();
6912                        while (i > 0) {
6913                            i--;
6914                            WindowState w = mWindows.get(i);
6915                            if (w.mOrientationChanging) {
6916                                w.mOrientationChanging = false;
6917                                Slog.w(TAG, "Force clearing orientation change: " + w);
6918                            }
6919                        }
6920                        performLayoutAndPlaceSurfacesLocked();
6921                    }
6922                    break;
6923                }
6924
6925                case HOLD_SCREEN_CHANGED: {
6926                    Session oldHold;
6927                    Session newHold;
6928                    synchronized (mWindowMap) {
6929                        oldHold = mLastReportedHold;
6930                        newHold = (Session)msg.obj;
6931                        mLastReportedHold = newHold;
6932                    }
6933
6934                    if (oldHold != newHold) {
6935                        try {
6936                            if (oldHold != null) {
6937                                mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
6938                                        "window",
6939                                        BatteryStats.WAKE_TYPE_WINDOW);
6940                            }
6941                            if (newHold != null) {
6942                                mBatteryStats.noteStartWakelock(newHold.mUid, -1,
6943                                        "window",
6944                                        BatteryStats.WAKE_TYPE_WINDOW);
6945                            }
6946                        } catch (RemoteException e) {
6947                        }
6948                    }
6949                    break;
6950                }
6951
6952                case APP_TRANSITION_TIMEOUT: {
6953                    synchronized (mWindowMap) {
6954                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
6955                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
6956                                    "*** APP TRANSITION TIMEOUT");
6957                            mAppTransitionReady = true;
6958                            mAppTransitionTimeout = true;
6959                            performLayoutAndPlaceSurfacesLocked();
6960                        }
6961                    }
6962                    break;
6963                }
6964
6965                case PERSIST_ANIMATION_SCALE: {
6966                    Settings.System.putFloat(mContext.getContentResolver(),
6967                            Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
6968                    Settings.System.putFloat(mContext.getContentResolver(),
6969                            Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
6970                    Settings.System.putFloat(mContext.getContentResolver(),
6971                            Settings.System.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
6972                    break;
6973                }
6974
6975                case FORCE_GC: {
6976                    synchronized(mWindowMap) {
6977                        if (mAnimationScheduled) {
6978                            // If we are animating, don't do the gc now but
6979                            // delay a bit so we don't interrupt the animation.
6980                            mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
6981                                    2000);
6982                            return;
6983                        }
6984                        // If we are currently rotating the display, it will
6985                        // schedule a new message when done.
6986                        if (mDisplayFrozen) {
6987                            return;
6988                        }
6989                    }
6990                    Runtime.getRuntime().gc();
6991                    break;
6992                }
6993
6994                case ENABLE_SCREEN: {
6995                    performEnableScreen();
6996                    break;
6997                }
6998
6999                case APP_FREEZE_TIMEOUT: {
7000                    synchronized (mWindowMap) {
7001                        synchronized (mAnimator) {
7002                            Slog.w(TAG, "App freeze timeout expired.");
7003                            int i = mAppTokens.size();
7004                            while (i > 0) {
7005                                i--;
7006                                AppWindowToken tok = mAppTokens.get(i);
7007                                if (tok.mAppAnimator.freezingScreen) {
7008                                    Slog.w(TAG, "Force clearing freeze: " + tok);
7009                                    unsetAppFreezingScreenLocked(tok, true, true);
7010                                }
7011                            }
7012                        }
7013                    }
7014                    break;
7015                }
7016
7017                case SEND_NEW_CONFIGURATION: {
7018                    removeMessages(SEND_NEW_CONFIGURATION);
7019                    sendNewConfiguration();
7020                    break;
7021                }
7022
7023                case REPORT_WINDOWS_CHANGE: {
7024                    if (mWindowsChanged) {
7025                        synchronized (mWindowMap) {
7026                            mWindowsChanged = false;
7027                        }
7028                        notifyWindowsChanged();
7029                    }
7030                    break;
7031                }
7032
7033                case DRAG_START_TIMEOUT: {
7034                    IBinder win = (IBinder)msg.obj;
7035                    if (DEBUG_DRAG) {
7036                        Slog.w(TAG, "Timeout starting drag by win " + win);
7037                    }
7038                    synchronized (mWindowMap) {
7039                        // !!! TODO: ANR the app that has failed to start the drag in time
7040                        if (mDragState != null) {
7041                            mDragState.unregister();
7042                            mInputMonitor.updateInputWindowsLw(true /*force*/);
7043                            mDragState.reset();
7044                            mDragState = null;
7045                        }
7046                    }
7047                    break;
7048                }
7049
7050                case DRAG_END_TIMEOUT: {
7051                    IBinder win = (IBinder)msg.obj;
7052                    if (DEBUG_DRAG) {
7053                        Slog.w(TAG, "Timeout ending drag to win " + win);
7054                    }
7055                    synchronized (mWindowMap) {
7056                        // !!! TODO: ANR the drag-receiving app
7057                        if (mDragState != null) {
7058                            mDragState.mDragResult = false;
7059                            mDragState.endDragLw();
7060                        }
7061                    }
7062                    break;
7063                }
7064
7065                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
7066                    notifyHardKeyboardStatusChange();
7067                    break;
7068                }
7069
7070                case BOOT_TIMEOUT: {
7071                    performBootTimeout();
7072                    break;
7073                }
7074
7075                case WAITING_FOR_DRAWN_TIMEOUT: {
7076                    Pair<WindowState, IRemoteCallback> pair;
7077                    synchronized (mWindowMap) {
7078                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
7079                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
7080                        if (!mWaitingForDrawn.remove(pair)) {
7081                            return;
7082                        }
7083                    }
7084                    try {
7085                        pair.second.sendResult(null);
7086                    } catch (RemoteException e) {
7087                    }
7088                    break;
7089                }
7090
7091                case BULK_UPDATE_PARAMETERS: {
7092                    // Used to send multiple changes from the animation side to the layout side.
7093                    synchronized (mWindowMap) {
7094                        boolean doRequest = false;
7095                        // TODO(cmautner): As the number of bits grows, use masks of bit groups to
7096                        //  eliminate unnecessary tests.
7097                        if ((msg.arg1 & LayoutFields.SET_UPDATE_ROTATION) != 0) {
7098                            mInnerFields.mUpdateRotation = true;
7099                            doRequest = true;
7100                        }
7101                        if ((msg.arg1 & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
7102                            mInnerFields.mWallpaperMayChange = true;
7103                            doRequest = true;
7104                        }
7105                        if ((msg.arg1 & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
7106                            mInnerFields.mWallpaperForceHidingChanged = true;
7107                            doRequest = true;
7108                        }
7109                        if ((msg.arg1 & LayoutFields.CLEAR_ORIENTATION_CHANGE_COMPLETE) != 0) {
7110                            mInnerFields.mOrientationChangeComplete = false;
7111                        } else {
7112                            mInnerFields.mOrientationChangeComplete = true;
7113                            if (mWindowsFreezingScreen) {
7114                                doRequest = true;
7115                            }
7116                        }
7117                        if ((msg.arg1 & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
7118                            mTurnOnScreen = true;
7119                        }
7120
7121                        mPendingLayoutChanges |= msg.arg2;
7122                        if (mPendingLayoutChanges != 0) {
7123                            doRequest = true;
7124                        }
7125
7126                        if (doRequest) {
7127                            mH.sendEmptyMessage(CLEAR_PENDING_ACTIONS);
7128                            performLayoutAndPlaceSurfacesLocked();
7129                        }
7130                    }
7131                    break;
7132                }
7133
7134                // Animation messages. Move to Window{State}Animator
7135                case SET_TRANSPARENT_REGION: {
7136                    Pair<WindowStateAnimator, Region> pair =
7137                                (Pair<WindowStateAnimator, Region>) msg.obj;
7138                    final WindowStateAnimator winAnimator = pair.first;
7139                    winAnimator.setTransparentRegionHint(pair.second);
7140                    break;
7141                }
7142
7143                case SET_WALLPAPER_OFFSET: {
7144                    final WindowStateAnimator winAnimator = (WindowStateAnimator) msg.obj;
7145                    winAnimator.setWallpaperOffset(msg.arg1, msg.arg2);
7146
7147                    scheduleAnimationLocked();
7148                    break;
7149                }
7150
7151                case SET_DIM_PARAMETERS: {
7152                    mAnimator.mDimParams = (DimAnimator.Parameters) msg.obj;
7153
7154                    scheduleAnimationLocked();
7155                    break;
7156                }
7157
7158                case SET_MOVE_ANIMATION: {
7159                    WindowAnimator.SetAnimationParams params =
7160                            (WindowAnimator.SetAnimationParams) msg.obj;
7161                    WindowStateAnimator winAnimator = params.mWinAnimator;
7162                    winAnimator.setAnimation(params.mAnimation);
7163                    winAnimator.mAnimDw = params.mAnimDw;
7164                    winAnimator.mAnimDh = params.mAnimDh;
7165
7166                    scheduleAnimationLocked();
7167                    break;
7168                }
7169
7170                case CLEAR_PENDING_ACTIONS: {
7171                    mAnimator.clearPendingActions();
7172                    break;
7173                }
7174            }
7175            if (DEBUG_WINDOW_TRACE) {
7176                Slog.v(TAG, "handleMessage: exit");
7177            }
7178        }
7179    }
7180
7181    // -------------------------------------------------------------
7182    // IWindowManager API
7183    // -------------------------------------------------------------
7184
7185    @Override
7186    public IWindowSession openSession(IInputMethodClient client,
7187            IInputContext inputContext) {
7188        if (client == null) throw new IllegalArgumentException("null client");
7189        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7190        Session session = new Session(this, client, inputContext);
7191        return session;
7192    }
7193
7194    @Override
7195    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7196        synchronized (mWindowMap) {
7197            // The focus for the client is the window immediately below
7198            // where we would place the input method window.
7199            int idx = findDesiredInputMethodWindowIndexLocked(false);
7200            WindowState imFocus;
7201            if (idx > 0) {
7202                imFocus = mWindows.get(idx-1);
7203                //Log.i(TAG, "Desired input method target: " + imFocus);
7204                //Log.i(TAG, "Current focus: " + this.mCurrentFocus);
7205                //Log.i(TAG, "Last focus: " + this.mLastFocus);
7206                if (imFocus != null) {
7207                    // This may be a starting window, in which case we still want
7208                    // to count it as okay.
7209                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
7210                            && imFocus.mAppToken != null) {
7211                        // The client has definitely started, so it really should
7212                        // have a window in this app token.  Let's look for it.
7213                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
7214                            WindowState w = imFocus.mAppToken.windows.get(i);
7215                            if (w != imFocus) {
7216                                //Log.i(TAG, "Switching to real app window: " + w);
7217                                imFocus = w;
7218                                break;
7219                            }
7220                        }
7221                    }
7222                    //Log.i(TAG, "IM target client: " + imFocus.mSession.mClient);
7223                    //if (imFocus.mSession.mClient != null) {
7224                    //    Log.i(TAG, "IM target client binder: " + imFocus.mSession.mClient.asBinder());
7225                    //    Log.i(TAG, "Requesting client binder: " + client.asBinder());
7226                    //}
7227                    if (imFocus.mSession.mClient != null &&
7228                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7229                        return true;
7230                    }
7231
7232                    // Okay, how about this...  what is the current focus?
7233                    // It seems in some cases we may not have moved the IM
7234                    // target window, such as when it was in a pop-up window,
7235                    // so let's also look at the current focus.  (An example:
7236                    // go to Gmail, start searching so the keyboard goes up,
7237                    // press home.  Sometimes the IME won't go down.)
7238                    // Would be nice to fix this more correctly, but it's
7239                    // way at the end of a release, and this should be good enough.
7240                    if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null &&
7241                            mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7242                        return true;
7243                    }
7244                }
7245            }
7246        }
7247        return false;
7248    }
7249
7250    public void getDisplaySize(Point size) {
7251        synchronized(mDisplaySizeLock) {
7252            size.x = mAppDisplayWidth;
7253            size.y = mAppDisplayHeight;
7254        }
7255    }
7256
7257    public void getRealDisplaySize(Point size) {
7258        synchronized(mDisplaySizeLock) {
7259            size.x = mCurDisplayWidth;
7260            size.y = mCurDisplayHeight;
7261        }
7262    }
7263
7264    public void getInitialDisplaySize(Point size) {
7265        synchronized(mDisplaySizeLock) {
7266            size.x = mInitialDisplayWidth;
7267            size.y = mInitialDisplayHeight;
7268        }
7269    }
7270
7271    public int getMaximumSizeDimension() {
7272        synchronized(mDisplaySizeLock) {
7273            // Do this based on the raw screen size, until we are smarter.
7274            return mBaseDisplayWidth > mBaseDisplayHeight
7275                    ? mBaseDisplayWidth : mBaseDisplayHeight;
7276        }
7277    }
7278
7279    public void getCurrentSizeRange(Point smallestSize, Point largestSize) {
7280        synchronized(mDisplaySizeLock) {
7281            smallestSize.x = mSmallestDisplayWidth;
7282            smallestSize.y = mSmallestDisplayHeight;
7283            largestSize.x = mLargestDisplayWidth;
7284            largestSize.y = mLargestDisplayHeight;
7285        }
7286    }
7287
7288    public void setForcedDisplaySize(int longDimen, int shortDimen) {
7289        synchronized(mWindowMap) {
7290            int width, height;
7291            if (mInitialDisplayWidth < mInitialDisplayHeight) {
7292                width = shortDimen < mInitialDisplayWidth
7293                        ? shortDimen : mInitialDisplayWidth;
7294                height = longDimen < mInitialDisplayHeight
7295                        ? longDimen : mInitialDisplayHeight;
7296            } else {
7297                width = longDimen < mInitialDisplayWidth
7298                        ? longDimen : mInitialDisplayWidth;
7299                height = shortDimen < mInitialDisplayHeight
7300                        ? shortDimen : mInitialDisplayHeight;
7301            }
7302            setForcedDisplaySizeLocked(width, height);
7303            Settings.Secure.putString(mContext.getContentResolver(),
7304                    Settings.Secure.DISPLAY_SIZE_FORCED, width + "," + height);
7305        }
7306    }
7307
7308    private void rebuildBlackFrame() {
7309        if (mBlackFrame != null) {
7310            mBlackFrame.kill();
7311            mBlackFrame = null;
7312        }
7313        if (mBaseDisplayWidth < mInitialDisplayWidth
7314                || mBaseDisplayHeight < mInitialDisplayHeight) {
7315            int initW, initH, baseW, baseH;
7316            final boolean rotated = (mRotation == Surface.ROTATION_90
7317                    || mRotation == Surface.ROTATION_270);
7318            if (rotated) {
7319                initW = mInitialDisplayHeight;
7320                initH = mInitialDisplayWidth;
7321                baseW = mBaseDisplayHeight;
7322                baseH = mBaseDisplayWidth;
7323            } else {
7324                initW = mInitialDisplayWidth;
7325                initH = mInitialDisplayHeight;
7326                baseW = mBaseDisplayWidth;
7327                baseH = mBaseDisplayHeight;
7328            }
7329            Rect outer = new Rect(0, 0, initW, initH);
7330            Rect inner = new Rect(0, 0, baseW, baseH);
7331            try {
7332                mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
7333            } catch (Surface.OutOfResourcesException e) {
7334            }
7335        }
7336    }
7337
7338    private void readForcedDisplaySizeLocked() {
7339        final String str = Settings.Secure.getString(mContext.getContentResolver(),
7340                Settings.Secure.DISPLAY_SIZE_FORCED);
7341        if (str == null || str.length() == 0) {
7342            return;
7343        }
7344        final int pos = str.indexOf(',');
7345        if (pos <= 0 || str.lastIndexOf(',') != pos) {
7346            return;
7347        }
7348        int width, height;
7349        try {
7350            width = Integer.parseInt(str.substring(0, pos));
7351            height = Integer.parseInt(str.substring(pos+1));
7352        } catch (NumberFormatException ex) {
7353            return;
7354        }
7355        setForcedDisplaySizeLocked(width, height);
7356    }
7357
7358    private void setForcedDisplaySizeLocked(int width, int height) {
7359        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7360
7361        synchronized(mDisplaySizeLock) {
7362            mBaseDisplayWidth = width;
7363            mBaseDisplayHeight = height;
7364        }
7365        mPolicy.setInitialDisplaySize(mDisplay, mBaseDisplayWidth, mBaseDisplayHeight);
7366
7367        mLayoutNeeded = true;
7368
7369        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7370        mTempConfiguration.setToDefaults();
7371        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7372        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7373            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7374                configChanged = true;
7375            }
7376        }
7377
7378        if (configChanged) {
7379            mWaitingForConfig = true;
7380            startFreezingDisplayLocked(false);
7381            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7382        }
7383
7384        rebuildBlackFrame();
7385
7386        performLayoutAndPlaceSurfacesLocked();
7387    }
7388
7389    public void clearForcedDisplaySize() {
7390        synchronized(mWindowMap) {
7391            setForcedDisplaySizeLocked(mInitialDisplayWidth, mInitialDisplayHeight);
7392            Settings.Secure.putString(mContext.getContentResolver(),
7393                    Settings.Secure.DISPLAY_SIZE_FORCED, "");
7394        }
7395    }
7396
7397    public boolean hasSystemNavBar() {
7398        return mPolicy.hasSystemNavBar();
7399    }
7400
7401    // -------------------------------------------------------------
7402    // Internals
7403    // -------------------------------------------------------------
7404
7405    final WindowState windowForClientLocked(Session session, IWindow client,
7406            boolean throwOnError) {
7407        return windowForClientLocked(session, client.asBinder(), throwOnError);
7408    }
7409
7410    final WindowState windowForClientLocked(Session session, IBinder client,
7411            boolean throwOnError) {
7412        WindowState win = mWindowMap.get(client);
7413        if (localLOGV) Slog.v(
7414            TAG, "Looking up client " + client + ": " + win);
7415        if (win == null) {
7416            RuntimeException ex = new IllegalArgumentException(
7417                    "Requested window " + client + " does not exist");
7418            if (throwOnError) {
7419                throw ex;
7420            }
7421            Slog.w(TAG, "Failed looking up window", ex);
7422            return null;
7423        }
7424        if (session != null && win.mSession != session) {
7425            RuntimeException ex = new IllegalArgumentException(
7426                    "Requested window " + client + " is in session " +
7427                    win.mSession + ", not " + session);
7428            if (throwOnError) {
7429                throw ex;
7430            }
7431            Slog.w(TAG, "Failed looking up window", ex);
7432            return null;
7433        }
7434
7435        return win;
7436    }
7437
7438    final void rebuildAppWindowListLocked() {
7439        int NW = mWindows.size();
7440        int i;
7441        int lastWallpaper = -1;
7442        int numRemoved = 0;
7443
7444        if (mRebuildTmp.length < NW) {
7445            mRebuildTmp = new WindowState[NW+10];
7446        }
7447
7448        // First remove all existing app windows.
7449        i=0;
7450        while (i < NW) {
7451            WindowState w = mWindows.get(i);
7452            if (w.mAppToken != null) {
7453                WindowState win = mWindows.remove(i);
7454                win.mRebuilding = true;
7455                mRebuildTmp[numRemoved] = win;
7456                mWindowsChanged = true;
7457                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
7458                        "Rebuild removing window: " + win);
7459                NW--;
7460                numRemoved++;
7461                continue;
7462            } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER
7463                    && lastWallpaper == i-1) {
7464                lastWallpaper = i;
7465            }
7466            i++;
7467        }
7468
7469        // The wallpaper window(s) typically live at the bottom of the stack,
7470        // so skip them before adding app tokens.
7471        lastWallpaper++;
7472        i = lastWallpaper;
7473
7474        // First add all of the exiting app tokens...  these are no longer
7475        // in the main app list, but still have windows shown.  We put them
7476        // in the back because now that the animation is over we no longer
7477        // will care about them.
7478        int NT = mExitingAppTokens.size();
7479        for (int j=0; j<NT; j++) {
7480            i = reAddAppWindowsLocked(i, mExitingAppTokens.get(j));
7481        }
7482
7483        // And add in the still active app tokens in Z order.
7484        NT = mAppTokens.size();
7485        for (int j=0; j<NT; j++) {
7486            i = reAddAppWindowsLocked(i, mAppTokens.get(j));
7487        }
7488
7489        i -= lastWallpaper;
7490        if (i != numRemoved) {
7491            Slog.w(TAG, "Rebuild removed " + numRemoved
7492                    + " windows but added " + i);
7493            for (i=0; i<numRemoved; i++) {
7494                WindowState ws = mRebuildTmp[i];
7495                if (ws.mRebuilding) {
7496                    StringWriter sw = new StringWriter();
7497                    PrintWriter pw = new PrintWriter(sw);
7498                    ws.dump(pw, "", true);
7499                    pw.flush();
7500                    Slog.w(TAG, "This window was lost: " + ws);
7501                    Slog.w(TAG, sw.toString());
7502                    ws.mWinAnimator.destroySurfaceLocked();
7503                }
7504            }
7505            Slog.w(TAG, "Current app token list:");
7506            dumpAppTokensLocked();
7507            Slog.w(TAG, "Final window list:");
7508            dumpWindowsLocked();
7509        }
7510    }
7511
7512    private final void assignLayersLocked() {
7513        int N = mWindows.size();
7514        int curBaseLayer = 0;
7515        int curLayer = 0;
7516        int i;
7517
7518        if (DEBUG_LAYERS) {
7519            RuntimeException here = new RuntimeException("here");
7520            here.fillInStackTrace();
7521            Slog.v(TAG, "Assigning layers", here);
7522        }
7523
7524        for (i=0; i<N; i++) {
7525            WindowState w = mWindows.get(i);
7526            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
7527                    || (i > 0 && w.mIsWallpaper)) {
7528                curLayer += WINDOW_LAYER_MULTIPLIER;
7529                w.mLayer = curLayer;
7530            } else {
7531                curBaseLayer = curLayer = w.mBaseLayer;
7532                w.mLayer = curLayer;
7533            }
7534            if (w.mTargetAppToken != null) {
7535                w.mWinAnimator.mAnimLayer =
7536                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
7537            } else if (w.mAppToken != null) {
7538                w.mWinAnimator.mAnimLayer =
7539                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
7540            } else {
7541                w.mWinAnimator.mAnimLayer = w.mLayer;
7542            }
7543            if (w.mIsImWindow) {
7544                w.mWinAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
7545            } else if (w.mIsWallpaper) {
7546                w.mWinAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
7547            }
7548            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
7549                    + w.mWinAnimator.mAnimLayer);
7550            //System.out.println(
7551            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7552        }
7553    }
7554
7555    private boolean mInLayout = false;
7556    private final void performLayoutAndPlaceSurfacesLocked() {
7557        if (mInLayout) {
7558            if (DEBUG) {
7559                throw new RuntimeException("Recursive call!");
7560            }
7561            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
7562            return;
7563        }
7564
7565        if (mWaitingForConfig) {
7566            // Our configuration has changed (most likely rotation), but we
7567            // don't yet have the complete configuration to report to
7568            // applications.  Don't do any window layout until we have it.
7569            return;
7570        }
7571
7572        if (mDisplay == null) {
7573            // Not yet initialized, nothing to do.
7574            return;
7575        }
7576
7577        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
7578        mInLayout = true;
7579        boolean recoveringMemory = false;
7580
7581        try {
7582            if (mForceRemoves != null) {
7583                recoveringMemory = true;
7584                // Wait a little bit for things to settle down, and off we go.
7585                for (int i=0; i<mForceRemoves.size(); i++) {
7586                    WindowState ws = mForceRemoves.get(i);
7587                    Slog.i(TAG, "Force removing: " + ws);
7588                    removeWindowInnerLocked(ws.mSession, ws);
7589                }
7590                mForceRemoves = null;
7591                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
7592                Object tmp = new Object();
7593                synchronized (tmp) {
7594                    try {
7595                        tmp.wait(250);
7596                    } catch (InterruptedException e) {
7597                    }
7598                }
7599            }
7600        } catch (RuntimeException e) {
7601            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
7602        }
7603
7604        try {
7605            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
7606
7607            final int N = mPendingRemove.size();
7608            if (N > 0) {
7609                if (mPendingRemoveTmp.length < N) {
7610                    mPendingRemoveTmp = new WindowState[N+10];
7611                }
7612                mPendingRemove.toArray(mPendingRemoveTmp);
7613                mPendingRemove.clear();
7614                for (int i=0; i<N; i++) {
7615                    WindowState w = mPendingRemoveTmp[i];
7616                    removeWindowInnerLocked(w.mSession, w);
7617                }
7618
7619                mInLayout = false;
7620                assignLayersLocked();
7621                mLayoutNeeded = true;
7622                // XXX this recursion seems broken!
7623                Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
7624                performLayoutAndPlaceSurfacesLocked();
7625                Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
7626
7627            } else {
7628                mInLayout = false;
7629            }
7630
7631            if (mLayoutNeeded) {
7632                if (++mLayoutRepeatCount < 6) {
7633                    requestTraversalLocked();
7634                } else {
7635                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
7636                    mLayoutRepeatCount = 0;
7637                }
7638            } else {
7639                mLayoutRepeatCount = 0;
7640            }
7641
7642            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
7643                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
7644                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
7645            }
7646        } catch (RuntimeException e) {
7647            mInLayout = false;
7648            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
7649        }
7650
7651        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
7652    }
7653
7654    private final void performLayoutLockedInner(boolean initial, boolean updateInputWindows) {
7655        if (!mLayoutNeeded) {
7656            return;
7657        }
7658
7659        mLayoutNeeded = false;
7660
7661        final int dw = mCurDisplayWidth;
7662        final int dh = mCurDisplayHeight;
7663
7664        final int NFW = mFakeWindows.size();
7665        for (int i=0; i<NFW; i++) {
7666            mFakeWindows.get(i).layout(dw, dh);
7667        }
7668
7669        final int N = mWindows.size();
7670        int i;
7671
7672        if (DEBUG_LAYOUT) {
7673            Slog.v(TAG, "-------------------------------------");
7674            Slog.v(TAG, "performLayout: needed="
7675                    + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
7676        }
7677
7678        mPolicy.beginLayoutLw(dw, dh, mRotation);
7679
7680        int seq = mLayoutSeq+1;
7681        if (seq < 0) seq = 0;
7682        mLayoutSeq = seq;
7683
7684        // First perform layout of any root windows (not attached
7685        // to another window).
7686        int topAttached = -1;
7687        for (i = N-1; i >= 0; i--) {
7688            final WindowState win = mWindows.get(i);
7689
7690            // Don't do layout of a window if it is not visible, or
7691            // soon won't be visible, to avoid wasting time and funky
7692            // changes while a window is animating away.
7693            final boolean gone = win.isGoneForLayoutLw();
7694
7695            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
7696                Slog.v(TAG, "1ST PASS " + win
7697                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
7698                        + " mLayoutAttached=" + win.mLayoutAttached);
7699                final AppWindowToken atoken = win.mAppToken;
7700                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
7701                        + win.mViewVisibility + " mRelayoutCalled="
7702                        + win.mRelayoutCalled + " hidden="
7703                        + win.mRootToken.hidden + " hiddenRequested="
7704                        + (atoken != null && atoken.hiddenRequested)
7705                        + " mAttachedHidden=" + win.mAttachedHidden);
7706                else Slog.v(TAG, "  VIS: mViewVisibility="
7707                        + win.mViewVisibility + " mRelayoutCalled="
7708                        + win.mRelayoutCalled + " hidden="
7709                        + win.mRootToken.hidden + " hiddenRequested="
7710                        + (atoken != null && atoken.hiddenRequested)
7711                        + " mAttachedHidden=" + win.mAttachedHidden);
7712            }
7713
7714            // If this view is GONE, then skip it -- keep the current
7715            // frame, and let the caller know so they can ignore it
7716            // if they want.  (We do the normal layout for INVISIBLE
7717            // windows, since that means "perform layout as normal,
7718            // just don't display").
7719            if (!gone || !win.mHaveFrame || win.mLayoutNeeded) {
7720                if (!win.mLayoutAttached) {
7721                    if (initial) {
7722                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7723                        win.mContentChanged = false;
7724                    }
7725                    win.mLayoutNeeded = false;
7726                    win.prelayout();
7727                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
7728                    win.mLayoutSeq = seq;
7729                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7730                            + win.mFrame + " mContainingFrame="
7731                            + win.mContainingFrame + " mDisplayFrame="
7732                            + win.mDisplayFrame);
7733                } else {
7734                    if (topAttached < 0) topAttached = i;
7735                }
7736            }
7737        }
7738
7739        // Now perform layout of attached windows, which usually
7740        // depend on the position of the window they are attached to.
7741        // XXX does not deal with windows that are attached to windows
7742        // that are themselves attached.
7743        for (i = topAttached; i >= 0; i--) {
7744            final WindowState win = mWindows.get(i);
7745
7746            if (win.mLayoutAttached) {
7747                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
7748                        + " mHaveFrame=" + win.mHaveFrame
7749                        + " mViewVisibility=" + win.mViewVisibility
7750                        + " mRelayoutCalled=" + win.mRelayoutCalled);
7751                // If this view is GONE, then skip it -- keep the current
7752                // frame, and let the caller know so they can ignore it
7753                // if they want.  (We do the normal layout for INVISIBLE
7754                // windows, since that means "perform layout as normal,
7755                // just don't display").
7756                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7757                        || !win.mHaveFrame || win.mLayoutNeeded) {
7758                    if (initial) {
7759                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7760                        win.mContentChanged = false;
7761                    }
7762                    win.mLayoutNeeded = false;
7763                    win.prelayout();
7764                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7765                    win.mLayoutSeq = seq;
7766                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7767                            + win.mFrame + " mContainingFrame="
7768                            + win.mContainingFrame + " mDisplayFrame="
7769                            + win.mDisplayFrame);
7770                }
7771            }
7772        }
7773
7774        // Window frames may have changed.  Tell the input dispatcher about it.
7775        mInputMonitor.setUpdateInputWindowsNeededLw();
7776        if (updateInputWindows) {
7777            mInputMonitor.updateInputWindowsLw(false /*force*/);
7778        }
7779
7780        mPolicy.finishLayoutLw();
7781    }
7782
7783    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
7784        // If the screen is currently frozen or off, then keep
7785        // it frozen/off until this window draws at its new
7786        // orientation.
7787        if (!okToDisplay()) {
7788            if (DEBUG_ORIENTATION) Slog.v(TAG,
7789                    "Changing surface while display frozen: " + w);
7790            w.mOrientationChanging = true;
7791            mInnerFields.mOrientationChangeComplete = false;
7792            if (!mWindowsFreezingScreen) {
7793                mWindowsFreezingScreen = true;
7794                // XXX should probably keep timeout from
7795                // when we first froze the display.
7796                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
7797                mH.sendMessageDelayed(mH.obtainMessage(
7798                        H.WINDOW_FREEZE_TIMEOUT), 2000);
7799            }
7800        }
7801    }
7802
7803    /**
7804     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
7805     *
7806     * @return bitmap indicating if another pass through layout must be made.
7807     */
7808    public int handleAppTransitionReadyLocked() {
7809        int changes = 0;
7810        int i;
7811        int NN = mOpeningApps.size();
7812        boolean goodToGo = true;
7813        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7814                "Checking " + NN + " opening apps (frozen="
7815                + mDisplayFrozen + " timeout="
7816                + mAppTransitionTimeout + ")...");
7817        if (!mDisplayFrozen && !mAppTransitionTimeout) {
7818            // If the display isn't frozen, wait to do anything until
7819            // all of the apps are ready.  Otherwise just go because
7820            // we'll unfreeze the display when everyone is ready.
7821            for (i=0; i<NN && goodToGo; i++) {
7822                AppWindowToken wtoken = mOpeningApps.get(i);
7823                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7824                        "Check opening app" + wtoken + ": allDrawn="
7825                        + wtoken.allDrawn + " startingDisplayed="
7826                        + wtoken.startingDisplayed + " startingMoved="
7827                        + wtoken.startingMoved);
7828                if (!wtoken.allDrawn && !wtoken.startingDisplayed
7829                        && !wtoken.startingMoved) {
7830                    goodToGo = false;
7831                }
7832            }
7833        }
7834        if (goodToGo) {
7835            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
7836            int transit = mNextAppTransition;
7837            if (mSkipAppTransitionAnimation) {
7838                transit = WindowManagerPolicy.TRANSIT_UNSET;
7839            }
7840            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
7841            mAppTransitionReady = false;
7842            mAppTransitionRunning = true;
7843            mAppTransitionTimeout = false;
7844            mStartingIconInTransition = false;
7845            mSkipAppTransitionAnimation = false;
7846
7847            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
7848
7849            // If there are applications waiting to come to the
7850            // top of the stack, now is the time to move their windows.
7851            // (Note that we don't do apps going to the bottom
7852            // here -- we want to keep their windows in the old
7853            // Z-order until the animation completes.)
7854            if (mToTopApps.size() > 0) {
7855                NN = mAppTokens.size();
7856                for (i=0; i<NN; i++) {
7857                    AppWindowToken wtoken = mAppTokens.get(i);
7858                    if (wtoken.sendingToTop) {
7859                        wtoken.sendingToTop = false;
7860                        moveAppWindowsLocked(wtoken, NN, false);
7861                    }
7862                }
7863                mToTopApps.clear();
7864            }
7865
7866            WindowState oldWallpaper =
7867                    mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
7868                    ? null : mWallpaperTarget;
7869
7870            adjustWallpaperWindowsLocked();
7871            mInnerFields.mWallpaperMayChange = false;
7872
7873            // The top-most window will supply the layout params,
7874            // and we will determine it below.
7875            LayoutParams animLp = null;
7876            int bestAnimLayer = -1;
7877            boolean fullscreenAnim = false;
7878
7879            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7880                    "New wallpaper target=" + mWallpaperTarget
7881                    + ", lower target=" + mLowerWallpaperTarget
7882                    + ", upper target=" + mUpperWallpaperTarget);
7883            int foundWallpapers = 0;
7884            // Do a first pass through the tokens for two
7885            // things:
7886            // (1) Determine if both the closing and opening
7887            // app token sets are wallpaper targets, in which
7888            // case special animations are needed
7889            // (since the wallpaper needs to stay static
7890            // behind them).
7891            // (2) Find the layout params of the top-most
7892            // application window in the tokens, which is
7893            // what will control the animation theme.
7894            final int NC = mClosingApps.size();
7895            NN = NC + mOpeningApps.size();
7896            for (i=0; i<NN; i++) {
7897                AppWindowToken wtoken;
7898                int mode;
7899                if (i < NC) {
7900                    wtoken = mClosingApps.get(i);
7901                    mode = 1;
7902                } else {
7903                    wtoken = mOpeningApps.get(i-NC);
7904                    mode = 2;
7905                }
7906                if (mLowerWallpaperTarget != null) {
7907                    if (mLowerWallpaperTarget.mAppToken == wtoken
7908                            || mUpperWallpaperTarget.mAppToken == wtoken) {
7909                        foundWallpapers |= mode;
7910                    }
7911                }
7912                if (wtoken.appFullscreen) {
7913                    WindowState ws = wtoken.findMainWindow();
7914                    if (ws != null) {
7915                        animLp = ws.mAttrs;
7916                        bestAnimLayer = ws.mLayer;
7917                        fullscreenAnim = true;
7918                    }
7919                } else if (!fullscreenAnim) {
7920                    WindowState ws = wtoken.findMainWindow();
7921                    if (ws != null) {
7922                        if (ws.mLayer > bestAnimLayer) {
7923                            animLp = ws.mAttrs;
7924                            bestAnimLayer = ws.mLayer;
7925                        }
7926                    }
7927                }
7928            }
7929
7930            if (foundWallpapers == 3) {
7931                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7932                        "Wallpaper animation!");
7933                switch (transit) {
7934                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
7935                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
7936                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
7937                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
7938                        break;
7939                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
7940                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
7941                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
7942                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
7943                        break;
7944                }
7945                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7946                        "New transit: " + transit);
7947            } else if (oldWallpaper != null) {
7948                // We are transitioning from an activity with
7949                // a wallpaper to one without.
7950                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
7951                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7952                        "New transit away from wallpaper: " + transit);
7953            } else if (mWallpaperTarget != null) {
7954                // We are transitioning from an activity without
7955                // a wallpaper to now showing the wallpaper
7956                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
7957                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7958                        "New transit into wallpaper: " + transit);
7959            }
7960
7961            // If all closing windows are obscured, then there is
7962            // no need to do an animation.  This is the case, for
7963            // example, when this transition is being done behind
7964            // the lock screen.
7965            if (!mPolicy.allowAppAnimationsLw()) {
7966                animLp = null;
7967            }
7968
7969            AppWindowToken topOpeningApp = null;
7970            int topOpeningLayer = 0;
7971
7972            // TODO(cmautner): Move to animation side.
7973            NN = mOpeningApps.size();
7974            for (i=0; i<NN; i++) {
7975                AppWindowToken wtoken = mOpeningApps.get(i);
7976                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
7977                wtoken.mAppAnimator.clearThumbnail();
7978                wtoken.reportedVisible = false;
7979                wtoken.inPendingTransaction = false;
7980                wtoken.mAppAnimator.animation = null;
7981                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
7982                wtoken.updateReportedVisibilityLocked();
7983                wtoken.waitingToShow = false;
7984                mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked();
7985                if (animLp != null) {
7986                    int layer = -1;
7987                    for (int j=0; j<wtoken.windows.size(); j++) {
7988                        WindowState win = wtoken.windows.get(j);
7989                        if (win.mWinAnimator.mAnimLayer > layer) {
7990                            layer = win.mWinAnimator.mAnimLayer;
7991                        }
7992                    }
7993                    if (topOpeningApp == null || layer > topOpeningLayer) {
7994                        topOpeningApp = wtoken;
7995                        topOpeningLayer = layer;
7996                    }
7997                }
7998            }
7999            NN = mClosingApps.size();
8000            for (i=0; i<NN; i++) {
8001                AppWindowToken wtoken = mClosingApps.get(i);
8002                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8003                        "Now closing app" + wtoken);
8004                wtoken.mAppAnimator.clearThumbnail();
8005                wtoken.inPendingTransaction = false;
8006                wtoken.mAppAnimator.animation = null;
8007                setTokenVisibilityLocked(wtoken, animLp, false,
8008                        transit, false);
8009                wtoken.updateReportedVisibilityLocked();
8010                wtoken.waitingToHide = false;
8011                // Force the allDrawn flag, because we want to start
8012                // this guy's animations regardless of whether it's
8013                // gotten drawn.
8014                wtoken.allDrawn = true;
8015            }
8016
8017            if (mNextAppTransitionThumbnail != null && topOpeningApp != null
8018                    && topOpeningApp.mAppAnimator.animation != null) {
8019                // This thumbnail animation is very special, we need to have
8020                // an extra surface with the thumbnail included with the animation.
8021                Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
8022                        mNextAppTransitionThumbnail.getHeight());
8023                try {
8024                    Surface surface = new Surface(mFxSession, Process.myPid(),
8025                            "thumbnail anim", 0, dirty.width(), dirty.height(),
8026                            PixelFormat.TRANSLUCENT, Surface.HIDDEN);
8027                    topOpeningApp.mAppAnimator.thumbnail = surface;
8028                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
8029                            + surface + ": CREATE");
8030                    Surface drawSurface = new Surface();
8031                    drawSurface.copyFrom(surface);
8032                    Canvas c = drawSurface.lockCanvas(dirty);
8033                    c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
8034                    drawSurface.unlockCanvasAndPost(c);
8035                    drawSurface.release();
8036                    topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
8037                    Animation anim = createThumbnailAnimationLocked(transit, true, true);
8038                    topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
8039                    anim.restrictDuration(MAX_ANIMATION_DURATION);
8040                    anim.scaleCurrentDuration(mTransitionAnimationScale);
8041                    topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX;
8042                    topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY;
8043                } catch (Surface.OutOfResourcesException e) {
8044                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
8045                            + " h=" + dirty.height(), e);
8046                    topOpeningApp.mAppAnimator.clearThumbnail();
8047                }
8048            }
8049
8050            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
8051            mNextAppTransitionPackage = null;
8052            mNextAppTransitionThumbnail = null;
8053            if (mNextAppTransitionCallback != null) {
8054                try {
8055                    mNextAppTransitionCallback.sendResult(null);
8056                } catch (RemoteException e) {
8057                }
8058            }
8059
8060            mOpeningApps.clear();
8061            mClosingApps.clear();
8062
8063            // This has changed the visibility of windows, so perform
8064            // a new layout to get them all up-to-date.
8065            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
8066                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8067            mLayoutNeeded = true;
8068            if (!moveInputMethodWindowsIfNeededLocked(true)) {
8069                assignLayersLocked();
8070            }
8071            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8072                    false /*updateInputWindows*/);
8073            mFocusMayChange = false;
8074        }
8075
8076        return changes;
8077    }
8078
8079    /**
8080     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8081     *
8082     * @return bitmap indicating if another pass through layout must be made.
8083     */
8084    private int handleAnimatingStoppedAndTransitionLocked() {
8085        int changes = 0;
8086
8087        mAppTransitionRunning = false;
8088        // Clear information about apps that were moving.
8089        mToBottomApps.clear();
8090
8091        rebuildAppWindowListLocked();
8092        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8093        mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
8094        moveInputMethodWindowsIfNeededLocked(false);
8095        mInnerFields.mWallpaperMayChange = true;
8096        // Since the window list has been rebuilt, focus might
8097        // have to be recomputed since the actual order of windows
8098        // might have changed again.
8099        mFocusMayChange = true;
8100
8101        return changes;
8102    }
8103
8104    /**
8105     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8106     *
8107     * @return bitmap indicating if another pass through layout must be made.
8108     */
8109    private int animateAwayWallpaperLocked() {
8110        int changes = 0;
8111        WindowState oldWallpaper = mWallpaperTarget;
8112        if (mLowerWallpaperTarget != null
8113                && mLowerWallpaperTarget.mAppToken != null) {
8114            if (DEBUG_WALLPAPER) Slog.v(TAG,
8115                    "wallpaperForceHiding changed with lower="
8116                    + mLowerWallpaperTarget);
8117            if (DEBUG_WALLPAPER) Slog.v(TAG,
8118                    "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
8119                    " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
8120            if (mLowerWallpaperTarget.mAppToken.hidden) {
8121                // The lower target has become hidden before we
8122                // actually started the animation...  let's completely
8123                // re-evaluate everything.
8124                mLowerWallpaperTarget = mUpperWallpaperTarget = null;
8125                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8126            }
8127        }
8128        mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8129        if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
8130                + " NEW: " + mWallpaperTarget
8131                + " LOWER: " + mLowerWallpaperTarget);
8132        return changes;
8133    }
8134
8135    private void updateResizingWindows(final WindowState w) {
8136        final WindowStateAnimator winAnimator = w.mWinAnimator;
8137        if (w.mHasSurface && !w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
8138            w.mSystemInsetsChanged |=
8139                    !w.mLastSystemInsets.equals(w.mSystemInsets);
8140            w.mContentInsetsChanged |=
8141                    !w.mLastContentInsets.equals(w.mContentInsets);
8142            w.mVisibleInsetsChanged |=
8143                    !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8144            boolean configChanged =
8145                w.mConfiguration != mCurConfiguration
8146                && (w.mConfiguration == null
8147                        || mCurConfiguration.diff(w.mConfiguration) != 0);
8148            if (DEBUG_CONFIGURATION && configChanged) {
8149                Slog.v(TAG, "Win " + w + " config changed: "
8150                        + mCurConfiguration);
8151            }
8152            if (localLOGV) Slog.v(TAG, "Resizing " + w
8153                    + ": configChanged=" + configChanged
8154                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8155            w.mLastFrame.set(w.mFrame);
8156            if (w.mSystemInsetsChanged
8157                    || w.mContentInsetsChanged
8158                    || w.mVisibleInsetsChanged
8159                    || winAnimator.mSurfaceResized
8160                    || configChanged) {
8161                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8162                    Slog.v(TAG, "Resize reasons: "
8163                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8164                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8165                            + " surfaceResized=" + winAnimator.mSurfaceResized
8166                            + " configChanged=" + configChanged);
8167                }
8168
8169                w.mLastSystemInsets.set(w.mSystemInsets);
8170                w.mLastContentInsets.set(w.mContentInsets);
8171                w.mLastVisibleInsets.set(w.mVisibleInsets);
8172                makeWindowFreezingScreenIfNeededLocked(w);
8173                // If the orientation is changing, then we need to
8174                // hold off on unfreezing the display until this
8175                // window has been redrawn; to do that, we need
8176                // to go through the process of getting informed
8177                // by the application when it has finished drawing.
8178                if (w.mOrientationChanging) {
8179                    if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
8180                            "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
8181                            + w + ", surface " + winAnimator.mSurface);
8182                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8183                    if (w.mAppToken != null) {
8184                        w.mAppToken.allDrawn = false;
8185                    }
8186                }
8187                if (!mResizingWindows.contains(w)) {
8188                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8189                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8190                            + "x" + winAnimator.mSurfaceH);
8191                    mResizingWindows.add(w);
8192                }
8193            } else if (w.mOrientationChanging) {
8194                if (w.isDrawnLw()) {
8195                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8196                            "Orientation not waiting for draw in "
8197                            + w + ", surface " + winAnimator.mSurface);
8198                    w.mOrientationChanging = false;
8199                }
8200            }
8201        }
8202    }
8203
8204    /**
8205     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8206     *
8207     * @param w WindowState this method is applied to.
8208     * @param currentTime The time which animations use for calculating transitions.
8209     * @param innerDw Width of app window.
8210     * @param innerDh Height of app window.
8211     */
8212    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8213                                         final int innerDw, final int innerDh) {
8214        final WindowManager.LayoutParams attrs = w.mAttrs;
8215        final int attrFlags = attrs.flags;
8216        final boolean canBeSeen = w.isDisplayedLw();
8217
8218        if (w.mHasSurface) {
8219            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8220                mInnerFields.mHoldScreen = w.mSession;
8221            }
8222            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8223                    && mInnerFields.mScreenBrightness < 0) {
8224                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8225            }
8226            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8227                    && mInnerFields.mButtonBrightness < 0) {
8228                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8229            }
8230            if (canBeSeen
8231                    && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8232                     || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8233                     || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
8234                mInnerFields.mSyswin = true;
8235            }
8236        }
8237
8238        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8239        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8240            // This window completely covers everything behind it,
8241            // so we want to leave all of them as undimmed (for
8242            // performance reasons).
8243            mInnerFields.mObscured = true;
8244        } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0
8245                && !(w.mAppToken != null && w.mAppToken.hiddenRequested)) {
8246            if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured);
8247            if (!mInnerFields.mDimming) {
8248                //Slog.i(TAG, "DIM BEHIND: " + w);
8249                mInnerFields.mDimming = true;
8250                if (!mAnimator.isDimming()) {
8251                    final int width, height;
8252                    if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
8253                        width = mCurDisplayWidth;
8254                        height = mCurDisplayHeight;
8255                    } else {
8256                        width = innerDw;
8257                        height = innerDh;
8258                    }
8259                    mAnimator.startDimming(w.mWinAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount,
8260                            width, height);
8261                }
8262            }
8263        }
8264    }
8265
8266    // "Something has changed!  Let's make it correct now."
8267    private final void performLayoutAndPlaceSurfacesLockedInner(
8268            boolean recoveringMemory) {
8269        if (DEBUG_WINDOW_TRACE) {
8270            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8271                    + Debug.getCallers(3));
8272        }
8273        if (mDisplay == null) {
8274            Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
8275            return;
8276        }
8277
8278        final long currentTime = SystemClock.uptimeMillis();
8279        final int dw = mCurDisplayWidth;
8280        final int dh = mCurDisplayHeight;
8281        final int innerDw = mAppDisplayWidth;
8282        final int innerDh = mAppDisplayHeight;
8283
8284        int i;
8285
8286        if (mFocusMayChange) {
8287            mFocusMayChange = false;
8288            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8289                    false /*updateInputWindows*/);
8290        }
8291
8292        // Initialize state of exiting tokens.
8293        for (i=mExitingTokens.size()-1; i>=0; i--) {
8294            mExitingTokens.get(i).hasVisible = false;
8295        }
8296
8297        // Initialize state of exiting applications.
8298        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8299            mExitingAppTokens.get(i).hasVisible = false;
8300        }
8301
8302        mInnerFields.mHoldScreen = null;
8303        mInnerFields.mScreenBrightness = -1;
8304        mInnerFields.mButtonBrightness = -1;
8305
8306        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8307                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8308
8309        Surface.openTransaction();
8310
8311        if (mWatermark != null) {
8312            mWatermark.positionSurface(dw, dh);
8313        }
8314        if (mStrictModeFlash != null) {
8315            mStrictModeFlash.positionSurface(dw, dh);
8316        }
8317
8318        try {
8319            int repeats = 0;
8320
8321            do {
8322                repeats++;
8323                if (repeats > 6) {
8324                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
8325                    mLayoutNeeded = false;
8326                    break;
8327                }
8328
8329                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
8330                    mPendingLayoutChanges);
8331
8332                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
8333                    if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8334                        assignLayersLocked();
8335                        mLayoutNeeded = true;
8336                    }
8337                }
8338
8339                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
8340                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
8341                    if (updateOrientationFromAppTokensLocked(true)) {
8342                        mLayoutNeeded = true;
8343                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8344                    }
8345                }
8346
8347                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8348                    mLayoutNeeded = true;
8349                }
8350
8351                // FIRST LOOP: Perform a layout, if needed.
8352                if (repeats < 4) {
8353                    performLayoutLockedInner(repeats == 1, false /*updateInputWindows*/);
8354                } else {
8355                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
8356                }
8357
8358                // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
8359                // it is animating.
8360                mPendingLayoutChanges = 0;
8361                if (DEBUG_LAYOUT_REPEATS)  debugLayoutRepeats("loop number " + mLayoutRepeatCount,
8362                    mPendingLayoutChanges);
8363                mPolicy.beginAnimationLw(dw, dh);
8364                for (i = mWindows.size() - 1; i >= 0; i--) {
8365                    WindowState w = mWindows.get(i);
8366                    if (w.mHasSurface) {
8367                        mPolicy.animatingWindowLw(w, w.mAttrs);
8368                    }
8369                }
8370                mPendingLayoutChanges |= mPolicy.finishAnimationLw();
8371                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishAnimationLw",
8372                    mPendingLayoutChanges);
8373            } while (mPendingLayoutChanges != 0);
8374
8375            final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
8376
8377            mInnerFields.mObscured = false;
8378            mInnerFields.mDimming = false;
8379            mInnerFields.mSyswin = false;
8380
8381            boolean focusDisplayed = false;
8382            final int N = mWindows.size();
8383            for (i=N-1; i>=0; i--) {
8384                WindowState w = mWindows.get(i);
8385
8386                final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
8387
8388                // Update effect.
8389                w.mObscured = mInnerFields.mObscured;
8390                if (!mInnerFields.mObscured) {
8391                    handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
8392                }
8393
8394                if (obscuredChanged && mWallpaperTarget == w) {
8395                    // This is the wallpaper target and its obscured state
8396                    // changed... make sure the current wallaper's visibility
8397                    // has been updated accordingly.
8398                    updateWallpaperVisibilityLocked();
8399                }
8400
8401                final WindowStateAnimator winAnimator = w.mWinAnimator;
8402
8403                // If the window has moved due to its containing
8404                // content frame changing, then we'd like to animate
8405                // it.
8406                if (w.mHasSurface && w.shouldAnimateMove()) {
8407                    // Frame has moved, containing content frame
8408                    // has also moved, and we're not currently animating...
8409                    // let's do something.
8410                    Animation a = AnimationUtils.loadAnimation(mContext,
8411                            com.android.internal.R.anim.window_move_from_decor);
8412                    winAnimator.setAnimation(a);
8413                    winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
8414                    winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
8415                } else {
8416                    winAnimator.mAnimDw = innerDw;
8417                    winAnimator.mAnimDh = innerDh;
8418                }
8419
8420                //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
8421                w.mContentChanged = false;
8422
8423                // Moved from updateWindowsAndWallpaperLocked().
8424                if (w.mHasSurface) {
8425                    // Take care of the window being ready to display.
8426                    if (winAnimator.commitFinishDrawingLocked(currentTime)) {
8427                        if ((w.mAttrs.flags
8428                                & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
8429                            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
8430                                    "First draw done in potential wallpaper target " + w);
8431                            mInnerFields.mWallpaperMayChange = true;
8432                            mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
8433                            if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
8434                                debugLayoutRepeats("updateWindowsAndWallpaperLocked 1",
8435                                    mPendingLayoutChanges);
8436                            }
8437                        }
8438                    }
8439
8440                    winAnimator.setSurfaceBoundaries(recoveringMemory);
8441                }
8442
8443                if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) {
8444                    focusDisplayed = true;
8445                }
8446
8447                updateResizingWindows(w);
8448            }
8449
8450            if (focusDisplayed) {
8451                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8452            }
8453
8454            if (!mInnerFields.mDimming && mAnimator.isDimming()) {
8455                mAnimator.stopDimming();
8456            }
8457        } catch (RuntimeException e) {
8458            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
8459        } finally {
8460            Surface.closeTransaction();
8461        }
8462
8463        // If we are ready to perform an app transition, check through
8464        // all of the app tokens to be shown and see if they are ready
8465        // to go.
8466        if (mAppTransitionReady) {
8467            mPendingLayoutChanges |= handleAppTransitionReadyLocked();
8468            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
8469                mPendingLayoutChanges);
8470        }
8471
8472        mInnerFields.mAdjResult = 0;
8473
8474        if (!mAnimator.mAnimating && mAppTransitionRunning) {
8475            // We have finished the animation of an app transition.  To do
8476            // this, we have delayed a lot of operations like showing and
8477            // hiding apps, moving apps in Z-order, etc.  The app token list
8478            // reflects the correct Z-order, but the window list may now
8479            // be out of sync with it.  So here we will just rebuild the
8480            // entire app window list.  Fun!
8481            mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
8482            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
8483                mPendingLayoutChanges);
8484        }
8485
8486        if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 &&
8487                !mAppTransitionReady) {
8488            // At this point, there was a window with a wallpaper that
8489            // was force hiding other windows behind it, but now it
8490            // is going away.  This may be simple -- just animate
8491            // away the wallpaper and its window -- or it may be
8492            // hard -- the wallpaper now needs to be shown behind
8493            // something that was hidden.
8494            mPendingLayoutChanges |= animateAwayWallpaperLocked();
8495            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
8496                mPendingLayoutChanges);
8497        }
8498        mInnerFields.mWallpaperForceHidingChanged = false;
8499
8500        if (mInnerFields.mWallpaperMayChange) {
8501            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
8502                    "Wallpaper may change!  Adjusting");
8503            mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8504        }
8505
8506        if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8507            if (DEBUG_WALLPAPER) Slog.v(TAG,
8508                    "Wallpaper layer changed: assigning layers + relayout");
8509            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8510            assignLayersLocked();
8511        } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
8512            if (DEBUG_WALLPAPER) Slog.v(TAG,
8513                    "Wallpaper visibility changed: relayout");
8514            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8515        }
8516
8517        if (mFocusMayChange) {
8518            mFocusMayChange = false;
8519            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8520                    false /*updateInputWindows*/)) {
8521                mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8522                mInnerFields.mAdjResult = 0;
8523            }
8524        }
8525
8526        if (mLayoutNeeded) {
8527            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8528            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges);
8529        }
8530
8531        if (!mResizingWindows.isEmpty()) {
8532            for (i = mResizingWindows.size() - 1; i >= 0; i--) {
8533                WindowState win = mResizingWindows.get(i);
8534                final WindowStateAnimator winAnimator = win.mWinAnimator;
8535                try {
8536                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8537                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
8538                    int diff = 0;
8539                    boolean configChanged =
8540                        win.mConfiguration != mCurConfiguration
8541                        && (win.mConfiguration == null
8542                                || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0);
8543                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
8544                            && configChanged) {
8545                        Slog.i(TAG, "Sending new config to window " + win + ": "
8546                                + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
8547                                + " / " + mCurConfiguration + " / 0x"
8548                                + Integer.toHexString(diff));
8549                    }
8550                    win.mConfiguration = mCurConfiguration;
8551                    if (DEBUG_ORIENTATION &&
8552                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
8553                            TAG, "Resizing " + win + " WITH DRAW PENDING");
8554                    win.mClient.resized((int)winAnimator.mSurfaceW,
8555                            (int)winAnimator.mSurfaceH, win.mLastSystemInsets,
8556                            win.mLastContentInsets, win.mLastVisibleInsets,
8557                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
8558                            configChanged ? win.mConfiguration : null);
8559                    win.mSystemInsetsChanged = false;
8560                    win.mContentInsetsChanged = false;
8561                    win.mVisibleInsetsChanged = false;
8562                    winAnimator.mSurfaceResized = false;
8563                } catch (RemoteException e) {
8564                    win.mOrientationChanging = false;
8565                }
8566            }
8567            mResizingWindows.clear();
8568        }
8569
8570        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
8571                "With display frozen, orientationChangeComplete="
8572                + mInnerFields.mOrientationChangeComplete);
8573        if (mInnerFields.mOrientationChangeComplete) {
8574            if (mWindowsFreezingScreen) {
8575                mWindowsFreezingScreen = false;
8576                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8577            }
8578            stopFreezingDisplayLocked();
8579        }
8580
8581        // Destroy the surface of any windows that are no longer visible.
8582        boolean wallpaperDestroyed = false;
8583        i = mDestroySurface.size();
8584        if (i > 0) {
8585            do {
8586                i--;
8587                WindowState win = mDestroySurface.get(i);
8588                win.mDestroying = false;
8589                if (mInputMethodWindow == win) {
8590                    mInputMethodWindow = null;
8591                }
8592                if (win == mWallpaperTarget) {
8593                    wallpaperDestroyed = true;
8594                }
8595                win.mWinAnimator.destroySurfaceLocked();
8596            } while (i > 0);
8597            mDestroySurface.clear();
8598        }
8599
8600        // Time to remove any exiting tokens?
8601        for (i=mExitingTokens.size()-1; i>=0; i--) {
8602            WindowToken token = mExitingTokens.get(i);
8603            if (!token.hasVisible) {
8604                mExitingTokens.remove(i);
8605                if (token.windowType == TYPE_WALLPAPER) {
8606                    mWallpaperTokens.remove(token);
8607                }
8608            }
8609        }
8610
8611        // Time to remove any exiting applications?
8612        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8613            AppWindowToken token = mExitingAppTokens.get(i);
8614            if (!token.hasVisible && !mClosingApps.contains(token)) {
8615                // Make sure there is no animation running on this token,
8616                // so any windows associated with it will be removed as
8617                // soon as their animations are complete
8618                token.mAppAnimator.clearAnimation();
8619                token.mAppAnimator.animating = false;
8620                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
8621                        "performLayout: App token exiting now removed" + token);
8622                mAppTokens.remove(token);
8623                mExitingAppTokens.remove(i);
8624            }
8625        }
8626
8627        if (!mAnimator.mAnimating && mAppTransitionRunning) {
8628            // We have finished the animation of an app transition.  To do
8629            // this, we have delayed a lot of operations like showing and
8630            // hiding apps, moving apps in Z-order, etc.  The app token list
8631            // reflects the correct Z-order, but the window list may now
8632            // be out of sync with it.  So here we will just rebuild the
8633            // entire app window list.  Fun!
8634            mAppTransitionRunning = false;
8635            mLayoutNeeded = true;
8636            rebuildAppWindowListLocked();
8637            assignLayersLocked();
8638            // Clear information about apps that were moving.
8639            mToBottomApps.clear();
8640        }
8641
8642        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
8643            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
8644                try {
8645                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
8646                } catch (RemoteException e) {
8647                }
8648            }
8649            mRelayoutWhileAnimating.clear();
8650        }
8651
8652        if (wallpaperDestroyed) {
8653            mLayoutNeeded |= adjustWallpaperWindowsLocked() != 0;
8654        }
8655        if (mPendingLayoutChanges != 0) {
8656            mLayoutNeeded = true;
8657        }
8658
8659        // Finally update all input windows now that the window changes have stabilized.
8660        mInputMonitor.updateInputWindowsLw(true /*force*/);
8661
8662        setHoldScreenLocked(mInnerFields.mHoldScreen != null);
8663        if (!mDisplayFrozen) {
8664            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
8665                mPowerManager.setScreenBrightnessOverride(-1);
8666            } else {
8667                mPowerManager.setScreenBrightnessOverride((int)
8668                        (mInnerFields.mScreenBrightness * Power.BRIGHTNESS_ON));
8669            }
8670            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
8671                mPowerManager.setButtonBrightnessOverride(-1);
8672            } else {
8673                mPowerManager.setButtonBrightnessOverride((int)
8674                        (mInnerFields.mButtonBrightness * Power.BRIGHTNESS_ON));
8675            }
8676        }
8677        if (mInnerFields.mHoldScreen != mHoldingScreenOn) {
8678            mHoldingScreenOn = mInnerFields.mHoldScreen;
8679            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, mInnerFields.mHoldScreen);
8680            mH.sendMessage(m);
8681        }
8682
8683        if (mTurnOnScreen) {
8684            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
8685            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
8686                    LocalPowerManager.BUTTON_EVENT, true);
8687            mTurnOnScreen = false;
8688        }
8689
8690        if (mInnerFields.mUpdateRotation) {
8691            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8692            if (updateRotationUncheckedLocked(false)) {
8693                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8694            } else {
8695                mInnerFields.mUpdateRotation = false;
8696            }
8697        }
8698
8699        if (mInnerFields.mOrientationChangeComplete && !mLayoutNeeded &&
8700                !mInnerFields.mUpdateRotation) {
8701            checkDrawnWindowsLocked();
8702        }
8703
8704        // Check to see if we are now in a state where the screen should
8705        // be enabled, because the window obscured flags have changed.
8706        enableScreenIfNeededLocked();
8707
8708        scheduleAnimationLocked();
8709
8710        if (DEBUG_WINDOW_TRACE) {
8711            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges="
8712                + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded
8713                + " animating=" + mAnimator.mAnimating);
8714        }
8715    }
8716
8717    void checkDrawnWindowsLocked() {
8718        if (mWaitingForDrawn.size() > 0) {
8719            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
8720                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
8721                WindowState win = pair.first;
8722                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
8723                //        + win.mRemoved + " visible=" + win.isVisibleLw()
8724                //        + " shown=" + win.mSurfaceShown);
8725                if (win.mRemoved || !win.isVisibleLw()) {
8726                    // Window has been removed or made invisible; no draw
8727                    // will now happen, so stop waiting.
8728                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
8729                    try {
8730                        pair.second.sendResult(null);
8731                    } catch (RemoteException e) {
8732                    }
8733                    mWaitingForDrawn.remove(pair);
8734                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8735                } else if (win.mWinAnimator.mSurfaceShown) {
8736                    // Window is now drawn (and shown).
8737                    try {
8738                        pair.second.sendResult(null);
8739                    } catch (RemoteException e) {
8740                    }
8741                    mWaitingForDrawn.remove(pair);
8742                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8743                }
8744            }
8745        }
8746    }
8747
8748    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
8749        synchronized (mWindowMap) {
8750            WindowState win = windowForClientLocked(null, token, true);
8751            if (win != null) {
8752                Pair<WindowState, IRemoteCallback> pair =
8753                        new Pair<WindowState, IRemoteCallback>(win, callback);
8754                Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8755                mH.sendMessageDelayed(m, 2000);
8756                mWaitingForDrawn.add(pair);
8757                checkDrawnWindowsLocked();
8758            }
8759        }
8760    }
8761
8762    /**
8763     * Must be called with the main window manager lock held.
8764     */
8765    void setHoldScreenLocked(boolean holding) {
8766        boolean state = mHoldingScreenWakeLock.isHeld();
8767        if (holding != state) {
8768            if (holding) {
8769                mPolicy.screenOnStartedLw();
8770                mHoldingScreenWakeLock.acquire();
8771            } else {
8772                mPolicy.screenOnStoppedLw();
8773                mHoldingScreenWakeLock.release();
8774            }
8775        }
8776    }
8777
8778    void requestTraversalLocked() {
8779        if (!mTraversalScheduled) {
8780            mTraversalScheduled = true;
8781            mH.sendEmptyMessage(H.DO_TRAVERSAL);
8782        }
8783    }
8784
8785    void scheduleAnimationLocked() {
8786        if (!mAnimationScheduled) {
8787            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationRunnable, null);
8788            mAnimationScheduled = true;
8789        }
8790    }
8791
8792    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
8793                                           boolean secure) {
8794        final Surface surface = winAnimator.mSurface;
8795        boolean leakedSurface = false;
8796        boolean killedApps = false;
8797
8798        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
8799                winAnimator.mSession.mPid, operation);
8800
8801        if (mForceRemoves == null) {
8802            mForceRemoves = new ArrayList<WindowState>();
8803        }
8804
8805        long callingIdentity = Binder.clearCallingIdentity();
8806        try {
8807            // There was some problem...   first, do a sanity check of the
8808            // window list to make sure we haven't left any dangling surfaces
8809            // around.
8810            int N = mWindows.size();
8811            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
8812            for (int i=0; i<N; i++) {
8813                WindowState ws = mWindows.get(i);
8814                WindowStateAnimator wsa = ws.mWinAnimator;
8815                if (wsa.mSurface != null) {
8816                    if (!mSessions.contains(wsa.mSession)) {
8817                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8818                                + ws + " surface=" + wsa.mSurface
8819                                + " token=" + ws.mToken
8820                                + " pid=" + ws.mSession.mPid
8821                                + " uid=" + ws.mSession.mUid);
8822                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8823                        wsa.mSurface.destroy();
8824                        wsa.mSurfaceShown = false;
8825                        wsa.mSurface = null;
8826                        ws.mHasSurface = false;
8827                        mForceRemoves.add(ws);
8828                        i--;
8829                        N--;
8830                        leakedSurface = true;
8831                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
8832                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
8833                                + ws + " surface=" + wsa.mSurface
8834                                + " token=" + ws.mAppToken);
8835                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8836                        wsa.mSurface.destroy();
8837                        wsa.mSurfaceShown = false;
8838                        wsa.mSurface = null;
8839                        ws.mHasSurface = false;
8840                        leakedSurface = true;
8841                    }
8842                }
8843            }
8844
8845            if (!leakedSurface) {
8846                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
8847                SparseIntArray pidCandidates = new SparseIntArray();
8848                for (int i=0; i<N; i++) {
8849                    WindowStateAnimator wsa = mWindows.get(i).mWinAnimator;
8850                    if (wsa.mSurface != null) {
8851                        pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
8852                    }
8853                }
8854                if (pidCandidates.size() > 0) {
8855                    int[] pids = new int[pidCandidates.size()];
8856                    for (int i=0; i<pids.length; i++) {
8857                        pids[i] = pidCandidates.keyAt(i);
8858                    }
8859                    try {
8860                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
8861                            killedApps = true;
8862                        }
8863                    } catch (RemoteException e) {
8864                    }
8865                }
8866            }
8867
8868            if (leakedSurface || killedApps) {
8869                // We managed to reclaim some memory, so get rid of the trouble
8870                // surface and ask the app to request another one.
8871                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8872                if (surface != null) {
8873                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
8874                            "RECOVER DESTROY", null);
8875                    surface.destroy();
8876                    winAnimator.mSurfaceShown = false;
8877                    winAnimator.mSurface = null;
8878                    winAnimator.mWin.mHasSurface = false;
8879                }
8880
8881                try {
8882                    winAnimator.mWin.mClient.dispatchGetNewSurface();
8883                } catch (RemoteException e) {
8884                }
8885            }
8886        } finally {
8887            Binder.restoreCallingIdentity(callingIdentity);
8888        }
8889
8890        return leakedSurface || killedApps;
8891    }
8892
8893    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
8894        WindowState newFocus = computeFocusedWindowLocked();
8895        if (mCurrentFocus != newFocus) {
8896            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
8897            // This check makes sure that we don't already have the focus
8898            // change message pending.
8899            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
8900            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
8901            if (localLOGV) Slog.v(
8902                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
8903            final WindowState oldFocus = mCurrentFocus;
8904            mCurrentFocus = newFocus;
8905            mAnimator.setCurrentFocus(newFocus);
8906            mLosingFocus.remove(newFocus);
8907            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
8908
8909            final WindowState imWindow = mInputMethodWindow;
8910            if (newFocus != imWindow && oldFocus != imWindow) {
8911                if (moveInputMethodWindowsIfNeededLocked(
8912                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
8913                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
8914                    mLayoutNeeded = true;
8915                }
8916                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8917                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
8918                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
8919                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
8920                    // Client will do the layout, but we need to assign layers
8921                    // for handleNewWindowLocked() below.
8922                    assignLayersLocked();
8923                }
8924            }
8925
8926            if ((focusChanged&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8927                // The change in focus caused us to need to do a layout.  Okay.
8928                mLayoutNeeded = true;
8929                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8930                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
8931                }
8932            }
8933
8934            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
8935                // If we defer assigning layers, then the caller is responsible for
8936                // doing this part.
8937                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
8938            }
8939
8940            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
8941            return true;
8942        }
8943        return false;
8944    }
8945
8946    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
8947        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
8948    }
8949
8950    private WindowState computeFocusedWindowLocked() {
8951        WindowState result = null;
8952        WindowState win;
8953
8954        int nextAppIndex = mAppTokens.size()-1;
8955        WindowToken nextApp = nextAppIndex >= 0
8956            ? mAppTokens.get(nextAppIndex) : null;
8957
8958        for (int i = mWindows.size() - 1; i >= 0; i--) {
8959            win = mWindows.get(i);
8960
8961            if (localLOGV || DEBUG_FOCUS) Slog.v(
8962                TAG, "Looking for focus: " + i
8963                + " = " + win
8964                + ", flags=" + win.mAttrs.flags
8965                + ", canReceive=" + win.canReceiveKeys());
8966
8967            AppWindowToken thisApp = win.mAppToken;
8968
8969            // If this window's application has been removed, just skip it.
8970            if (thisApp != null && thisApp.removed) {
8971                continue;
8972            }
8973
8974            // If there is a focused app, don't allow focus to go to any
8975            // windows below it.  If this is an application window, step
8976            // through the app tokens until we find its app.
8977            if (thisApp != null && nextApp != null && thisApp != nextApp
8978                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
8979                int origAppIndex = nextAppIndex;
8980                while (nextAppIndex > 0) {
8981                    if (nextApp == mFocusedApp) {
8982                        // Whoops, we are below the focused app...  no focus
8983                        // for you!
8984                        if (localLOGV || DEBUG_FOCUS) Slog.v(
8985                            TAG, "Reached focused app: " + mFocusedApp);
8986                        return null;
8987                    }
8988                    nextAppIndex--;
8989                    nextApp = mAppTokens.get(nextAppIndex);
8990                    if (nextApp == thisApp) {
8991                        break;
8992                    }
8993                }
8994                if (thisApp != nextApp) {
8995                    // Uh oh, the app token doesn't exist!  This shouldn't
8996                    // happen, but if it does we can get totally hosed...
8997                    // so restart at the original app.
8998                    nextAppIndex = origAppIndex;
8999                    nextApp = mAppTokens.get(nextAppIndex);
9000                }
9001            }
9002
9003            // Dispatch to this window if it is wants key events.
9004            if (win.canReceiveKeys()) {
9005                if (DEBUG_FOCUS) Slog.v(
9006                        TAG, "Found focus @ " + i + " = " + win);
9007                result = win;
9008                break;
9009            }
9010        }
9011
9012        return result;
9013    }
9014
9015    private void startFreezingDisplayLocked(boolean inTransaction) {
9016        if (mDisplayFrozen) {
9017            return;
9018        }
9019
9020        if (mDisplay == null || !mPolicy.isScreenOnFully()) {
9021            // No need to freeze the screen before the system is ready or if
9022            // the screen is off.
9023            return;
9024        }
9025
9026        mScreenFrozenLock.acquire();
9027
9028        mDisplayFrozen = true;
9029
9030        mInputMonitor.freezeInputDispatchingLw();
9031
9032        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
9033            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
9034            mNextAppTransitionType = ActivityOptions.ANIM_NONE;
9035            mNextAppTransitionPackage = null;
9036            mNextAppTransitionThumbnail = null;
9037            mAppTransitionReady = true;
9038        }
9039
9040        if (PROFILE_ORIENTATION) {
9041            File file = new File("/data/system/frozen");
9042            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9043        }
9044
9045        if (CUSTOM_SCREEN_ROTATION) {
9046            if (mAnimator.mScreenRotationAnimation != null) {
9047                mAnimator.mScreenRotationAnimation.kill();
9048                mAnimator.mScreenRotationAnimation = null;
9049            }
9050
9051            mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
9052                    mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight,
9053                    mDisplay.getRotation());
9054
9055            if (!mAnimator.mScreenRotationAnimation.hasScreenshot()) {
9056                Surface.freezeDisplay(0);
9057            }
9058        } else {
9059            Surface.freezeDisplay(0);
9060        }
9061    }
9062
9063    private void stopFreezingDisplayLocked() {
9064        if (!mDisplayFrozen) {
9065            return;
9066        }
9067
9068        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
9069            if (DEBUG_ORIENTATION) Slog.d(TAG,
9070                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
9071                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
9072                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen);
9073            return;
9074        }
9075
9076        mDisplayFrozen = false;
9077        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9078        if (PROFILE_ORIENTATION) {
9079            Debug.stopMethodTracing();
9080        }
9081
9082        boolean updateRotation = false;
9083
9084        if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
9085                && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
9086            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
9087            if (mAnimator.mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9088                    mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
9089                scheduleAnimationLocked();
9090            } else {
9091                mAnimator.mScreenRotationAnimation.kill();
9092                mAnimator.mScreenRotationAnimation = null;
9093                updateRotation = true;
9094            }
9095        } else {
9096            if (mAnimator.mScreenRotationAnimation != null) {
9097                mAnimator.mScreenRotationAnimation.kill();
9098                mAnimator.mScreenRotationAnimation = null;
9099            }
9100            updateRotation = true;
9101        }
9102        Surface.unfreezeDisplay(0);
9103
9104        mInputMonitor.thawInputDispatchingLw();
9105
9106        boolean configChanged;
9107
9108        // While the display is frozen we don't re-compute the orientation
9109        // to avoid inconsistent states.  However, something interesting
9110        // could have actually changed during that time so re-evaluate it
9111        // now to catch that.
9112        configChanged = updateOrientationFromAppTokensLocked(false);
9113
9114        // A little kludge: a lot could have happened while the
9115        // display was frozen, so now that we are coming back we
9116        // do a gc so that any remote references the system
9117        // processes holds on others can be released if they are
9118        // no longer needed.
9119        mH.removeMessages(H.FORCE_GC);
9120        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
9121                2000);
9122
9123        mScreenFrozenLock.release();
9124
9125        if (updateRotation) {
9126            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9127            configChanged |= updateRotationUncheckedLocked(false);
9128        }
9129
9130        if (configChanged) {
9131            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9132        }
9133    }
9134
9135    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
9136            DisplayMetrics dm) {
9137        if (index < tokens.length) {
9138            String str = tokens[index];
9139            if (str != null && str.length() > 0) {
9140                try {
9141                    int val = Integer.parseInt(str);
9142                    return val;
9143                } catch (Exception e) {
9144                }
9145            }
9146        }
9147        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
9148            return defDps;
9149        }
9150        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
9151        return val;
9152    }
9153
9154    void createWatermark() {
9155        if (mWatermark != null) {
9156            return;
9157        }
9158
9159        File file = new File("/system/etc/setup.conf");
9160        FileInputStream in = null;
9161        try {
9162            in = new FileInputStream(file);
9163            DataInputStream ind = new DataInputStream(in);
9164            String line = ind.readLine();
9165            if (line != null) {
9166                String[] toks = line.split("%");
9167                if (toks != null && toks.length > 0) {
9168                    mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks);
9169                }
9170            }
9171        } catch (FileNotFoundException e) {
9172        } catch (IOException e) {
9173        } finally {
9174            if (in != null) {
9175                try {
9176                    in.close();
9177                } catch (IOException e) {
9178                }
9179            }
9180        }
9181    }
9182
9183    @Override
9184    public void statusBarVisibilityChanged(int visibility) {
9185        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
9186                != PackageManager.PERMISSION_GRANTED) {
9187            throw new SecurityException("Caller does not hold permission "
9188                    + android.Manifest.permission.STATUS_BAR);
9189        }
9190
9191        synchronized (mWindowMap) {
9192            mLastStatusBarVisibility = visibility;
9193            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
9194            updateStatusBarVisibilityLocked(visibility);
9195        }
9196    }
9197
9198    void updateStatusBarVisibilityLocked(int visibility) {
9199        mInputManager.setSystemUiVisibility(visibility);
9200        final int N = mWindows.size();
9201        for (int i = 0; i < N; i++) {
9202            WindowState ws = mWindows.get(i);
9203            try {
9204                int curValue = ws.mSystemUiVisibility;
9205                int diff = curValue ^ visibility;
9206                // We are only interested in differences of one of the
9207                // clearable flags...
9208                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
9209                // ...if it has actually been cleared.
9210                diff &= ~visibility;
9211                int newValue = (curValue&~diff) | (visibility&diff);
9212                if (newValue != curValue) {
9213                    ws.mSeq++;
9214                    ws.mSystemUiVisibility = newValue;
9215                }
9216                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
9217                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
9218                            visibility, newValue, diff);
9219                }
9220            } catch (RemoteException e) {
9221                // so sorry
9222            }
9223        }
9224    }
9225
9226    @Override
9227    public void reevaluateStatusBarVisibility() {
9228        synchronized (mWindowMap) {
9229            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
9230            updateStatusBarVisibilityLocked(visibility);
9231            performLayoutAndPlaceSurfacesLocked();
9232        }
9233    }
9234
9235    @Override
9236    public FakeWindow addFakeWindow(Looper looper,
9237            InputEventReceiver.Factory inputEventReceiverFactory,
9238            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
9239            boolean hasFocus, boolean touchFullscreen) {
9240        synchronized (mWindowMap) {
9241            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
9242                    name, windowType,
9243                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
9244            int i=0;
9245            while (i<mFakeWindows.size()) {
9246                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
9247                    break;
9248                }
9249            }
9250            mFakeWindows.add(i, fw);
9251            mInputMonitor.updateInputWindowsLw(true);
9252            return fw;
9253        }
9254    }
9255
9256    boolean removeFakeWindowLocked(FakeWindow window) {
9257        synchronized (mWindowMap) {
9258            if (mFakeWindows.remove(window)) {
9259                mInputMonitor.updateInputWindowsLw(true);
9260                return true;
9261            }
9262            return false;
9263        }
9264    }
9265
9266    @Override
9267    public boolean hasNavigationBar() {
9268        return mPolicy.hasNavigationBar();
9269    }
9270
9271    public void lockNow() {
9272        mPolicy.lockNow();
9273    }
9274
9275    void dumpPolicyLocked(FileDescriptor fd, PrintWriter pw, String[] args, boolean dumpAll) {
9276        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
9277        mPolicy.dump("    ", fd, pw, args);
9278    }
9279
9280    void dumpTokensLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9281        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
9282        if (mTokenMap.size() > 0) {
9283            pw.println("  All tokens:");
9284            Iterator<WindowToken> it = mTokenMap.values().iterator();
9285            while (it.hasNext()) {
9286                WindowToken token = it.next();
9287                pw.print("  Token "); pw.print(token.token);
9288                if (dumpAll) {
9289                    pw.println(':');
9290                    token.dump(pw, "    ");
9291                } else {
9292                    pw.println();
9293                }
9294            }
9295        }
9296        if (mWallpaperTokens.size() > 0) {
9297            pw.println();
9298            pw.println("  Wallpaper tokens:");
9299            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
9300                WindowToken token = mWallpaperTokens.get(i);
9301                pw.print("  Wallpaper #"); pw.print(i);
9302                        pw.print(' '); pw.print(token);
9303                if (dumpAll) {
9304                    pw.println(':');
9305                    token.dump(pw, "    ");
9306                } else {
9307                    pw.println();
9308                }
9309            }
9310        }
9311        if (mAppTokens.size() > 0) {
9312            pw.println();
9313            pw.println("  Application tokens in Z order:");
9314            for (int i=mAppTokens.size()-1; i>=0; i--) {
9315                pw.print("  App #"); pw.print(i); pw.println(": ");
9316                        mAppTokens.get(i).dump(pw, "    ");
9317            }
9318        }
9319        if (mFinishedStarting.size() > 0) {
9320            pw.println();
9321            pw.println("  Finishing start of application tokens:");
9322            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9323                WindowToken token = mFinishedStarting.get(i);
9324                pw.print("  Finished Starting #"); pw.print(i);
9325                        pw.print(' '); pw.print(token);
9326                if (dumpAll) {
9327                    pw.println(':');
9328                    token.dump(pw, "    ");
9329                } else {
9330                    pw.println();
9331                }
9332            }
9333        }
9334        if (mExitingTokens.size() > 0) {
9335            pw.println();
9336            pw.println("  Exiting tokens:");
9337            for (int i=mExitingTokens.size()-1; i>=0; i--) {
9338                WindowToken token = mExitingTokens.get(i);
9339                pw.print("  Exiting #"); pw.print(i);
9340                        pw.print(' '); pw.print(token);
9341                if (dumpAll) {
9342                    pw.println(':');
9343                    token.dump(pw, "    ");
9344                } else {
9345                    pw.println();
9346                }
9347            }
9348        }
9349        if (mExitingAppTokens.size() > 0) {
9350            pw.println();
9351            pw.println("  Exiting application tokens:");
9352            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9353                WindowToken token = mExitingAppTokens.get(i);
9354                pw.print("  Exiting App #"); pw.print(i);
9355                        pw.print(' '); pw.print(token);
9356                if (dumpAll) {
9357                    pw.println(':');
9358                    token.dump(pw, "    ");
9359                } else {
9360                    pw.println();
9361                }
9362            }
9363        }
9364        pw.println();
9365        if (mOpeningApps.size() > 0) {
9366            pw.print("  mOpeningApps="); pw.println(mOpeningApps);
9367        }
9368        if (mClosingApps.size() > 0) {
9369            pw.print("  mClosingApps="); pw.println(mClosingApps);
9370        }
9371        if (mToTopApps.size() > 0) {
9372            pw.print("  mToTopApps="); pw.println(mToTopApps);
9373        }
9374        if (mToBottomApps.size() > 0) {
9375            pw.print("  mToBottomApps="); pw.println(mToBottomApps);
9376        }
9377    }
9378
9379    void dumpSessionsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9380        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
9381        if (mSessions.size() > 0) {
9382            Iterator<Session> it = mSessions.iterator();
9383            while (it.hasNext()) {
9384                Session s = it.next();
9385                pw.print("  Session "); pw.print(s); pw.println(':');
9386                s.dump(pw, "    ");
9387            }
9388        }
9389    }
9390
9391    void dumpWindowsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
9392            ArrayList<WindowState> windows) {
9393        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
9394        for (int i=mWindows.size()-1; i>=0; i--) {
9395            WindowState w = mWindows.get(i);
9396            if (windows == null || windows.contains(w)) {
9397                pw.print("  Window #"); pw.print(i); pw.print(' ');
9398                        pw.print(w); pw.println(":");
9399                w.dump(pw, "    ", dumpAll || windows != null);
9400            }
9401        }
9402        if (mInputMethodDialogs.size() > 0) {
9403            pw.println();
9404            pw.println("  Input method dialogs:");
9405            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
9406                WindowState w = mInputMethodDialogs.get(i);
9407                if (windows == null || windows.contains(w)) {
9408                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
9409                }
9410            }
9411        }
9412        if (mPendingRemove.size() > 0) {
9413            pw.println();
9414            pw.println("  Remove pending for:");
9415            for (int i=mPendingRemove.size()-1; i>=0; i--) {
9416                WindowState w = mPendingRemove.get(i);
9417                if (windows == null || windows.contains(w)) {
9418                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
9419                            pw.print(w);
9420                    if (dumpAll) {
9421                        pw.println(":");
9422                        w.dump(pw, "    ", true);
9423                    } else {
9424                        pw.println();
9425                    }
9426                }
9427            }
9428        }
9429        if (mForceRemoves != null && mForceRemoves.size() > 0) {
9430            pw.println();
9431            pw.println("  Windows force removing:");
9432            for (int i=mForceRemoves.size()-1; i>=0; i--) {
9433                WindowState w = mForceRemoves.get(i);
9434                pw.print("  Removing #"); pw.print(i); pw.print(' ');
9435                        pw.print(w);
9436                if (dumpAll) {
9437                    pw.println(":");
9438                    w.dump(pw, "    ", true);
9439                } else {
9440                    pw.println();
9441                }
9442            }
9443        }
9444        if (mDestroySurface.size() > 0) {
9445            pw.println();
9446            pw.println("  Windows waiting to destroy their surface:");
9447            for (int i=mDestroySurface.size()-1; i>=0; i--) {
9448                WindowState w = mDestroySurface.get(i);
9449                if (windows == null || windows.contains(w)) {
9450                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
9451                            pw.print(w);
9452                    if (dumpAll) {
9453                        pw.println(":");
9454                        w.dump(pw, "    ", true);
9455                    } else {
9456                        pw.println();
9457                    }
9458                }
9459            }
9460        }
9461        if (mLosingFocus.size() > 0) {
9462            pw.println();
9463            pw.println("  Windows losing focus:");
9464            for (int i=mLosingFocus.size()-1; i>=0; i--) {
9465                WindowState w = mLosingFocus.get(i);
9466                if (windows == null || windows.contains(w)) {
9467                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
9468                            pw.print(w);
9469                    if (dumpAll) {
9470                        pw.println(":");
9471                        w.dump(pw, "    ", true);
9472                    } else {
9473                        pw.println();
9474                    }
9475                }
9476            }
9477        }
9478        if (mResizingWindows.size() > 0) {
9479            pw.println();
9480            pw.println("  Windows waiting to resize:");
9481            for (int i=mResizingWindows.size()-1; i>=0; i--) {
9482                WindowState w = mResizingWindows.get(i);
9483                if (windows == null || windows.contains(w)) {
9484                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
9485                            pw.print(w);
9486                    if (dumpAll) {
9487                        pw.println(":");
9488                        w.dump(pw, "    ", true);
9489                    } else {
9490                        pw.println();
9491                    }
9492                }
9493            }
9494        }
9495        if (mWaitingForDrawn.size() > 0) {
9496            pw.println();
9497            pw.println("  Clients waiting for these windows to be drawn:");
9498            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
9499                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
9500                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
9501                        pw.print(": "); pw.println(pair.second);
9502            }
9503        }
9504        pw.println();
9505        if (mDisplay != null) {
9506            pw.print("  Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
9507                    pw.print(mInitialDisplayHeight);
9508                    if (mInitialDisplayWidth != mBaseDisplayWidth
9509                            || mInitialDisplayHeight != mBaseDisplayHeight) {
9510                        pw.print(" base=");
9511                        pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
9512                    }
9513                    final int rawWidth = mDisplay.getRawWidth();
9514                    final int rawHeight = mDisplay.getRawHeight();
9515                    if (rawWidth != mCurDisplayWidth || rawHeight != mCurDisplayHeight) {
9516                        pw.print(" raw="); pw.print(rawWidth); pw.print("x"); pw.print(rawHeight);
9517                    }
9518                    pw.print(" cur=");
9519                    pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
9520                    pw.print(" app=");
9521                    pw.print(mAppDisplayWidth); pw.print("x"); pw.print(mAppDisplayHeight);
9522                    pw.print(" rng="); pw.print(mSmallestDisplayWidth);
9523                    pw.print("x"); pw.print(mSmallestDisplayHeight);
9524                    pw.print("-"); pw.print(mLargestDisplayWidth);
9525                    pw.print("x"); pw.println(mLargestDisplayHeight);
9526        } else {
9527            pw.println("  NO DISPLAY");
9528        }
9529        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
9530        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
9531        if (mLastFocus != mCurrentFocus) {
9532            pw.print("  mLastFocus="); pw.println(mLastFocus);
9533        }
9534        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
9535        if (mInputMethodTarget != null) {
9536            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
9537        }
9538        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
9539                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
9540        if (dumpAll) {
9541            if (mLastStatusBarVisibility != 0) {
9542                pw.print("  mLastStatusBarVisibility=0x");
9543                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
9544            }
9545            if (mInputMethodWindow != null) {
9546                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
9547            }
9548            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
9549            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
9550                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
9551                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
9552            }
9553            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
9554                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
9555            if (mInputMethodAnimLayerAdjustment != 0 ||
9556                    mWallpaperAnimLayerAdjustment != 0) {
9557                pw.print("  mInputMethodAnimLayerAdjustment=");
9558                        pw.print(mInputMethodAnimLayerAdjustment);
9559                        pw.print("  mWallpaperAnimLayerAdjustment=");
9560                        pw.println(mWallpaperAnimLayerAdjustment);
9561            }
9562            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
9563                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9564            pw.print("  mLayoutNeeded="); pw.println(mLayoutNeeded);
9565            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
9566                    pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9567                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
9568                    pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
9569            pw.print("  mRotation="); pw.print(mRotation);
9570                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
9571            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
9572                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
9573            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
9574            if (mAnimator.mScreenRotationAnimation != null) {
9575                pw.println("  mScreenRotationAnimation:");
9576                mAnimator.mScreenRotationAnimation.printTo("    ", pw);
9577            }
9578            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9579                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
9580                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
9581            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
9582                    pw.print("  mNextAppTransition=0x");
9583                    pw.print(Integer.toHexString(mNextAppTransition));
9584                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
9585            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
9586                    pw.print(" mAppTransitionTimeout="); pw.println(mAppTransitionTimeout);
9587            if (mNextAppTransitionType != ActivityOptions.ANIM_NONE) {
9588                pw.print("  mNextAppTransitionType="); pw.println(mNextAppTransitionType);
9589            }
9590            switch (mNextAppTransitionType) {
9591                case ActivityOptions.ANIM_CUSTOM:
9592                    pw.print("  mNextAppTransitionPackage=");
9593                            pw.print(mNextAppTransitionPackage);
9594                            pw.print(" mNextAppTransitionEnter=0x");
9595                            pw.print(Integer.toHexString(mNextAppTransitionEnter));
9596                            pw.print(" mNextAppTransitionExit=0x");
9597                            pw.print(Integer.toHexString(mNextAppTransitionExit));
9598                    break;
9599                case ActivityOptions.ANIM_SCALE_UP:
9600                    pw.print("  mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
9601                            pw.print(" mNextAppTransitionStartY=");
9602                            pw.println(mNextAppTransitionStartY);
9603                    pw.print("  mNextAppTransitionStartWidth=");
9604                            pw.print(mNextAppTransitionStartWidth);
9605                            pw.print(" mNextAppTransitionStartHeight=");
9606                            pw.println(mNextAppTransitionStartHeight);
9607                    break;
9608                case ActivityOptions.ANIM_THUMBNAIL:
9609                    pw.print("  mNextAppTransitionThumbnail=");
9610                            pw.print(mNextAppTransitionThumbnail);
9611                            pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
9612                            pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY);
9613                    break;
9614            }
9615            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9616                    pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9617        }
9618    }
9619
9620    boolean dumpWindows(FileDescriptor fd, PrintWriter pw, String name, String[] args,
9621            int opti, boolean dumpAll) {
9622        ArrayList<WindowState> windows = new ArrayList<WindowState>();
9623        if ("visible".equals(name)) {
9624            synchronized(mWindowMap) {
9625                for (int i=mWindows.size()-1; i>=0; i--) {
9626                    WindowState w = mWindows.get(i);
9627                    if (w.mWinAnimator.mSurfaceShown) {
9628                        windows.add(w);
9629                    }
9630                }
9631            }
9632        } else {
9633            int objectId = 0;
9634            // See if this is an object ID.
9635            try {
9636                objectId = Integer.parseInt(name, 16);
9637                name = null;
9638            } catch (RuntimeException e) {
9639            }
9640            synchronized(mWindowMap) {
9641                for (int i=mWindows.size()-1; i>=0; i--) {
9642                    WindowState w = mWindows.get(i);
9643                    if (name != null) {
9644                        if (w.mAttrs.getTitle().toString().contains(name)) {
9645                            windows.add(w);
9646                        }
9647                    } else if (System.identityHashCode(w) == objectId) {
9648                        windows.add(w);
9649                    }
9650                }
9651            }
9652        }
9653
9654        if (windows.size() <= 0) {
9655            return false;
9656        }
9657
9658        synchronized(mWindowMap) {
9659            dumpWindowsLocked(fd, pw, dumpAll, windows);
9660        }
9661        return true;
9662    }
9663
9664    @Override
9665    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9666        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
9667                != PackageManager.PERMISSION_GRANTED) {
9668            pw.println("Permission Denial: can't dump WindowManager from from pid="
9669                    + Binder.getCallingPid()
9670                    + ", uid=" + Binder.getCallingUid());
9671            return;
9672        }
9673
9674        boolean dumpAll = false;
9675
9676        int opti = 0;
9677        while (opti < args.length) {
9678            String opt = args[opti];
9679            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9680                break;
9681            }
9682            opti++;
9683            if ("-a".equals(opt)) {
9684                dumpAll = true;
9685            } else if ("-h".equals(opt)) {
9686                pw.println("Window manager dump options:");
9687                pw.println("  [-a] [-h] [cmd] ...");
9688                pw.println("  cmd may be one of:");
9689                pw.println("    p[policy]: policy state");
9690                pw.println("    s[essions]: active sessions");
9691                pw.println("    t[okens]: token list");
9692                pw.println("    w[indows]: window list");
9693                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
9694                pw.println("    be a partial substring in a window name, a");
9695                pw.println("    Window hex object identifier, or");
9696                pw.println("    \"all\" for all windows, or");
9697                pw.println("    \"visible\" for the visible windows.");
9698                pw.println("  -a: include all available server state.");
9699                return;
9700            } else {
9701                pw.println("Unknown argument: " + opt + "; use -h for help");
9702            }
9703        }
9704
9705        // Is the caller requesting to dump a particular piece of data?
9706        if (opti < args.length) {
9707            String cmd = args[opti];
9708            opti++;
9709            if ("policy".equals(cmd) || "p".equals(cmd)) {
9710                synchronized(mWindowMap) {
9711                    dumpPolicyLocked(fd, pw, args, true);
9712                }
9713                return;
9714            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
9715                synchronized(mWindowMap) {
9716                    dumpSessionsLocked(fd, pw, true);
9717                }
9718                return;
9719            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
9720                synchronized(mWindowMap) {
9721                    dumpTokensLocked(fd, pw, true);
9722                }
9723                return;
9724            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
9725                synchronized(mWindowMap) {
9726                    dumpWindowsLocked(fd, pw, true, null);
9727                }
9728                return;
9729            } else if ("all".equals(cmd) || "a".equals(cmd)) {
9730                synchronized(mWindowMap) {
9731                    dumpWindowsLocked(fd, pw, true, null);
9732                }
9733                return;
9734            } else {
9735                // Dumping a single name?
9736                if (!dumpWindows(fd, pw, cmd, args, opti, dumpAll)) {
9737                    pw.println("Bad window command, or no windows match: " + cmd);
9738                    pw.println("Use -h for help.");
9739                }
9740                return;
9741            }
9742        }
9743
9744        synchronized(mWindowMap) {
9745            if (dumpAll) {
9746                pw.println("-------------------------------------------------------------------------------");
9747            }
9748            dumpPolicyLocked(fd, pw, args, dumpAll);
9749            pw.println();
9750            if (dumpAll) {
9751                pw.println("-------------------------------------------------------------------------------");
9752            }
9753            dumpSessionsLocked(fd, pw, dumpAll);
9754            pw.println();
9755            if (dumpAll) {
9756                pw.println("-------------------------------------------------------------------------------");
9757            }
9758            dumpTokensLocked(fd, pw, dumpAll);
9759            pw.println();
9760            if (dumpAll) {
9761                pw.println("-------------------------------------------------------------------------------");
9762            }
9763            dumpWindowsLocked(fd, pw, dumpAll, null);
9764        }
9765    }
9766
9767    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
9768    public void monitor() {
9769        synchronized (mWindowMap) { }
9770        synchronized (mKeyguardTokenWatcher) { }
9771    }
9772
9773    public interface OnHardKeyboardStatusChangeListener {
9774        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
9775    }
9776
9777    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
9778        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
9779            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
9780                    Integer.toHexString(pendingLayoutChanges));
9781        }
9782    }
9783
9784    void bulkSetParameters(final int bulkUpdateParams, int pendingLayoutChanges) {
9785        mH.sendMessage(mH.obtainMessage(H.BULK_UPDATE_PARAMETERS, bulkUpdateParams,
9786                pendingLayoutChanges));
9787    }
9788}
9789