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