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