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