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