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