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