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