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