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