WindowManagerService.java revision 09a68ac943e0d21ad61a94ed4eac1d6099657602
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        scale = fixScale(scale);
4883        switch (which) {
4884            case 0: mWindowAnimationScale = scale; break;
4885            case 1: mTransitionAnimationScale = scale; break;
4886            case 2: mAnimatorDurationScale = scale; break;
4887        }
4888
4889        // Persist setting
4890        mH.sendEmptyMessage(H.PERSIST_ANIMATION_SCALE);
4891    }
4892
4893    @Override
4894    public void setAnimationScales(float[] scales) {
4895        if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
4896                "setAnimationScale()")) {
4897            throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
4898        }
4899
4900        if (scales != null) {
4901            if (scales.length >= 1) {
4902                mWindowAnimationScale = fixScale(scales[0]);
4903            }
4904            if (scales.length >= 2) {
4905                mTransitionAnimationScale = fixScale(scales[1]);
4906            }
4907            if (scales.length >= 3) {
4908                setAnimatorDurationScale(fixScale(scales[2]));
4909            }
4910        }
4911
4912        // Persist setting
4913        mH.sendEmptyMessage(H.PERSIST_ANIMATION_SCALE);
4914    }
4915
4916    private void setAnimatorDurationScale(float scale) {
4917        mAnimatorDurationScale = scale;
4918        ValueAnimator.setDurationScale(scale);
4919    }
4920
4921    @Override
4922    public float getAnimationScale(int which) {
4923        switch (which) {
4924            case 0: return mWindowAnimationScale;
4925            case 1: return mTransitionAnimationScale;
4926            case 2: return mAnimatorDurationScale;
4927        }
4928        return 0;
4929    }
4930
4931    @Override
4932    public float[] getAnimationScales() {
4933        return new float[] { mWindowAnimationScale, mTransitionAnimationScale,
4934                mAnimatorDurationScale };
4935    }
4936
4937    // Called by window manager policy. Not exposed externally.
4938    @Override
4939    public int getLidState() {
4940        int sw = mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY,
4941                InputManagerService.SW_LID);
4942        if (sw > 0) {
4943            // Switch state: AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL.
4944            return LID_CLOSED;
4945        } else if (sw == 0) {
4946            // Switch state: AKEY_STATE_UP.
4947            return LID_OPEN;
4948        } else {
4949            // Switch state: AKEY_STATE_UNKNOWN.
4950            return LID_ABSENT;
4951        }
4952    }
4953
4954    // Called by window manager policy.  Not exposed externally.
4955    @Override
4956    public InputChannel monitorInput(String inputChannelName) {
4957        return mInputManager.monitorInput(inputChannelName);
4958    }
4959
4960    // Called by window manager policy.  Not exposed externally.
4961    @Override
4962    public void switchKeyboardLayout(int deviceId, int direction) {
4963        mInputManager.switchKeyboardLayout(deviceId, direction);
4964    }
4965
4966    // Called by window manager policy.  Not exposed externally.
4967    @Override
4968    public void shutdown(boolean confirm) {
4969        ShutdownThread.shutdown(mContext, confirm);
4970    }
4971
4972    // Called by window manager policy.  Not exposed externally.
4973    @Override
4974    public void rebootSafeMode(boolean confirm) {
4975        ShutdownThread.rebootSafeMode(mContext, confirm);
4976    }
4977
4978    @Override
4979    public void setInputFilter(IInputFilter filter) {
4980        if (!checkCallingPermission(android.Manifest.permission.FILTER_EVENTS, "setInputFilter()")) {
4981            throw new SecurityException("Requires FILTER_EVENTS permission");
4982        }
4983        mInputManager.setInputFilter(filter);
4984    }
4985
4986    public void setCurrentUser(final int newUserId) {
4987        synchronized (mWindowMap) {
4988            mCurrentUserId = newUserId;
4989            mAppTransition.setCurrentUser(newUserId);
4990            mPolicy.setCurrentUserLw(newUserId);
4991
4992            // Hide windows that should not be seen by the new user.
4993            final int numDisplays = mDisplayContents.size();
4994            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
4995                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
4996                final WindowList windows = displayContent.getWindowList();
4997                for (int i = 0; i < windows.size(); i++) {
4998                    final WindowState win = windows.get(i);
4999                    if (win.isHiddenFromUserLocked()) {
5000                        Slog.w(TAG, "current user violation " + newUserId + " hiding "
5001                                + win + ", attrs=" + win.mAttrs.type + ", belonging to "
5002                                + win.mOwnerUid);
5003                        win.hideLw(false);
5004                    }
5005                }
5006            }
5007            performLayoutAndPlaceSurfacesLocked();
5008        }
5009    }
5010
5011    public void enableScreenAfterBoot() {
5012        synchronized(mWindowMap) {
5013            if (DEBUG_BOOT) {
5014                RuntimeException here = new RuntimeException("here");
5015                here.fillInStackTrace();
5016                Slog.i(TAG, "enableScreenAfterBoot: mDisplayEnabled=" + mDisplayEnabled
5017                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5018                        + " mShowingBootMessages=" + mShowingBootMessages
5019                        + " mSystemBooted=" + mSystemBooted, here);
5020            }
5021            if (mSystemBooted) {
5022                return;
5023            }
5024            mSystemBooted = true;
5025            hideBootMessagesLocked();
5026            // If the screen still doesn't come up after 30 seconds, give
5027            // up and turn it on.
5028            mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30*1000);
5029        }
5030
5031        mPolicy.systemBooted();
5032
5033        performEnableScreen();
5034    }
5035
5036    void enableScreenIfNeededLocked() {
5037        if (DEBUG_BOOT) {
5038            RuntimeException here = new RuntimeException("here");
5039            here.fillInStackTrace();
5040            Slog.i(TAG, "enableScreenIfNeededLocked: mDisplayEnabled=" + mDisplayEnabled
5041                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5042                    + " mShowingBootMessages=" + mShowingBootMessages
5043                    + " mSystemBooted=" + mSystemBooted, here);
5044        }
5045        if (mDisplayEnabled) {
5046            return;
5047        }
5048        if (!mSystemBooted && !mShowingBootMessages) {
5049            return;
5050        }
5051        mH.sendEmptyMessage(H.ENABLE_SCREEN);
5052    }
5053
5054    public void performBootTimeout() {
5055        synchronized(mWindowMap) {
5056            if (mDisplayEnabled || mHeadless) {
5057                return;
5058            }
5059            Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled");
5060            mForceDisplayEnabled = true;
5061        }
5062        performEnableScreen();
5063    }
5064
5065    public void performEnableScreen() {
5066        synchronized(mWindowMap) {
5067            if (DEBUG_BOOT) {
5068                RuntimeException here = new RuntimeException("here");
5069                here.fillInStackTrace();
5070                Slog.i(TAG, "performEnableScreen: mDisplayEnabled=" + mDisplayEnabled
5071                        + " mForceDisplayEnabled=" + mForceDisplayEnabled
5072                        + " mShowingBootMessages=" + mShowingBootMessages
5073                        + " mSystemBooted=" + mSystemBooted
5074                        + " mOnlyCore=" + mOnlyCore, here);
5075            }
5076            if (mDisplayEnabled) {
5077                return;
5078            }
5079            if (!mSystemBooted && !mShowingBootMessages) {
5080                return;
5081            }
5082
5083            if (!mForceDisplayEnabled) {
5084                // Don't enable the screen until all existing windows
5085                // have been drawn.
5086                boolean haveBootMsg = false;
5087                boolean haveApp = false;
5088                // if the wallpaper service is disabled on the device, we're never going to have
5089                // wallpaper, don't bother waiting for it
5090                boolean haveWallpaper = false;
5091                boolean wallpaperEnabled = mContext.getResources().getBoolean(
5092                        com.android.internal.R.bool.config_enableWallpaperService)
5093                        && !mOnlyCore;
5094                boolean haveKeyguard = true;
5095                // TODO(multidisplay): Expand to all displays?
5096                final WindowList windows = getDefaultWindowListLocked();
5097                final int N = windows.size();
5098                for (int i=0; i<N; i++) {
5099                    WindowState w = windows.get(i);
5100                    if (w.mAttrs.type == TYPE_KEYGUARD) {
5101                        // Only if there is a keyguard attached to the window manager
5102                        // will we consider ourselves as having a keyguard.  If it
5103                        // isn't attached, we don't know if it wants to be shown or
5104                        // hidden.  If it is attached, we will say we have a keyguard
5105                        // if the window doesn't want to be visible, because in that
5106                        // case it explicitly doesn't want to be shown so we should
5107                        // not delay turning the screen on for it.
5108                        boolean vis = w.mViewVisibility == View.VISIBLE
5109                                && w.mPolicyVisibility;
5110                        haveKeyguard = !vis;
5111                    }
5112                    if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
5113                        return;
5114                    }
5115                    if (w.isDrawnLw()) {
5116                        if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
5117                            haveBootMsg = true;
5118                        } else if (w.mAttrs.type == TYPE_APPLICATION) {
5119                            haveApp = true;
5120                        } else if (w.mAttrs.type == TYPE_WALLPAPER) {
5121                            haveWallpaper = true;
5122                        } else if (w.mAttrs.type == TYPE_KEYGUARD) {
5123                            haveKeyguard = true;
5124                        }
5125                    }
5126                }
5127
5128                if (DEBUG_SCREEN_ON || DEBUG_BOOT) {
5129                    Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages
5130                            + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp
5131                            + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled
5132                            + " haveKeyguard=" + haveKeyguard);
5133                }
5134
5135                // If we are turning on the screen to show the boot message,
5136                // don't do it until the boot message is actually displayed.
5137                if (!mSystemBooted && !haveBootMsg) {
5138                    return;
5139                }
5140
5141                // If we are turning on the screen after the boot is completed
5142                // normally, don't do so until we have the application and
5143                // wallpaper.
5144                if (mSystemBooted && ((!haveApp && !haveKeyguard) ||
5145                        (wallpaperEnabled && !haveWallpaper))) {
5146                    return;
5147                }
5148            }
5149
5150            mDisplayEnabled = true;
5151            if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG, "******************** ENABLING SCREEN!");
5152            if (false) {
5153                StringWriter sw = new StringWriter();
5154                PrintWriter pw = new PrintWriter(sw);
5155                this.dump(null, pw, null);
5156                Slog.i(TAG, sw.toString());
5157            }
5158            try {
5159                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
5160                if (surfaceFlinger != null) {
5161                    //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
5162                    Parcel data = Parcel.obtain();
5163                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
5164                    surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
5165                                            data, null, 0);
5166                    data.recycle();
5167                }
5168            } catch (RemoteException ex) {
5169                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
5170            }
5171
5172            // Enable input dispatch.
5173            mInputMonitor.setEventDispatchingLw(mEventDispatchingEnabled);
5174        }
5175
5176        mPolicy.enableScreenAfterBoot();
5177
5178        // Make sure the last requested orientation has been applied.
5179        updateRotationUnchecked(false, false);
5180    }
5181
5182    public void showBootMessage(final CharSequence msg, final boolean always) {
5183        boolean first = false;
5184        synchronized(mWindowMap) {
5185            if (DEBUG_BOOT) {
5186                RuntimeException here = new RuntimeException("here");
5187                here.fillInStackTrace();
5188                Slog.i(TAG, "showBootMessage: msg=" + msg + " always=" + always
5189                        + " mAllowBootMessages=" + mAllowBootMessages
5190                        + " mShowingBootMessages=" + mShowingBootMessages
5191                        + " mSystemBooted=" + mSystemBooted, here);
5192            }
5193            if (!mAllowBootMessages) {
5194                return;
5195            }
5196            if (!mShowingBootMessages) {
5197                if (!always) {
5198                    return;
5199                }
5200                first = true;
5201            }
5202            if (mSystemBooted) {
5203                return;
5204            }
5205            mShowingBootMessages = true;
5206            mPolicy.showBootMessage(msg, always);
5207        }
5208        if (first) {
5209            performEnableScreen();
5210        }
5211    }
5212
5213    public void hideBootMessagesLocked() {
5214        if (DEBUG_BOOT) {
5215            RuntimeException here = new RuntimeException("here");
5216            here.fillInStackTrace();
5217            Slog.i(TAG, "hideBootMessagesLocked: mDisplayEnabled=" + mDisplayEnabled
5218                    + " mForceDisplayEnabled=" + mForceDisplayEnabled
5219                    + " mShowingBootMessages=" + mShowingBootMessages
5220                    + " mSystemBooted=" + mSystemBooted, here);
5221        }
5222        if (mShowingBootMessages) {
5223            mShowingBootMessages = false;
5224            mPolicy.hideBootMessages();
5225        }
5226    }
5227
5228    @Override
5229    public void setInTouchMode(boolean mode) {
5230        synchronized(mWindowMap) {
5231            mInTouchMode = mode;
5232        }
5233    }
5234
5235    // TODO: more accounting of which pid(s) turned it on, keep count,
5236    // only allow disables from pids which have count on, etc.
5237    @Override
5238    public void showStrictModeViolation(boolean on) {
5239        if (mHeadless) return;
5240        int pid = Binder.getCallingPid();
5241        mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, pid));
5242    }
5243
5244    private void showStrictModeViolation(int arg, int pid) {
5245        final boolean on = arg != 0;
5246        synchronized(mWindowMap) {
5247            // Ignoring requests to enable the red border from clients
5248            // which aren't on screen.  (e.g. Broadcast Receivers in
5249            // the background..)
5250            if (on) {
5251                boolean isVisible = false;
5252                final int numDisplays = mDisplayContents.size();
5253                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
5254                    final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
5255                    final int numWindows = windows.size();
5256                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
5257                        final WindowState ws = windows.get(winNdx);
5258                        if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
5259                            isVisible = true;
5260                            break;
5261                        }
5262                    }
5263                }
5264                if (!isVisible) {
5265                    return;
5266                }
5267            }
5268
5269            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5270                    ">>> OPEN TRANSACTION showStrictModeViolation");
5271            SurfaceControl.openTransaction();
5272            try {
5273                // TODO(multi-display): support multiple displays
5274                if (mStrictModeFlash == null) {
5275                    mStrictModeFlash = new StrictModeFlash(
5276                            getDefaultDisplayContentLocked().getDisplay(), mFxSession);
5277                }
5278                mStrictModeFlash.setVisibility(on);
5279            } finally {
5280                SurfaceControl.closeTransaction();
5281                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5282                        "<<< CLOSE TRANSACTION showStrictModeViolation");
5283            }
5284        }
5285    }
5286
5287    @Override
5288    public void setStrictModeVisualIndicatorPreference(String value) {
5289        SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
5290    }
5291
5292    /**
5293     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
5294     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
5295     * of the target image.
5296     *
5297     * @param displayId the Display to take a screenshot of.
5298     * @param width the width of the target bitmap
5299     * @param height the height of the target bitmap
5300     */
5301    @Override
5302    public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height) {
5303        if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
5304                "screenshotApplications()")) {
5305            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
5306        }
5307
5308        Bitmap rawss = null;
5309
5310        int maxLayer = 0;
5311        final Rect frame = new Rect();
5312
5313        float scale = 0;
5314        int dw, dh;
5315        int rot = Surface.ROTATION_0;
5316
5317        boolean screenshotReady;
5318        int minLayer;
5319        if (appToken == null) {
5320            screenshotReady = true;
5321            minLayer = 0;
5322        } else {
5323            screenshotReady = false;
5324            minLayer = Integer.MAX_VALUE;
5325        }
5326
5327        int retryCount = 0;
5328        WindowState appWin = null;
5329
5330        do {
5331            if (retryCount++ > 0) {
5332                try {
5333                    Thread.sleep(100);
5334                } catch (InterruptedException e) {
5335                }
5336            }
5337            synchronized(mWindowMap) {
5338                final DisplayContent displayContent = getDisplayContentLocked(displayId);
5339                if (displayContent == null) {
5340                    return null;
5341                }
5342                final DisplayInfo displayInfo = displayContent.getDisplayInfo();
5343                dw = displayInfo.logicalWidth;
5344                dh = displayInfo.logicalHeight;
5345
5346                int aboveAppLayer = mPolicy.windowTypeToLayerLw(TYPE_APPLICATION)
5347                        * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
5348                aboveAppLayer += TYPE_LAYER_MULTIPLIER;
5349
5350                boolean isImeTarget = mInputMethodTarget != null
5351                        && mInputMethodTarget.mAppToken != null
5352                        && mInputMethodTarget.mAppToken.appToken != null
5353                        && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
5354
5355                // Figure out the part of the screen that is actually the app.
5356                boolean including = false;
5357                appWin = null;
5358                final WindowList windows = displayContent.getWindowList();
5359                for (int i = windows.size() - 1; i >= 0; i--) {
5360                    WindowState ws = windows.get(i);
5361                    if (!ws.mHasSurface) {
5362                        continue;
5363                    }
5364                    if (ws.mLayer >= aboveAppLayer) {
5365                        continue;
5366                    }
5367                    // When we will skip windows: when we are not including
5368                    // ones behind a window we didn't skip, and we are actually
5369                    // taking a screenshot of a specific app.
5370                    if (!including && appToken != null) {
5371                        // Also, we can possibly skip this window if it is not
5372                        // an IME target or the application for the screenshot
5373                        // is not the current IME target.
5374                        if (!ws.mIsImWindow || !isImeTarget) {
5375                            // And finally, this window is of no interest if it
5376                            // is not associated with the screenshot app.
5377                            if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
5378                                continue;
5379                            }
5380                            appWin = ws;
5381                        }
5382                    }
5383
5384                    // We keep on including windows until we go past a full-screen
5385                    // window.
5386                    boolean fullscreen = ws.isFullscreen(dw, dh);
5387                    including = !ws.mIsImWindow && !fullscreen;
5388
5389                    final WindowStateAnimator winAnim = ws.mWinAnimator;
5390                    if (maxLayer < winAnim.mSurfaceLayer) {
5391                        maxLayer = winAnim.mSurfaceLayer;
5392                    }
5393                    if (minLayer > winAnim.mSurfaceLayer) {
5394                        minLayer = winAnim.mSurfaceLayer;
5395                    }
5396
5397                    // Don't include wallpaper in bounds calculation
5398                    if (!ws.mIsWallpaper) {
5399                        final Rect wf = ws.mFrame;
5400                        final Rect cr = ws.mContentInsets;
5401                        int left = wf.left + cr.left;
5402                        int top = wf.top + cr.top;
5403                        int right = wf.right - cr.right;
5404                        int bottom = wf.bottom - cr.bottom;
5405                        frame.union(left, top, right, bottom);
5406                    }
5407
5408                    if (ws.mAppToken != null && ws.mAppToken.token == appToken &&
5409                            ws.isDisplayedLw()) {
5410                        screenshotReady = true;
5411                    }
5412
5413                    if (fullscreen) {
5414                        // No point in continuing down through windows.
5415                        break;
5416                    }
5417                }
5418
5419                if (appToken != null && appWin == null) {
5420                    // Can't find a window to snapshot.
5421                    if (DEBUG_SCREENSHOT) Slog.i(TAG,
5422                            "Screenshot: Couldn't find a surface matching " + appToken);
5423                    return null;
5424                }
5425                if (!screenshotReady) {
5426                    // Delay and hope that window gets drawn.
5427                    if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot: No image ready for " + appToken
5428                            + ", " + appWin + " drawState=" + appWin.mWinAnimator.mDrawState);
5429                    continue;
5430                }
5431
5432                // Constrain frame to the screen size.
5433                frame.intersect(0, 0, dw, dh);
5434
5435                if (frame.isEmpty() || maxLayer == 0) {
5436                    if (DEBUG_SCREENSHOT) Slog.i(TAG, "Screenshot of " + appToken
5437                            + ": returning null frame=" + frame.toShortString() + " maxLayer="
5438                            + maxLayer);
5439                    return null;
5440                }
5441
5442                // The screenshot API does not apply the current screen rotation.
5443                rot = getDefaultDisplayContentLocked().getDisplay().getRotation();
5444                int fw = frame.width();
5445                int fh = frame.height();
5446
5447                // Constrain thumbnail to smaller of screen width or height. Assumes aspect
5448                // of thumbnail is the same as the screen (in landscape) or square.
5449                float targetWidthScale = width / (float) fw;
5450                float targetHeightScale = height / (float) fh;
5451                if (dw <= dh) {
5452                    scale = targetWidthScale;
5453                    // If aspect of thumbnail is the same as the screen (in landscape),
5454                    // select the slightly larger value so we fill the entire bitmap
5455                    if (targetHeightScale > scale && (int) (targetHeightScale * fw) == width) {
5456                        scale = targetHeightScale;
5457                    }
5458                } else {
5459                    scale = targetHeightScale;
5460                    // If aspect of thumbnail is the same as the screen (in landscape),
5461                    // select the slightly larger value so we fill the entire bitmap
5462                    if (targetWidthScale > scale && (int) (targetWidthScale * fh) == height) {
5463                        scale = targetWidthScale;
5464                    }
5465                }
5466
5467                // The screen shot will contain the entire screen.
5468                dw = (int)(dw*scale);
5469                dh = (int)(dh*scale);
5470                if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
5471                    int tmp = dw;
5472                    dw = dh;
5473                    dh = tmp;
5474                    rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
5475                }
5476                if (DEBUG_SCREENSHOT) {
5477                    Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
5478                            + maxLayer + " appToken=" + appToken);
5479                    for (int i = 0; i < windows.size(); i++) {
5480                        WindowState win = windows.get(i);
5481                        Slog.i(TAG, win + ": " + win.mLayer
5482                                + " animLayer=" + win.mWinAnimator.mAnimLayer
5483                                + " surfaceLayer=" + win.mWinAnimator.mSurfaceLayer);
5484                    }
5485                }
5486                rawss = SurfaceControl.screenshot(dw, dh, minLayer, maxLayer);
5487            }
5488        } while (!screenshotReady && retryCount <= MAX_SCREENSHOT_RETRIES);
5489        if (retryCount > MAX_SCREENSHOT_RETRIES)  Slog.i(TAG, "Screenshot max retries " +
5490                retryCount + " of " + appToken + " appWin=" + (appWin == null ?
5491                        "null" : (appWin + " drawState=" + appWin.mWinAnimator.mDrawState)));
5492
5493        if (rawss == null) {
5494            Slog.w(TAG, "Screenshot failure taking screenshot for (" + dw + "x" + dh
5495                    + ") to layer " + maxLayer);
5496            return null;
5497        }
5498
5499        Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
5500        Matrix matrix = new Matrix();
5501        ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
5502        matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale));
5503        Canvas canvas = new Canvas(bm);
5504        canvas.drawColor(0xFF000000);
5505        canvas.drawBitmap(rawss, matrix, null);
5506        canvas.setBitmap(null);
5507
5508        if (true || DEBUG_SCREENSHOT) {
5509            // TEST IF IT's ALL BLACK
5510            int[] buffer = new int[bm.getWidth() * bm.getHeight()];
5511            bm.getPixels(buffer, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight());
5512            boolean allBlack = true;
5513            for (int i = 0; i < buffer.length; i++) {
5514                if (buffer[i] != Color.BLACK) {
5515                    allBlack = false;
5516                    break;
5517                }
5518            }
5519            if (allBlack) {
5520                Slog.i(TAG, "Screenshot " + appWin + " was all black! mSurfaceLayer=" +
5521                        (appWin != null ? appWin.mWinAnimator.mSurfaceLayer : "null") +
5522                        " minLayer=" + minLayer + " maxLayer=" + maxLayer);
5523            }
5524        }
5525
5526        rawss.recycle();
5527        return bm;
5528    }
5529
5530    /**
5531     * Freeze rotation changes.  (Enable "rotation lock".)
5532     * Persists across reboots.
5533     * @param rotation The desired rotation to freeze to, or -1 to use the
5534     * current rotation.
5535     */
5536    @Override
5537    public void freezeRotation(int rotation) {
5538        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5539                "freezeRotation()")) {
5540            throw new SecurityException("Requires SET_ORIENTATION permission");
5541        }
5542        if (rotation < -1 || rotation > Surface.ROTATION_270) {
5543            throw new IllegalArgumentException("Rotation argument must be -1 or a valid "
5544                    + "rotation constant.");
5545        }
5546
5547        if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
5548
5549        long origId = Binder.clearCallingIdentity();
5550        try {
5551            mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED,
5552                    rotation == -1 ? mRotation : rotation);
5553        } finally {
5554            Binder.restoreCallingIdentity(origId);
5555        }
5556
5557        updateRotationUnchecked(false, false);
5558    }
5559
5560    /**
5561     * Thaw rotation changes.  (Disable "rotation lock".)
5562     * Persists across reboots.
5563     */
5564    @Override
5565    public void thawRotation() {
5566        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
5567                "thawRotation()")) {
5568            throw new SecurityException("Requires SET_ORIENTATION permission");
5569        }
5570
5571        if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
5572
5573        long origId = Binder.clearCallingIdentity();
5574        try {
5575            mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE,
5576                    777); // rot not used
5577        } finally {
5578            Binder.restoreCallingIdentity(origId);
5579        }
5580
5581        updateRotationUnchecked(false, false);
5582    }
5583
5584    /**
5585     * Recalculate the current rotation.
5586     *
5587     * Called by the window manager policy whenever the state of the system changes
5588     * such that the current rotation might need to be updated, such as when the
5589     * device is docked or rotated into a new posture.
5590     */
5591    @Override
5592    public void updateRotation(boolean alwaysSendConfiguration, boolean forceRelayout) {
5593        updateRotationUnchecked(alwaysSendConfiguration, forceRelayout);
5594    }
5595
5596    /**
5597     * Temporarily pauses rotation changes until resumed.
5598     *
5599     * This can be used to prevent rotation changes from occurring while the user is
5600     * performing certain operations, such as drag and drop.
5601     *
5602     * This call nests and must be matched by an equal number of calls to
5603     * {@link #resumeRotationLocked}.
5604     */
5605    void pauseRotationLocked() {
5606        mDeferredRotationPauseCount += 1;
5607    }
5608
5609    /**
5610     * Resumes normal rotation changes after being paused.
5611     */
5612    void resumeRotationLocked() {
5613        if (mDeferredRotationPauseCount > 0) {
5614            mDeferredRotationPauseCount -= 1;
5615            if (mDeferredRotationPauseCount == 0) {
5616                boolean changed = updateRotationUncheckedLocked(false);
5617                if (changed) {
5618                    mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
5619                }
5620            }
5621        }
5622    }
5623
5624    public void updateRotationUnchecked(boolean alwaysSendConfiguration, boolean forceRelayout) {
5625        if(DEBUG_ORIENTATION) Slog.v(TAG, "updateRotationUnchecked("
5626                   + "alwaysSendConfiguration=" + alwaysSendConfiguration + ")");
5627
5628        long origId = Binder.clearCallingIdentity();
5629        boolean changed;
5630        synchronized(mWindowMap) {
5631            changed = updateRotationUncheckedLocked(false);
5632            if (!changed || forceRelayout) {
5633                getDefaultDisplayContentLocked().layoutNeeded = true;
5634                performLayoutAndPlaceSurfacesLocked();
5635            }
5636        }
5637
5638        if (changed || alwaysSendConfiguration) {
5639            sendNewConfiguration();
5640        }
5641
5642        Binder.restoreCallingIdentity(origId);
5643    }
5644
5645    // TODO(multidisplay): Rotate any display?
5646    /**
5647     * Updates the current rotation.
5648     *
5649     * Returns true if the rotation has been changed.  In this case YOU
5650     * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN.
5651     */
5652    public boolean updateRotationUncheckedLocked(boolean inTransaction) {
5653        if (mDeferredRotationPauseCount > 0) {
5654            // Rotation updates have been paused temporarily.  Defer the update until
5655            // updates have been resumed.
5656            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, rotation is paused.");
5657            return false;
5658        }
5659
5660        ScreenRotationAnimation screenRotationAnimation =
5661                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
5662        if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
5663            // Rotation updates cannot be performed while the previous rotation change
5664            // animation is still in progress.  Skip this update.  We will try updating
5665            // again after the animation is finished and the display is unfrozen.
5666            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, animation in progress.");
5667            return false;
5668        }
5669
5670        if (!mDisplayEnabled) {
5671            // No point choosing a rotation if the display is not enabled.
5672            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation, display is not enabled.");
5673            return false;
5674        }
5675
5676        // TODO: Implement forced rotation changes.
5677        //       Set mAltOrientation to indicate that the application is receiving
5678        //       an orientation that has different metrics than it expected.
5679        //       eg. Portrait instead of Landscape.
5680
5681        int rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation, mRotation);
5682        boolean altOrientation = !mPolicy.rotationHasCompatibleMetricsLw(
5683                mForcedAppOrientation, rotation);
5684
5685        if (DEBUG_ORIENTATION) {
5686            Slog.v(TAG, "Application requested orientation "
5687                    + mForcedAppOrientation + ", got rotation " + rotation
5688                    + " which has " + (altOrientation ? "incompatible" : "compatible")
5689                    + " metrics");
5690        }
5691
5692        if (mRotation == rotation && mAltOrientation == altOrientation) {
5693            // No change.
5694            return false;
5695        }
5696
5697        if (DEBUG_ORIENTATION) {
5698            Slog.v(TAG,
5699                "Rotation changed to " + rotation + (altOrientation ? " (alt)" : "")
5700                + " from " + mRotation + (mAltOrientation ? " (alt)" : "")
5701                + ", forceApp=" + mForcedAppOrientation);
5702        }
5703
5704        mRotation = rotation;
5705        mAltOrientation = altOrientation;
5706        mPolicy.setRotationLw(mRotation);
5707
5708        mWindowsFreezingScreen = true;
5709        mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
5710        mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
5711        mWaitingForConfig = true;
5712        getDefaultDisplayContentLocked().layoutNeeded = true;
5713        final int[] anim = new int[2];
5714        if (mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY)) {
5715            anim[0] = anim[1] = 0;
5716        } else {
5717            mPolicy.selectRotationAnimationLw(anim);
5718        }
5719        startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
5720        // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
5721        screenRotationAnimation =
5722                mAnimator.getScreenRotationAnimationLocked(Display.DEFAULT_DISPLAY);
5723
5724        // We need to update our screen size information to match the new
5725        // rotation.  Note that this is redundant with the later call to
5726        // sendNewConfiguration() that must be called after this function
5727        // returns...  however we need to do the screen size part of that
5728        // before then so we have the correct size to use when initializing
5729        // the rotation animation for the new rotation.
5730        computeScreenConfigurationLocked(null);
5731
5732        final DisplayContent displayContent = getDefaultDisplayContentLocked();
5733        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
5734        if (!inTransaction) {
5735            if (SHOW_TRANSACTIONS) {
5736                Slog.i(TAG, ">>> OPEN TRANSACTION setRotationUnchecked");
5737            }
5738            SurfaceControl.openTransaction();
5739        }
5740        try {
5741            // NOTE: We disable the rotation in the emulator because
5742            //       it doesn't support hardware OpenGL emulation yet.
5743            if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
5744                    && screenRotationAnimation.hasScreenshot()) {
5745                if (screenRotationAnimation.setRotationInTransaction(
5746                        rotation, mFxSession,
5747                        MAX_ANIMATION_DURATION, mTransitionAnimationScale,
5748                        displayInfo.logicalWidth, displayInfo.logicalHeight)) {
5749                    scheduleAnimationLocked();
5750                }
5751            }
5752
5753            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
5754        } finally {
5755            if (!inTransaction) {
5756                SurfaceControl.closeTransaction();
5757                if (SHOW_LIGHT_TRANSACTIONS) {
5758                    Slog.i(TAG, "<<< CLOSE TRANSACTION setRotationUnchecked");
5759                }
5760            }
5761        }
5762
5763        final WindowList windows = displayContent.getWindowList();
5764        for (int i = windows.size() - 1; i >= 0; i--) {
5765            WindowState w = windows.get(i);
5766            if (w.mHasSurface) {
5767                if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
5768                w.mOrientationChanging = true;
5769                mInnerFields.mOrientationChangeComplete = false;
5770            }
5771            w.mLastFreezeDuration = 0;
5772        }
5773
5774        for (int i=mRotationWatchers.size()-1; i>=0; i--) {
5775            try {
5776                mRotationWatchers.get(i).onRotationChanged(rotation);
5777            } catch (RemoteException e) {
5778            }
5779        }
5780
5781        //TODO (multidisplay): Magnification is supported only for the default display.
5782        if (mDisplayMagnifier != null
5783                && displayContent.getDisplayId() == Display.DEFAULT_DISPLAY) {
5784            mDisplayMagnifier.onRotationChangedLocked(getDefaultDisplayContentLocked(), rotation);
5785        }
5786
5787        return true;
5788    }
5789
5790    @Override
5791    public int getRotation() {
5792        return mRotation;
5793    }
5794
5795    @Override
5796    public boolean isRotationFrozen() {
5797        return mPolicy.getUserRotationMode() == WindowManagerPolicy.USER_ROTATION_LOCKED;
5798    }
5799
5800    @Override
5801    public int watchRotation(IRotationWatcher watcher) {
5802        final IBinder watcherBinder = watcher.asBinder();
5803        IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
5804            @Override
5805            public void binderDied() {
5806                synchronized (mWindowMap) {
5807                    for (int i=0; i<mRotationWatchers.size(); i++) {
5808                        if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
5809                            IRotationWatcher removed = mRotationWatchers.remove(i);
5810                            if (removed != null) {
5811                                removed.asBinder().unlinkToDeath(this, 0);
5812                            }
5813                            i--;
5814                        }
5815                    }
5816                }
5817            }
5818        };
5819
5820        synchronized (mWindowMap) {
5821            try {
5822                watcher.asBinder().linkToDeath(dr, 0);
5823                mRotationWatchers.add(watcher);
5824            } catch (RemoteException e) {
5825                // Client died, no cleanup needed.
5826            }
5827
5828            return mRotation;
5829        }
5830    }
5831
5832    @Override
5833    public void removeRotationWatcher(IRotationWatcher watcher) {
5834        final IBinder watcherBinder = watcher.asBinder();
5835        synchronized (mWindowMap) {
5836            for (int i=0; i<mRotationWatchers.size(); i++) {
5837                if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
5838                    mRotationWatchers.remove(i);
5839                    i--;
5840                }
5841            }
5842        }
5843    }
5844
5845    /**
5846     * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
5847     * theme attribute) on devices that feature a physical options menu key attempt to position
5848     * their menu panel window along the edge of the screen nearest the physical menu key.
5849     * This lowers the travel distance between invoking the menu panel and selecting
5850     * a menu option.
5851     *
5852     * This method helps control where that menu is placed. Its current implementation makes
5853     * assumptions about the menu key and its relationship to the screen based on whether
5854     * the device's natural orientation is portrait (width < height) or landscape.
5855     *
5856     * The menu key is assumed to be located along the bottom edge of natural-portrait
5857     * devices and along the right edge of natural-landscape devices. If these assumptions
5858     * do not hold for the target device, this method should be changed to reflect that.
5859     *
5860     * @return A {@link Gravity} value for placing the options menu window
5861     */
5862    @Override
5863    public int getPreferredOptionsPanelGravity() {
5864        synchronized (mWindowMap) {
5865            final int rotation = getRotation();
5866
5867            // TODO(multidisplay): Assume that such devices physical keys are on the main screen.
5868            final DisplayContent displayContent = getDefaultDisplayContentLocked();
5869            if (displayContent.mInitialDisplayWidth < displayContent.mInitialDisplayHeight) {
5870                // On devices with a natural orientation of portrait
5871                switch (rotation) {
5872                    default:
5873                    case Surface.ROTATION_0:
5874                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5875                    case Surface.ROTATION_90:
5876                        return Gravity.RIGHT | Gravity.BOTTOM;
5877                    case Surface.ROTATION_180:
5878                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5879                    case Surface.ROTATION_270:
5880                        return Gravity.START | Gravity.BOTTOM;
5881                }
5882            }
5883
5884            // On devices with a natural orientation of landscape
5885            switch (rotation) {
5886                default:
5887                case Surface.ROTATION_0:
5888                    return Gravity.RIGHT | Gravity.BOTTOM;
5889                case Surface.ROTATION_90:
5890                    return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5891                case Surface.ROTATION_180:
5892                    return Gravity.START | Gravity.BOTTOM;
5893                case Surface.ROTATION_270:
5894                    return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5895            }
5896        }
5897    }
5898
5899    /**
5900     * Starts the view server on the specified port.
5901     *
5902     * @param port The port to listener to.
5903     *
5904     * @return True if the server was successfully started, false otherwise.
5905     *
5906     * @see com.android.server.wm.ViewServer
5907     * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
5908     */
5909    @Override
5910    public boolean startViewServer(int port) {
5911        if (isSystemSecure()) {
5912            return false;
5913        }
5914
5915        if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
5916            return false;
5917        }
5918
5919        if (port < 1024) {
5920            return false;
5921        }
5922
5923        if (mViewServer != null) {
5924            if (!mViewServer.isRunning()) {
5925                try {
5926                    return mViewServer.start();
5927                } catch (IOException e) {
5928                    Slog.w(TAG, "View server did not start");
5929                }
5930            }
5931            return false;
5932        }
5933
5934        try {
5935            mViewServer = new ViewServer(this, port);
5936            return mViewServer.start();
5937        } catch (IOException e) {
5938            Slog.w(TAG, "View server did not start");
5939        }
5940        return false;
5941    }
5942
5943    private boolean isSystemSecure() {
5944        return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
5945                "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
5946    }
5947
5948    /**
5949     * Stops the view server if it exists.
5950     *
5951     * @return True if the server stopped, false if it wasn't started or
5952     *         couldn't be stopped.
5953     *
5954     * @see com.android.server.wm.ViewServer
5955     */
5956    @Override
5957    public boolean stopViewServer() {
5958        if (isSystemSecure()) {
5959            return false;
5960        }
5961
5962        if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
5963            return false;
5964        }
5965
5966        if (mViewServer != null) {
5967            return mViewServer.stop();
5968        }
5969        return false;
5970    }
5971
5972    /**
5973     * Indicates whether the view server is running.
5974     *
5975     * @return True if the server is running, false otherwise.
5976     *
5977     * @see com.android.server.wm.ViewServer
5978     */
5979    @Override
5980    public boolean isViewServerRunning() {
5981        if (isSystemSecure()) {
5982            return false;
5983        }
5984
5985        if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
5986            return false;
5987        }
5988
5989        return mViewServer != null && mViewServer.isRunning();
5990    }
5991
5992    /**
5993     * Lists all availble windows in the system. The listing is written in the
5994     * specified Socket's output stream with the following syntax:
5995     * windowHashCodeInHexadecimal windowName
5996     * Each line of the ouput represents a different window.
5997     *
5998     * @param client The remote client to send the listing to.
5999     * @return False if an error occured, true otherwise.
6000     */
6001    boolean viewServerListWindows(Socket client) {
6002        if (isSystemSecure()) {
6003            return false;
6004        }
6005
6006        boolean result = true;
6007
6008        WindowList windows = new WindowList();
6009        synchronized (mWindowMap) {
6010            //noinspection unchecked
6011            final int numDisplays = mDisplayContents.size();
6012            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
6013                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
6014                windows.addAll(displayContent.getWindowList());
6015            }
6016        }
6017
6018        BufferedWriter out = null;
6019
6020        // Any uncaught exception will crash the system process
6021        try {
6022            OutputStream clientStream = client.getOutputStream();
6023            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
6024
6025            final int count = windows.size();
6026            for (int i = 0; i < count; i++) {
6027                final WindowState w = windows.get(i);
6028                out.write(Integer.toHexString(System.identityHashCode(w)));
6029                out.write(' ');
6030                out.append(w.mAttrs.getTitle());
6031                out.write('\n');
6032            }
6033
6034            out.write("DONE.\n");
6035            out.flush();
6036        } catch (Exception e) {
6037            result = false;
6038        } finally {
6039            if (out != null) {
6040                try {
6041                    out.close();
6042                } catch (IOException e) {
6043                    result = false;
6044                }
6045            }
6046        }
6047
6048        return result;
6049    }
6050
6051    // TODO(multidisplay): Extend to multiple displays.
6052    /**
6053     * Returns the focused window in the following format:
6054     * windowHashCodeInHexadecimal windowName
6055     *
6056     * @param client The remote client to send the listing to.
6057     * @return False if an error occurred, true otherwise.
6058     */
6059    boolean viewServerGetFocusedWindow(Socket client) {
6060        if (isSystemSecure()) {
6061            return false;
6062        }
6063
6064        boolean result = true;
6065
6066        WindowState focusedWindow = getFocusedWindow();
6067
6068        BufferedWriter out = null;
6069
6070        // Any uncaught exception will crash the system process
6071        try {
6072            OutputStream clientStream = client.getOutputStream();
6073            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
6074
6075            if(focusedWindow != null) {
6076                out.write(Integer.toHexString(System.identityHashCode(focusedWindow)));
6077                out.write(' ');
6078                out.append(focusedWindow.mAttrs.getTitle());
6079            }
6080            out.write('\n');
6081            out.flush();
6082        } catch (Exception e) {
6083            result = false;
6084        } finally {
6085            if (out != null) {
6086                try {
6087                    out.close();
6088                } catch (IOException e) {
6089                    result = false;
6090                }
6091            }
6092        }
6093
6094        return result;
6095    }
6096
6097    /**
6098     * Sends a command to a target window. The result of the command, if any, will be
6099     * written in the output stream of the specified socket.
6100     *
6101     * The parameters must follow this syntax:
6102     * windowHashcode extra
6103     *
6104     * Where XX is the length in characeters of the windowTitle.
6105     *
6106     * The first parameter is the target window. The window with the specified hashcode
6107     * will be the target. If no target can be found, nothing happens. The extra parameters
6108     * will be delivered to the target window and as parameters to the command itself.
6109     *
6110     * @param client The remote client to sent the result, if any, to.
6111     * @param command The command to execute.
6112     * @param parameters The command parameters.
6113     *
6114     * @return True if the command was successfully delivered, false otherwise. This does
6115     *         not indicate whether the command itself was successful.
6116     */
6117    boolean viewServerWindowCommand(Socket client, String command, String parameters) {
6118        if (isSystemSecure()) {
6119            return false;
6120        }
6121
6122        boolean success = true;
6123        Parcel data = null;
6124        Parcel reply = null;
6125
6126        BufferedWriter out = null;
6127
6128        // Any uncaught exception will crash the system process
6129        try {
6130            // Find the hashcode of the window
6131            int index = parameters.indexOf(' ');
6132            if (index == -1) {
6133                index = parameters.length();
6134            }
6135            final String code = parameters.substring(0, index);
6136            int hashCode = (int) Long.parseLong(code, 16);
6137
6138            // Extract the command's parameter after the window description
6139            if (index < parameters.length()) {
6140                parameters = parameters.substring(index + 1);
6141            } else {
6142                parameters = "";
6143            }
6144
6145            final WindowState window = findWindow(hashCode);
6146            if (window == null) {
6147                return false;
6148            }
6149
6150            data = Parcel.obtain();
6151            data.writeInterfaceToken("android.view.IWindow");
6152            data.writeString(command);
6153            data.writeString(parameters);
6154            data.writeInt(1);
6155            ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
6156
6157            reply = Parcel.obtain();
6158
6159            final IBinder binder = window.mClient.asBinder();
6160            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
6161            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
6162
6163            reply.readException();
6164
6165            if (!client.isOutputShutdown()) {
6166                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
6167                out.write("DONE\n");
6168                out.flush();
6169            }
6170
6171        } catch (Exception e) {
6172            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
6173            success = false;
6174        } finally {
6175            if (data != null) {
6176                data.recycle();
6177            }
6178            if (reply != null) {
6179                reply.recycle();
6180            }
6181            if (out != null) {
6182                try {
6183                    out.close();
6184                } catch (IOException e) {
6185
6186                }
6187            }
6188        }
6189
6190        return success;
6191    }
6192
6193    public void addWindowChangeListener(WindowChangeListener listener) {
6194        synchronized(mWindowMap) {
6195            mWindowChangeListeners.add(listener);
6196        }
6197    }
6198
6199    public void removeWindowChangeListener(WindowChangeListener listener) {
6200        synchronized(mWindowMap) {
6201            mWindowChangeListeners.remove(listener);
6202        }
6203    }
6204
6205    private void notifyWindowsChanged() {
6206        WindowChangeListener[] windowChangeListeners;
6207        synchronized(mWindowMap) {
6208            if(mWindowChangeListeners.isEmpty()) {
6209                return;
6210            }
6211            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6212            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6213        }
6214        int N = windowChangeListeners.length;
6215        for(int i = 0; i < N; i++) {
6216            windowChangeListeners[i].windowsChanged();
6217        }
6218    }
6219
6220    private void notifyFocusChanged() {
6221        WindowChangeListener[] windowChangeListeners;
6222        synchronized(mWindowMap) {
6223            if(mWindowChangeListeners.isEmpty()) {
6224                return;
6225            }
6226            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
6227            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
6228        }
6229        int N = windowChangeListeners.length;
6230        for(int i = 0; i < N; i++) {
6231            windowChangeListeners[i].focusChanged();
6232        }
6233    }
6234
6235    private WindowState findWindow(int hashCode) {
6236        if (hashCode == -1) {
6237            // TODO(multidisplay): Extend to multiple displays.
6238            return getFocusedWindow();
6239        }
6240
6241        synchronized (mWindowMap) {
6242            final int numDisplays = mDisplayContents.size();
6243            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
6244                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
6245                final int numWindows = windows.size();
6246                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
6247                    final WindowState w = windows.get(winNdx);
6248                    if (System.identityHashCode(w) == hashCode) {
6249                        return w;
6250                    }
6251                }
6252            }
6253        }
6254
6255        return null;
6256    }
6257
6258    /*
6259     * Instruct the Activity Manager to fetch the current configuration and broadcast
6260     * that to config-changed listeners if appropriate.
6261     */
6262    void sendNewConfiguration() {
6263        try {
6264            mActivityManager.updateConfiguration(null);
6265        } catch (RemoteException e) {
6266        }
6267    }
6268
6269    public Configuration computeNewConfiguration() {
6270        synchronized (mWindowMap) {
6271            Configuration config = computeNewConfigurationLocked();
6272            if (config == null && mWaitingForConfig) {
6273                // Nothing changed but we are waiting for something... stop that!
6274                mWaitingForConfig = false;
6275                mLastFinishedFreezeSource = "new-config";
6276                performLayoutAndPlaceSurfacesLocked();
6277            }
6278            return config;
6279        }
6280    }
6281
6282    Configuration computeNewConfigurationLocked() {
6283        Configuration config = new Configuration();
6284        config.fontScale = 0;
6285        if (!computeScreenConfigurationLocked(config)) {
6286            return null;
6287        }
6288        return config;
6289    }
6290
6291    private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) {
6292        // TODO: Multidisplay: for now only use with default display.
6293        final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation);
6294        if (width < displayInfo.smallestNominalAppWidth) {
6295            displayInfo.smallestNominalAppWidth = width;
6296        }
6297        if (width > displayInfo.largestNominalAppWidth) {
6298            displayInfo.largestNominalAppWidth = width;
6299        }
6300        final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation);
6301        if (height < displayInfo.smallestNominalAppHeight) {
6302            displayInfo.smallestNominalAppHeight = height;
6303        }
6304        if (height > displayInfo.largestNominalAppHeight) {
6305            displayInfo.largestNominalAppHeight = height;
6306        }
6307    }
6308
6309    private int reduceConfigLayout(int curLayout, int rotation, float density,
6310            int dw, int dh) {
6311        // TODO: Multidisplay: for now only use with default display.
6312        // Get the app screen size at this rotation.
6313        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6314        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6315
6316        // Compute the screen layout size class for this rotation.
6317        int longSize = w;
6318        int shortSize = h;
6319        if (longSize < shortSize) {
6320            int tmp = longSize;
6321            longSize = shortSize;
6322            shortSize = tmp;
6323        }
6324        longSize = (int)(longSize/density);
6325        shortSize = (int)(shortSize/density);
6326        return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
6327    }
6328
6329    private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated,
6330                  int dw, int dh, float density, Configuration outConfig) {
6331        // TODO: Multidisplay: for now only use with default display.
6332
6333        // We need to determine the smallest width that will occur under normal
6334        // operation.  To this, start with the base screen size and compute the
6335        // width under the different possible rotations.  We need to un-rotate
6336        // the current screen dimensions before doing this.
6337        int unrotDw, unrotDh;
6338        if (rotated) {
6339            unrotDw = dh;
6340            unrotDh = dw;
6341        } else {
6342            unrotDw = dw;
6343            unrotDh = dh;
6344        }
6345        displayInfo.smallestNominalAppWidth = 1<<30;
6346        displayInfo.smallestNominalAppHeight = 1<<30;
6347        displayInfo.largestNominalAppWidth = 0;
6348        displayInfo.largestNominalAppHeight = 0;
6349        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh);
6350        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw);
6351        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh);
6352        adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw);
6353        int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
6354        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
6355        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
6356        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
6357        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
6358        outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
6359        outConfig.screenLayout = sl;
6360    }
6361
6362    private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
6363            int dw, int dh) {
6364        // TODO: Multidisplay: for now only use with default display.
6365        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
6366        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6367        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
6368        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
6369        if (curSize == 0 || size < curSize) {
6370            curSize = size;
6371        }
6372        return curSize;
6373    }
6374
6375    private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
6376        // TODO: Multidisplay: for now only use with default display.
6377        mTmpDisplayMetrics.setTo(dm);
6378        final DisplayMetrics tmpDm = mTmpDisplayMetrics;
6379        final int unrotDw, unrotDh;
6380        if (rotated) {
6381            unrotDw = dh;
6382            unrotDh = dw;
6383        } else {
6384            unrotDw = dw;
6385            unrotDh = dh;
6386        }
6387        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh);
6388        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw);
6389        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh);
6390        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw);
6391        return sw;
6392    }
6393
6394    boolean computeScreenConfigurationLocked(Configuration config) {
6395        if (!mDisplayReady) {
6396            return false;
6397        }
6398
6399        // TODO(multidisplay): For now, apply Configuration to main screen only.
6400        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6401
6402        // Use the effective "visual" dimensions based on current rotation
6403        final boolean rotated = (mRotation == Surface.ROTATION_90
6404                || mRotation == Surface.ROTATION_270);
6405        final int realdw = rotated ?
6406                displayContent.mBaseDisplayHeight : displayContent.mBaseDisplayWidth;
6407        final int realdh = rotated ?
6408                displayContent.mBaseDisplayWidth : displayContent.mBaseDisplayHeight;
6409        int dw = realdw;
6410        int dh = realdh;
6411
6412        if (mAltOrientation) {
6413            if (realdw > realdh) {
6414                // Turn landscape into portrait.
6415                int maxw = (int)(realdh/1.3f);
6416                if (maxw < realdw) {
6417                    dw = maxw;
6418                }
6419            } else {
6420                // Turn portrait into landscape.
6421                int maxh = (int)(realdw/1.3f);
6422                if (maxh < realdh) {
6423                    dh = maxh;
6424                }
6425            }
6426        }
6427
6428        if (config != null) {
6429            config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
6430                    Configuration.ORIENTATION_LANDSCAPE;
6431        }
6432
6433        // Update application display metrics.
6434        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
6435        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
6436        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
6437        synchronized(displayContent.mDisplaySizeLock) {
6438            displayInfo.rotation = mRotation;
6439            displayInfo.logicalWidth = dw;
6440            displayInfo.logicalHeight = dh;
6441            displayInfo.logicalDensityDpi = displayContent.mBaseDisplayDensity;
6442            displayInfo.appWidth = appWidth;
6443            displayInfo.appHeight = appHeight;
6444            displayInfo.getLogicalMetrics(mRealDisplayMetrics, null);
6445            displayInfo.getAppMetrics(mDisplayMetrics, null);
6446            mDisplayManagerService.setDisplayInfoOverrideFromWindowManager(
6447                    displayContent.getDisplayId(), displayInfo);
6448        }
6449        if (false) {
6450            Slog.i(TAG, "Set app display size: " + appWidth + " x " + appHeight);
6451        }
6452
6453        final DisplayMetrics dm = mDisplayMetrics;
6454        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
6455                mCompatDisplayMetrics);
6456
6457        if (config != null) {
6458            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
6459                    / dm.density);
6460            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
6461                    / dm.density);
6462            computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, dm.density, config);
6463
6464            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
6465            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
6466            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
6467            config.densityDpi = displayContent.mBaseDisplayDensity;
6468
6469            // Update the configuration based on available input devices, lid switch,
6470            // and platform configuration.
6471            config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6472            config.keyboard = Configuration.KEYBOARD_NOKEYS;
6473            config.navigation = Configuration.NAVIGATION_NONAV;
6474
6475            int keyboardPresence = 0;
6476            int navigationPresence = 0;
6477            final InputDevice[] devices = mInputManager.getInputDevices();
6478            final int len = devices.length;
6479            for (int i = 0; i < len; i++) {
6480                InputDevice device = devices[i];
6481                if (!device.isVirtual()) {
6482                    final int sources = device.getSources();
6483                    final int presenceFlag = device.isExternal() ?
6484                            WindowManagerPolicy.PRESENCE_EXTERNAL :
6485                                    WindowManagerPolicy.PRESENCE_INTERNAL;
6486
6487                    if (mIsTouchDevice) {
6488                        if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
6489                                InputDevice.SOURCE_TOUCHSCREEN) {
6490                            config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
6491                        }
6492                    } else {
6493                        config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
6494                    }
6495
6496                    if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
6497                        config.navigation = Configuration.NAVIGATION_TRACKBALL;
6498                        navigationPresence |= presenceFlag;
6499                    } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
6500                            && config.navigation == Configuration.NAVIGATION_NONAV) {
6501                        config.navigation = Configuration.NAVIGATION_DPAD;
6502                        navigationPresence |= presenceFlag;
6503                    }
6504
6505                    if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
6506                        config.keyboard = Configuration.KEYBOARD_QWERTY;
6507                        keyboardPresence |= presenceFlag;
6508                    }
6509                }
6510            }
6511
6512            // Determine whether a hard keyboard is available and enabled.
6513            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6514            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6515                mHardKeyboardAvailable = hardKeyboardAvailable;
6516                mHardKeyboardEnabled = hardKeyboardAvailable;
6517                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6518                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6519            }
6520            if (!mHardKeyboardEnabled) {
6521                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6522            }
6523
6524            // Let the policy update hidden states.
6525            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6526            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6527            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6528            mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
6529        }
6530
6531        return true;
6532    }
6533
6534    public boolean isHardKeyboardAvailable() {
6535        synchronized (mWindowMap) {
6536            return mHardKeyboardAvailable;
6537        }
6538    }
6539
6540    public boolean isHardKeyboardEnabled() {
6541        synchronized (mWindowMap) {
6542            return mHardKeyboardEnabled;
6543        }
6544    }
6545
6546    public void setHardKeyboardEnabled(boolean enabled) {
6547        synchronized (mWindowMap) {
6548            if (mHardKeyboardEnabled != enabled) {
6549                mHardKeyboardEnabled = enabled;
6550                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6551            }
6552        }
6553    }
6554
6555    public void setOnHardKeyboardStatusChangeListener(
6556            OnHardKeyboardStatusChangeListener listener) {
6557        synchronized (mWindowMap) {
6558            mHardKeyboardStatusChangeListener = listener;
6559        }
6560    }
6561
6562    void notifyHardKeyboardStatusChange() {
6563        final boolean available, enabled;
6564        final OnHardKeyboardStatusChangeListener listener;
6565        synchronized (mWindowMap) {
6566            listener = mHardKeyboardStatusChangeListener;
6567            available = mHardKeyboardAvailable;
6568            enabled = mHardKeyboardEnabled;
6569        }
6570        if (listener != null) {
6571            listener.onHardKeyboardStatusChange(available, enabled);
6572        }
6573    }
6574
6575    // -------------------------------------------------------------
6576    // Drag and drop
6577    // -------------------------------------------------------------
6578
6579    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
6580            int flags, int width, int height, Surface outSurface) {
6581        if (DEBUG_DRAG) {
6582            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
6583                    + " flags=" + Integer.toHexString(flags) + " win=" + window
6584                    + " asbinder=" + window.asBinder());
6585        }
6586
6587        final int callerPid = Binder.getCallingPid();
6588        final long origId = Binder.clearCallingIdentity();
6589        IBinder token = null;
6590
6591        try {
6592            synchronized (mWindowMap) {
6593                try {
6594                    if (mDragState == null) {
6595                        // TODO(multi-display): support other displays
6596                        final DisplayContent displayContent = getDefaultDisplayContentLocked();
6597                        final Display display = displayContent.getDisplay();
6598                        SurfaceControl surface = new SurfaceControl(session, "drag surface",
6599                                width, height, PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
6600                        surface.setLayerStack(display.getLayerStack());
6601                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
6602                                + surface + ": CREATE");
6603                        outSurface.copyFrom(surface);
6604                        final IBinder winBinder = window.asBinder();
6605                        token = new Binder();
6606                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
6607                        token = mDragState.mToken = new Binder();
6608
6609                        // 5 second timeout for this window to actually begin the drag
6610                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
6611                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
6612                        mH.sendMessageDelayed(msg, 5000);
6613                    } else {
6614                        Slog.w(TAG, "Drag already in progress");
6615                    }
6616                } catch (SurfaceControl.OutOfResourcesException e) {
6617                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
6618                    if (mDragState != null) {
6619                        mDragState.reset();
6620                        mDragState = null;
6621                    }
6622                }
6623            }
6624        } finally {
6625            Binder.restoreCallingIdentity(origId);
6626        }
6627
6628        return token;
6629    }
6630
6631    // -------------------------------------------------------------
6632    // Input Events and Focus Management
6633    // -------------------------------------------------------------
6634
6635    final InputMonitor mInputMonitor = new InputMonitor(this);
6636    private boolean mEventDispatchingEnabled;
6637
6638    @Override
6639    public void pauseKeyDispatching(IBinder _token) {
6640        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6641                "pauseKeyDispatching()")) {
6642            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6643        }
6644
6645        synchronized (mWindowMap) {
6646            WindowToken token = mTokenMap.get(_token);
6647            if (token != null) {
6648                mInputMonitor.pauseDispatchingLw(token);
6649            }
6650        }
6651    }
6652
6653    @Override
6654    public void resumeKeyDispatching(IBinder _token) {
6655        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6656                "resumeKeyDispatching()")) {
6657            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6658        }
6659
6660        synchronized (mWindowMap) {
6661            WindowToken token = mTokenMap.get(_token);
6662            if (token != null) {
6663                mInputMonitor.resumeDispatchingLw(token);
6664            }
6665        }
6666    }
6667
6668    @Override
6669    public void setEventDispatching(boolean enabled) {
6670        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6671                "setEventDispatching()")) {
6672            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6673        }
6674
6675        synchronized (mWindowMap) {
6676            mEventDispatchingEnabled = enabled;
6677            if (mDisplayEnabled) {
6678                mInputMonitor.setEventDispatchingLw(enabled);
6679            }
6680            sendScreenStatusToClientsLocked();
6681        }
6682    }
6683
6684    @Override
6685    public IBinder getFocusedWindowToken() {
6686        if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
6687                "getFocusedWindowToken()")) {
6688            throw new SecurityException("Requires RETRIEVE_WINDOW_INFO permission.");
6689        }
6690        synchronized (mWindowMap) {
6691            WindowState windowState = getFocusedWindowLocked();
6692            if (windowState != null) {
6693                return windowState.mClient.asBinder();
6694            }
6695            return null;
6696        }
6697    }
6698
6699    private WindowState getFocusedWindow() {
6700        synchronized (mWindowMap) {
6701            return getFocusedWindowLocked();
6702        }
6703    }
6704
6705    private WindowState getFocusedWindowLocked() {
6706        return mCurrentFocus;
6707    }
6708
6709    public boolean detectSafeMode() {
6710        if (!mInputMonitor.waitForInputDevicesReady(
6711                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
6712            Slog.w(TAG, "Devices still not ready after waiting "
6713                   + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
6714                   + " milliseconds before attempting to detect safe mode.");
6715        }
6716
6717        int menuState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6718                KeyEvent.KEYCODE_MENU);
6719        int sState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY, KeyEvent.KEYCODE_S);
6720        int dpadState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_DPAD,
6721                KeyEvent.KEYCODE_DPAD_CENTER);
6722        int trackballState = mInputManager.getScanCodeState(-1, InputDevice.SOURCE_TRACKBALL,
6723                InputManagerService.BTN_MOUSE);
6724        int volumeDownState = mInputManager.getKeyCodeState(-1, InputDevice.SOURCE_ANY,
6725                KeyEvent.KEYCODE_VOLUME_DOWN);
6726        mSafeMode = menuState > 0 || sState > 0 || dpadState > 0 || trackballState > 0
6727                || volumeDownState > 0;
6728        try {
6729            if (SystemProperties.getInt(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, 0) != 0) {
6730                mSafeMode = true;
6731                SystemProperties.set(ShutdownThread.REBOOT_SAFEMODE_PROPERTY, "");
6732            }
6733        } catch (IllegalArgumentException e) {
6734        }
6735        if (mSafeMode) {
6736            Log.i(TAG, "SAFE MODE ENABLED (menu=" + menuState + " s=" + sState
6737                    + " dpad=" + dpadState + " trackball=" + trackballState + ")");
6738        } else {
6739            Log.i(TAG, "SAFE MODE not enabled");
6740        }
6741        mPolicy.setSafeMode(mSafeMode);
6742        return mSafeMode;
6743    }
6744
6745    public void displayReady() {
6746        displayReady(Display.DEFAULT_DISPLAY);
6747
6748        synchronized(mWindowMap) {
6749            final DisplayContent displayContent = getDefaultDisplayContentLocked();
6750            readForcedDisplaySizeAndDensityLocked(displayContent);
6751
6752            mDisplayReady = true;
6753            mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
6754                    PackageManager.FEATURE_TOUCHSCREEN);
6755
6756            mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
6757                    displayContent.mInitialDisplayWidth,
6758                    displayContent.mInitialDisplayHeight,
6759                    displayContent.mInitialDisplayDensity);
6760        }
6761
6762        try {
6763            mActivityManager.updateConfiguration(null);
6764        } catch (RemoteException e) {
6765        }
6766    }
6767
6768    private void displayReady(int displayId) {
6769        synchronized(mWindowMap) {
6770            final DisplayContent displayContent = getDisplayContentLocked(displayId);
6771            if (displayContent != null) {
6772                mAnimator.addDisplayLocked(displayId);
6773                synchronized(displayContent.mDisplaySizeLock) {
6774                    // Bootstrap the default logical display from the display manager.
6775                    final DisplayInfo displayInfo = displayContent.getDisplayInfo();
6776                    DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId);
6777                    if (newDisplayInfo != null) {
6778                        displayInfo.copyFrom(newDisplayInfo);
6779                    }
6780                    displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
6781                    displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
6782                    displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
6783                    displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
6784                    displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
6785                    displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
6786                }
6787            }
6788        }
6789    }
6790
6791    public void systemReady() {
6792        mPolicy.systemReady();
6793    }
6794
6795    // TODO(multidisplay): Call isScreenOn for each display.
6796    private void sendScreenStatusToClientsLocked() {
6797        final boolean on = mPowerManager.isScreenOn();
6798        final int numDisplays = mDisplayContents.size();
6799        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
6800            final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
6801            final int numWindows = windows.size();
6802            for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
6803                try {
6804                    windows.get(winNdx).mClient.dispatchScreenState(on);
6805                } catch (RemoteException e) {
6806                    // Ignored
6807                }
6808            }
6809        }
6810    }
6811
6812    // -------------------------------------------------------------
6813    // Async Handler
6814    // -------------------------------------------------------------
6815
6816    final class H extends Handler {
6817        public static final int REPORT_FOCUS_CHANGE = 2;
6818        public static final int REPORT_LOSING_FOCUS = 3;
6819        public static final int DO_TRAVERSAL = 4;
6820        public static final int ADD_STARTING = 5;
6821        public static final int REMOVE_STARTING = 6;
6822        public static final int FINISHED_STARTING = 7;
6823        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
6824        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
6825        public static final int WINDOW_FREEZE_TIMEOUT = 11;
6826
6827        public static final int APP_TRANSITION_TIMEOUT = 13;
6828        public static final int PERSIST_ANIMATION_SCALE = 14;
6829        public static final int FORCE_GC = 15;
6830        public static final int ENABLE_SCREEN = 16;
6831        public static final int APP_FREEZE_TIMEOUT = 17;
6832        public static final int SEND_NEW_CONFIGURATION = 18;
6833        public static final int REPORT_WINDOWS_CHANGE = 19;
6834        public static final int DRAG_START_TIMEOUT = 20;
6835        public static final int DRAG_END_TIMEOUT = 21;
6836        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
6837        public static final int BOOT_TIMEOUT = 23;
6838        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
6839        public static final int SHOW_STRICT_MODE_VIOLATION = 25;
6840        public static final int DO_ANIMATION_CALLBACK = 26;
6841
6842        public static final int DO_DISPLAY_ADDED = 27;
6843        public static final int DO_DISPLAY_REMOVED = 28;
6844        public static final int DO_DISPLAY_CHANGED = 29;
6845
6846        public static final int CLIENT_FREEZE_TIMEOUT = 30;
6847
6848        @Override
6849        public void handleMessage(Message msg) {
6850            if (DEBUG_WINDOW_TRACE) {
6851                Slog.v(TAG, "handleMessage: entry what=" + msg.what);
6852            }
6853            switch (msg.what) {
6854                case REPORT_FOCUS_CHANGE: {
6855                    WindowState lastFocus;
6856                    WindowState newFocus;
6857
6858                    synchronized(mWindowMap) {
6859                        lastFocus = mLastFocus;
6860                        newFocus = mCurrentFocus;
6861                        if (lastFocus == newFocus) {
6862                            // Focus is not changing, so nothing to do.
6863                            return;
6864                        }
6865                        mLastFocus = newFocus;
6866                        //Slog.i(TAG, "Focus moving from " + lastFocus
6867                        //        + " to " + newFocus);
6868                        if (newFocus != null && lastFocus != null
6869                                && !newFocus.isDisplayedLw()) {
6870                            //Slog.i(TAG, "Delaying loss of focus...");
6871                            mLosingFocus.add(lastFocus);
6872                            lastFocus = null;
6873                        }
6874                    }
6875
6876                    if (lastFocus != newFocus) {
6877                        //System.out.println("Changing focus from " + lastFocus
6878                        //                   + " to " + newFocus);
6879                        if (newFocus != null) {
6880                            //Slog.i(TAG, "Gaining focus: " + newFocus);
6881                            newFocus.reportFocusChangedSerialized(true, mInTouchMode);
6882                            notifyFocusChanged();
6883                        }
6884
6885                        if (lastFocus != null) {
6886                            //Slog.i(TAG, "Losing focus: " + lastFocus);
6887                            lastFocus.reportFocusChangedSerialized(false, mInTouchMode);
6888                        }
6889                    }
6890                } break;
6891
6892                case REPORT_LOSING_FOCUS: {
6893                    ArrayList<WindowState> losers;
6894
6895                    synchronized(mWindowMap) {
6896                        losers = mLosingFocus;
6897                        mLosingFocus = new ArrayList<WindowState>();
6898                    }
6899
6900                    final int N = losers.size();
6901                    for (int i=0; i<N; i++) {
6902                        //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
6903                        losers.get(i).reportFocusChangedSerialized(false, mInTouchMode);
6904                    }
6905                } break;
6906
6907                case DO_TRAVERSAL: {
6908                    synchronized(mWindowMap) {
6909                        mTraversalScheduled = false;
6910                        performLayoutAndPlaceSurfacesLocked();
6911                    }
6912                } break;
6913
6914                case ADD_STARTING: {
6915                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6916                    final StartingData sd = wtoken.startingData;
6917
6918                    if (sd == null) {
6919                        // Animation has been canceled... do nothing.
6920                        return;
6921                    }
6922
6923                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
6924                            + wtoken + ": pkg=" + sd.pkg);
6925
6926                    View view = null;
6927                    try {
6928                        view = mPolicy.addStartingWindow(
6929                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
6930                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
6931                    } catch (Exception e) {
6932                        Slog.w(TAG, "Exception when adding starting window", e);
6933                    }
6934
6935                    if (view != null) {
6936                        boolean abort = false;
6937
6938                        synchronized(mWindowMap) {
6939                            if (wtoken.removed || wtoken.startingData == null) {
6940                                // If the window was successfully added, then
6941                                // we need to remove it.
6942                                if (wtoken.startingWindow != null) {
6943                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6944                                            "Aborted starting " + wtoken
6945                                            + ": removed=" + wtoken.removed
6946                                            + " startingData=" + wtoken.startingData);
6947                                    wtoken.startingWindow = null;
6948                                    wtoken.startingData = null;
6949                                    abort = true;
6950                                }
6951                            } else {
6952                                wtoken.startingView = view;
6953                            }
6954                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
6955                                    "Added starting " + wtoken
6956                                    + ": startingWindow="
6957                                    + wtoken.startingWindow + " startingView="
6958                                    + wtoken.startingView);
6959                        }
6960
6961                        if (abort) {
6962                            try {
6963                                mPolicy.removeStartingWindow(wtoken.token, view);
6964                            } catch (Exception e) {
6965                                Slog.w(TAG, "Exception when removing starting window", e);
6966                            }
6967                        }
6968                    }
6969                } break;
6970
6971                case REMOVE_STARTING: {
6972                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6973                    IBinder token = null;
6974                    View view = null;
6975                    synchronized (mWindowMap) {
6976                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
6977                                + wtoken + ": startingWindow="
6978                                + wtoken.startingWindow + " startingView="
6979                                + wtoken.startingView);
6980                        if (wtoken.startingWindow != null) {
6981                            view = wtoken.startingView;
6982                            token = wtoken.token;
6983                            wtoken.startingData = null;
6984                            wtoken.startingView = null;
6985                            wtoken.startingWindow = null;
6986                            wtoken.startingDisplayed = false;
6987                        }
6988                    }
6989                    if (view != null) {
6990                        try {
6991                            mPolicy.removeStartingWindow(token, view);
6992                        } catch (Exception e) {
6993                            Slog.w(TAG, "Exception when removing starting window", e);
6994                        }
6995                    }
6996                } break;
6997
6998                case FINISHED_STARTING: {
6999                    IBinder token = null;
7000                    View view = null;
7001                    while (true) {
7002                        synchronized (mWindowMap) {
7003                            final int N = mFinishedStarting.size();
7004                            if (N <= 0) {
7005                                break;
7006                            }
7007                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
7008
7009                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
7010                                    "Finished starting " + wtoken
7011                                    + ": startingWindow=" + wtoken.startingWindow
7012                                    + " startingView=" + wtoken.startingView);
7013
7014                            if (wtoken.startingWindow == null) {
7015                                continue;
7016                            }
7017
7018                            view = wtoken.startingView;
7019                            token = wtoken.token;
7020                            wtoken.startingData = null;
7021                            wtoken.startingView = null;
7022                            wtoken.startingWindow = null;
7023                            wtoken.startingDisplayed = false;
7024                        }
7025
7026                        try {
7027                            mPolicy.removeStartingWindow(token, view);
7028                        } catch (Exception e) {
7029                            Slog.w(TAG, "Exception when removing starting window", e);
7030                        }
7031                    }
7032                } break;
7033
7034                case REPORT_APPLICATION_TOKEN_DRAWN: {
7035                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7036
7037                    try {
7038                        if (DEBUG_VISIBILITY) Slog.v(
7039                                TAG, "Reporting drawn in " + wtoken);
7040                        wtoken.appToken.windowsDrawn();
7041                    } catch (RemoteException ex) {
7042                    }
7043                } break;
7044
7045                case REPORT_APPLICATION_TOKEN_WINDOWS: {
7046                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
7047
7048                    boolean nowVisible = msg.arg1 != 0;
7049                    boolean nowGone = msg.arg2 != 0;
7050
7051                    try {
7052                        if (DEBUG_VISIBILITY) Slog.v(
7053                                TAG, "Reporting visible in " + wtoken
7054                                + " visible=" + nowVisible
7055                                + " gone=" + nowGone);
7056                        if (nowVisible) {
7057                            wtoken.appToken.windowsVisible();
7058                        } else {
7059                            wtoken.appToken.windowsGone();
7060                        }
7061                    } catch (RemoteException ex) {
7062                    }
7063                } break;
7064
7065                case WINDOW_FREEZE_TIMEOUT: {
7066                    // TODO(multidisplay): Can non-default displays rotate?
7067                    synchronized (mWindowMap) {
7068                        Slog.w(TAG, "Window freeze timeout expired.");
7069                        final WindowList windows = getDefaultWindowListLocked();
7070                        int i = windows.size();
7071                        while (i > 0) {
7072                            i--;
7073                            WindowState w = windows.get(i);
7074                            if (w.mOrientationChanging) {
7075                                w.mOrientationChanging = false;
7076                                w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
7077                                        - mDisplayFreezeTime);
7078                                Slog.w(TAG, "Force clearing orientation change: " + w);
7079                            }
7080                        }
7081                        performLayoutAndPlaceSurfacesLocked();
7082                    }
7083                    break;
7084                }
7085
7086                case APP_TRANSITION_TIMEOUT: {
7087                    synchronized (mWindowMap) {
7088                        if (mAppTransition.isTransitionSet()) {
7089                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** APP TRANSITION TIMEOUT");
7090                            mAppTransition.setTimeout();
7091                            mAnimatingAppTokens.clear();
7092                            mAnimatingAppTokens.addAll(mAppTokens);
7093                            performLayoutAndPlaceSurfacesLocked();
7094                        }
7095                    }
7096                    break;
7097                }
7098
7099                case PERSIST_ANIMATION_SCALE: {
7100                    Settings.Global.putFloat(mContext.getContentResolver(),
7101                            Settings.Global.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
7102                    Settings.Global.putFloat(mContext.getContentResolver(),
7103                            Settings.Global.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
7104                    Settings.Global.putFloat(mContext.getContentResolver(),
7105                            Settings.Global.ANIMATOR_DURATION_SCALE, mAnimatorDurationScale);
7106                    break;
7107                }
7108
7109                case FORCE_GC: {
7110                    synchronized (mWindowMap) {
7111                        // Since we're holding both mWindowMap and mAnimator we don't need to
7112                        // hold mAnimator.mLayoutToAnim.
7113                        if (mAnimator.mAnimating || mAnimationScheduled) {
7114                            // If we are animating, don't do the gc now but
7115                            // delay a bit so we don't interrupt the animation.
7116                            sendEmptyMessageDelayed(H.FORCE_GC, 2000);
7117                            return;
7118                        }
7119                        // If we are currently rotating the display, it will
7120                        // schedule a new message when done.
7121                        if (mDisplayFrozen) {
7122                            return;
7123                        }
7124                    }
7125                    Runtime.getRuntime().gc();
7126                    break;
7127                }
7128
7129                case ENABLE_SCREEN: {
7130                    performEnableScreen();
7131                    break;
7132                }
7133
7134                case APP_FREEZE_TIMEOUT: {
7135                    synchronized (mWindowMap) {
7136                        Slog.w(TAG, "App freeze timeout expired.");
7137                        int i = mAppTokens.size();
7138                        while (i > 0) {
7139                            i--;
7140                            AppWindowToken tok = mAppTokens.get(i);
7141                            if (tok.mAppAnimator.freezingScreen) {
7142                                Slog.w(TAG, "Force clearing freeze: " + tok);
7143                                unsetAppFreezingScreenLocked(tok, true, true);
7144                            }
7145                        }
7146                    }
7147                    break;
7148                }
7149
7150                case CLIENT_FREEZE_TIMEOUT: {
7151                    synchronized (mWindowMap) {
7152                        if (mClientFreezingScreen) {
7153                            mClientFreezingScreen = false;
7154                            mLastFinishedFreezeSource = "client-timeout";
7155                            stopFreezingDisplayLocked();
7156                        }
7157                    }
7158                    break;
7159                }
7160
7161                case SEND_NEW_CONFIGURATION: {
7162                    removeMessages(SEND_NEW_CONFIGURATION);
7163                    sendNewConfiguration();
7164                    break;
7165                }
7166
7167                case REPORT_WINDOWS_CHANGE: {
7168                    if (mWindowsChanged) {
7169                        synchronized (mWindowMap) {
7170                            mWindowsChanged = false;
7171                        }
7172                        notifyWindowsChanged();
7173                    }
7174                    break;
7175                }
7176
7177                case DRAG_START_TIMEOUT: {
7178                    IBinder win = (IBinder)msg.obj;
7179                    if (DEBUG_DRAG) {
7180                        Slog.w(TAG, "Timeout starting drag by win " + win);
7181                    }
7182                    synchronized (mWindowMap) {
7183                        // !!! TODO: ANR the app that has failed to start the drag in time
7184                        if (mDragState != null) {
7185                            mDragState.unregister();
7186                            mInputMonitor.updateInputWindowsLw(true /*force*/);
7187                            mDragState.reset();
7188                            mDragState = null;
7189                        }
7190                    }
7191                    break;
7192                }
7193
7194                case DRAG_END_TIMEOUT: {
7195                    IBinder win = (IBinder)msg.obj;
7196                    if (DEBUG_DRAG) {
7197                        Slog.w(TAG, "Timeout ending drag to win " + win);
7198                    }
7199                    synchronized (mWindowMap) {
7200                        // !!! TODO: ANR the drag-receiving app
7201                        if (mDragState != null) {
7202                            mDragState.mDragResult = false;
7203                            mDragState.endDragLw();
7204                        }
7205                    }
7206                    break;
7207                }
7208
7209                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
7210                    notifyHardKeyboardStatusChange();
7211                    break;
7212                }
7213
7214                case BOOT_TIMEOUT: {
7215                    performBootTimeout();
7216                    break;
7217                }
7218
7219                case WAITING_FOR_DRAWN_TIMEOUT: {
7220                    Pair<WindowState, IRemoteCallback> pair;
7221                    synchronized (mWindowMap) {
7222                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
7223                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
7224                        if (!mWaitingForDrawn.remove(pair)) {
7225                            return;
7226                        }
7227                    }
7228                    try {
7229                        pair.second.sendResult(null);
7230                    } catch (RemoteException e) {
7231                    }
7232                    break;
7233                }
7234
7235                case SHOW_STRICT_MODE_VIOLATION: {
7236                    showStrictModeViolation(msg.arg1, msg.arg2);
7237                    break;
7238                }
7239
7240                case DO_ANIMATION_CALLBACK: {
7241                    try {
7242                        ((IRemoteCallback)msg.obj).sendResult(null);
7243                    } catch (RemoteException e) {
7244                    }
7245                    break;
7246                }
7247
7248                case DO_DISPLAY_ADDED:
7249                    synchronized (mWindowMap) {
7250                        handleDisplayAddedLocked(msg.arg1);
7251                    }
7252                    break;
7253
7254                case DO_DISPLAY_REMOVED:
7255                    synchronized (mWindowMap) {
7256                        handleDisplayRemovedLocked(msg.arg1);
7257                    }
7258                    break;
7259
7260                case DO_DISPLAY_CHANGED:
7261                    synchronized (mWindowMap) {
7262                        handleDisplayChangedLocked(msg.arg1);
7263                    }
7264                    break;
7265            }
7266            if (DEBUG_WINDOW_TRACE) {
7267                Slog.v(TAG, "handleMessage: exit");
7268            }
7269        }
7270    }
7271
7272    // -------------------------------------------------------------
7273    // IWindowManager API
7274    // -------------------------------------------------------------
7275
7276    @Override
7277    public IWindowSession openSession(IInputMethodClient client,
7278            IInputContext inputContext) {
7279        if (client == null) throw new IllegalArgumentException("null client");
7280        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
7281        Session session = new Session(this, client, inputContext);
7282        return session;
7283    }
7284
7285    @Override
7286    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
7287        synchronized (mWindowMap) {
7288            // The focus for the client is the window immediately below
7289            // where we would place the input method window.
7290            int idx = findDesiredInputMethodWindowIndexLocked(false);
7291            if (idx > 0) {
7292                // TODO(multidisplay): IMEs are only supported on the default display.
7293                WindowState imFocus = getDefaultWindowListLocked().get(idx-1);
7294                if (DEBUG_INPUT_METHOD) {
7295                    Slog.i(TAG, "Desired input method target: " + imFocus);
7296                    Slog.i(TAG, "Current focus: " + mCurrentFocus);
7297                    Slog.i(TAG, "Last focus: " + mLastFocus);
7298                }
7299                if (imFocus != null) {
7300                    // This may be a starting window, in which case we still want
7301                    // to count it as okay.
7302                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
7303                            && imFocus.mAppToken != null) {
7304                        // The client has definitely started, so it really should
7305                        // have a window in this app token.  Let's look for it.
7306                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
7307                            WindowState w = imFocus.mAppToken.windows.get(i);
7308                            if (w != imFocus) {
7309                                Log.i(TAG, "Switching to real app window: " + w);
7310                                imFocus = w;
7311                                break;
7312                            }
7313                        }
7314                    }
7315                    if (DEBUG_INPUT_METHOD) {
7316                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
7317                        if (imFocus.mSession.mClient != null) {
7318                            Slog.i(TAG, "IM target client binder: "
7319                                    + imFocus.mSession.mClient.asBinder());
7320                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
7321                        }
7322                    }
7323                    if (imFocus.mSession.mClient != null &&
7324                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
7325                        return true;
7326                    }
7327                }
7328            }
7329
7330            // Okay, how about this...  what is the current focus?
7331            // It seems in some cases we may not have moved the IM
7332            // target window, such as when it was in a pop-up window,
7333            // so let's also look at the current focus.  (An example:
7334            // go to Gmail, start searching so the keyboard goes up,
7335            // press home.  Sometimes the IME won't go down.)
7336            // Would be nice to fix this more correctly, but it's
7337            // way at the end of a release, and this should be good enough.
7338            if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null
7339                    && mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7340                return true;
7341            }
7342        }
7343        return false;
7344    }
7345
7346    @Override
7347    public void getInitialDisplaySize(int displayId, Point size) {
7348        synchronized (mWindowMap) {
7349            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7350            if (displayContent != null) {
7351                synchronized(displayContent.mDisplaySizeLock) {
7352                    size.x = displayContent.mInitialDisplayWidth;
7353                    size.y = displayContent.mInitialDisplayHeight;
7354                }
7355            }
7356        }
7357    }
7358
7359    @Override
7360    public void getBaseDisplaySize(int displayId, Point size) {
7361        synchronized (mWindowMap) {
7362            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7363            if (displayContent != null) {
7364                synchronized(displayContent.mDisplaySizeLock) {
7365                    size.x = displayContent.mBaseDisplayWidth;
7366                    size.y = displayContent.mBaseDisplayHeight;
7367                }
7368            }
7369        }
7370    }
7371
7372    @Override
7373    public void setForcedDisplaySize(int displayId, int width, int height) {
7374        if (mContext.checkCallingOrSelfPermission(
7375                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7376                PackageManager.PERMISSION_GRANTED) {
7377            throw new SecurityException("Must hold permission " +
7378                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7379        }
7380        if (displayId != Display.DEFAULT_DISPLAY) {
7381            throw new IllegalArgumentException("Can only set the default display");
7382        }
7383        synchronized(mWindowMap) {
7384            // Set some sort of reasonable bounds on the size of the display that we
7385            // will try to emulate.
7386            final int MIN_WIDTH = 200;
7387            final int MIN_HEIGHT = 200;
7388            final int MAX_SCALE = 2;
7389            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7390            if (displayContent != null) {
7391                width = Math.min(Math.max(width, MIN_WIDTH),
7392                        displayContent.mInitialDisplayWidth * MAX_SCALE);
7393                height = Math.min(Math.max(height, MIN_HEIGHT),
7394                        displayContent.mInitialDisplayHeight * MAX_SCALE);
7395                setForcedDisplaySizeLocked(displayContent, width, height);
7396                Settings.Global.putString(mContext.getContentResolver(),
7397                        Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
7398            }
7399        }
7400    }
7401
7402    private void readForcedDisplaySizeAndDensityLocked(final DisplayContent displayContent) {
7403        final String sizeStr = Settings.Global.getString(mContext.getContentResolver(),
7404                Settings.Global.DISPLAY_SIZE_FORCED);
7405        if (sizeStr != null && sizeStr.length() > 0) {
7406            final int pos = sizeStr.indexOf(',');
7407            if (pos > 0 && sizeStr.lastIndexOf(',') == pos) {
7408                int width, height;
7409                try {
7410                    width = Integer.parseInt(sizeStr.substring(0, pos));
7411                    height = Integer.parseInt(sizeStr.substring(pos+1));
7412                    synchronized(displayContent.mDisplaySizeLock) {
7413                        if (displayContent.mBaseDisplayWidth != width
7414                                || displayContent.mBaseDisplayHeight != height) {
7415                            Slog.i(TAG, "FORCED DISPLAY SIZE: " + width + "x" + height);
7416                            displayContent.mBaseDisplayWidth = width;
7417                            displayContent.mBaseDisplayHeight = height;
7418                        }
7419                    }
7420                } catch (NumberFormatException ex) {
7421                }
7422            }
7423        }
7424        final String densityStr = Settings.Global.getString(mContext.getContentResolver(),
7425                Settings.Global.DISPLAY_DENSITY_FORCED);
7426        if (densityStr != null && densityStr.length() > 0) {
7427            int density;
7428            try {
7429                density = Integer.parseInt(densityStr);
7430                synchronized(displayContent.mDisplaySizeLock) {
7431                    if (displayContent.mBaseDisplayDensity != density) {
7432                        Slog.i(TAG, "FORCED DISPLAY DENSITY: " + density);
7433                        displayContent.mBaseDisplayDensity = density;
7434                    }
7435                }
7436            } catch (NumberFormatException ex) {
7437            }
7438        }
7439    }
7440
7441    // displayContent must not be null
7442    private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
7443        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7444
7445        synchronized(displayContent.mDisplaySizeLock) {
7446            displayContent.mBaseDisplayWidth = width;
7447            displayContent.mBaseDisplayHeight = height;
7448        }
7449        reconfigureDisplayLocked(displayContent);
7450    }
7451
7452    @Override
7453    public void clearForcedDisplaySize(int displayId) {
7454        if (mContext.checkCallingOrSelfPermission(
7455                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7456                PackageManager.PERMISSION_GRANTED) {
7457            throw new SecurityException("Must hold permission " +
7458                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7459        }
7460        if (displayId != Display.DEFAULT_DISPLAY) {
7461            throw new IllegalArgumentException("Can only set the default display");
7462        }
7463        synchronized(mWindowMap) {
7464            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7465            if (displayContent != null) {
7466                setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
7467                        displayContent.mInitialDisplayHeight);
7468                Settings.Global.putString(mContext.getContentResolver(),
7469                        Settings.Global.DISPLAY_SIZE_FORCED, "");
7470            }
7471        }
7472    }
7473
7474    @Override
7475    public int getInitialDisplayDensity(int displayId) {
7476        synchronized (mWindowMap) {
7477            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7478            if (displayContent != null) {
7479                synchronized(displayContent.mDisplaySizeLock) {
7480                    return displayContent.mInitialDisplayDensity;
7481                }
7482            }
7483        }
7484        return -1;
7485    }
7486
7487    @Override
7488    public int getBaseDisplayDensity(int displayId) {
7489        synchronized (mWindowMap) {
7490            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7491            if (displayContent != null) {
7492                synchronized(displayContent.mDisplaySizeLock) {
7493                    return displayContent.mBaseDisplayDensity;
7494                }
7495            }
7496        }
7497        return -1;
7498    }
7499
7500    @Override
7501    public void setForcedDisplayDensity(int displayId, int density) {
7502        if (mContext.checkCallingOrSelfPermission(
7503                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7504                PackageManager.PERMISSION_GRANTED) {
7505            throw new SecurityException("Must hold permission " +
7506                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7507        }
7508        if (displayId != Display.DEFAULT_DISPLAY) {
7509            throw new IllegalArgumentException("Can only set the default display");
7510        }
7511        synchronized(mWindowMap) {
7512            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7513            if (displayContent != null) {
7514                setForcedDisplayDensityLocked(displayContent, density);
7515                Settings.Global.putString(mContext.getContentResolver(),
7516                        Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
7517            }
7518        }
7519    }
7520
7521    // displayContent must not be null
7522    private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) {
7523        Slog.i(TAG, "Using new display density: " + density);
7524
7525        synchronized(displayContent.mDisplaySizeLock) {
7526            displayContent.mBaseDisplayDensity = density;
7527        }
7528        reconfigureDisplayLocked(displayContent);
7529    }
7530
7531    @Override
7532    public void clearForcedDisplayDensity(int displayId) {
7533        if (mContext.checkCallingOrSelfPermission(
7534                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7535                PackageManager.PERMISSION_GRANTED) {
7536            throw new SecurityException("Must hold permission " +
7537                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7538        }
7539        if (displayId != Display.DEFAULT_DISPLAY) {
7540            throw new IllegalArgumentException("Can only set the default display");
7541        }
7542        synchronized(mWindowMap) {
7543            final DisplayContent displayContent = getDisplayContentLocked(displayId);
7544            if (displayContent != null) {
7545                setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity);
7546                Settings.Global.putString(mContext.getContentResolver(),
7547                        Settings.Global.DISPLAY_DENSITY_FORCED, "");
7548            }
7549        }
7550    }
7551
7552    // displayContent must not be null
7553    private void reconfigureDisplayLocked(DisplayContent displayContent) {
7554        // TODO: Multidisplay: for now only use with default display.
7555        mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
7556                displayContent.mBaseDisplayWidth,
7557                displayContent.mBaseDisplayHeight,
7558                displayContent.mBaseDisplayDensity);
7559
7560        displayContent.layoutNeeded = true;
7561
7562        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7563        mTempConfiguration.setToDefaults();
7564        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7565        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7566            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7567                configChanged = true;
7568            }
7569        }
7570
7571        if (configChanged) {
7572            mWaitingForConfig = true;
7573            startFreezingDisplayLocked(false, 0, 0);
7574            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7575        }
7576
7577        performLayoutAndPlaceSurfacesLocked();
7578    }
7579
7580    @Override
7581    public void setOverscan(int displayId, int left, int top, int right, int bottom) {
7582        if (mContext.checkCallingOrSelfPermission(
7583                android.Manifest.permission.WRITE_SECURE_SETTINGS) !=
7584                PackageManager.PERMISSION_GRANTED) {
7585            throw new SecurityException("Must hold permission " +
7586                    android.Manifest.permission.WRITE_SECURE_SETTINGS);
7587        }
7588        synchronized(mWindowMap) {
7589            DisplayContent displayContent = getDisplayContentLocked(displayId);
7590            if (displayContent != null) {
7591                mDisplayManagerService.setOverscan(displayId, left, top, right, bottom);
7592                final DisplayInfo displayInfo = displayContent.getDisplayInfo();
7593                synchronized(displayContent.mDisplaySizeLock) {
7594                    displayInfo.overscanLeft = left;
7595                    displayInfo.overscanTop = top;
7596                    displayInfo.overscanRight = right;
7597                    displayInfo.overscanBottom = bottom;
7598                }
7599                mPolicy.setDisplayOverscan(displayContent.getDisplay(), left, top, right, bottom);
7600                displayContent.layoutNeeded = true;
7601                mDisplaySettings.setOverscanLocked(displayInfo.name, left, top, right, bottom);
7602                mDisplaySettings.writeSettingsLocked();
7603                performLayoutAndPlaceSurfacesLocked();
7604            }
7605        }
7606    }
7607
7608    @Override
7609    public boolean hasSystemNavBar() {
7610        return mPolicy.hasSystemNavBar();
7611    }
7612
7613    // -------------------------------------------------------------
7614    // Internals
7615    // -------------------------------------------------------------
7616
7617    final WindowState windowForClientLocked(Session session, IWindow client,
7618            boolean throwOnError) {
7619        return windowForClientLocked(session, client.asBinder(), throwOnError);
7620    }
7621
7622    final WindowState windowForClientLocked(Session session, IBinder client,
7623            boolean throwOnError) {
7624        WindowState win = mWindowMap.get(client);
7625        if (localLOGV) Slog.v(
7626            TAG, "Looking up client " + client + ": " + win);
7627        if (win == null) {
7628            RuntimeException ex = new IllegalArgumentException(
7629                    "Requested window " + client + " does not exist");
7630            if (throwOnError) {
7631                throw ex;
7632            }
7633            Slog.w(TAG, "Failed looking up window", ex);
7634            return null;
7635        }
7636        if (session != null && win.mSession != session) {
7637            RuntimeException ex = new IllegalArgumentException(
7638                    "Requested window " + client + " is in session " +
7639                    win.mSession + ", not " + session);
7640            if (throwOnError) {
7641                throw ex;
7642            }
7643            Slog.w(TAG, "Failed looking up window", ex);
7644            return null;
7645        }
7646
7647        return win;
7648    }
7649
7650    final void rebuildAppWindowListLocked() {
7651        final int numDisplays = mDisplayContents.size();
7652        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
7653            rebuildAppWindowListLocked(mDisplayContents.valueAt(displayNdx));
7654        }
7655    }
7656
7657    private void rebuildAppWindowListLocked(final DisplayContent displayContent) {
7658        final WindowList windows = displayContent.getWindowList();
7659        int NW = windows.size();
7660        int i;
7661        int lastBelow = -1;
7662        int numRemoved = 0;
7663
7664        if (mRebuildTmp.length < NW) {
7665            mRebuildTmp = new WindowState[NW+10];
7666        }
7667
7668        // First remove all existing app windows.
7669        i=0;
7670        while (i < NW) {
7671            WindowState w = windows.get(i);
7672            if (w.mAppToken != null) {
7673                WindowState win = windows.remove(i);
7674                win.mRebuilding = true;
7675                mRebuildTmp[numRemoved] = win;
7676                mWindowsChanged = true;
7677                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
7678                        "Rebuild removing window: " + win);
7679                NW--;
7680                numRemoved++;
7681                continue;
7682            } else if (lastBelow == i-1) {
7683                if (w.mAttrs.type == TYPE_WALLPAPER || w.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
7684                    lastBelow = i;
7685                }
7686            }
7687            i++;
7688        }
7689
7690        // Keep whatever windows were below the app windows still below,
7691        // by skipping them.
7692        lastBelow++;
7693        i = lastBelow;
7694
7695        // First add all of the exiting app tokens...  these are no longer
7696        // in the main app list, but still have windows shown.  We put them
7697        // in the back because now that the animation is over we no longer
7698        // will care about them.
7699        int NT = mExitingAppTokens.size();
7700        for (int j=0; j<NT; j++) {
7701            i = reAddAppWindowsLocked(displayContent, i, mExitingAppTokens.get(j));
7702        }
7703
7704        // And add in the still active app tokens in Z order.
7705        NT = mAnimatingAppTokens.size();
7706        for (int j=0; j<NT; j++) {
7707            i = reAddAppWindowsLocked(displayContent, i, mAnimatingAppTokens.get(j));
7708        }
7709
7710        i -= lastBelow;
7711        if (i != numRemoved) {
7712            Slog.w(TAG, "Rebuild removed " + numRemoved
7713                    + " windows but added " + i);
7714            for (i=0; i<numRemoved; i++) {
7715                WindowState ws = mRebuildTmp[i];
7716                if (ws.mRebuilding) {
7717                    StringWriter sw = new StringWriter();
7718                    PrintWriter pw = new PrintWriter(sw);
7719                    ws.dump(pw, "", true);
7720                    pw.flush();
7721                    Slog.w(TAG, "This window was lost: " + ws);
7722                    Slog.w(TAG, sw.toString());
7723                    ws.mWinAnimator.destroySurfaceLocked();
7724                }
7725            }
7726            Slog.w(TAG, "Current app token list:");
7727            dumpAnimatingAppTokensLocked();
7728            Slog.w(TAG, "Final window list:");
7729            dumpWindowsLocked();
7730        }
7731    }
7732
7733    private final void assignLayersLocked(WindowList windows) {
7734        int N = windows.size();
7735        int curBaseLayer = 0;
7736        int curLayer = 0;
7737        int i;
7738
7739        if (DEBUG_LAYERS) {
7740            RuntimeException here = new RuntimeException("here");
7741            here.fillInStackTrace();
7742            Slog.v(TAG, "Assigning layers", here);
7743        }
7744
7745        boolean anyLayerChanged = false;
7746
7747        for (i=0; i<N; i++) {
7748            final WindowState w = windows.get(i);
7749            final WindowStateAnimator winAnimator = w.mWinAnimator;
7750            boolean layerChanged = false;
7751            int oldLayer = w.mLayer;
7752            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
7753                    || (i > 0 && w.mIsWallpaper)) {
7754                curLayer += WINDOW_LAYER_MULTIPLIER;
7755                w.mLayer = curLayer;
7756            } else {
7757                curBaseLayer = curLayer = w.mBaseLayer;
7758                w.mLayer = curLayer;
7759            }
7760            if (w.mLayer != oldLayer) {
7761                layerChanged = true;
7762                anyLayerChanged = true;
7763            }
7764            oldLayer = winAnimator.mAnimLayer;
7765            if (w.mTargetAppToken != null) {
7766                winAnimator.mAnimLayer =
7767                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
7768            } else if (w.mAppToken != null) {
7769                winAnimator.mAnimLayer =
7770                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
7771            } else {
7772                winAnimator.mAnimLayer = w.mLayer;
7773            }
7774            if (w.mIsImWindow) {
7775                winAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
7776            } else if (w.mIsWallpaper) {
7777                winAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
7778            }
7779            if (winAnimator.mAnimLayer != oldLayer) {
7780                layerChanged = true;
7781                anyLayerChanged = true;
7782            }
7783            if (layerChanged && mAnimator.isDimmingLocked(winAnimator)) {
7784                // Force an animation pass just to update the mDimAnimator layer.
7785                scheduleAnimationLocked();
7786            }
7787            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
7788                    + "mBase=" + w.mBaseLayer
7789                    + " mLayer=" + w.mLayer
7790                    + (w.mAppToken == null ?
7791                            "" : " mAppLayer=" + w.mAppToken.mAppAnimator.animLayerAdjustment)
7792                    + " =mAnimLayer=" + winAnimator.mAnimLayer);
7793            //System.out.println(
7794            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7795        }
7796
7797        //TODO (multidisplay): Magnification is supported only for the default display.
7798        if (mDisplayMagnifier != null && anyLayerChanged
7799                && windows.get(windows.size() - 1).getDisplayId() == Display.DEFAULT_DISPLAY) {
7800            mDisplayMagnifier.onWindowLayersChangedLocked();
7801        }
7802    }
7803
7804    private final void performLayoutAndPlaceSurfacesLocked() {
7805        int loopCount = 6;
7806        do {
7807            mTraversalScheduled = false;
7808            performLayoutAndPlaceSurfacesLockedLoop();
7809            mH.removeMessages(H.DO_TRAVERSAL);
7810            loopCount--;
7811        } while (mTraversalScheduled && loopCount > 0);
7812        mInnerFields.mWallpaperActionPending = false;
7813    }
7814
7815    private boolean mInLayout = false;
7816    private final void performLayoutAndPlaceSurfacesLockedLoop() {
7817        if (mInLayout) {
7818            if (DEBUG) {
7819                throw new RuntimeException("Recursive call!");
7820            }
7821            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
7822                    + Debug.getCallers(3));
7823            return;
7824        }
7825
7826        if (mWaitingForConfig) {
7827            // Our configuration has changed (most likely rotation), but we
7828            // don't yet have the complete configuration to report to
7829            // applications.  Don't do any window layout until we have it.
7830            return;
7831        }
7832
7833        if (!mDisplayReady) {
7834            // Not yet initialized, nothing to do.
7835            return;
7836        }
7837
7838        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
7839        mInLayout = true;
7840        boolean recoveringMemory = false;
7841
7842        try {
7843            if (mForceRemoves != null) {
7844                recoveringMemory = true;
7845                // Wait a little bit for things to settle down, and off we go.
7846                for (int i=0; i<mForceRemoves.size(); i++) {
7847                    WindowState ws = mForceRemoves.get(i);
7848                    Slog.i(TAG, "Force removing: " + ws);
7849                    removeWindowInnerLocked(ws.mSession, ws);
7850                }
7851                mForceRemoves = null;
7852                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
7853                Object tmp = new Object();
7854                synchronized (tmp) {
7855                    try {
7856                        tmp.wait(250);
7857                    } catch (InterruptedException e) {
7858                    }
7859                }
7860            }
7861        } catch (RuntimeException e) {
7862            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
7863        }
7864
7865        try {
7866            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
7867
7868            mInLayout = false;
7869
7870            if (needsLayout()) {
7871                if (++mLayoutRepeatCount < 6) {
7872                    requestTraversalLocked();
7873                } else {
7874                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
7875                    mLayoutRepeatCount = 0;
7876                }
7877            } else {
7878                mLayoutRepeatCount = 0;
7879            }
7880
7881            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
7882                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
7883                mH.sendEmptyMessage(H.REPORT_WINDOWS_CHANGE);
7884            }
7885        } catch (RuntimeException e) {
7886            mInLayout = false;
7887            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
7888        }
7889
7890        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
7891    }
7892
7893    private final void performLayoutLockedInner(final DisplayContent displayContent,
7894                                    boolean initial, boolean updateInputWindows) {
7895        if (!displayContent.layoutNeeded) {
7896            return;
7897        }
7898        displayContent.layoutNeeded = false;
7899        WindowList windows = displayContent.getWindowList();
7900        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
7901
7902        DisplayInfo displayInfo = displayContent.getDisplayInfo();
7903        final int dw = displayInfo.logicalWidth;
7904        final int dh = displayInfo.logicalHeight;
7905
7906        final int NFW = mFakeWindows.size();
7907        for (int i=0; i<NFW; i++) {
7908            mFakeWindows.get(i).layout(dw, dh);
7909        }
7910
7911        final int N = windows.size();
7912        int i;
7913
7914        if (DEBUG_LAYOUT) {
7915            Slog.v(TAG, "-------------------------------------");
7916            Slog.v(TAG, "performLayout: needed="
7917                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
7918        }
7919
7920        WindowStateAnimator universeBackground = null;
7921
7922        mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
7923        if (isDefaultDisplay) {
7924            // Not needed on non-default displays.
7925            mSystemDecorLayer = mPolicy.getSystemDecorRectLw(mSystemDecorRect);
7926            mScreenRect.set(0, 0, dw, dh);
7927        }
7928
7929        int seq = mLayoutSeq+1;
7930        if (seq < 0) seq = 0;
7931        mLayoutSeq = seq;
7932
7933        boolean behindDream = false;
7934
7935        // First perform layout of any root windows (not attached
7936        // to another window).
7937        int topAttached = -1;
7938        for (i = N-1; i >= 0; i--) {
7939            final WindowState win = windows.get(i);
7940
7941            // Don't do layout of a window if it is not visible, or
7942            // soon won't be visible, to avoid wasting time and funky
7943            // changes while a window is animating away.
7944            final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
7945                    || win.isGoneForLayoutLw();
7946
7947            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
7948                Slog.v(TAG, "1ST PASS " + win
7949                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
7950                        + " mLayoutAttached=" + win.mLayoutAttached
7951                        + " screen changed=" + win.isConfigChanged());
7952                final AppWindowToken atoken = win.mAppToken;
7953                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
7954                        + win.mViewVisibility + " mRelayoutCalled="
7955                        + win.mRelayoutCalled + " hidden="
7956                        + win.mRootToken.hidden + " hiddenRequested="
7957                        + (atoken != null && atoken.hiddenRequested)
7958                        + " mAttachedHidden=" + win.mAttachedHidden);
7959                else Slog.v(TAG, "  VIS: mViewVisibility="
7960                        + win.mViewVisibility + " mRelayoutCalled="
7961                        + win.mRelayoutCalled + " hidden="
7962                        + win.mRootToken.hidden + " hiddenRequested="
7963                        + (atoken != null && atoken.hiddenRequested)
7964                        + " mAttachedHidden=" + win.mAttachedHidden);
7965            }
7966
7967            // If this view is GONE, then skip it -- keep the current
7968            // frame, and let the caller know so they can ignore it
7969            // if they want.  (We do the normal layout for INVISIBLE
7970            // windows, since that means "perform layout as normal,
7971            // just don't display").
7972            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
7973                    || (win.mAttrs.type == TYPE_KEYGUARD && win.isConfigChanged())
7974                    || win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
7975                if (!win.mLayoutAttached) {
7976                    if (initial) {
7977                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7978                        win.mContentChanged = false;
7979                    }
7980                    if (win.mAttrs.type == TYPE_DREAM) {
7981                        // Don't layout windows behind a dream, so that if it
7982                        // does stuff like hide the status bar we won't get a
7983                        // bad transition when it goes away.
7984                        behindDream = true;
7985                    }
7986                    win.mLayoutNeeded = false;
7987                    win.prelayout();
7988                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
7989                    win.mLayoutSeq = seq;
7990                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7991                            + win.mFrame + " mContainingFrame="
7992                            + win.mContainingFrame + " mDisplayFrame="
7993                            + win.mDisplayFrame);
7994                } else {
7995                    if (topAttached < 0) topAttached = i;
7996                }
7997            }
7998            if (win.mViewVisibility == View.VISIBLE
7999                    && win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND
8000                    && universeBackground == null) {
8001                universeBackground = win.mWinAnimator;
8002            }
8003        }
8004
8005        if (mAnimator.mUniverseBackground  != universeBackground) {
8006            mFocusMayChange = true;
8007            mAnimator.mUniverseBackground = universeBackground;
8008        }
8009
8010        boolean attachedBehindDream = false;
8011
8012        // Now perform layout of attached windows, which usually
8013        // depend on the position of the window they are attached to.
8014        // XXX does not deal with windows that are attached to windows
8015        // that are themselves attached.
8016        for (i = topAttached; i >= 0; i--) {
8017            final WindowState win = windows.get(i);
8018
8019            if (win.mLayoutAttached) {
8020                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
8021                        + " mHaveFrame=" + win.mHaveFrame
8022                        + " mViewVisibility=" + win.mViewVisibility
8023                        + " mRelayoutCalled=" + win.mRelayoutCalled);
8024                // If this view is GONE, then skip it -- keep the current
8025                // frame, and let the caller know so they can ignore it
8026                // if they want.  (We do the normal layout for INVISIBLE
8027                // windows, since that means "perform layout as normal,
8028                // just don't display").
8029                if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
8030                    continue;
8031                }
8032                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
8033                        || !win.mHaveFrame || win.mLayoutNeeded) {
8034                    if (initial) {
8035                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
8036                        win.mContentChanged = false;
8037                    }
8038                    win.mLayoutNeeded = false;
8039                    win.prelayout();
8040                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
8041                    win.mLayoutSeq = seq;
8042                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
8043                            + win.mFrame + " mContainingFrame="
8044                            + win.mContainingFrame + " mDisplayFrame="
8045                            + win.mDisplayFrame);
8046                }
8047            } else if (win.mAttrs.type == TYPE_DREAM) {
8048                // Don't layout windows behind a dream, so that if it
8049                // does stuff like hide the status bar we won't get a
8050                // bad transition when it goes away.
8051                attachedBehindDream = behindDream;
8052            }
8053        }
8054
8055        // Window frames may have changed.  Tell the input dispatcher about it.
8056        mInputMonitor.setUpdateInputWindowsNeededLw();
8057        if (updateInputWindows) {
8058            mInputMonitor.updateInputWindowsLw(false /*force*/);
8059        }
8060
8061        mPolicy.finishLayoutLw();
8062    }
8063
8064    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
8065        // If the screen is currently frozen or off, then keep
8066        // it frozen/off until this window draws at its new
8067        // orientation.
8068        if (!okToDisplay()) {
8069            if (DEBUG_ORIENTATION) Slog.v(TAG,
8070                    "Changing surface while display frozen: " + w);
8071            w.mOrientationChanging = true;
8072            w.mLastFreezeDuration = 0;
8073            mInnerFields.mOrientationChangeComplete = false;
8074            if (!mWindowsFreezingScreen) {
8075                mWindowsFreezingScreen = true;
8076                // XXX should probably keep timeout from
8077                // when we first froze the display.
8078                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8079                mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT,
8080                        WINDOW_FREEZE_TIMEOUT_DURATION);
8081            }
8082        }
8083    }
8084
8085    /**
8086     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8087     * @param windows List of windows on default display.
8088     * @return bitmap indicating if another pass through layout must be made.
8089     */
8090    public int handleAppTransitionReadyLocked(WindowList windows) {
8091        int changes = 0;
8092        int i;
8093        int NN = mOpeningApps.size();
8094        boolean goodToGo = true;
8095        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8096                "Checking " + NN + " opening apps (frozen="
8097                + mDisplayFrozen + " timeout="
8098                + mAppTransition.isTimeout() + ")...");
8099        if (!mDisplayFrozen && !mAppTransition.isTimeout()) {
8100            // If the display isn't frozen, wait to do anything until
8101            // all of the apps are ready.  Otherwise just go because
8102            // we'll unfreeze the display when everyone is ready.
8103            for (i=0; i<NN && goodToGo; i++) {
8104                AppWindowToken wtoken = mOpeningApps.get(i);
8105                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8106                        "Check opening app=" + wtoken + ": allDrawn="
8107                        + wtoken.allDrawn + " startingDisplayed="
8108                        + wtoken.startingDisplayed + " startingMoved="
8109                        + wtoken.startingMoved);
8110                if (!wtoken.allDrawn && !wtoken.startingDisplayed
8111                        && !wtoken.startingMoved) {
8112                    goodToGo = false;
8113                }
8114            }
8115        }
8116        if (goodToGo) {
8117            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
8118            int transit = mAppTransition.getAppTransition();
8119            if (mSkipAppTransitionAnimation) {
8120                transit = AppTransition.TRANSIT_UNSET;
8121            }
8122            mAppTransition.goodToGo();
8123            mStartingIconInTransition = false;
8124            mSkipAppTransitionAnimation = false;
8125
8126            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
8127
8128            rebuildAppWindowListLocked();
8129
8130            // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
8131            WindowState oldWallpaper =
8132                    mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
8133                        && !mWallpaperTarget.mWinAnimator.isDummyAnimation()
8134                    ? null : mWallpaperTarget;
8135
8136            mInnerFields.mWallpaperMayChange = false;
8137
8138            // The top-most window will supply the layout params,
8139            // and we will determine it below.
8140            LayoutParams animLp = null;
8141            int bestAnimLayer = -1;
8142            boolean fullscreenAnim = false;
8143
8144            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8145                    "New wallpaper target=" + mWallpaperTarget
8146                    + ", oldWallpaper=" + oldWallpaper
8147                    + ", lower target=" + mLowerWallpaperTarget
8148                    + ", upper target=" + mUpperWallpaperTarget);
8149
8150            boolean openingAppHasWallpaper = false;
8151            boolean closingAppHasWallpaper = false;
8152            final AppWindowToken lowerWallpaperAppToken;
8153            final AppWindowToken upperWallpaperAppToken;
8154            if (mLowerWallpaperTarget == null) {
8155                lowerWallpaperAppToken = upperWallpaperAppToken = null;
8156            } else {
8157                lowerWallpaperAppToken = mLowerWallpaperTarget.mAppToken;
8158                upperWallpaperAppToken = mUpperWallpaperTarget.mAppToken;
8159            }
8160
8161            // Do a first pass through the tokens for two
8162            // things:
8163            // (1) Determine if both the closing and opening
8164            // app token sets are wallpaper targets, in which
8165            // case special animations are needed
8166            // (since the wallpaper needs to stay static
8167            // behind them).
8168            // (2) Find the layout params of the top-most
8169            // application window in the tokens, which is
8170            // what will control the animation theme.
8171            final int NC = mClosingApps.size();
8172            NN = NC + mOpeningApps.size();
8173            for (i=0; i<NN; i++) {
8174                final AppWindowToken wtoken;
8175                if (i < NC) {
8176                    wtoken = mClosingApps.get(i);
8177                    if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
8178                        closingAppHasWallpaper = true;
8179                    }
8180                } else {
8181                    wtoken = mOpeningApps.get(i - NC);
8182                    if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
8183                        openingAppHasWallpaper = true;
8184                    }
8185                }
8186
8187                if (wtoken.appFullscreen) {
8188                    WindowState ws = wtoken.findMainWindow();
8189                    if (ws != null) {
8190                        animLp = ws.mAttrs;
8191                        bestAnimLayer = ws.mLayer;
8192                        fullscreenAnim = true;
8193                    }
8194                } else if (!fullscreenAnim) {
8195                    WindowState ws = wtoken.findMainWindow();
8196                    if (ws != null) {
8197                        if (ws.mLayer > bestAnimLayer) {
8198                            animLp = ws.mAttrs;
8199                            bestAnimLayer = ws.mLayer;
8200                        }
8201                    }
8202                }
8203            }
8204
8205            if (closingAppHasWallpaper && openingAppHasWallpaper) {
8206                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
8207                switch (transit) {
8208                    case AppTransition.TRANSIT_ACTIVITY_OPEN:
8209                    case AppTransition.TRANSIT_TASK_OPEN:
8210                    case AppTransition.TRANSIT_TASK_TO_FRONT:
8211                        transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
8212                        break;
8213                    case AppTransition.TRANSIT_ACTIVITY_CLOSE:
8214                    case AppTransition.TRANSIT_TASK_CLOSE:
8215                    case AppTransition.TRANSIT_TASK_TO_BACK:
8216                        transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
8217                        break;
8218                }
8219                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit: " + transit);
8220            } else if ((oldWallpaper != null) && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
8221                // We are transitioning from an activity with
8222                // a wallpaper to one without.
8223                transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
8224                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8225                        "New transit away from wallpaper: " + transit);
8226            } else if (mWallpaperTarget != null && mWallpaperTarget.isVisibleLw()) {
8227                // We are transitioning from an activity without
8228                // a wallpaper to now showing the wallpaper
8229                transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
8230                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8231                        "New transit into wallpaper: " + transit);
8232            }
8233
8234            // If all closing windows are obscured, then there is
8235            // no need to do an animation.  This is the case, for
8236            // example, when this transition is being done behind
8237            // the lock screen.
8238            if (!mPolicy.allowAppAnimationsLw()) {
8239                animLp = null;
8240            }
8241
8242            AppWindowToken topOpeningApp = null;
8243            int topOpeningLayer = 0;
8244
8245            NN = mOpeningApps.size();
8246            for (i=0; i<NN; i++) {
8247                AppWindowToken wtoken = mOpeningApps.get(i);
8248                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
8249                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
8250                appAnimator.clearThumbnail();
8251                wtoken.inPendingTransaction = false;
8252                appAnimator.animation = null;
8253                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
8254                wtoken.updateReportedVisibilityLocked();
8255                wtoken.waitingToShow = false;
8256
8257                appAnimator.mAllAppWinAnimators.clear();
8258                final int N = wtoken.allAppWindows.size();
8259                for (int j = 0; j < N; j++) {
8260                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
8261                }
8262                mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
8263
8264                if (animLp != null) {
8265                    int layer = -1;
8266                    for (int j=0; j<wtoken.windows.size(); j++) {
8267                        WindowState win = wtoken.windows.get(j);
8268                        if (win.mWinAnimator.mAnimLayer > layer) {
8269                            layer = win.mWinAnimator.mAnimLayer;
8270                        }
8271                    }
8272                    if (topOpeningApp == null || layer > topOpeningLayer) {
8273                        topOpeningApp = wtoken;
8274                        topOpeningLayer = layer;
8275                    }
8276                }
8277            }
8278            NN = mClosingApps.size();
8279            for (i=0; i<NN; i++) {
8280                AppWindowToken wtoken = mClosingApps.get(i);
8281                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8282                        "Now closing app " + wtoken);
8283                wtoken.mAppAnimator.clearThumbnail();
8284                wtoken.inPendingTransaction = false;
8285                wtoken.mAppAnimator.animation = null;
8286                setTokenVisibilityLocked(wtoken, animLp, false,
8287                        transit, false);
8288                wtoken.updateReportedVisibilityLocked();
8289                wtoken.waitingToHide = false;
8290                // Force the allDrawn flag, because we want to start
8291                // this guy's animations regardless of whether it's
8292                // gotten drawn.
8293                wtoken.allDrawn = true;
8294                wtoken.deferClearAllDrawn = false;
8295            }
8296
8297            AppWindowAnimator appAnimator =
8298                    topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
8299            Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
8300            if (nextAppTransitionThumbnail != null && appAnimator != null
8301                    && appAnimator.animation != null) {
8302                // This thumbnail animation is very special, we need to have
8303                // an extra surface with the thumbnail included with the animation.
8304                Rect dirty = new Rect(0, 0, nextAppTransitionThumbnail.getWidth(),
8305                        nextAppTransitionThumbnail.getHeight());
8306                try {
8307                    // TODO(multi-display): support other displays
8308                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
8309                    final Display display = displayContent.getDisplay();
8310                    SurfaceControl surfaceControl = new SurfaceControl(mFxSession,
8311                            "thumbnail anim",
8312                            dirty.width(), dirty.height(),
8313                            PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
8314                    surfaceControl.setLayerStack(display.getLayerStack());
8315                    appAnimator.thumbnail = surfaceControl;
8316                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");
8317                    Surface drawSurface = new Surface();
8318                    drawSurface.copyFrom(surfaceControl);
8319                    Canvas c = drawSurface.lockCanvas(dirty);
8320                    c.drawBitmap(nextAppTransitionThumbnail, 0, 0, null);
8321                    drawSurface.unlockCanvasAndPost(c);
8322                    drawSurface.release();
8323                    appAnimator.thumbnailLayer = topOpeningLayer;
8324                    DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
8325                    Animation anim = mAppTransition.createThumbnailAnimationLocked(
8326                            transit, true, true, displayInfo.appWidth, displayInfo.appHeight);
8327                    appAnimator.thumbnailAnimation = anim;
8328                    anim.restrictDuration(MAX_ANIMATION_DURATION);
8329                    anim.scaleCurrentDuration(mTransitionAnimationScale);
8330                    Point p = new Point();
8331                    mAppTransition.getStartingPoint(p);
8332                    appAnimator.thumbnailX = p.x;
8333                    appAnimator.thumbnailY = p.y;
8334                } catch (SurfaceControl.OutOfResourcesException e) {
8335                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
8336                            + " h=" + dirty.height(), e);
8337                    appAnimator.clearThumbnail();
8338                } catch (Surface.OutOfResourcesException e) {
8339                    Slog.e(TAG, "Can't allocate Canvas surface w=" + dirty.width()
8340                            + " h=" + dirty.height(), e);
8341                    appAnimator.clearThumbnail();
8342                }
8343            }
8344
8345            mAppTransition.postAnimationCallback();
8346            mAppTransition.clear();
8347
8348            mOpeningApps.clear();
8349            mClosingApps.clear();
8350
8351            // This has changed the visibility of windows, so perform
8352            // a new layout to get them all up-to-date.
8353            changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
8354                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8355            getDefaultDisplayContentLocked().layoutNeeded = true;
8356
8357            // TODO(multidisplay): IMEs are only supported on the default display.
8358            if (windows == getDefaultWindowListLocked()
8359                    && !moveInputMethodWindowsIfNeededLocked(true)) {
8360                assignLayersLocked(windows);
8361            }
8362            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, false /*updateInputWindows*/);
8363            mFocusMayChange = false;
8364        }
8365
8366        return changes;
8367    }
8368
8369    /**
8370     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8371     * @return bitmap indicating if another pass through layout must be made.
8372     */
8373    private int handleAnimatingStoppedAndTransitionLocked() {
8374        int changes = 0;
8375
8376        mAppTransition.setIdle();
8377        // Restore window app tokens to the ActivityManager views
8378        for (int i = mAnimatingAppTokens.size() - 1; i >= 0; i--) {
8379            mAnimatingAppTokens.get(i).sendingToBottom = false;
8380        }
8381        mAnimatingAppTokens.clear();
8382        mAnimatingAppTokens.addAll(mAppTokens);
8383        rebuildAppWindowListLocked();
8384
8385        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8386        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
8387                "Wallpaper layer changed: assigning layers + relayout");
8388        moveInputMethodWindowsIfNeededLocked(true);
8389        mInnerFields.mWallpaperMayChange = true;
8390        // Since the window list has been rebuilt, focus might
8391        // have to be recomputed since the actual order of windows
8392        // might have changed again.
8393        mFocusMayChange = true;
8394
8395        return changes;
8396    }
8397
8398    private void updateResizingWindows(final WindowState w) {
8399        final WindowStateAnimator winAnimator = w.mWinAnimator;
8400        if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
8401            w.mOverscanInsetsChanged |=
8402                    !w.mLastOverscanInsets.equals(w.mOverscanInsets);
8403            w.mContentInsetsChanged |=
8404                    !w.mLastContentInsets.equals(w.mContentInsets);
8405            w.mVisibleInsetsChanged |=
8406                    !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8407            boolean configChanged = w.isConfigChanged();
8408            if (DEBUG_CONFIGURATION && configChanged) {
8409                Slog.v(TAG, "Win " + w + " config changed: "
8410                        + mCurConfiguration);
8411            }
8412            if (localLOGV) Slog.v(TAG, "Resizing " + w
8413                    + ": configChanged=" + configChanged
8414                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8415            w.mLastFrame.set(w.mFrame);
8416            if (w.mContentInsetsChanged
8417                    || w.mVisibleInsetsChanged
8418                    || winAnimator.mSurfaceResized
8419                    || configChanged) {
8420                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8421                    Slog.v(TAG, "Resize reasons: "
8422                            + " contentInsetsChanged=" + w.mContentInsetsChanged
8423                            + " " + w.mContentInsets.toShortString()
8424                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8425                            + " " + w.mVisibleInsets.toShortString()
8426                            + " surfaceResized=" + winAnimator.mSurfaceResized
8427                            + " configChanged=" + configChanged);
8428                }
8429
8430                w.mLastOverscanInsets.set(w.mOverscanInsets);
8431                w.mLastContentInsets.set(w.mContentInsets);
8432                w.mLastVisibleInsets.set(w.mVisibleInsets);
8433                makeWindowFreezingScreenIfNeededLocked(w);
8434                // If the orientation is changing, then we need to
8435                // hold off on unfreezing the display until this
8436                // window has been redrawn; to do that, we need
8437                // to go through the process of getting informed
8438                // by the application when it has finished drawing.
8439                if (w.mOrientationChanging) {
8440                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
8441                            "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
8442                            + w + ", surface " + winAnimator.mSurfaceControl);
8443                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
8444                    if (w.mAppToken != null) {
8445                        w.mAppToken.allDrawn = false;
8446                        w.mAppToken.deferClearAllDrawn = false;
8447                    }
8448                }
8449                if (!mResizingWindows.contains(w)) {
8450                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8451                            "Resizing window " + w + " to " + winAnimator.mSurfaceW
8452                            + "x" + winAnimator.mSurfaceH);
8453                    mResizingWindows.add(w);
8454                }
8455            } else if (w.mOrientationChanging) {
8456                if (w.isDrawnLw()) {
8457                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8458                            "Orientation not waiting for draw in "
8459                            + w + ", surface " + winAnimator.mSurfaceControl);
8460                    w.mOrientationChanging = false;
8461                    w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
8462                            - mDisplayFreezeTime);
8463                }
8464            }
8465        }
8466    }
8467
8468    /**
8469     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
8470     *
8471     * @param w WindowState this method is applied to.
8472     * @param currentTime The time which animations use for calculating transitions.
8473     * @param innerDw Width of app window.
8474     * @param innerDh Height of app window.
8475     */
8476    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
8477                                         final int innerDw, final int innerDh) {
8478        final WindowManager.LayoutParams attrs = w.mAttrs;
8479        final int attrFlags = attrs.flags;
8480        final boolean canBeSeen = w.isDisplayedLw();
8481
8482        if (w.mHasSurface) {
8483            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8484                mInnerFields.mHoldScreen = w.mSession;
8485            }
8486            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
8487                    && mInnerFields.mScreenBrightness < 0) {
8488                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
8489            }
8490            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
8491                    && mInnerFields.mButtonBrightness < 0) {
8492                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
8493            }
8494            if (!mInnerFields.mSyswin && w.mAttrs.userActivityTimeout >= 0
8495                    && mInnerFields.mUserActivityTimeout < 0) {
8496                mInnerFields.mUserActivityTimeout = w.mAttrs.userActivityTimeout;
8497            }
8498
8499            final int type = attrs.type;
8500            if (canBeSeen
8501                    && (type == TYPE_SYSTEM_DIALOG
8502                     || type == TYPE_RECENTS_OVERLAY
8503                     || type == TYPE_KEYGUARD
8504                     || type == TYPE_SYSTEM_ERROR)) {
8505                mInnerFields.mSyswin = true;
8506            }
8507
8508            if (canBeSeen) {
8509                if (type == TYPE_DREAM || type == TYPE_KEYGUARD) {
8510                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_MIRROR;
8511                } else if (mInnerFields.mDisplayHasContent
8512                        == LayoutFields.DISPLAY_CONTENT_UNKNOWN) {
8513                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNIQUE;
8514                }
8515            }
8516        }
8517
8518        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8519        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8520            // This window completely covers everything behind it,
8521            // so we want to leave all of them as undimmed (for
8522            // performance reasons).
8523            mInnerFields.mObscured = true;
8524        }
8525    }
8526
8527    private void handleFlagDimBehind(WindowState w, int innerDw, int innerDh) {
8528        final WindowManager.LayoutParams attrs = w.mAttrs;
8529        if ((attrs.flags & FLAG_DIM_BEHIND) != 0
8530                && w.isDisplayedLw()
8531                && !w.mExiting) {
8532            mInnerFields.mDimming = true;
8533            final WindowStateAnimator winAnimator = w.mWinAnimator;
8534            if (!mAnimator.isDimmingLocked(winAnimator)) {
8535                if (localLOGV) Slog.v(TAG, "Win " + w + " start dimming.");
8536                startDimmingLocked(winAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount);
8537            }
8538        }
8539    }
8540
8541    private void updateAllDrawnLocked() {
8542        // See if any windows have been drawn, so they (and others
8543        // associated with them) can now be shown.
8544        final ArrayList<AppWindowToken> appTokens = mAnimatingAppTokens;
8545        final int NT = appTokens.size();
8546        for (int i=0; i<NT; i++) {
8547            AppWindowToken wtoken = appTokens.get(i);
8548            if (!wtoken.allDrawn) {
8549                int numInteresting = wtoken.numInterestingWindows;
8550                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
8551                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
8552                            "allDrawn: " + wtoken
8553                            + " interesting=" + numInteresting
8554                            + " drawn=" + wtoken.numDrawnWindows);
8555                    wtoken.allDrawn = true;
8556                }
8557            }
8558        }
8559    }
8560
8561    // "Something has changed!  Let's make it correct now."
8562    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
8563        if (DEBUG_WINDOW_TRACE) {
8564            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
8565                    + Debug.getCallers(3));
8566        }
8567
8568        final long currentTime = SystemClock.uptimeMillis();
8569
8570        int i;
8571
8572        if (mFocusMayChange) {
8573            mFocusMayChange = false;
8574            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8575                    false /*updateInputWindows*/);
8576        }
8577
8578        // Initialize state of exiting tokens.
8579        for (i=mExitingTokens.size()-1; i>=0; i--) {
8580            mExitingTokens.get(i).hasVisible = false;
8581        }
8582
8583        // Initialize state of exiting applications.
8584        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8585            mExitingAppTokens.get(i).hasVisible = false;
8586        }
8587
8588        mInnerFields.mHoldScreen = null;
8589        mInnerFields.mScreenBrightness = -1;
8590        mInnerFields.mButtonBrightness = -1;
8591        mInnerFields.mUserActivityTimeout = -1;
8592        mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
8593
8594        mTransactionSequence++;
8595
8596        final DisplayContent defaultDisplay = getDefaultDisplayContentLocked();
8597        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
8598        final int defaultDw = defaultInfo.logicalWidth;
8599        final int defaultDh = defaultInfo.logicalHeight;
8600
8601        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8602                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8603        SurfaceControl.openTransaction();
8604        try {
8605
8606            if (mWatermark != null) {
8607                mWatermark.positionSurface(defaultDw, defaultDh);
8608            }
8609            if (mStrictModeFlash != null) {
8610                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
8611            }
8612
8613            boolean focusDisplayed = false;
8614            boolean updateAllDrawn = false;
8615
8616        final int numDisplays = mDisplayContents.size();
8617        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
8618                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
8619                WindowList windows = displayContent.getWindowList();
8620                DisplayInfo displayInfo = displayContent.getDisplayInfo();
8621                final int displayId = displayContent.getDisplayId();
8622                final int dw = displayInfo.logicalWidth;
8623                final int dh = displayInfo.logicalHeight;
8624                final int innerDw = displayInfo.appWidth;
8625                final int innerDh = displayInfo.appHeight;
8626                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
8627
8628                // Reset for each display unless we are forcing mirroring.
8629                if (mInnerFields.mDisplayHasContent != LayoutFields.DISPLAY_CONTENT_MIRROR) {
8630                    mInnerFields.mDisplayHasContent = LayoutFields.DISPLAY_CONTENT_UNKNOWN;
8631                }
8632
8633                int repeats = 0;
8634                do {
8635                    repeats++;
8636                    if (repeats > 6) {
8637                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
8638                        displayContent.layoutNeeded = false;
8639                        break;
8640                    }
8641
8642                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
8643                        displayContent.pendingLayoutChanges);
8644
8645                    if ((displayContent.pendingLayoutChanges &
8646                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
8647                            (adjustWallpaperWindowsLocked() &
8648                                    ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8649                        assignLayersLocked(windows);
8650                        displayContent.layoutNeeded = true;
8651                    }
8652
8653                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
8654                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
8655                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
8656                        if (updateOrientationFromAppTokensLocked(true)) {
8657                            displayContent.layoutNeeded = true;
8658                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8659                        }
8660                    }
8661
8662                    if ((displayContent.pendingLayoutChanges
8663                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8664                        displayContent.layoutNeeded = true;
8665                    }
8666
8667                    // FIRST LOOP: Perform a layout, if needed.
8668                    if (repeats < 4) {
8669                        performLayoutLockedInner(displayContent, repeats == 1,
8670                                false /*updateInputWindows*/);
8671                    } else {
8672                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
8673                    }
8674
8675                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
8676                    // it is animating.
8677                    displayContent.pendingLayoutChanges = 0;
8678
8679                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number "
8680                            + mLayoutRepeatCount, displayContent.pendingLayoutChanges);
8681
8682                    if (isDefaultDisplay) {
8683                        mPolicy.beginPostLayoutPolicyLw(dw, dh);
8684                        for (i = windows.size() - 1; i >= 0; i--) {
8685                            WindowState w = windows.get(i);
8686                            if (w.mHasSurface) {
8687                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs);
8688                            }
8689                        }
8690                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
8691                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
8692                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
8693                    }
8694                } while (displayContent.pendingLayoutChanges != 0);
8695
8696                mInnerFields.mObscured = false;
8697                mInnerFields.mDimming = false;
8698                mInnerFields.mSyswin = false;
8699
8700                // Only used if default window
8701                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
8702
8703                final int N = windows.size();
8704                for (i=N-1; i>=0; i--) {
8705                    WindowState w = windows.get(i);
8706
8707                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
8708
8709                    // Update effect.
8710                    w.mObscured = mInnerFields.mObscured;
8711                    if (!mInnerFields.mObscured) {
8712                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
8713                    }
8714
8715                    if (!mInnerFields.mDimming) {
8716                        handleFlagDimBehind(w, innerDw, innerDh);
8717                    }
8718
8719                    if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
8720                            && w.isVisibleLw()) {
8721                        // This is the wallpaper target and its obscured state
8722                        // changed... make sure the current wallaper's visibility
8723                        // has been updated accordingly.
8724                        updateWallpaperVisibilityLocked();
8725                    }
8726
8727                    final WindowStateAnimator winAnimator = w.mWinAnimator;
8728
8729                    // If the window has moved due to its containing
8730                    // content frame changing, then we'd like to animate
8731                    // it.
8732                    if (w.mHasSurface && w.shouldAnimateMove()) {
8733                        // Frame has moved, containing content frame
8734                        // has also moved, and we're not currently animating...
8735                        // let's do something.
8736                        Animation a = AnimationUtils.loadAnimation(mContext,
8737                                com.android.internal.R.anim.window_move_from_decor);
8738                        winAnimator.setAnimation(a);
8739                        winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
8740                        winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
8741                        try {
8742                            w.mClient.moved(w.mFrame.left, w.mFrame.top);
8743                        } catch (RemoteException e) {
8744                        }
8745                    }
8746
8747                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
8748                    w.mContentChanged = false;
8749
8750                    // Moved from updateWindowsAndWallpaperLocked().
8751                    if (w.mHasSurface) {
8752                        // Take care of the window being ready to display.
8753                        final boolean committed =
8754                                winAnimator.commitFinishDrawingLocked(currentTime);
8755                        if (isDefaultDisplay && committed) {
8756                            if (w.mAttrs.type == TYPE_DREAM) {
8757                                // HACK: When a dream is shown, it may at that
8758                                // point hide the lock screen.  So we need to
8759                                // redo the layout to let the phone window manager
8760                                // make this happen.
8761                                displayContent.pendingLayoutChanges |=
8762                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
8763                                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
8764                                    debugLayoutRepeats(
8765                                        "dream and commitFinishDrawingLocked true",
8766                                        displayContent.pendingLayoutChanges);
8767                                }
8768                            }
8769                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
8770                                if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
8771                                        "First draw done in potential wallpaper target " + w);
8772                                mInnerFields.mWallpaperMayChange = true;
8773                                displayContent.pendingLayoutChanges |=
8774                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
8775                                if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
8776                                    debugLayoutRepeats(
8777                                        "wallpaper and commitFinishDrawingLocked true",
8778                                        displayContent.pendingLayoutChanges);
8779                                }
8780                            }
8781                        }
8782
8783                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
8784
8785                        final AppWindowToken atoken = w.mAppToken;
8786                        if (DEBUG_STARTING_WINDOW && atoken != null
8787                                && w == atoken.startingWindow) {
8788                            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
8789                                + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
8790                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
8791                        }
8792                        if (atoken != null
8793                                && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
8794                            if (atoken.lastTransactionSequence != mTransactionSequence) {
8795                                atoken.lastTransactionSequence = mTransactionSequence;
8796                                atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
8797                                atoken.startingDisplayed = false;
8798                            }
8799                            if ((w.isOnScreen() || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
8800                                    && !w.mExiting && !w.mDestroying) {
8801                                if (WindowManagerService.DEBUG_VISIBILITY ||
8802                                        WindowManagerService.DEBUG_ORIENTATION) {
8803                                    Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
8804                                            + ", isAnimating=" + winAnimator.isAnimating());
8805                                    if (!w.isDrawnLw()) {
8806                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceControl
8807                                                + " pv=" + w.mPolicyVisibility
8808                                                + " mDrawState=" + winAnimator.mDrawState
8809                                                + " ah=" + w.mAttachedHidden
8810                                                + " th=" + atoken.hiddenRequested
8811                                                + " a=" + winAnimator.mAnimating);
8812                                    }
8813                                }
8814                                if (w != atoken.startingWindow) {
8815                                    if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
8816                                        atoken.numInterestingWindows++;
8817                                        if (w.isDrawnLw()) {
8818                                            atoken.numDrawnWindows++;
8819                                            if (WindowManagerService.DEBUG_VISIBILITY ||
8820                                                    WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
8821                                                    "tokenMayBeDrawn: " + atoken
8822                                                    + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
8823                                                    + " mAppFreezing=" + w.mAppFreezing);
8824                                            updateAllDrawn = true;
8825                                        }
8826                                    }
8827                                } else if (w.isDrawnLw()) {
8828                                    atoken.startingDisplayed = true;
8829                                }
8830                            }
8831                        }
8832                    }
8833
8834                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
8835                            && w.isDisplayedLw()) {
8836                        focusDisplayed = true;
8837                    }
8838
8839                    updateResizingWindows(w);
8840                }
8841
8842                final boolean hasUniqueContent;
8843                switch (mInnerFields.mDisplayHasContent) {
8844                    case LayoutFields.DISPLAY_CONTENT_MIRROR:
8845                        hasUniqueContent = isDefaultDisplay;
8846                        break;
8847                    case LayoutFields.DISPLAY_CONTENT_UNIQUE:
8848                        hasUniqueContent = true;
8849                        break;
8850                    case LayoutFields.DISPLAY_CONTENT_UNKNOWN:
8851                    default:
8852                        hasUniqueContent = false;
8853                        break;
8854                }
8855                mDisplayManagerService.setDisplayHasContent(displayId, hasUniqueContent,
8856                        true /* inTraversal, must call performTraversalInTrans... below */);
8857
8858                if (!mInnerFields.mDimming && mAnimator.isDimmingLocked(displayId)) {
8859                    stopDimmingLocked(displayId);
8860                }
8861            }
8862
8863            if (updateAllDrawn) {
8864                updateAllDrawnLocked();
8865            }
8866
8867            if (focusDisplayed) {
8868                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8869            }
8870
8871            // Give the display manager a chance to adjust properties
8872            // like display rotation if it needs to.
8873            mDisplayManagerService.performTraversalInTransactionFromWindowManager();
8874
8875        } catch (RuntimeException e) {
8876            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
8877        } finally {
8878            SurfaceControl.closeTransaction();
8879            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8880                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
8881        }
8882
8883        final WindowList defaultWindows = defaultDisplay.getWindowList();
8884
8885        // If we are ready to perform an app transition, check through
8886        // all of the app tokens to be shown and see if they are ready
8887        // to go.
8888        if (mAppTransition.isReady()) {
8889            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
8890            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
8891                    defaultDisplay.pendingLayoutChanges);
8892        }
8893
8894        if (!mAnimator.mAnimating && mAppTransition.isRunning()) {
8895            // We have finished the animation of an app transition.  To do
8896            // this, we have delayed a lot of operations like showing and
8897            // hiding apps, moving apps in Z-order, etc.  The app token list
8898            // reflects the correct Z-order, but the window list may now
8899            // be out of sync with it.  So here we will just rebuild the
8900            // entire app window list.  Fun!
8901            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
8902            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
8903                defaultDisplay.pendingLayoutChanges);
8904        }
8905
8906        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
8907                && !mAppTransition.isReady()) {
8908            // At this point, there was a window with a wallpaper that
8909            // was force hiding other windows behind it, but now it
8910            // is going away.  This may be simple -- just animate
8911            // away the wallpaper and its window -- or it may be
8912            // hard -- the wallpaper now needs to be shown behind
8913            // something that was hidden.
8914            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
8915            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
8916                defaultDisplay.pendingLayoutChanges);
8917        }
8918        mInnerFields.mWallpaperForceHidingChanged = false;
8919
8920        if (mInnerFields.mWallpaperMayChange) {
8921            if (WindowManagerService.DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
8922                    "Wallpaper may change!  Adjusting");
8923            defaultDisplay.pendingLayoutChanges |=
8924                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
8925            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
8926                    defaultDisplay.pendingLayoutChanges);
8927        }
8928
8929        if (mFocusMayChange) {
8930            mFocusMayChange = false;
8931            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8932                    false /*updateInputWindows*/)) {
8933                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
8934            }
8935        }
8936
8937        if (needsLayout()) {
8938            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
8939            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
8940                    defaultDisplay.pendingLayoutChanges);
8941        }
8942
8943        for (i = mResizingWindows.size() - 1; i >= 0; i--) {
8944            WindowState win = mResizingWindows.get(i);
8945            if (win.mAppFreezing) {
8946                // Don't remove this window until rotation has completed.
8947                continue;
8948            }
8949            final WindowStateAnimator winAnimator = win.mWinAnimator;
8950            try {
8951                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8952                        "Reporting new frame to " + win + ": " + win.mCompatFrame);
8953                int diff = 0;
8954                boolean configChanged = win.isConfigChanged();
8955                if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
8956                        && configChanged) {
8957                    Slog.i(TAG, "Sending new config to window " + win + ": "
8958                            + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
8959                            + " / " + mCurConfiguration + " / 0x"
8960                            + Integer.toHexString(diff));
8961                }
8962                win.setConfiguration(mCurConfiguration);
8963                if (DEBUG_ORIENTATION &&
8964                        winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
8965                        TAG, "Resizing " + win + " WITH DRAW PENDING");
8966                final IWindow client = win.mClient;
8967                final Rect frame = win.mFrame;
8968                final Rect overscanInsets = win.mLastOverscanInsets;
8969                final Rect contentInsets = win.mLastContentInsets;
8970                final Rect visibleInsets = win.mLastVisibleInsets;
8971                final boolean reportDraw
8972                        = winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
8973                final Configuration newConfig = configChanged ? win.mConfiguration : null;
8974                if (win.mClient instanceof IWindow.Stub) {
8975                    // To prevent deadlock simulate one-way call if win.mClient is a local object.
8976                    mH.post(new Runnable() {
8977                        @Override
8978                        public void run() {
8979                            try {
8980                                client.resized(frame, overscanInsets, contentInsets,
8981                                        visibleInsets, reportDraw, newConfig);
8982                            } catch (RemoteException e) {
8983                                // Not a remote call, RemoteException won't be raised.
8984                            }
8985                        }
8986                    });
8987                } else {
8988                   client.resized(frame, overscanInsets, contentInsets, visibleInsets, reportDraw,
8989                           newConfig);
8990                }
8991                win.mOverscanInsetsChanged = false;
8992                win.mContentInsetsChanged = false;
8993                win.mVisibleInsetsChanged = false;
8994                winAnimator.mSurfaceResized = false;
8995            } catch (RemoteException e) {
8996                win.mOrientationChanging = false;
8997                win.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
8998                        - mDisplayFreezeTime);
8999            }
9000            mResizingWindows.remove(i);
9001        }
9002
9003        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
9004                "With display frozen, orientationChangeComplete="
9005                + mInnerFields.mOrientationChangeComplete);
9006        if (mInnerFields.mOrientationChangeComplete) {
9007            if (mWindowsFreezingScreen) {
9008                mWindowsFreezingScreen = false;
9009                mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
9010                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
9011            }
9012            stopFreezingDisplayLocked();
9013        }
9014
9015        // Destroy the surface of any windows that are no longer visible.
9016        boolean wallpaperDestroyed = false;
9017        i = mDestroySurface.size();
9018        if (i > 0) {
9019            do {
9020                i--;
9021                WindowState win = mDestroySurface.get(i);
9022                win.mDestroying = false;
9023                if (mInputMethodWindow == win) {
9024                    mInputMethodWindow = null;
9025                }
9026                if (win == mWallpaperTarget) {
9027                    wallpaperDestroyed = true;
9028                }
9029                win.mWinAnimator.destroySurfaceLocked();
9030            } while (i > 0);
9031            mDestroySurface.clear();
9032        }
9033
9034        // Time to remove any exiting tokens?
9035        for (i=mExitingTokens.size()-1; i>=0; i--) {
9036            WindowToken token = mExitingTokens.get(i);
9037            if (!token.hasVisible) {
9038                mExitingTokens.remove(i);
9039                if (token.windowType == TYPE_WALLPAPER) {
9040                    mWallpaperTokens.remove(token);
9041                }
9042            }
9043        }
9044
9045        // Time to remove any exiting applications?
9046        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
9047            AppWindowToken token = mExitingAppTokens.get(i);
9048            if (!token.hasVisible && !mClosingApps.contains(token)) {
9049                // Make sure there is no animation running on this token,
9050                // so any windows associated with it will be removed as
9051                // soon as their animations are complete
9052                token.mAppAnimator.clearAnimation();
9053                token.mAppAnimator.animating = false;
9054                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
9055                        "performLayout: App token exiting now removed" + token);
9056                mAppTokens.remove(token);
9057                mAnimatingAppTokens.remove(token);
9058                mExitingAppTokens.remove(i);
9059            }
9060        }
9061
9062        if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
9063            for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
9064                try {
9065                    mRelayoutWhileAnimating.get(j).mClient.doneAnimating();
9066                } catch (RemoteException e) {
9067                }
9068            }
9069            mRelayoutWhileAnimating.clear();
9070        }
9071
9072        if (wallpaperDestroyed) {
9073            defaultDisplay.pendingLayoutChanges |=
9074                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
9075            defaultDisplay.layoutNeeded = true;
9076        }
9077
9078        final int numDisplays = mDisplayContents.size();
9079        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9080            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
9081            if (displayContent.pendingLayoutChanges != 0) {
9082                displayContent.layoutNeeded = true;
9083            }
9084        }
9085
9086        // Finally update all input windows now that the window changes have stabilized.
9087        mInputMonitor.updateInputWindowsLw(true /*force*/);
9088
9089        setHoldScreenLocked(mInnerFields.mHoldScreen);
9090        if (!mDisplayFrozen) {
9091            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
9092                mPowerManager.setScreenBrightnessOverrideFromWindowManager(-1);
9093            } else {
9094                mPowerManager.setScreenBrightnessOverrideFromWindowManager(
9095                        toBrightnessOverride(mInnerFields.mScreenBrightness));
9096            }
9097            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
9098                mPowerManager.setButtonBrightnessOverrideFromWindowManager(-1);
9099            } else {
9100                mPowerManager.setButtonBrightnessOverrideFromWindowManager(
9101                        toBrightnessOverride(mInnerFields.mButtonBrightness));
9102            }
9103            mPowerManager.setUserActivityTimeoutOverrideFromWindowManager(
9104                    mInnerFields.mUserActivityTimeout);
9105        }
9106
9107        if (mTurnOnScreen) {
9108            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
9109            mPowerManager.wakeUp(SystemClock.uptimeMillis());
9110            mTurnOnScreen = false;
9111        }
9112
9113        if (mInnerFields.mUpdateRotation) {
9114            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9115            if (updateRotationUncheckedLocked(false)) {
9116                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9117            } else {
9118                mInnerFields.mUpdateRotation = false;
9119            }
9120        }
9121
9122        if (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded
9123                && !mInnerFields.mUpdateRotation) {
9124            checkDrawnWindowsLocked();
9125        }
9126
9127        final int N = mPendingRemove.size();
9128        if (N > 0) {
9129            if (mPendingRemoveTmp.length < N) {
9130                mPendingRemoveTmp = new WindowState[N+10];
9131            }
9132            mPendingRemove.toArray(mPendingRemoveTmp);
9133            mPendingRemove.clear();
9134            DisplayContentList displayList = new DisplayContentList();
9135            for (i = 0; i < N; i++) {
9136                WindowState w = mPendingRemoveTmp[i];
9137                removeWindowInnerLocked(w.mSession, w);
9138                if (!displayList.contains(w.mDisplayContent)) {
9139                    displayList.add(w.mDisplayContent);
9140                }
9141            }
9142
9143            for (DisplayContent displayContent : displayList) {
9144                assignLayersLocked(displayContent.getWindowList());
9145                displayContent.layoutNeeded = true;
9146            }
9147        }
9148
9149        // Check to see if we are now in a state where the screen should
9150        // be enabled, because the window obscured flags have changed.
9151        enableScreenIfNeededLocked();
9152
9153        scheduleAnimationLocked();
9154
9155        if (DEBUG_WINDOW_TRACE) {
9156            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
9157                    + mAnimator.mAnimating);
9158        }
9159    }
9160
9161    private int toBrightnessOverride(float value) {
9162        return (int)(value * PowerManager.BRIGHTNESS_ON);
9163    }
9164
9165    void checkDrawnWindowsLocked() {
9166        if (mWaitingForDrawn.size() > 0) {
9167            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
9168                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
9169                WindowState win = pair.first;
9170                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
9171                //        + win.mRemoved + " visible=" + win.isVisibleLw()
9172                //        + " shown=" + win.mSurfaceShown);
9173                if (win.mRemoved || !win.isVisibleLw()) {
9174                    // Window has been removed or made invisible; no draw
9175                    // will now happen, so stop waiting.
9176                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
9177                    try {
9178                        pair.second.sendResult(null);
9179                    } catch (RemoteException e) {
9180                    }
9181                    mWaitingForDrawn.remove(pair);
9182                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9183                } else if (win.mWinAnimator.mSurfaceShown) {
9184                    // Window is now drawn (and shown).
9185                    try {
9186                        pair.second.sendResult(null);
9187                    } catch (RemoteException e) {
9188                    }
9189                    mWaitingForDrawn.remove(pair);
9190                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9191                }
9192            }
9193        }
9194    }
9195
9196    @Override
9197    public boolean waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
9198        if (token != null && callback != null) {
9199            synchronized (mWindowMap) {
9200                WindowState win = windowForClientLocked(null, token, true);
9201                if (win != null) {
9202                    Pair<WindowState, IRemoteCallback> pair =
9203                            new Pair<WindowState, IRemoteCallback>(win, callback);
9204                    Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
9205                    mH.sendMessageDelayed(m, 2000);
9206                    mWaitingForDrawn.add(pair);
9207                    checkDrawnWindowsLocked();
9208                    return true;
9209                }
9210            }
9211        }
9212        return false;
9213    }
9214
9215    void setHoldScreenLocked(final Session newHoldScreen) {
9216        final boolean hold = newHoldScreen != null;
9217
9218        if (hold && mHoldingScreenOn != newHoldScreen) {
9219            mHoldingScreenWakeLock.setWorkSource(new WorkSource(newHoldScreen.mUid));
9220        }
9221        mHoldingScreenOn = newHoldScreen;
9222
9223        final boolean state = mHoldingScreenWakeLock.isHeld();
9224        if (hold != state) {
9225            if (hold) {
9226                mHoldingScreenWakeLock.acquire();
9227                mPolicy.keepScreenOnStartedLw();
9228            } else {
9229                mPolicy.keepScreenOnStoppedLw();
9230                mHoldingScreenWakeLock.release();
9231            }
9232        }
9233    }
9234
9235    @Override
9236    public void requestTraversal() {
9237        synchronized (mWindowMap) {
9238            requestTraversalLocked();
9239        }
9240    }
9241
9242    void requestTraversalLocked() {
9243        if (!mTraversalScheduled) {
9244            mTraversalScheduled = true;
9245            mH.sendEmptyMessage(H.DO_TRAVERSAL);
9246        }
9247    }
9248
9249    /** Note that Locked in this case is on mLayoutToAnim */
9250    void scheduleAnimationLocked() {
9251        if (!mAnimationScheduled) {
9252            mAnimationScheduled = true;
9253            mChoreographer.postCallback(
9254                    Choreographer.CALLBACK_ANIMATION, mAnimator.mAnimationRunnable, null);
9255        }
9256    }
9257
9258    void startDimmingLocked(final WindowStateAnimator winAnimator, final float target) {
9259        mAnimator.setDimWinAnimatorLocked(winAnimator.mWin.getDisplayId(), winAnimator);
9260    }
9261
9262    void stopDimmingLocked(int displayId) {
9263        mAnimator.setDimWinAnimatorLocked(displayId, null);
9264    }
9265
9266    private boolean needsLayout() {
9267        final int numDisplays = mDisplayContents.size();
9268        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9269            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
9270            if (displayContent.layoutNeeded) {
9271                return true;
9272            }
9273        }
9274        return false;
9275    }
9276
9277    boolean copyAnimToLayoutParamsLocked() {
9278        boolean doRequest = false;
9279
9280        final int bulkUpdateParams = mAnimator.mBulkUpdateParams;
9281        if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
9282            mInnerFields.mUpdateRotation = true;
9283            doRequest = true;
9284        }
9285        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
9286            mInnerFields.mWallpaperMayChange = true;
9287            doRequest = true;
9288        }
9289        if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
9290            mInnerFields.mWallpaperForceHidingChanged = true;
9291            doRequest = true;
9292        }
9293        if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
9294            mInnerFields.mOrientationChangeComplete = false;
9295        } else {
9296            mInnerFields.mOrientationChangeComplete = true;
9297            mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
9298            if (mWindowsFreezingScreen) {
9299                doRequest = true;
9300            }
9301        }
9302        if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
9303            mTurnOnScreen = true;
9304        }
9305        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_ACTION_PENDING) != 0) {
9306            mInnerFields.mWallpaperActionPending = true;
9307        }
9308
9309        return doRequest;
9310    }
9311
9312    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
9313                                           boolean secure) {
9314        final SurfaceControl surface = winAnimator.mSurfaceControl;
9315        boolean leakedSurface = false;
9316        boolean killedApps = false;
9317
9318        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
9319                winAnimator.mSession.mPid, operation);
9320
9321        if (mForceRemoves == null) {
9322            mForceRemoves = new ArrayList<WindowState>();
9323        }
9324
9325        long callingIdentity = Binder.clearCallingIdentity();
9326        try {
9327            // There was some problem...   first, do a sanity check of the
9328            // window list to make sure we haven't left any dangling surfaces
9329            // around.
9330
9331            final int numDisplays = mDisplayContents.size();
9332            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9333                final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
9334                final int numWindows = windows.size();
9335                for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
9336                    final WindowState ws = windows.get(winNdx);
9337                    WindowStateAnimator wsa = ws.mWinAnimator;
9338                    if (wsa.mSurfaceControl != null) {
9339                        if (!mSessions.contains(wsa.mSession)) {
9340                            Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
9341                                    + ws + " surface=" + wsa.mSurfaceControl
9342                                    + " token=" + ws.mToken
9343                                    + " pid=" + ws.mSession.mPid
9344                                    + " uid=" + ws.mSession.mUid);
9345                            if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9346                            wsa.mSurfaceControl.destroy();
9347                            wsa.mSurfaceShown = false;
9348                            wsa.mSurfaceControl = null;
9349                            ws.mHasSurface = false;
9350                            mForceRemoves.add(ws);
9351                            leakedSurface = true;
9352                        } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
9353                            Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
9354                                    + ws + " surface=" + wsa.mSurfaceControl
9355                                    + " token=" + ws.mAppToken);
9356                            if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9357                            wsa.mSurfaceControl.destroy();
9358                            wsa.mSurfaceShown = false;
9359                            wsa.mSurfaceControl = null;
9360                            ws.mHasSurface = false;
9361                            leakedSurface = true;
9362                        }
9363                    }
9364                }
9365            }
9366
9367            if (!leakedSurface) {
9368                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
9369                SparseIntArray pidCandidates = new SparseIntArray();
9370                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
9371                    final WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
9372                    final int numWindows = windows.size();
9373                    for (int winNdx = 0; winNdx < numWindows; ++winNdx) {
9374                        final WindowState ws = windows.get(winNdx);
9375                        if (mForceRemoves.contains(ws)) {
9376                            continue;
9377                        }
9378                        WindowStateAnimator wsa = ws.mWinAnimator;
9379                        if (wsa.mSurfaceControl != null) {
9380                            pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
9381                        }
9382                    }
9383                    if (pidCandidates.size() > 0) {
9384                        int[] pids = new int[pidCandidates.size()];
9385                        for (int i=0; i<pids.length; i++) {
9386                            pids[i] = pidCandidates.keyAt(i);
9387                        }
9388                        try {
9389                            if (mActivityManager.killPids(pids, "Free memory", secure)) {
9390                                killedApps = true;
9391                            }
9392                        } catch (RemoteException e) {
9393                        }
9394                    }
9395                }
9396            }
9397
9398            if (leakedSurface || killedApps) {
9399                // We managed to reclaim some memory, so get rid of the trouble
9400                // surface and ask the app to request another one.
9401                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9402                if (surface != null) {
9403                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
9404                            "RECOVER DESTROY", null);
9405                    surface.destroy();
9406                    winAnimator.mSurfaceShown = false;
9407                    winAnimator.mSurfaceControl = null;
9408                    winAnimator.mWin.mHasSurface = false;
9409                }
9410
9411                try {
9412                    winAnimator.mWin.mClient.dispatchGetNewSurface();
9413                } catch (RemoteException e) {
9414                }
9415            }
9416        } finally {
9417            Binder.restoreCallingIdentity(callingIdentity);
9418        }
9419
9420        return leakedSurface || killedApps;
9421    }
9422
9423    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9424        WindowState newFocus = computeFocusedWindowLocked();
9425        if (mCurrentFocus != newFocus) {
9426            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
9427            // This check makes sure that we don't already have the focus
9428            // change message pending.
9429            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9430            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9431            if (localLOGV) Slog.v(
9432                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
9433            final WindowState oldFocus = mCurrentFocus;
9434            mCurrentFocus = newFocus;
9435            mAnimator.setCurrentFocus(newFocus);
9436            mLosingFocus.remove(newFocus);
9437            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9438
9439            // TODO(multidisplay): Focused windows on default display only.
9440            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9441
9442            final WindowState imWindow = mInputMethodWindow;
9443            if (newFocus != imWindow && oldFocus != imWindow) {
9444                if (moveInputMethodWindowsIfNeededLocked(
9445                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
9446                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
9447                    displayContent.layoutNeeded = true;
9448                }
9449                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9450                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9451                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9452                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9453                    // Client will do the layout, but we need to assign layers
9454                    // for handleNewWindowLocked() below.
9455                    assignLayersLocked(displayContent.getWindowList());
9456                }
9457            }
9458
9459            if ((focusChanged & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9460                // The change in focus caused us to need to do a layout.  Okay.
9461                displayContent.layoutNeeded = true;
9462                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9463                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
9464                }
9465            }
9466
9467            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9468                // If we defer assigning layers, then the caller is responsible for
9469                // doing this part.
9470                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9471            }
9472
9473            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
9474            return true;
9475        }
9476        return false;
9477    }
9478
9479    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9480        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9481    }
9482
9483    private WindowState computeFocusedWindowLocked() {
9484        if (mAnimator.mUniverseBackground != null
9485                && mAnimator.mUniverseBackground.mWin.canReceiveKeys()) {
9486            return mAnimator.mUniverseBackground.mWin;
9487        }
9488
9489        final int displayCount = mDisplayContents.size();
9490        for (int i = 0; i < displayCount; i++) {
9491            final DisplayContent displayContent = mDisplayContents.valueAt(i);
9492            WindowState win = findFocusedWindowLocked(displayContent);
9493            if (win != null) {
9494                return win;
9495            }
9496        }
9497        return null;
9498    }
9499
9500    private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
9501        int nextAppIndex = mAppTokens.size()-1;
9502        WindowToken nextApp = nextAppIndex >= 0 ? mAppTokens.get(nextAppIndex) : null;
9503
9504        final WindowList windows = displayContent.getWindowList();
9505        for (int i = windows.size() - 1; i >= 0; i--) {
9506            final WindowState win = windows.get(i);
9507
9508            if (localLOGV || DEBUG_FOCUS) Slog.v(
9509                TAG, "Looking for focus: " + i
9510                + " = " + win
9511                + ", flags=" + win.mAttrs.flags
9512                + ", canReceive=" + win.canReceiveKeys());
9513
9514            AppWindowToken thisApp = win.mAppToken;
9515
9516            // If this window's application has been removed, just skip it.
9517            if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
9518                if (DEBUG_FOCUS) Slog.v(TAG, "Skipping app because " + (thisApp.removed
9519                        ? "removed" : "sendingToBottom"));
9520                continue;
9521            }
9522
9523            // If there is a focused app, don't allow focus to go to any
9524            // windows below it.  If this is an application window, step
9525            // through the app tokens until we find its app.
9526            if (thisApp != null && nextApp != null && thisApp != nextApp
9527                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
9528                int origAppIndex = nextAppIndex;
9529                while (nextAppIndex > 0) {
9530                    if (nextApp == mFocusedApp) {
9531                        // Whoops, we are below the focused app...  no focus
9532                        // for you!
9533                        if (localLOGV || DEBUG_FOCUS) Slog.v(
9534                            TAG, "Reached focused app: " + mFocusedApp);
9535                        return null;
9536                    }
9537                    nextAppIndex--;
9538                    nextApp = mAppTokens.get(nextAppIndex);
9539                    if (nextApp == thisApp) {
9540                        break;
9541                    }
9542                }
9543                if (thisApp != nextApp) {
9544                    // Uh oh, the app token doesn't exist!  This shouldn't
9545                    // happen, but if it does we can get totally hosed...
9546                    // so restart at the original app.
9547                    nextAppIndex = origAppIndex;
9548                    nextApp = mAppTokens.get(nextAppIndex);
9549                }
9550            }
9551
9552            // Dispatch to this window if it is wants key events.
9553            if (win.canReceiveKeys()) {
9554                if (DEBUG_FOCUS) Slog.v(
9555                        TAG, "Found focus @ " + i + " = " + win);
9556                return win;
9557            }
9558        }
9559        return null;
9560    }
9561
9562    private void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
9563        if (mDisplayFrozen) {
9564            return;
9565        }
9566
9567        if (!mDisplayReady || !mPolicy.isScreenOnFully()) {
9568            // No need to freeze the screen before the system is ready or if
9569            // the screen is off.
9570            return;
9571        }
9572
9573        mScreenFrozenLock.acquire();
9574
9575        mDisplayFrozen = true;
9576        mDisplayFreezeTime = SystemClock.elapsedRealtime();
9577        mLastFinishedFreezeSource = null;
9578
9579        mInputMonitor.freezeInputDispatchingLw();
9580
9581        // Clear the last input window -- that is just used for
9582        // clean transitions between IMEs, and if we are freezing
9583        // the screen then the whole world is changing behind the scenes.
9584        mPolicy.setLastInputMethodWindowLw(null, null);
9585
9586        if (mAppTransition.isTransitionSet()) {
9587            mAppTransition.freeze();
9588        }
9589
9590        if (PROFILE_ORIENTATION) {
9591            File file = new File("/data/system/frozen");
9592            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9593        }
9594
9595        if (CUSTOM_SCREEN_ROTATION) {
9596            mExitAnimId = exitAnim;
9597            mEnterAnimId = enterAnim;
9598            final DisplayContent displayContent = getDefaultDisplayContentLocked();
9599            final int displayId = displayContent.getDisplayId();
9600            ScreenRotationAnimation screenRotationAnimation =
9601                    mAnimator.getScreenRotationAnimationLocked(displayId);
9602            if (screenRotationAnimation != null) {
9603                screenRotationAnimation.kill();
9604            }
9605
9606            // TODO(multidisplay): rotation on main screen only.
9607            final Display display = displayContent.getDisplay();
9608            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
9609            screenRotationAnimation = new ScreenRotationAnimation(mContext,
9610                    display, mFxSession, inTransaction, displayInfo.logicalWidth,
9611                    displayInfo.logicalHeight, display.getRotation());
9612            mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9613        }
9614    }
9615
9616    private void stopFreezingDisplayLocked() {
9617        if (!mDisplayFrozen) {
9618            return;
9619        }
9620
9621        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
9622                || mClientFreezingScreen) {
9623            if (DEBUG_ORIENTATION) Slog.d(TAG,
9624                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
9625                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
9626                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen
9627                + ", mClientFreezingScreen=" + mClientFreezingScreen);
9628            return;
9629        }
9630
9631        mDisplayFrozen = false;
9632        mLastDisplayFreezeDuration = (int)(SystemClock.elapsedRealtime() - mDisplayFreezeTime);
9633        StringBuilder sb = new StringBuilder(128);
9634        sb.append("Screen frozen for ");
9635        TimeUtils.formatDuration(mLastDisplayFreezeDuration, sb);
9636        if (mLastFinishedFreezeSource != null) {
9637            sb.append(" due to ");
9638            sb.append(mLastFinishedFreezeSource);
9639        }
9640        Slog.i(TAG, sb.toString());
9641        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9642        mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
9643        if (PROFILE_ORIENTATION) {
9644            Debug.stopMethodTracing();
9645        }
9646
9647        boolean updateRotation = false;
9648
9649        final DisplayContent displayContent = getDefaultDisplayContentLocked();
9650        final int displayId = displayContent.getDisplayId();
9651        ScreenRotationAnimation screenRotationAnimation =
9652                mAnimator.getScreenRotationAnimationLocked(displayId);
9653        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
9654                && screenRotationAnimation.hasScreenshot()) {
9655            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
9656            // TODO(multidisplay): rotation on main screen only.
9657            DisplayInfo displayInfo = displayContent.getDisplayInfo();
9658            // Get rotation animation again, with new top window
9659            boolean isDimming = mAnimator.isDimmingLocked(Display.DEFAULT_DISPLAY);
9660            if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, isDimming)) {
9661                mExitAnimId = mEnterAnimId = 0;
9662            }
9663            if (screenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9664                    mTransitionAnimationScale, displayInfo.logicalWidth,
9665                        displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
9666                scheduleAnimationLocked();
9667            } else {
9668                screenRotationAnimation.kill();
9669                screenRotationAnimation = null;
9670                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9671                updateRotation = true;
9672            }
9673        } else {
9674            if (screenRotationAnimation != null) {
9675                screenRotationAnimation.kill();
9676                screenRotationAnimation = null;
9677                mAnimator.setScreenRotationAnimationLocked(displayId, screenRotationAnimation);
9678            }
9679            updateRotation = true;
9680        }
9681
9682        mInputMonitor.thawInputDispatchingLw();
9683
9684        boolean configChanged;
9685
9686        // While the display is frozen we don't re-compute the orientation
9687        // to avoid inconsistent states.  However, something interesting
9688        // could have actually changed during that time so re-evaluate it
9689        // now to catch that.
9690        configChanged = updateOrientationFromAppTokensLocked(false);
9691
9692        // A little kludge: a lot could have happened while the
9693        // display was frozen, so now that we are coming back we
9694        // do a gc so that any remote references the system
9695        // processes holds on others can be released if they are
9696        // no longer needed.
9697        mH.removeMessages(H.FORCE_GC);
9698        mH.sendEmptyMessageDelayed(H.FORCE_GC, 2000);
9699
9700        mScreenFrozenLock.release();
9701
9702        if (updateRotation) {
9703            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9704            configChanged |= updateRotationUncheckedLocked(false);
9705        }
9706
9707        if (configChanged) {
9708            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9709        }
9710    }
9711
9712    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
9713            DisplayMetrics dm) {
9714        if (index < tokens.length) {
9715            String str = tokens[index];
9716            if (str != null && str.length() > 0) {
9717                try {
9718                    int val = Integer.parseInt(str);
9719                    return val;
9720                } catch (Exception e) {
9721                }
9722            }
9723        }
9724        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
9725            return defDps;
9726        }
9727        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
9728        return val;
9729    }
9730
9731    void createWatermarkInTransaction() {
9732        if (mWatermark != null) {
9733            return;
9734        }
9735
9736        File file = new File("/system/etc/setup.conf");
9737        FileInputStream in = null;
9738        DataInputStream ind = null;
9739        try {
9740            in = new FileInputStream(file);
9741            ind = new DataInputStream(in);
9742            String line = ind.readLine();
9743            if (line != null) {
9744                String[] toks = line.split("%");
9745                if (toks != null && toks.length > 0) {
9746                    mWatermark = new Watermark(getDefaultDisplayContentLocked().getDisplay(),
9747                            mRealDisplayMetrics, mFxSession, toks);
9748                }
9749            }
9750        } catch (FileNotFoundException e) {
9751        } catch (IOException e) {
9752        } finally {
9753            if (ind != null) {
9754                try {
9755                    ind.close();
9756                } catch (IOException e) {
9757                }
9758            } else if (in != null) {
9759                try {
9760                    in.close();
9761                } catch (IOException e) {
9762                }
9763            }
9764        }
9765    }
9766
9767    @Override
9768    public void statusBarVisibilityChanged(int visibility) {
9769        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
9770                != PackageManager.PERMISSION_GRANTED) {
9771            throw new SecurityException("Caller does not hold permission "
9772                    + android.Manifest.permission.STATUS_BAR);
9773        }
9774
9775        synchronized (mWindowMap) {
9776            mLastStatusBarVisibility = visibility;
9777            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
9778            updateStatusBarVisibilityLocked(visibility);
9779        }
9780    }
9781
9782    // TOOD(multidisplay): StatusBar on multiple screens?
9783    void updateStatusBarVisibilityLocked(int visibility) {
9784        mInputManager.setSystemUiVisibility(visibility);
9785        final WindowList windows = getDefaultWindowListLocked();
9786        final int N = windows.size();
9787        for (int i = 0; i < N; i++) {
9788            WindowState ws = windows.get(i);
9789            try {
9790                int curValue = ws.mSystemUiVisibility;
9791                int diff = curValue ^ visibility;
9792                // We are only interested in differences of one of the
9793                // clearable flags...
9794                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
9795                // ...if it has actually been cleared.
9796                diff &= ~visibility;
9797                int newValue = (curValue&~diff) | (visibility&diff);
9798                if (newValue != curValue) {
9799                    ws.mSeq++;
9800                    ws.mSystemUiVisibility = newValue;
9801                }
9802                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
9803                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
9804                            visibility, newValue, diff);
9805                }
9806            } catch (RemoteException e) {
9807                // so sorry
9808            }
9809        }
9810    }
9811
9812    @Override
9813    public void reevaluateStatusBarVisibility() {
9814        synchronized (mWindowMap) {
9815            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
9816            updateStatusBarVisibilityLocked(visibility);
9817            performLayoutAndPlaceSurfacesLocked();
9818        }
9819    }
9820
9821    @Override
9822    public FakeWindow addFakeWindow(Looper looper,
9823            InputEventReceiver.Factory inputEventReceiverFactory,
9824            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
9825            boolean hasFocus, boolean touchFullscreen) {
9826        synchronized (mWindowMap) {
9827            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
9828                    name, windowType,
9829                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
9830            int i=0;
9831            while (i<mFakeWindows.size()) {
9832                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
9833                    break;
9834                }
9835            }
9836            mFakeWindows.add(i, fw);
9837            mInputMonitor.updateInputWindowsLw(true);
9838            return fw;
9839        }
9840    }
9841
9842    boolean removeFakeWindowLocked(FakeWindow window) {
9843        synchronized (mWindowMap) {
9844            if (mFakeWindows.remove(window)) {
9845                mInputMonitor.updateInputWindowsLw(true);
9846                return true;
9847            }
9848            return false;
9849        }
9850    }
9851
9852    // It is assumed that this method is called only by InputMethodManagerService.
9853    public void saveLastInputMethodWindowForTransition() {
9854        synchronized (mWindowMap) {
9855            // TODO(multidisplay): Pass in the displayID.
9856            DisplayContent displayContent = getDefaultDisplayContentLocked();
9857            if (mInputMethodWindow != null) {
9858                mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
9859            }
9860        }
9861    }
9862
9863    @Override
9864    public boolean hasNavigationBar() {
9865        return mPolicy.hasNavigationBar();
9866    }
9867
9868    @Override
9869    public void lockNow(Bundle options) {
9870        mPolicy.lockNow(options);
9871    }
9872
9873    @Override
9874    public boolean isSafeModeEnabled() {
9875        return mSafeMode;
9876    }
9877
9878    @Override
9879    public void showAssistant() {
9880        // TODO: What permission?
9881        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER)
9882                != PackageManager.PERMISSION_GRANTED) {
9883            return;
9884        }
9885        mPolicy.showAssistant();
9886    }
9887
9888    void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
9889        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
9890        mPolicy.dump("    ", pw, args);
9891    }
9892
9893    void dumpAnimatorLocked(PrintWriter pw, String[] args, boolean dumpAll) {
9894        pw.println("WINDOW MANAGER ANIMATOR STATE (dumpsys window animator)");
9895        mAnimator.dumpLocked(pw, "    ", dumpAll);
9896    }
9897
9898    void dumpTokensLocked(PrintWriter pw, boolean dumpAll) {
9899        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
9900        if (mTokenMap.size() > 0) {
9901            pw.println("  All tokens:");
9902            Iterator<WindowToken> it = mTokenMap.values().iterator();
9903            while (it.hasNext()) {
9904                WindowToken token = it.next();
9905                pw.print("  "); pw.print(token);
9906                if (dumpAll) {
9907                    pw.println(':');
9908                    token.dump(pw, "    ");
9909                } else {
9910                    pw.println();
9911                }
9912            }
9913        }
9914        if (mWallpaperTokens.size() > 0) {
9915            pw.println();
9916            pw.println("  Wallpaper tokens:");
9917            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
9918                WindowToken token = mWallpaperTokens.get(i);
9919                pw.print("  Wallpaper #"); pw.print(i);
9920                        pw.print(' '); pw.print(token);
9921                if (dumpAll) {
9922                    pw.println(':');
9923                    token.dump(pw, "    ");
9924                } else {
9925                    pw.println();
9926                }
9927            }
9928        }
9929        if (mAppTokens.size() > 0) {
9930            pw.println();
9931            pw.println("  Application tokens in Z order:");
9932            for (int i=mAppTokens.size()-1; i>=0; i--) {
9933                pw.print("  App #"); pw.print(i);
9934                        pw.print(' '); pw.print(mAppTokens.get(i)); pw.println(":");
9935                mAppTokens.get(i).dump(pw, "    ");
9936            }
9937        }
9938        if (mFinishedStarting.size() > 0) {
9939            pw.println();
9940            pw.println("  Finishing start of application tokens:");
9941            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9942                WindowToken token = mFinishedStarting.get(i);
9943                pw.print("  Finished Starting #"); pw.print(i);
9944                        pw.print(' '); pw.print(token);
9945                if (dumpAll) {
9946                    pw.println(':');
9947                    token.dump(pw, "    ");
9948                } else {
9949                    pw.println();
9950                }
9951            }
9952        }
9953        if (mExitingTokens.size() > 0) {
9954            pw.println();
9955            pw.println("  Exiting tokens:");
9956            for (int i=mExitingTokens.size()-1; i>=0; i--) {
9957                WindowToken token = mExitingTokens.get(i);
9958                pw.print("  Exiting #"); pw.print(i);
9959                        pw.print(' '); pw.print(token);
9960                if (dumpAll) {
9961                    pw.println(':');
9962                    token.dump(pw, "    ");
9963                } else {
9964                    pw.println();
9965                }
9966            }
9967        }
9968        if (mExitingAppTokens.size() > 0) {
9969            pw.println();
9970            pw.println("  Exiting application tokens:");
9971            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9972                WindowToken token = mExitingAppTokens.get(i);
9973                pw.print("  Exiting App #"); pw.print(i);
9974                        pw.print(' '); pw.print(token);
9975                if (dumpAll) {
9976                    pw.println(':');
9977                    token.dump(pw, "    ");
9978                } else {
9979                    pw.println();
9980                }
9981            }
9982        }
9983        if (mAppTransition.isRunning() && mAnimatingAppTokens.size() > 0) {
9984            pw.println();
9985            pw.println("  Application tokens during animation:");
9986            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
9987                WindowToken token = mAnimatingAppTokens.get(i);
9988                pw.print("  App moving to bottom #"); pw.print(i);
9989                        pw.print(' '); pw.print(token);
9990                if (dumpAll) {
9991                    pw.println(':');
9992                    token.dump(pw, "    ");
9993                } else {
9994                    pw.println();
9995                }
9996            }
9997        }
9998        if (mOpeningApps.size() > 0 || mClosingApps.size() > 0) {
9999            pw.println();
10000            if (mOpeningApps.size() > 0) {
10001                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
10002            }
10003            if (mClosingApps.size() > 0) {
10004                pw.print("  mClosingApps="); pw.println(mClosingApps);
10005            }
10006        }
10007    }
10008
10009    void dumpSessionsLocked(PrintWriter pw, boolean dumpAll) {
10010        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
10011        if (mSessions.size() > 0) {
10012            Iterator<Session> it = mSessions.iterator();
10013            while (it.hasNext()) {
10014                Session s = it.next();
10015                pw.print("  Session "); pw.print(s); pw.println(':');
10016                s.dump(pw, "    ");
10017            }
10018        }
10019    }
10020
10021    void dumpDisplayContentsLocked(PrintWriter pw, boolean dumpAll) {
10022        pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)");
10023        if (mDisplayReady) {
10024            final int numDisplays = mDisplayContents.size();
10025            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10026                mDisplayContents.valueAt(displayNdx).dump("  ", pw);
10027            }
10028        } else {
10029            pw.println("  NO DISPLAY");
10030        }
10031    }
10032
10033    void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
10034            ArrayList<WindowState> windows) {
10035        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
10036        dumpWindowsNoHeaderLocked(pw, dumpAll, windows);
10037    }
10038
10039    void dumpWindowsNoHeaderLocked(PrintWriter pw, boolean dumpAll,
10040            ArrayList<WindowState> windows) {
10041        int j = 0;
10042        final int numDisplays = mDisplayContents.size();
10043        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10044            final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
10045            for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10046                final WindowState w = windowList.get(winNdx);
10047                if (windows == null || windows.contains(w)) {
10048                    pw.print("  Window #"); pw.print(j++); pw.print(' ');
10049                            pw.print(w); pw.println(":");
10050                    w.dump(pw, "    ", dumpAll || windows != null);
10051                }
10052            }
10053        }
10054        if (mInputMethodDialogs.size() > 0) {
10055            pw.println();
10056            pw.println("  Input method dialogs:");
10057            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
10058                WindowState w = mInputMethodDialogs.get(i);
10059                if (windows == null || windows.contains(w)) {
10060                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
10061                }
10062            }
10063        }
10064        if (mPendingRemove.size() > 0) {
10065            pw.println();
10066            pw.println("  Remove pending for:");
10067            for (int i=mPendingRemove.size()-1; i>=0; i--) {
10068                WindowState w = mPendingRemove.get(i);
10069                if (windows == null || windows.contains(w)) {
10070                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
10071                            pw.print(w);
10072                    if (dumpAll) {
10073                        pw.println(":");
10074                        w.dump(pw, "    ", true);
10075                    } else {
10076                        pw.println();
10077                    }
10078                }
10079            }
10080        }
10081        if (mForceRemoves != null && mForceRemoves.size() > 0) {
10082            pw.println();
10083            pw.println("  Windows force removing:");
10084            for (int i=mForceRemoves.size()-1; i>=0; i--) {
10085                WindowState w = mForceRemoves.get(i);
10086                pw.print("  Removing #"); pw.print(i); pw.print(' ');
10087                        pw.print(w);
10088                if (dumpAll) {
10089                    pw.println(":");
10090                    w.dump(pw, "    ", true);
10091                } else {
10092                    pw.println();
10093                }
10094            }
10095        }
10096        if (mDestroySurface.size() > 0) {
10097            pw.println();
10098            pw.println("  Windows waiting to destroy their surface:");
10099            for (int i=mDestroySurface.size()-1; i>=0; i--) {
10100                WindowState w = mDestroySurface.get(i);
10101                if (windows == null || windows.contains(w)) {
10102                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
10103                            pw.print(w);
10104                    if (dumpAll) {
10105                        pw.println(":");
10106                        w.dump(pw, "    ", true);
10107                    } else {
10108                        pw.println();
10109                    }
10110                }
10111            }
10112        }
10113        if (mLosingFocus.size() > 0) {
10114            pw.println();
10115            pw.println("  Windows losing focus:");
10116            for (int i=mLosingFocus.size()-1; i>=0; i--) {
10117                WindowState w = mLosingFocus.get(i);
10118                if (windows == null || windows.contains(w)) {
10119                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
10120                            pw.print(w);
10121                    if (dumpAll) {
10122                        pw.println(":");
10123                        w.dump(pw, "    ", true);
10124                    } else {
10125                        pw.println();
10126                    }
10127                }
10128            }
10129        }
10130        if (mResizingWindows.size() > 0) {
10131            pw.println();
10132            pw.println("  Windows waiting to resize:");
10133            for (int i=mResizingWindows.size()-1; i>=0; i--) {
10134                WindowState w = mResizingWindows.get(i);
10135                if (windows == null || windows.contains(w)) {
10136                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
10137                            pw.print(w);
10138                    if (dumpAll) {
10139                        pw.println(":");
10140                        w.dump(pw, "    ", true);
10141                    } else {
10142                        pw.println();
10143                    }
10144                }
10145            }
10146        }
10147        if (mWaitingForDrawn.size() > 0) {
10148            pw.println();
10149            pw.println("  Clients waiting for these windows to be drawn:");
10150            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
10151                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
10152                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
10153                        pw.print(": "); pw.println(pair.second);
10154            }
10155        }
10156        pw.println();
10157        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
10158        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
10159        if (mLastFocus != mCurrentFocus) {
10160            pw.print("  mLastFocus="); pw.println(mLastFocus);
10161        }
10162        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
10163        if (mInputMethodTarget != null) {
10164            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
10165        }
10166        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
10167                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
10168        pw.print("  mLastDisplayFreezeDuration=");
10169                TimeUtils.formatDuration(mLastDisplayFreezeDuration, pw);
10170                if ( mLastFinishedFreezeSource != null) {
10171                    pw.print(" due to ");
10172                    pw.print(mLastFinishedFreezeSource);
10173                }
10174                pw.println();
10175        if (dumpAll) {
10176            pw.print("  mSystemDecorRect="); pw.print(mSystemDecorRect.toShortString());
10177                    pw.print(" mSystemDecorLayer="); pw.print(mSystemDecorLayer);
10178                    pw.print(" mScreenRect="); pw.println(mScreenRect.toShortString());
10179            if (mLastStatusBarVisibility != 0) {
10180                pw.print("  mLastStatusBarVisibility=0x");
10181                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
10182            }
10183            if (mInputMethodWindow != null) {
10184                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
10185            }
10186            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
10187            if (mLowerWallpaperTarget != null || mUpperWallpaperTarget != null) {
10188                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
10189                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
10190            }
10191            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
10192                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
10193            if (mInputMethodAnimLayerAdjustment != 0 ||
10194                    mWallpaperAnimLayerAdjustment != 0) {
10195                pw.print("  mInputMethodAnimLayerAdjustment=");
10196                        pw.print(mInputMethodAnimLayerAdjustment);
10197                        pw.print("  mWallpaperAnimLayerAdjustment=");
10198                        pw.println(mWallpaperAnimLayerAdjustment);
10199            }
10200            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
10201                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
10202            if (needsLayout()) {
10203                pw.print("  layoutNeeded on displays=");
10204                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10205                    final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
10206                    if (displayContent.layoutNeeded) {
10207                        pw.print(displayContent.getDisplayId());
10208                    }
10209                }
10210                pw.println();
10211            }
10212            pw.print("  mTransactionSequence="); pw.println(mTransactionSequence);
10213            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
10214                    pw.print(" windows="); pw.print(mWindowsFreezingScreen);
10215                    pw.print(" client="); pw.print(mClientFreezingScreen);
10216                    pw.print(" apps="); pw.print(mAppsFreezingScreen);
10217                    pw.print(" waitingForConfig="); pw.println(mWaitingForConfig);
10218            pw.print("  mRotation="); pw.print(mRotation);
10219                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
10220            pw.print("  mLastWindowForcedOrientation="); pw.print(mLastWindowForcedOrientation);
10221                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
10222            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
10223            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
10224                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
10225                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
10226            pw.print("  mTraversalScheduled="); pw.println(mTraversalScheduled);
10227            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
10228                    pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
10229            pw.println("  mLayoutToAnim:");
10230            mAppTransition.dump(pw);
10231        }
10232    }
10233
10234    boolean dumpWindows(PrintWriter pw, String name, String[] args,
10235            int opti, boolean dumpAll) {
10236        WindowList windows = new WindowList();
10237        if ("visible".equals(name)) {
10238            synchronized(mWindowMap) {
10239                final int numDisplays = mDisplayContents.size();
10240                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10241                    final WindowList windowList =
10242                            mDisplayContents.valueAt(displayNdx).getWindowList();
10243                    for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10244                        final WindowState w = windowList.get(winNdx);
10245                        if (w.mWinAnimator.mSurfaceShown) {
10246                            windows.add(w);
10247                        }
10248                    }
10249                }
10250            }
10251        } else {
10252            int objectId = 0;
10253            // See if this is an object ID.
10254            try {
10255                objectId = Integer.parseInt(name, 16);
10256                name = null;
10257            } catch (RuntimeException e) {
10258            }
10259            synchronized(mWindowMap) {
10260                final int numDisplays = mDisplayContents.size();
10261                for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
10262                    final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList();
10263                    for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) {
10264                        final WindowState w = windowList.get(winNdx);
10265                        if (name != null) {
10266                            if (w.mAttrs.getTitle().toString().contains(name)) {
10267                                windows.add(w);
10268                            }
10269                        } else if (System.identityHashCode(w) == objectId) {
10270                            windows.add(w);
10271                        }
10272                    }
10273                }
10274            }
10275        }
10276
10277        if (windows.size() <= 0) {
10278            return false;
10279        }
10280
10281        synchronized(mWindowMap) {
10282            dumpWindowsLocked(pw, dumpAll, windows);
10283        }
10284        return true;
10285    }
10286
10287    void dumpLastANRLocked(PrintWriter pw) {
10288        pw.println("WINDOW MANAGER LAST ANR (dumpsys window lastanr)");
10289        if (mLastANRState == null) {
10290            pw.println("  <no ANR has occurred since boot>");
10291        } else {
10292            pw.println(mLastANRState);
10293        }
10294    }
10295
10296    /**
10297     * Saves information about the state of the window manager at
10298     * the time an ANR occurred before anything else in the system changes
10299     * in response.
10300     *
10301     * @param appWindowToken The application that ANR'd, may be null.
10302     * @param windowState The window that ANR'd, may be null.
10303     */
10304    public void saveANRStateLocked(AppWindowToken appWindowToken, WindowState windowState) {
10305        StringWriter sw = new StringWriter();
10306        PrintWriter pw = new PrintWriter(sw);
10307        pw.println("  ANR time: " + DateFormat.getInstance().format(new Date()));
10308        if (appWindowToken != null) {
10309            pw.println("  Application at fault: " + appWindowToken.stringName);
10310        }
10311        if (windowState != null) {
10312            pw.println("  Window at fault: " + windowState.mAttrs.getTitle());
10313        }
10314        pw.println();
10315        dumpWindowsNoHeaderLocked(pw, true, null);
10316        pw.close();
10317        mLastANRState = sw.toString();
10318    }
10319
10320    @Override
10321    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
10322        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
10323                != PackageManager.PERMISSION_GRANTED) {
10324            pw.println("Permission Denial: can't dump WindowManager from from pid="
10325                    + Binder.getCallingPid()
10326                    + ", uid=" + Binder.getCallingUid());
10327            return;
10328        }
10329
10330        boolean dumpAll = false;
10331
10332        int opti = 0;
10333        while (opti < args.length) {
10334            String opt = args[opti];
10335            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
10336                break;
10337            }
10338            opti++;
10339            if ("-a".equals(opt)) {
10340                dumpAll = true;
10341            } else if ("-h".equals(opt)) {
10342                pw.println("Window manager dump options:");
10343                pw.println("  [-a] [-h] [cmd] ...");
10344                pw.println("  cmd may be one of:");
10345                pw.println("    l[astanr]: last ANR information");
10346                pw.println("    p[policy]: policy state");
10347                pw.println("    a[animator]: animator state");
10348                pw.println("    s[essions]: active sessions");
10349                pw.println("    d[isplays]: active display contents");
10350                pw.println("    t[okens]: token list");
10351                pw.println("    w[indows]: window list");
10352                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
10353                pw.println("    be a partial substring in a window name, a");
10354                pw.println("    Window hex object identifier, or");
10355                pw.println("    \"all\" for all windows, or");
10356                pw.println("    \"visible\" for the visible windows.");
10357                pw.println("  -a: include all available server state.");
10358                return;
10359            } else {
10360                pw.println("Unknown argument: " + opt + "; use -h for help");
10361            }
10362        }
10363
10364        // Is the caller requesting to dump a particular piece of data?
10365        if (opti < args.length) {
10366            String cmd = args[opti];
10367            opti++;
10368            if ("lastanr".equals(cmd) || "l".equals(cmd)) {
10369                synchronized(mWindowMap) {
10370                    dumpLastANRLocked(pw);
10371                }
10372                return;
10373            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
10374                synchronized(mWindowMap) {
10375                    dumpPolicyLocked(pw, args, true);
10376                }
10377                return;
10378            } else if ("animator".equals(cmd) || "a".equals(cmd)) {
10379                synchronized(mWindowMap) {
10380                    dumpAnimatorLocked(pw, args, true);
10381                }
10382                return;
10383            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
10384                synchronized(mWindowMap) {
10385                    dumpSessionsLocked(pw, true);
10386                }
10387                return;
10388            } else if ("displays".equals(cmd) || "d".equals(cmd)) {
10389                synchronized(mWindowMap) {
10390                    dumpDisplayContentsLocked(pw, true);
10391                }
10392                return;
10393            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
10394                synchronized(mWindowMap) {
10395                    dumpTokensLocked(pw, true);
10396                }
10397                return;
10398            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
10399                synchronized(mWindowMap) {
10400                    dumpWindowsLocked(pw, true, null);
10401                }
10402                return;
10403            } else if ("all".equals(cmd) || "a".equals(cmd)) {
10404                synchronized(mWindowMap) {
10405                    dumpWindowsLocked(pw, true, null);
10406                }
10407                return;
10408            } else {
10409                // Dumping a single name?
10410                if (!dumpWindows(pw, cmd, args, opti, dumpAll)) {
10411                    pw.println("Bad window command, or no windows match: " + cmd);
10412                    pw.println("Use -h for help.");
10413                }
10414                return;
10415            }
10416        }
10417
10418        synchronized(mWindowMap) {
10419            pw.println();
10420            if (dumpAll) {
10421                pw.println("-------------------------------------------------------------------------------");
10422            }
10423            dumpLastANRLocked(pw);
10424            pw.println();
10425            if (dumpAll) {
10426                pw.println("-------------------------------------------------------------------------------");
10427            }
10428            dumpPolicyLocked(pw, args, dumpAll);
10429            pw.println();
10430            if (dumpAll) {
10431                pw.println("-------------------------------------------------------------------------------");
10432            }
10433            dumpAnimatorLocked(pw, args, dumpAll);
10434            pw.println();
10435            if (dumpAll) {
10436                pw.println("-------------------------------------------------------------------------------");
10437            }
10438            dumpSessionsLocked(pw, dumpAll);
10439            pw.println();
10440            if (dumpAll) {
10441                pw.println("-------------------------------------------------------------------------------");
10442            }
10443            dumpDisplayContentsLocked(pw, dumpAll);
10444            pw.println();
10445            if (dumpAll) {
10446                pw.println("-------------------------------------------------------------------------------");
10447            }
10448            dumpTokensLocked(pw, dumpAll);
10449            pw.println();
10450            if (dumpAll) {
10451                pw.println("-------------------------------------------------------------------------------");
10452            }
10453            dumpWindowsLocked(pw, dumpAll, null);
10454        }
10455    }
10456
10457    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
10458    @Override
10459    public void monitor() {
10460        synchronized (mWindowMap) { }
10461    }
10462
10463    public interface OnHardKeyboardStatusChangeListener {
10464        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
10465    }
10466
10467    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
10468        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
10469            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
10470                    Integer.toHexString(pendingLayoutChanges));
10471        }
10472    }
10473
10474    private DisplayContent newDisplayContentLocked(final Display display) {
10475        DisplayContent displayContent = new DisplayContent(display);
10476        mDisplayContents.put(display.getDisplayId(), displayContent);
10477        final Rect rect = new Rect();
10478        DisplayInfo info = displayContent.getDisplayInfo();
10479        mDisplaySettings.getOverscanLocked(info.name, rect);
10480        info.overscanLeft = rect.left;
10481        info.overscanTop = rect.top;
10482        info.overscanRight = rect.right;
10483        info.overscanBottom = rect.bottom;
10484        mDisplayManagerService.setOverscan(display.getDisplayId(), rect.left, rect.top,
10485                rect.right, rect.bottom);
10486        mPolicy.setDisplayOverscan(displayContent.getDisplay(), rect.left, rect.top,
10487                rect.right, rect.bottom);
10488        return displayContent;
10489    }
10490
10491    public void createDisplayContentLocked(final Display display) {
10492        if (display == null) {
10493            throw new IllegalArgumentException("getDisplayContent: display must not be null");
10494        }
10495        newDisplayContentLocked(display);
10496    }
10497
10498    /**
10499     * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
10500     * there is a Display for the displayId.
10501     * @param displayId The display the caller is interested in.
10502     * @return The DisplayContent associated with displayId or null if there is no Display for it.
10503     */
10504    public DisplayContent getDisplayContentLocked(final int displayId) {
10505        DisplayContent displayContent = mDisplayContents.get(displayId);
10506        if (displayContent == null) {
10507            final Display display = mDisplayManager.getDisplay(displayId);
10508            if (display != null) {
10509                displayContent = newDisplayContentLocked(display);
10510            }
10511        }
10512        return displayContent;
10513    }
10514
10515    // There is an inherent assumption that this will never return null.
10516    public DisplayContent getDefaultDisplayContentLocked() {
10517        return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
10518    }
10519
10520    public WindowList getDefaultWindowListLocked() {
10521        return getDefaultDisplayContentLocked().getWindowList();
10522    }
10523
10524    public DisplayInfo getDefaultDisplayInfoLocked() {
10525        return getDefaultDisplayContentLocked().getDisplayInfo();
10526    }
10527
10528    /**
10529     * Return the list of WindowStates associated on the passed display.
10530     * @param display The screen to return windows from.
10531     * @return The list of WindowStates on the screen, or null if the there is no screen.
10532     */
10533    public WindowList getWindowListLocked(final Display display) {
10534        return getWindowListLocked(display.getDisplayId());
10535    }
10536
10537    /**
10538     * Return the list of WindowStates associated on the passed display.
10539     * @param displayId The screen to return windows from.
10540     * @return The list of WindowStates on the screen, or null if the there is no screen.
10541     */
10542    public WindowList getWindowListLocked(final int displayId) {
10543        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10544        return displayContent != null ? displayContent.getWindowList() : null;
10545    }
10546
10547    @Override
10548    public void onDisplayAdded(int displayId) {
10549        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_ADDED, displayId, 0));
10550    }
10551
10552    private void handleDisplayAddedLocked(int displayId) {
10553        final Display display = mDisplayManager.getDisplay(displayId);
10554        if (display != null) {
10555            createDisplayContentLocked(display);
10556            displayReady(displayId);
10557        }
10558    }
10559
10560    @Override
10561    public void onDisplayRemoved(int displayId) {
10562        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_REMOVED, displayId, 0));
10563    }
10564
10565    private void handleDisplayRemovedLocked(int displayId) {
10566        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10567        if (displayContent != null) {
10568            mDisplayContents.delete(displayId);
10569            WindowList windows = displayContent.getWindowList();
10570            while (!windows.isEmpty()) {
10571                final WindowState win = windows.get(windows.size() - 1);
10572                removeWindowLocked(win.mSession, win);
10573            }
10574        }
10575        mAnimator.removeDisplayLocked(displayId);
10576    }
10577
10578    @Override
10579    public void onDisplayChanged(int displayId) {
10580        mH.sendMessage(mH.obtainMessage(H.DO_DISPLAY_CHANGED, displayId, 0));
10581    }
10582
10583    private void handleDisplayChangedLocked(int displayId) {
10584        final DisplayContent displayContent = getDisplayContentLocked(displayId);
10585        if (displayContent != null) {
10586            displayContent.updateDisplayInfo();
10587        }
10588    }
10589}
10590