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