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