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