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