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