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