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