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