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