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