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