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