WindowManagerService.java revision 73850cb6991074e33c31d310ccb63a1f863f7b4e
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                        boolean doRequest = false;
6875                        // TODO(cmautner): As the number of bits grows, use masks of bit groups to
6876                        //  eliminate unnecessary tests.
6877                        if ((msg.arg1 & LayoutFields.SET_UPDATE_ROTATION) != 0) {
6878                            mInnerFields.mUpdateRotation = true;
6879                            doRequest = true;
6880                        }
6881                        if ((msg.arg1 & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
6882                            mInnerFields.mWallpaperMayChange = true;
6883                            doRequest = true;
6884                        }
6885                        if ((msg.arg1 & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
6886                            mInnerFields.mWallpaperForceHidingChanged = true;
6887                            doRequest = true;
6888                        }
6889                        if ((msg.arg1 & LayoutFields.CLEAR_ORIENTATION_CHANGE_COMPLETE) != 0) {
6890                            mInnerFields.mOrientationChangeComplete = false;
6891                        } else {
6892                            mInnerFields.mOrientationChangeComplete = true;
6893                            if (mWindowsFreezingScreen) {
6894                                doRequest = true;
6895                            }
6896                        }
6897
6898                        if (doRequest) {
6899                            requestTraversalLocked();
6900                        }
6901                    }
6902                    break;
6903                }
6904
6905                // Animation messages. Move to Window{State}Animator
6906                case SET_TRANSPARENT_REGION: {
6907                    Pair<WindowStateAnimator, Region> pair =
6908                                (Pair<WindowStateAnimator, Region>) msg.obj;
6909                    final WindowStateAnimator winAnimator = pair.first;
6910                    winAnimator.setTransparentRegionHint(pair.second);
6911
6912                    scheduleAnimationLocked();
6913                    break;
6914                }
6915
6916                case SET_WALLPAPER_OFFSET: {
6917                    final WindowStateAnimator winAnimator = (WindowStateAnimator) msg.obj;
6918                    winAnimator.setWallpaperOffset(msg.arg1, msg.arg2);
6919
6920                    scheduleAnimationLocked();
6921                    break;
6922                }
6923
6924                case SET_DIM_PARAMETERS: {
6925                    mAnimator.mDimParams = (DimAnimator.Parameters) msg.obj;
6926
6927                    scheduleAnimationLocked();
6928                    break;
6929                }
6930
6931                case SET_MOVE_ANIMATION: {
6932                    WindowAnimator.SetAnimationParams params =
6933                            (WindowAnimator.SetAnimationParams) msg.obj;
6934                    WindowStateAnimator winAnimator = params.mWinAnimator;
6935                    winAnimator.setAnimation(params.mAnimation);
6936                    winAnimator.mAnimDw = params.mAnimDw;
6937                    winAnimator.mAnimDh = params.mAnimDh;
6938
6939                    scheduleAnimationLocked();
6940                    break;
6941                }
6942            }
6943        }
6944    }
6945
6946    // -------------------------------------------------------------
6947    // IWindowManager API
6948    // -------------------------------------------------------------
6949
6950    public IWindowSession openSession(IInputMethodClient client,
6951            IInputContext inputContext) {
6952        if (client == null) throw new IllegalArgumentException("null client");
6953        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
6954        Session session = new Session(this, client, inputContext);
6955        return session;
6956    }
6957
6958    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
6959        synchronized (mWindowMap) {
6960            // The focus for the client is the window immediately below
6961            // where we would place the input method window.
6962            int idx = findDesiredInputMethodWindowIndexLocked(false);
6963            WindowState imFocus;
6964            if (idx > 0) {
6965                imFocus = mWindows.get(idx-1);
6966                //Log.i(TAG, "Desired input method target: " + imFocus);
6967                //Log.i(TAG, "Current focus: " + this.mCurrentFocus);
6968                //Log.i(TAG, "Last focus: " + this.mLastFocus);
6969                if (imFocus != null) {
6970                    // This may be a starting window, in which case we still want
6971                    // to count it as okay.
6972                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
6973                            && imFocus.mAppToken != null) {
6974                        // The client has definitely started, so it really should
6975                        // have a window in this app token.  Let's look for it.
6976                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
6977                            WindowState w = imFocus.mAppToken.windows.get(i);
6978                            if (w != imFocus) {
6979                                //Log.i(TAG, "Switching to real app window: " + w);
6980                                imFocus = w;
6981                                break;
6982                            }
6983                        }
6984                    }
6985                    //Log.i(TAG, "IM target client: " + imFocus.mSession.mClient);
6986                    //if (imFocus.mSession.mClient != null) {
6987                    //    Log.i(TAG, "IM target client binder: " + imFocus.mSession.mClient.asBinder());
6988                    //    Log.i(TAG, "Requesting client binder: " + client.asBinder());
6989                    //}
6990                    if (imFocus.mSession.mClient != null &&
6991                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
6992                        return true;
6993                    }
6994
6995                    // Okay, how about this...  what is the current focus?
6996                    // It seems in some cases we may not have moved the IM
6997                    // target window, such as when it was in a pop-up window,
6998                    // so let's also look at the current focus.  (An example:
6999                    // go to Gmail, start searching so the keyboard goes up,
7000                    // press home.  Sometimes the IME won't go down.)
7001                    // Would be nice to fix this more correctly, but it's
7002                    // way at the end of a release, and this should be good enough.
7003                    if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null &&
7004                            mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7005                        return true;
7006                    }
7007                }
7008            }
7009        }
7010        return false;
7011    }
7012
7013    public void getDisplaySize(Point size) {
7014        synchronized(mDisplaySizeLock) {
7015            size.x = mAppDisplayWidth;
7016            size.y = mAppDisplayHeight;
7017        }
7018    }
7019
7020    public void getRealDisplaySize(Point size) {
7021        synchronized(mDisplaySizeLock) {
7022            size.x = mCurDisplayWidth;
7023            size.y = mCurDisplayHeight;
7024        }
7025    }
7026
7027    public void getInitialDisplaySize(Point size) {
7028        synchronized(mDisplaySizeLock) {
7029            size.x = mInitialDisplayWidth;
7030            size.y = mInitialDisplayHeight;
7031        }
7032    }
7033
7034    public int getMaximumSizeDimension() {
7035        synchronized(mDisplaySizeLock) {
7036            // Do this based on the raw screen size, until we are smarter.
7037            return mBaseDisplayWidth > mBaseDisplayHeight
7038                    ? mBaseDisplayWidth : mBaseDisplayHeight;
7039        }
7040    }
7041
7042    public void setForcedDisplaySize(int longDimen, int shortDimen) {
7043        synchronized(mWindowMap) {
7044            int width, height;
7045            if (mInitialDisplayWidth < mInitialDisplayHeight) {
7046                width = shortDimen < mInitialDisplayWidth
7047                        ? shortDimen : mInitialDisplayWidth;
7048                height = longDimen < mInitialDisplayHeight
7049                        ? longDimen : mInitialDisplayHeight;
7050            } else {
7051                width = longDimen < mInitialDisplayWidth
7052                        ? longDimen : mInitialDisplayWidth;
7053                height = shortDimen < mInitialDisplayHeight
7054                        ? shortDimen : mInitialDisplayHeight;
7055            }
7056            setForcedDisplaySizeLocked(width, height);
7057            Settings.Secure.putString(mContext.getContentResolver(),
7058                    Settings.Secure.DISPLAY_SIZE_FORCED, width + "," + height);
7059        }
7060    }
7061
7062    private void rebuildBlackFrame() {
7063        if (mBlackFrame != null) {
7064            mBlackFrame.kill();
7065            mBlackFrame = null;
7066        }
7067        if (mBaseDisplayWidth < mInitialDisplayWidth
7068                || mBaseDisplayHeight < mInitialDisplayHeight) {
7069            int initW, initH, baseW, baseH;
7070            final boolean rotated = (mRotation == Surface.ROTATION_90
7071                    || mRotation == Surface.ROTATION_270);
7072            if (rotated) {
7073                initW = mInitialDisplayHeight;
7074                initH = mInitialDisplayWidth;
7075                baseW = mBaseDisplayHeight;
7076                baseH = mBaseDisplayWidth;
7077            } else {
7078                initW = mInitialDisplayWidth;
7079                initH = mInitialDisplayHeight;
7080                baseW = mBaseDisplayWidth;
7081                baseH = mBaseDisplayHeight;
7082            }
7083            Rect outer = new Rect(0, 0, initW, initH);
7084            Rect inner = new Rect(0, 0, baseW, baseH);
7085            try {
7086                mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
7087            } catch (Surface.OutOfResourcesException e) {
7088            }
7089        }
7090    }
7091
7092    private void readForcedDisplaySizeLocked() {
7093        final String str = Settings.Secure.getString(mContext.getContentResolver(),
7094                Settings.Secure.DISPLAY_SIZE_FORCED);
7095        if (str == null || str.length() == 0) {
7096            return;
7097        }
7098        final int pos = str.indexOf(',');
7099        if (pos <= 0 || str.lastIndexOf(',') != pos) {
7100            return;
7101        }
7102        int width, height;
7103        try {
7104            width = Integer.parseInt(str.substring(0, pos));
7105            height = Integer.parseInt(str.substring(pos+1));
7106        } catch (NumberFormatException ex) {
7107            return;
7108        }
7109        setForcedDisplaySizeLocked(width, height);
7110    }
7111
7112    private void setForcedDisplaySizeLocked(int width, int height) {
7113        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7114
7115        synchronized(mDisplaySizeLock) {
7116            mBaseDisplayWidth = width;
7117            mBaseDisplayHeight = height;
7118        }
7119        mPolicy.setInitialDisplaySize(mDisplay, mBaseDisplayWidth, mBaseDisplayHeight);
7120
7121        mLayoutNeeded = true;
7122
7123        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7124        mTempConfiguration.setToDefaults();
7125        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7126        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7127            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7128                configChanged = true;
7129            }
7130        }
7131
7132        if (configChanged) {
7133            mWaitingForConfig = true;
7134            startFreezingDisplayLocked(false);
7135            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7136        }
7137
7138        rebuildBlackFrame();
7139
7140        performLayoutAndPlaceSurfacesLocked();
7141    }
7142
7143    public void clearForcedDisplaySize() {
7144        synchronized(mWindowMap) {
7145            setForcedDisplaySizeLocked(mInitialDisplayWidth, mInitialDisplayHeight);
7146            Settings.Secure.putString(mContext.getContentResolver(),
7147                    Settings.Secure.DISPLAY_SIZE_FORCED, "");
7148        }
7149    }
7150
7151    public boolean hasSystemNavBar() {
7152        return mPolicy.hasSystemNavBar();
7153    }
7154
7155    // -------------------------------------------------------------
7156    // Internals
7157    // -------------------------------------------------------------
7158
7159    final WindowState windowForClientLocked(Session session, IWindow client,
7160            boolean throwOnError) {
7161        return windowForClientLocked(session, client.asBinder(), throwOnError);
7162    }
7163
7164    final WindowState windowForClientLocked(Session session, IBinder client,
7165            boolean throwOnError) {
7166        WindowState win = mWindowMap.get(client);
7167        if (localLOGV) Slog.v(
7168            TAG, "Looking up client " + client + ": " + win);
7169        if (win == null) {
7170            RuntimeException ex = new IllegalArgumentException(
7171                    "Requested window " + client + " does not exist");
7172            if (throwOnError) {
7173                throw ex;
7174            }
7175            Slog.w(TAG, "Failed looking up window", ex);
7176            return null;
7177        }
7178        if (session != null && win.mSession != session) {
7179            RuntimeException ex = new IllegalArgumentException(
7180                    "Requested window " + client + " is in session " +
7181                    win.mSession + ", not " + session);
7182            if (throwOnError) {
7183                throw ex;
7184            }
7185            Slog.w(TAG, "Failed looking up window", ex);
7186            return null;
7187        }
7188
7189        return win;
7190    }
7191
7192    final void rebuildAppWindowListLocked() {
7193        int NW = mWindows.size();
7194        int i;
7195        int lastWallpaper = -1;
7196        int numRemoved = 0;
7197
7198        if (mRebuildTmp.length < NW) {
7199            mRebuildTmp = new WindowState[NW+10];
7200        }
7201
7202        // First remove all existing app windows.
7203        i=0;
7204        while (i < NW) {
7205            WindowState w = mWindows.get(i);
7206            if (w.mAppToken != null) {
7207                WindowState win = mWindows.remove(i);
7208                win.mRebuilding = true;
7209                mRebuildTmp[numRemoved] = win;
7210                mWindowsChanged = true;
7211                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
7212                        "Rebuild removing window: " + win);
7213                NW--;
7214                numRemoved++;
7215                continue;
7216            } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER
7217                    && lastWallpaper == i-1) {
7218                lastWallpaper = i;
7219            }
7220            i++;
7221        }
7222
7223        // The wallpaper window(s) typically live at the bottom of the stack,
7224        // so skip them before adding app tokens.
7225        lastWallpaper++;
7226        i = lastWallpaper;
7227
7228        // First add all of the exiting app tokens...  these are no longer
7229        // in the main app list, but still have windows shown.  We put them
7230        // in the back because now that the animation is over we no longer
7231        // will care about them.
7232        int NT = mExitingAppTokens.size();
7233        for (int j=0; j<NT; j++) {
7234            i = reAddAppWindowsLocked(i, mExitingAppTokens.get(j));
7235        }
7236
7237        // And add in the still active app tokens in Z order.
7238        NT = mAppTokens.size();
7239        for (int j=0; j<NT; j++) {
7240            i = reAddAppWindowsLocked(i, mAppTokens.get(j));
7241        }
7242
7243        i -= lastWallpaper;
7244        if (i != numRemoved) {
7245            Slog.w(TAG, "Rebuild removed " + numRemoved
7246                    + " windows but added " + i);
7247            for (i=0; i<numRemoved; i++) {
7248                WindowState ws = mRebuildTmp[i];
7249                if (ws.mRebuilding) {
7250                    StringWriter sw = new StringWriter();
7251                    PrintWriter pw = new PrintWriter(sw);
7252                    ws.dump(pw, "", true);
7253                    pw.flush();
7254                    Slog.w(TAG, "This window was lost: " + ws);
7255                    Slog.w(TAG, sw.toString());
7256                }
7257            }
7258            Slog.w(TAG, "Current app token list:");
7259            dumpAppTokensLocked();
7260            Slog.w(TAG, "Final window list:");
7261            dumpWindowsLocked();
7262        }
7263    }
7264
7265    private final void assignLayersLocked() {
7266        int N = mWindows.size();
7267        int curBaseLayer = 0;
7268        int curLayer = 0;
7269        int i;
7270
7271        if (DEBUG_LAYERS) {
7272            RuntimeException here = new RuntimeException("here");
7273            here.fillInStackTrace();
7274            Slog.v(TAG, "Assigning layers", here);
7275        }
7276
7277        for (i=0; i<N; i++) {
7278            WindowState w = mWindows.get(i);
7279            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
7280                    || (i > 0 && w.mIsWallpaper)) {
7281                curLayer += WINDOW_LAYER_MULTIPLIER;
7282                w.mLayer = curLayer;
7283            } else {
7284                curBaseLayer = curLayer = w.mBaseLayer;
7285                w.mLayer = curLayer;
7286            }
7287            if (w.mTargetAppToken != null) {
7288                w.mWinAnimator.mAnimLayer =
7289                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
7290            } else if (w.mAppToken != null) {
7291                w.mWinAnimator.mAnimLayer =
7292                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
7293            } else {
7294                w.mWinAnimator.mAnimLayer = w.mLayer;
7295            }
7296            if (w.mIsImWindow) {
7297                w.mWinAnimator.mAnimLayer += mInputMethodAnimLayerAdjustment;
7298            } else if (w.mIsWallpaper) {
7299                w.mWinAnimator.mAnimLayer += mWallpaperAnimLayerAdjustment;
7300            }
7301            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
7302                    + w.mWinAnimator.mAnimLayer);
7303            //System.out.println(
7304            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7305        }
7306    }
7307
7308    private boolean mInLayout = false;
7309    private final void performLayoutAndPlaceSurfacesLocked() {
7310        if (mInLayout) {
7311            if (DEBUG) {
7312                throw new RuntimeException("Recursive call!");
7313            }
7314            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
7315            return;
7316        }
7317
7318        if (mWaitingForConfig) {
7319            // Our configuration has changed (most likely rotation), but we
7320            // don't yet have the complete configuration to report to
7321            // applications.  Don't do any window layout until we have it.
7322            return;
7323        }
7324
7325        if (mDisplay == null) {
7326            // Not yet initialized, nothing to do.
7327            return;
7328        }
7329
7330        mInLayout = true;
7331        boolean recoveringMemory = false;
7332
7333        try {
7334            if (mForceRemoves != null) {
7335                recoveringMemory = true;
7336                // Wait a little bit for things to settle down, and off we go.
7337                for (int i=0; i<mForceRemoves.size(); i++) {
7338                    WindowState ws = mForceRemoves.get(i);
7339                    Slog.i(TAG, "Force removing: " + ws);
7340                    removeWindowInnerLocked(ws.mSession, ws);
7341                }
7342                mForceRemoves = null;
7343                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
7344                Object tmp = new Object();
7345                synchronized (tmp) {
7346                    try {
7347                        tmp.wait(250);
7348                    } catch (InterruptedException e) {
7349                    }
7350                }
7351            }
7352        } catch (RuntimeException e) {
7353            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
7354        }
7355
7356        try {
7357            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
7358
7359            final int N = mPendingRemove.size();
7360            if (N > 0) {
7361                if (mPendingRemoveTmp.length < N) {
7362                    mPendingRemoveTmp = new WindowState[N+10];
7363                }
7364                mPendingRemove.toArray(mPendingRemoveTmp);
7365                mPendingRemove.clear();
7366                for (int i=0; i<N; i++) {
7367                    WindowState w = mPendingRemoveTmp[i];
7368                    removeWindowInnerLocked(w.mSession, w);
7369                }
7370
7371                mInLayout = false;
7372                assignLayersLocked();
7373                mLayoutNeeded = true;
7374                performLayoutAndPlaceSurfacesLocked();
7375
7376            } else {
7377                mInLayout = false;
7378            }
7379
7380            if (mLayoutNeeded) {
7381                if (++mLayoutRepeatCount < 6) {
7382                    requestTraversalLocked();
7383                } else {
7384                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
7385                    mLayoutRepeatCount = 0;
7386                }
7387            } else {
7388                mLayoutRepeatCount = 0;
7389            }
7390
7391            if (mAnimator.mAnimating) {
7392                // Do this even if requestTraversalLocked was called above so we get a frame drawn
7393                // at the proper time as well as the one drawn early.
7394                scheduleAnimationLocked();
7395            }
7396
7397            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
7398                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
7399                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
7400            }
7401        } catch (RuntimeException e) {
7402            mInLayout = false;
7403            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
7404        }
7405    }
7406
7407    private final void performLayoutLockedInner(boolean initial, boolean updateInputWindows) {
7408        if (!mLayoutNeeded) {
7409            return;
7410        }
7411
7412        mLayoutNeeded = false;
7413
7414        final int dw = mCurDisplayWidth;
7415        final int dh = mCurDisplayHeight;
7416
7417        final int NFW = mFakeWindows.size();
7418        for (int i=0; i<NFW; i++) {
7419            mFakeWindows.get(i).layout(dw, dh);
7420        }
7421
7422        final int N = mWindows.size();
7423        int i;
7424
7425        if (DEBUG_LAYOUT) {
7426            Slog.v(TAG, "-------------------------------------");
7427            Slog.v(TAG, "performLayout: needed="
7428                    + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
7429        }
7430
7431        mPolicy.beginLayoutLw(dw, dh, mRotation);
7432
7433        int seq = mLayoutSeq+1;
7434        if (seq < 0) seq = 0;
7435        mLayoutSeq = seq;
7436
7437        // First perform layout of any root windows (not attached
7438        // to another window).
7439        int topAttached = -1;
7440        for (i = N-1; i >= 0; i--) {
7441            final WindowState win = mWindows.get(i);
7442
7443            // Don't do layout of a window if it is not visible, or
7444            // soon won't be visible, to avoid wasting time and funky
7445            // changes while a window is animating away.
7446            final boolean gone = win.isGoneForLayoutLw();
7447
7448            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
7449                Slog.v(TAG, "1ST PASS " + win
7450                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
7451                        + " mLayoutAttached=" + win.mLayoutAttached);
7452                final AppWindowToken atoken = win.mAppToken;
7453                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
7454                        + win.mViewVisibility + " mRelayoutCalled="
7455                        + win.mRelayoutCalled + " hidden="
7456                        + win.mRootToken.hidden + " hiddenRequested="
7457                        + (atoken != null && atoken.hiddenRequested)
7458                        + " mAttachedHidden=" + win.mAttachedHidden);
7459                else Slog.v(TAG, "  VIS: mViewVisibility="
7460                        + win.mViewVisibility + " mRelayoutCalled="
7461                        + win.mRelayoutCalled + " hidden="
7462                        + win.mRootToken.hidden + " hiddenRequested="
7463                        + (atoken != null && atoken.hiddenRequested)
7464                        + " mAttachedHidden=" + win.mAttachedHidden);
7465            }
7466
7467            // If this view is GONE, then skip it -- keep the current
7468            // frame, and let the caller know so they can ignore it
7469            // if they want.  (We do the normal layout for INVISIBLE
7470            // windows, since that means "perform layout as normal,
7471            // just don't display").
7472            if (!gone || !win.mHaveFrame || win.mLayoutNeeded) {
7473                if (!win.mLayoutAttached) {
7474                    if (initial) {
7475                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7476                        win.mContentChanged = false;
7477                    }
7478                    win.mLayoutNeeded = false;
7479                    win.prelayout();
7480                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
7481                    win.mLayoutSeq = seq;
7482                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7483                            + win.mFrame + " mContainingFrame="
7484                            + win.mContainingFrame + " mDisplayFrame="
7485                            + win.mDisplayFrame);
7486                } else {
7487                    if (topAttached < 0) topAttached = i;
7488                }
7489            }
7490        }
7491
7492        // Now perform layout of attached windows, which usually
7493        // depend on the position of the window they are attached to.
7494        // XXX does not deal with windows that are attached to windows
7495        // that are themselves attached.
7496        for (i = topAttached; i >= 0; i--) {
7497            final WindowState win = mWindows.get(i);
7498
7499            if (win.mLayoutAttached) {
7500                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
7501                        + " mHaveFrame=" + win.mHaveFrame
7502                        + " mViewVisibility=" + win.mViewVisibility
7503                        + " mRelayoutCalled=" + win.mRelayoutCalled);
7504                // If this view is GONE, then skip it -- keep the current
7505                // frame, and let the caller know so they can ignore it
7506                // if they want.  (We do the normal layout for INVISIBLE
7507                // windows, since that means "perform layout as normal,
7508                // just don't display").
7509                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7510                        || !win.mHaveFrame || win.mLayoutNeeded) {
7511                    if (initial) {
7512                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7513                        win.mContentChanged = false;
7514                    }
7515                    win.mLayoutNeeded = false;
7516                    win.prelayout();
7517                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7518                    win.mLayoutSeq = seq;
7519                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7520                            + win.mFrame + " mContainingFrame="
7521                            + win.mContainingFrame + " mDisplayFrame="
7522                            + win.mDisplayFrame);
7523                }
7524            }
7525        }
7526
7527        // Window frames may have changed.  Tell the input dispatcher about it.
7528        mInputMonitor.setUpdateInputWindowsNeededLw();
7529        if (updateInputWindows) {
7530            mInputMonitor.updateInputWindowsLw(false /*force*/);
7531        }
7532
7533        mPolicy.finishLayoutLw();
7534    }
7535
7536    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
7537        // If the screen is currently frozen or off, then keep
7538        // it frozen/off until this window draws at its new
7539        // orientation.
7540        if (!okToDisplay()) {
7541            if (DEBUG_ORIENTATION) Slog.v(TAG,
7542                    "Changing surface while display frozen: " + w);
7543            w.mOrientationChanging = true;
7544            if (!mWindowsFreezingScreen) {
7545                mWindowsFreezingScreen = true;
7546                // XXX should probably keep timeout from
7547                // when we first froze the display.
7548                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
7549                mH.sendMessageDelayed(mH.obtainMessage(
7550                        H.WINDOW_FREEZE_TIMEOUT), 2000);
7551            }
7552        }
7553    }
7554
7555    /**
7556     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
7557     *
7558     * @return bitmap indicating if another pass through layout must be made.
7559     */
7560    public int handleAppTransitionReadyLocked() {
7561        int changes = 0;
7562        int i;
7563        int NN = mOpeningApps.size();
7564        boolean goodToGo = true;
7565        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7566                "Checking " + NN + " opening apps (frozen="
7567                + mDisplayFrozen + " timeout="
7568                + mAppTransitionTimeout + ")...");
7569        if (!mDisplayFrozen && !mAppTransitionTimeout) {
7570            // If the display isn't frozen, wait to do anything until
7571            // all of the apps are ready.  Otherwise just go because
7572            // we'll unfreeze the display when everyone is ready.
7573            for (i=0; i<NN && goodToGo; i++) {
7574                AppWindowToken wtoken = mOpeningApps.get(i);
7575                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7576                        "Check opening app" + wtoken + ": allDrawn="
7577                        + wtoken.allDrawn + " startingDisplayed="
7578                        + wtoken.startingDisplayed);
7579                if (!wtoken.allDrawn && !wtoken.startingDisplayed
7580                        && !wtoken.startingMoved) {
7581                    goodToGo = false;
7582                }
7583            }
7584        }
7585        if (goodToGo) {
7586            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
7587            int transit = mNextAppTransition;
7588            if (mSkipAppTransitionAnimation) {
7589                transit = WindowManagerPolicy.TRANSIT_UNSET;
7590            }
7591            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
7592            mAppTransitionReady = false;
7593            mAppTransitionRunning = true;
7594            mAppTransitionTimeout = false;
7595            mStartingIconInTransition = false;
7596            mSkipAppTransitionAnimation = false;
7597
7598            mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
7599
7600            // If there are applications waiting to come to the
7601            // top of the stack, now is the time to move their windows.
7602            // (Note that we don't do apps going to the bottom
7603            // here -- we want to keep their windows in the old
7604            // Z-order until the animation completes.)
7605            if (mToTopApps.size() > 0) {
7606                NN = mAppTokens.size();
7607                for (i=0; i<NN; i++) {
7608                    AppWindowToken wtoken = mAppTokens.get(i);
7609                    if (wtoken.sendingToTop) {
7610                        wtoken.sendingToTop = false;
7611                        moveAppWindowsLocked(wtoken, NN, false);
7612                    }
7613                }
7614                mToTopApps.clear();
7615            }
7616
7617            WindowState oldWallpaper = mWallpaperTarget;
7618
7619            adjustWallpaperWindowsLocked();
7620            mInnerFields.mWallpaperMayChange = false;
7621
7622            // The top-most window will supply the layout params,
7623            // and we will determine it below.
7624            LayoutParams animLp = null;
7625            int bestAnimLayer = -1;
7626            boolean fullscreenAnim = false;
7627
7628            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7629                    "New wallpaper target=" + mWallpaperTarget
7630                    + ", lower target=" + mLowerWallpaperTarget
7631                    + ", upper target=" + mUpperWallpaperTarget);
7632            int foundWallpapers = 0;
7633            // Do a first pass through the tokens for two
7634            // things:
7635            // (1) Determine if both the closing and opening
7636            // app token sets are wallpaper targets, in which
7637            // case special animations are needed
7638            // (since the wallpaper needs to stay static
7639            // behind them).
7640            // (2) Find the layout params of the top-most
7641            // application window in the tokens, which is
7642            // what will control the animation theme.
7643            final int NC = mClosingApps.size();
7644            NN = NC + mOpeningApps.size();
7645            for (i=0; i<NN; i++) {
7646                AppWindowToken wtoken;
7647                int mode;
7648                if (i < NC) {
7649                    wtoken = mClosingApps.get(i);
7650                    mode = 1;
7651                } else {
7652                    wtoken = mOpeningApps.get(i-NC);
7653                    mode = 2;
7654                }
7655                if (mLowerWallpaperTarget != null) {
7656                    if (mLowerWallpaperTarget.mAppToken == wtoken
7657                            || mUpperWallpaperTarget.mAppToken == wtoken) {
7658                        foundWallpapers |= mode;
7659                    }
7660                }
7661                if (wtoken.appFullscreen) {
7662                    WindowState ws = wtoken.findMainWindow();
7663                    if (ws != null) {
7664                        animLp = ws.mAttrs;
7665                        bestAnimLayer = ws.mLayer;
7666                        fullscreenAnim = true;
7667                    }
7668                } else if (!fullscreenAnim) {
7669                    WindowState ws = wtoken.findMainWindow();
7670                    if (ws != null) {
7671                        if (ws.mLayer > bestAnimLayer) {
7672                            animLp = ws.mAttrs;
7673                            bestAnimLayer = ws.mLayer;
7674                        }
7675                    }
7676                }
7677            }
7678
7679            if (foundWallpapers == 3) {
7680                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7681                        "Wallpaper animation!");
7682                switch (transit) {
7683                    case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
7684                    case WindowManagerPolicy.TRANSIT_TASK_OPEN:
7685                    case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
7686                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
7687                        break;
7688                    case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
7689                    case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
7690                    case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
7691                        transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
7692                        break;
7693                }
7694                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7695                        "New transit: " + transit);
7696            } else if (oldWallpaper != null) {
7697                // We are transitioning from an activity with
7698                // a wallpaper to one without.
7699                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
7700                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7701                        "New transit away from wallpaper: " + transit);
7702            } else if (mWallpaperTarget != null) {
7703                // We are transitioning from an activity without
7704                // a wallpaper to now showing the wallpaper
7705                transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
7706                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7707                        "New transit into wallpaper: " + transit);
7708            }
7709
7710            // If all closing windows are obscured, then there is
7711            // no need to do an animation.  This is the case, for
7712            // example, when this transition is being done behind
7713            // the lock screen.
7714            if (!mPolicy.allowAppAnimationsLw()) {
7715                animLp = null;
7716            }
7717
7718            AppWindowToken topOpeningApp = null;
7719            int topOpeningLayer = 0;
7720
7721            // TODO(cmautner): Move to animation side.
7722            NN = mOpeningApps.size();
7723            for (i=0; i<NN; i++) {
7724                AppWindowToken wtoken = mOpeningApps.get(i);
7725                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
7726                wtoken.mAppAnimator.clearThumbnail();
7727                wtoken.reportedVisible = false;
7728                wtoken.inPendingTransaction = false;
7729                wtoken.mAppAnimator.animation = null;
7730                setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
7731                wtoken.updateReportedVisibilityLocked();
7732                wtoken.waitingToShow = false;
7733                mAnimator.mAnimating |= wtoken.mAppAnimator.showAllWindowsLocked();
7734                if (animLp != null) {
7735                    int layer = -1;
7736                    for (int j=0; j<wtoken.windows.size(); j++) {
7737                        WindowState win = wtoken.windows.get(j);
7738                        if (win.mWinAnimator.mAnimLayer > layer) {
7739                            layer = win.mWinAnimator.mAnimLayer;
7740                        }
7741                    }
7742                    if (topOpeningApp == null || layer > topOpeningLayer) {
7743                        topOpeningApp = wtoken;
7744                        topOpeningLayer = layer;
7745                    }
7746                }
7747            }
7748            NN = mClosingApps.size();
7749            for (i=0; i<NN; i++) {
7750                AppWindowToken wtoken = mClosingApps.get(i);
7751                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7752                        "Now closing app" + wtoken);
7753                wtoken.mAppAnimator.clearThumbnail();
7754                wtoken.inPendingTransaction = false;
7755                wtoken.mAppAnimator.animation = null;
7756                setTokenVisibilityLocked(wtoken, animLp, false,
7757                        transit, false);
7758                wtoken.updateReportedVisibilityLocked();
7759                wtoken.waitingToHide = false;
7760                // Force the allDrawn flag, because we want to start
7761                // this guy's animations regardless of whether it's
7762                // gotten drawn.
7763                wtoken.allDrawn = true;
7764            }
7765
7766            if (mNextAppTransitionThumbnail != null && topOpeningApp != null
7767                    && topOpeningApp.mAppAnimator.animation != null) {
7768                // This thumbnail animation is very special, we need to have
7769                // an extra surface with the thumbnail included with the animation.
7770                Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
7771                        mNextAppTransitionThumbnail.getHeight());
7772                try {
7773                    Surface surface = new Surface(mFxSession, Process.myPid(),
7774                            "thumbnail anim", 0, dirty.width(), dirty.height(),
7775                            PixelFormat.TRANSLUCENT, Surface.HIDDEN);
7776                    topOpeningApp.mAppAnimator.thumbnail = surface;
7777                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
7778                            + surface + ": CREATE");
7779                    Surface drawSurface = new Surface();
7780                    drawSurface.copyFrom(surface);
7781                    Canvas c = drawSurface.lockCanvas(dirty);
7782                    c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
7783                    drawSurface.unlockCanvasAndPost(c);
7784                    drawSurface.release();
7785                    topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
7786                    Animation anim = createThumbnailAnimationLocked(transit, true, true);
7787                    topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
7788                    anim.restrictDuration(MAX_ANIMATION_DURATION);
7789                    anim.scaleCurrentDuration(mTransitionAnimationScale);
7790                    topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX;
7791                    topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY;
7792                } catch (Surface.OutOfResourcesException e) {
7793                    Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
7794                            + " h=" + dirty.height(), e);
7795                    topOpeningApp.mAppAnimator.clearThumbnail();
7796                }
7797            }
7798
7799            mNextAppTransitionPackage = null;
7800            mNextAppTransitionThumbnail = null;
7801            if (mNextAppTransitionCallback != null) {
7802                try {
7803                    mNextAppTransitionCallback.sendResult(null);
7804                } catch (RemoteException e) {
7805                }
7806            }
7807
7808            mOpeningApps.clear();
7809            mClosingApps.clear();
7810
7811            // This has changed the visibility of windows, so perform
7812            // a new layout to get them all up-to-date.
7813            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
7814                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
7815            mLayoutNeeded = true;
7816            if (!moveInputMethodWindowsIfNeededLocked(true)) {
7817                assignLayersLocked();
7818            }
7819            updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
7820                    false /*updateInputWindows*/);
7821            mFocusMayChange = false;
7822        }
7823
7824        return changes;
7825    }
7826
7827    /**
7828     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
7829     *
7830     * @return bitmap indicating if another pass through layout must be made.
7831     */
7832    private int handleAnimatingStoppedAndTransitionLocked() {
7833        int changes = 0;
7834
7835        mAppTransitionRunning = false;
7836        // Clear information about apps that were moving.
7837        mToBottomApps.clear();
7838
7839        rebuildAppWindowListLocked();
7840        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
7841        mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
7842        moveInputMethodWindowsIfNeededLocked(false);
7843        mInnerFields.mWallpaperMayChange = true;
7844        // Since the window list has been rebuilt, focus might
7845        // have to be recomputed since the actual order of windows
7846        // might have changed again.
7847        mFocusMayChange = true;
7848
7849        return changes;
7850    }
7851
7852    /**
7853     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
7854     *
7855     * @return bitmap indicating if another pass through layout must be made.
7856     */
7857    private int animateAwayWallpaperLocked() {
7858        int changes = 0;
7859        WindowState oldWallpaper = mWallpaperTarget;
7860        if (mLowerWallpaperTarget != null
7861                && mLowerWallpaperTarget.mAppToken != null) {
7862            if (DEBUG_WALLPAPER) Slog.v(TAG,
7863                    "wallpaperForceHiding changed with lower="
7864                    + mLowerWallpaperTarget);
7865            if (DEBUG_WALLPAPER) Slog.v(TAG,
7866                    "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
7867                    " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
7868            if (mLowerWallpaperTarget.mAppToken.hidden) {
7869                // The lower target has become hidden before we
7870                // actually started the animation...  let's completely
7871                // re-evaluate everything.
7872                mLowerWallpaperTarget = mUpperWallpaperTarget = null;
7873                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
7874            }
7875        }
7876        mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
7877        if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
7878                + " NEW: " + mWallpaperTarget
7879                + " LOWER: " + mLowerWallpaperTarget);
7880        if (mLowerWallpaperTarget == null) {
7881            // Whoops, we don't need a special wallpaper animation.
7882            // Clear them out.
7883            mAnimator.mForceHiding = false;
7884            for (int i=mWindows.size()-1; i>=0; i--) {
7885                WindowState w = mWindows.get(i);
7886                if (w.mHasSurface) {
7887                    final WindowManager.LayoutParams attrs = w.mAttrs;
7888                    if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
7889                        if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
7890                        mAnimator.mForceHiding = true;
7891                    } else if (mPolicy.canBeForceHidden(w, attrs)) {
7892                        if (!w.mWinAnimator.mAnimating) {
7893                            // We set the animation above so it
7894                            // is not yet running.
7895                            // TODO(cmautner): We lose the enter animation when this occurs.
7896                            w.mWinAnimator.clearAnimation();
7897                        }
7898                    }
7899                }
7900            }
7901        }
7902        return changes;
7903    }
7904
7905    private void updateResizingWindows(final WindowState w) {
7906        final WindowStateAnimator winAnimator = w.mWinAnimator;
7907        if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
7908            w.mContentInsetsChanged |=
7909                !w.mLastContentInsets.equals(w.mContentInsets);
7910            w.mVisibleInsetsChanged |=
7911                !w.mLastVisibleInsets.equals(w.mVisibleInsets);
7912            boolean configChanged =
7913                w.mConfiguration != mCurConfiguration
7914                && (w.mConfiguration == null
7915                        || mCurConfiguration.diff(w.mConfiguration) != 0);
7916            if (DEBUG_CONFIGURATION && configChanged) {
7917                Slog.v(TAG, "Win " + w + " config changed: "
7918                        + mCurConfiguration);
7919            }
7920            if (localLOGV) Slog.v(TAG, "Resizing " + w
7921                    + ": configChanged=" + configChanged
7922                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
7923            w.mLastFrame.set(w.mFrame);
7924            if (w.mContentInsetsChanged
7925                    || w.mVisibleInsetsChanged
7926                    || winAnimator.mSurfaceResized
7927                    || configChanged) {
7928                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
7929                    Slog.v(TAG, "Resize reasons: "
7930                            + " contentInsetsChanged=" + w.mContentInsetsChanged
7931                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
7932                            + " surfaceResized=" + w.mWinAnimator.mSurfaceResized
7933                            + " configChanged=" + configChanged);
7934                }
7935
7936                w.mLastContentInsets.set(w.mContentInsets);
7937                w.mLastVisibleInsets.set(w.mVisibleInsets);
7938                makeWindowFreezingScreenIfNeededLocked(w);
7939                // If the orientation is changing, then we need to
7940                // hold off on unfreezing the display until this
7941                // window has been redrawn; to do that, we need
7942                // to go through the process of getting informed
7943                // by the application when it has finished drawing.
7944                if (w.mOrientationChanging) {
7945                    if (DEBUG_ORIENTATION) Slog.v(TAG,
7946                            "Orientation start waiting for draw in "
7947                            + w + ", surface " + w.mWinAnimator.mSurface);
7948                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
7949                    if (w.mAppToken != null) {
7950                        w.mAppToken.allDrawn = false;
7951                    }
7952                }
7953                if (!mResizingWindows.contains(w)) {
7954                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
7955                            "Resizing window " + w + " to " + w.mWinAnimator.mSurfaceW
7956                            + "x" + w.mWinAnimator.mSurfaceH);
7957                    mResizingWindows.add(w);
7958                }
7959            } else if (w.mOrientationChanging) {
7960                if (w.isDrawnLw()) {
7961                    if (DEBUG_ORIENTATION) Slog.v(TAG,
7962                            "Orientation not waiting for draw in "
7963                            + w + ", surface " + w.mWinAnimator.mSurface);
7964                    w.mOrientationChanging = false;
7965                }
7966            }
7967        }
7968    }
7969
7970    /**
7971     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
7972     *
7973     * @param w WindowState this method is applied to.
7974     * @param currentTime The time which animations use for calculating transitions.
7975     * @param innerDw Width of app window.
7976     * @param innerDh Height of app window.
7977     */
7978    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
7979                                         final int innerDw, final int innerDh) {
7980        final WindowManager.LayoutParams attrs = w.mAttrs;
7981        final int attrFlags = attrs.flags;
7982        final boolean canBeSeen = w.isDisplayedLw();
7983
7984        if (w.mHasSurface) {
7985            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
7986                mInnerFields.mHoldScreen = w.mSession;
7987            }
7988            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
7989                    && mInnerFields.mScreenBrightness < 0) {
7990                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
7991            }
7992            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
7993                    && mInnerFields.mButtonBrightness < 0) {
7994                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
7995            }
7996            if (canBeSeen
7997                    && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
7998                     || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
7999                     || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
8000                mInnerFields.mSyswin = true;
8001            }
8002        }
8003
8004        boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8005        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8006            // This window completely covers everything behind it,
8007            // so we want to leave all of them as undimmed (for
8008            // performance reasons).
8009            mInnerFields.mObscured = true;
8010        } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0) {
8011            if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured);
8012            if (!mInnerFields.mDimming) {
8013                //Slog.i(TAG, "DIM BEHIND: " + w);
8014                mInnerFields.mDimming = true;
8015                final int width, height;
8016                if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) {
8017                    width = mCurDisplayWidth;
8018                    height = mCurDisplayHeight;
8019                } else {
8020                    width = innerDw;
8021                    height = innerDh;
8022                }
8023                mAnimator.startDimming(w.mWinAnimator, w.mExiting ? 0 : w.mAttrs.dimAmount,
8024                        width, height);
8025            }
8026        }
8027    }
8028
8029    // "Something has changed!  Let's make it correct now."
8030    private final void performLayoutAndPlaceSurfacesLockedInner(
8031            boolean recoveringMemory) {
8032        if (mDisplay == null) {
8033            Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
8034            return;
8035        }
8036
8037        final long currentTime = SystemClock.uptimeMillis();
8038        final int dw = mCurDisplayWidth;
8039        final int dh = mCurDisplayHeight;
8040        final int innerDw = mAppDisplayWidth;
8041        final int innerDh = mAppDisplayHeight;
8042
8043        int i;
8044
8045        if (mFocusMayChange) {
8046            mFocusMayChange = false;
8047            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
8048                    false /*updateInputWindows*/);
8049        }
8050
8051        // Initialize state of exiting tokens.
8052        for (i=mExitingTokens.size()-1; i>=0; i--) {
8053            mExitingTokens.get(i).hasVisible = false;
8054        }
8055
8056        // Initialize state of exiting applications.
8057        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8058            mExitingAppTokens.get(i).hasVisible = false;
8059        }
8060
8061        mInnerFields.mHoldScreen = null;
8062        mInnerFields.mScreenBrightness = -1;
8063        mInnerFields.mButtonBrightness = -1;
8064        boolean focusDisplayed = false;
8065        mAnimator.mAnimating = false;
8066        boolean createWatermark = false;
8067
8068        if (mFxSession == null) {
8069            mFxSession = new SurfaceSession();
8070            createWatermark = true;
8071        }
8072
8073        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8074                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
8075
8076        Surface.openTransaction();
8077
8078        if (createWatermark) {
8079            createWatermark();
8080        }
8081        if (mWatermark != null) {
8082            mWatermark.positionSurface(dw, dh);
8083        }
8084        if (mStrictModeFlash != null) {
8085            mStrictModeFlash.positionSurface(dw, dh);
8086        }
8087
8088        try {
8089            int repeats = 0;
8090
8091            do {
8092                repeats++;
8093                if (repeats > 6) {
8094                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
8095                    mLayoutNeeded = false;
8096                    break;
8097                }
8098
8099                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
8100                    mPendingLayoutChanges);
8101
8102                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
8103                    if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8104                        assignLayersLocked();
8105                        mLayoutNeeded = true;
8106                    }
8107                }
8108
8109                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
8110                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
8111                    if (updateOrientationFromAppTokensLocked(true)) {
8112                        mLayoutNeeded = true;
8113                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8114                    }
8115                }
8116
8117                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8118                    mLayoutNeeded = true;
8119                }
8120
8121                // FIRST LOOP: Perform a layout, if needed.
8122                if (repeats < 4) {
8123                    performLayoutLockedInner(repeats == 1, false /*updateInputWindows*/);
8124                } else {
8125                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
8126                }
8127
8128                // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
8129                // it is animating.
8130                mPendingLayoutChanges = 0;
8131                if (DEBUG_LAYOUT_REPEATS)  debugLayoutRepeats("loop number " + mLayoutRepeatCount,
8132                    mPendingLayoutChanges);
8133                mPolicy.beginAnimationLw(dw, dh);
8134                for (i = mWindows.size() - 1; i >= 0; i--) {
8135                    WindowState w = mWindows.get(i);
8136                    if (w.mHasSurface) {
8137                        mPolicy.animatingWindowLw(w, w.mAttrs);
8138                    }
8139                }
8140                mPendingLayoutChanges |= mPolicy.finishAnimationLw();
8141                if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishAnimationLw",
8142                    mPendingLayoutChanges);
8143            } while (mPendingLayoutChanges != 0);
8144
8145            final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
8146
8147            mInnerFields.mObscured = false;
8148            mInnerFields.mDimming = false;
8149            mInnerFields.mSyswin = false;
8150
8151            final int N = mWindows.size();
8152            for (i=N-1; i>=0; i--) {
8153                WindowState w = mWindows.get(i);
8154
8155                if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) {
8156                    focusDisplayed = true;
8157                }
8158
8159                final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
8160
8161                // Update effect.
8162                w.mObscured = mInnerFields.mObscured;
8163                if (!mInnerFields.mObscured) {
8164                    handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
8165                }
8166
8167                if (obscuredChanged && mWallpaperTarget == w) {
8168                    // This is the wallpaper target and its obscured state
8169                    // changed... make sure the current wallaper's visibility
8170                    // has been updated accordingly.
8171                    updateWallpaperVisibilityLocked();
8172                }
8173            }
8174            if (!mInnerFields.mDimming && mAnimator.mDimParams != null) {
8175                mAnimator.stopDimming();
8176            }
8177        } catch (RuntimeException e) {
8178            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
8179        } finally {
8180            Surface.closeTransaction();
8181        }
8182
8183        // If we are ready to perform an app transition, check through
8184        // all of the app tokens to be shown and see if they are ready
8185        // to go.
8186        if (mAppTransitionReady) {
8187            mPendingLayoutChanges |= handleAppTransitionReadyLocked();
8188            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
8189                mPendingLayoutChanges);
8190        }
8191
8192        mInnerFields.mAdjResult = 0;
8193
8194        if (!mAnimator.mAnimating && mAppTransitionRunning) {
8195            // We have finished the animation of an app transition.  To do
8196            // this, we have delayed a lot of operations like showing and
8197            // hiding apps, moving apps in Z-order, etc.  The app token list
8198            // reflects the correct Z-order, but the window list may now
8199            // be out of sync with it.  So here we will just rebuild the
8200            // entire app window list.  Fun!
8201            mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
8202            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
8203                mPendingLayoutChanges);
8204        }
8205
8206        if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 &&
8207                !mAppTransitionReady) {
8208            // At this point, there was a window with a wallpaper that
8209            // was force hiding other windows behind it, but now it
8210            // is going away.  This may be simple -- just animate
8211            // away the wallpaper and its window -- or it may be
8212            // hard -- the wallpaper now needs to be shown behind
8213            // something that was hidden.
8214            mPendingLayoutChanges |= animateAwayWallpaperLocked();
8215            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
8216                mPendingLayoutChanges);
8217        }
8218        mInnerFields.mWallpaperForceHidingChanged = false;
8219
8220        if (mInnerFields.mWallpaperMayChange) {
8221            if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
8222                    "Wallpaper may change!  Adjusting");
8223            mInnerFields.mAdjResult |= adjustWallpaperWindowsLocked();
8224        }
8225
8226        if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8227            if (DEBUG_WALLPAPER) Slog.v(TAG,
8228                    "Wallpaper layer changed: assigning layers + relayout");
8229            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8230            assignLayersLocked();
8231        } else if ((mInnerFields.mAdjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
8232            if (DEBUG_WALLPAPER) Slog.v(TAG,
8233                    "Wallpaper visibility changed: relayout");
8234            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8235        }
8236
8237        if (mFocusMayChange) {
8238            mFocusMayChange = false;
8239            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8240                    false /*updateInputWindows*/)) {
8241                mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8242                mInnerFields.mAdjResult = 0;
8243            }
8244        }
8245
8246        if (mLayoutNeeded) {
8247            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8248            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded", mPendingLayoutChanges);
8249        }
8250
8251        final int N = mWindows.size();
8252        for (i=N-1; i>=0; i--) {
8253            final WindowState w = mWindows.get(i);
8254            final WindowStateAnimator winAnimator = w.mWinAnimator;
8255
8256            // If the window has moved due to its containing
8257            // content frame changing, then we'd like to animate
8258            // it.
8259            if (w.mHasSurface && w.shouldAnimateMove()) {
8260                // Frame has moved, containing content frame
8261                // has also moved, and we're not currently animating...
8262                // let's do something.
8263                Animation a = AnimationUtils.loadAnimation(mContext,
8264                        com.android.internal.R.anim.window_move_from_decor);
8265                winAnimator.setAnimation(a);
8266                winAnimator.mAnimDw = w.mLastFrame.left - w.mFrame.left;
8267                winAnimator.mAnimDh = w.mLastFrame.top - w.mFrame.top;
8268            } else {
8269                winAnimator.mAnimDw = innerDw;
8270                winAnimator.mAnimDh = innerDh;
8271            }
8272
8273            //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
8274            w.mContentChanged = false;
8275
8276            // TODO(cmautner): Can this move up to the loop at the end of try/catch above?
8277            updateResizingWindows(w);
8278
8279            // Moved from updateWindowsAndWallpaperLocked().
8280            if (w.mHasSurface) {
8281                // Take care of the window being ready to display.
8282                if (winAnimator.commitFinishDrawingLocked(currentTime)) {
8283                    if ((w.mAttrs.flags
8284                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
8285                        if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
8286                                "First draw done in potential wallpaper target " + w);
8287                        mInnerFields.mWallpaperMayChange = true;
8288                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
8289                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
8290                            debugLayoutRepeats("updateWindowsAndWallpaperLocked 1",
8291                                mPendingLayoutChanges);
8292                        }
8293                    }
8294                }
8295            }
8296        }
8297
8298        // Update animations of all applications, including those
8299        // associated with exiting/removed apps
8300        mAnimator.animate();
8301        mPendingLayoutChanges |= mAnimator.mPendingLayoutChanges;
8302        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animate()", mPendingLayoutChanges);
8303
8304        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8305                "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
8306
8307        if (mWatermark != null) {
8308            mWatermark.drawIfNeeded();
8309        }
8310
8311        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
8312                "With display frozen, orientationChangeComplete="
8313                + mInnerFields.mOrientationChangeComplete);
8314        if (mInnerFields.mOrientationChangeComplete) {
8315            if (mWindowsFreezingScreen) {
8316                mWindowsFreezingScreen = false;
8317                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8318            }
8319            stopFreezingDisplayLocked();
8320        }
8321
8322        if (!mResizingWindows.isEmpty()) {
8323            for (i = mResizingWindows.size() - 1; i >= 0; i--) {
8324                WindowState win = mResizingWindows.get(i);
8325                final WindowStateAnimator winAnimator = win.mWinAnimator;
8326                try {
8327                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8328                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
8329                    int diff = 0;
8330                    boolean configChanged =
8331                        win.mConfiguration != mCurConfiguration
8332                        && (win.mConfiguration == null
8333                                || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0);
8334                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
8335                            && configChanged) {
8336                        Slog.i(TAG, "Sending new config to window " + win + ": "
8337                                + winAnimator.mSurfaceW + "x" + winAnimator.mSurfaceH
8338                                + " / " + mCurConfiguration + " / 0x"
8339                                + Integer.toHexString(diff));
8340                    }
8341                    win.mConfiguration = mCurConfiguration;
8342                    if (DEBUG_ORIENTATION &&
8343                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i(
8344                            TAG, "Resizing " + win + " WITH DRAW PENDING");
8345                    win.mClient.resized((int)winAnimator.mSurfaceW,
8346                            (int)winAnimator.mSurfaceH,
8347                            win.mLastContentInsets, win.mLastVisibleInsets,
8348                            winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING,
8349                            configChanged ? win.mConfiguration : null);
8350                    win.mContentInsetsChanged = false;
8351                    win.mVisibleInsetsChanged = false;
8352                    winAnimator.mSurfaceResized = false;
8353                } catch (RemoteException e) {
8354                    win.mOrientationChanging = false;
8355                }
8356            }
8357            mResizingWindows.clear();
8358        }
8359
8360        // Destroy the surface of any windows that are no longer visible.
8361        boolean wallpaperDestroyed = false;
8362        i = mDestroySurface.size();
8363        if (i > 0) {
8364            do {
8365                i--;
8366                WindowState win = mDestroySurface.get(i);
8367                win.mDestroying = false;
8368                if (mInputMethodWindow == win) {
8369                    mInputMethodWindow = null;
8370                }
8371                if (win == mWallpaperTarget) {
8372                    wallpaperDestroyed = true;
8373                }
8374                win.mWinAnimator.destroySurfaceLocked();
8375            } while (i > 0);
8376            mDestroySurface.clear();
8377        }
8378
8379        // Time to remove any exiting tokens?
8380        for (i=mExitingTokens.size()-1; i>=0; i--) {
8381            WindowToken token = mExitingTokens.get(i);
8382            if (!token.hasVisible) {
8383                mExitingTokens.remove(i);
8384                if (token.windowType == TYPE_WALLPAPER) {
8385                    mWallpaperTokens.remove(token);
8386                }
8387            }
8388        }
8389
8390        // Time to remove any exiting applications?
8391        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8392            AppWindowToken token = mExitingAppTokens.get(i);
8393            if (!token.hasVisible && !mClosingApps.contains(token)) {
8394                // Make sure there is no animation running on this token,
8395                // so any windows associated with it will be removed as
8396                // soon as their animations are complete
8397                token.mAppAnimator.clearAnimation();
8398                token.mAppAnimator.animating = false;
8399                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
8400                        "performLayout: App token exiting now removed" + token);
8401                mAppTokens.remove(token);
8402                mExitingAppTokens.remove(i);
8403            }
8404        }
8405
8406        if (!mAnimator.mAnimating && mAppTransitionRunning) {
8407            // We have finished the animation of an app transition.  To do
8408            // this, we have delayed a lot of operations like showing and
8409            // hiding apps, moving apps in Z-order, etc.  The app token list
8410            // reflects the correct Z-order, but the window list may now
8411            // be out of sync with it.  So here we will just rebuild the
8412            // entire app window list.  Fun!
8413            mAppTransitionRunning = false;
8414            mLayoutNeeded = true;
8415            rebuildAppWindowListLocked();
8416            assignLayersLocked();
8417            // Clear information about apps that were moving.
8418            mToBottomApps.clear();
8419        }
8420
8421        if (focusDisplayed) {
8422            mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8423        }
8424        if (wallpaperDestroyed) {
8425            mLayoutNeeded |= adjustWallpaperWindowsLocked() != 0;
8426        }
8427        if (mPendingLayoutChanges != 0) {
8428            mLayoutNeeded = true;
8429        }
8430
8431        // Finally update all input windows now that the window changes have stabilized.
8432        mInputMonitor.updateInputWindowsLw(true /*force*/);
8433
8434        setHoldScreenLocked(mInnerFields.mHoldScreen != null);
8435        if (!mDisplayFrozen) {
8436            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
8437                mPowerManager.setScreenBrightnessOverride(-1);
8438            } else {
8439                mPowerManager.setScreenBrightnessOverride((int)
8440                        (mInnerFields.mScreenBrightness * Power.BRIGHTNESS_ON));
8441            }
8442            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
8443                mPowerManager.setButtonBrightnessOverride(-1);
8444            } else {
8445                mPowerManager.setButtonBrightnessOverride((int)
8446                        (mInnerFields.mButtonBrightness * Power.BRIGHTNESS_ON));
8447            }
8448        }
8449        if (mInnerFields.mHoldScreen != mHoldingScreenOn) {
8450            mHoldingScreenOn = mInnerFields.mHoldScreen;
8451            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, mInnerFields.mHoldScreen);
8452            mH.sendMessage(m);
8453        }
8454
8455        if (mTurnOnScreen) {
8456            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
8457            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
8458                    LocalPowerManager.BUTTON_EVENT, true);
8459            mTurnOnScreen = false;
8460        }
8461
8462        if (mInnerFields.mUpdateRotation) {
8463            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8464            if (updateRotationUncheckedLocked(false)) {
8465                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8466            } else {
8467                mInnerFields.mUpdateRotation = false;
8468            }
8469        }
8470
8471        if (mInnerFields.mOrientationChangeComplete && !mLayoutNeeded &&
8472                !mInnerFields.mUpdateRotation) {
8473            checkDrawnWindowsLocked();
8474        }
8475
8476        // Check to see if we are now in a state where the screen should
8477        // be enabled, because the window obscured flags have changed.
8478        enableScreenIfNeededLocked();
8479//        Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: mPendingLayoutChanges="
8480//                + Integer.toHexString(mPendingLayoutChanges) + " mLayoutNeeded=" + mLayoutNeeded
8481//                + " animating=" + mAnimator.mAnimating);
8482    }
8483
8484    void checkDrawnWindowsLocked() {
8485        if (mWaitingForDrawn.size() > 0) {
8486            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
8487                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
8488                WindowState win = pair.first;
8489                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
8490                //        + win.mRemoved + " visible=" + win.isVisibleLw()
8491                //        + " shown=" + win.mSurfaceShown);
8492                if (win.mRemoved || !win.isVisibleLw()) {
8493                    // Window has been removed or made invisible; no draw
8494                    // will now happen, so stop waiting.
8495                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
8496                    try {
8497                        pair.second.sendResult(null);
8498                    } catch (RemoteException e) {
8499                    }
8500                    mWaitingForDrawn.remove(pair);
8501                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8502                } else if (win.mWinAnimator.mSurfaceShown) {
8503                    // Window is now drawn (and shown).
8504                    try {
8505                        pair.second.sendResult(null);
8506                    } catch (RemoteException e) {
8507                    }
8508                    mWaitingForDrawn.remove(pair);
8509                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8510                }
8511            }
8512        }
8513    }
8514
8515    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
8516        synchronized (mWindowMap) {
8517            WindowState win = windowForClientLocked(null, token, true);
8518            if (win != null) {
8519                Pair<WindowState, IRemoteCallback> pair =
8520                        new Pair<WindowState, IRemoteCallback>(win, callback);
8521                Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8522                mH.sendMessageDelayed(m, 2000);
8523                mWaitingForDrawn.add(pair);
8524                checkDrawnWindowsLocked();
8525            }
8526        }
8527    }
8528
8529    /**
8530     * Must be called with the main window manager lock held.
8531     */
8532    void setHoldScreenLocked(boolean holding) {
8533        boolean state = mHoldingScreenWakeLock.isHeld();
8534        if (holding != state) {
8535            if (holding) {
8536                mPolicy.screenOnStartedLw();
8537                mHoldingScreenWakeLock.acquire();
8538            } else {
8539                mPolicy.screenOnStoppedLw();
8540                mHoldingScreenWakeLock.release();
8541            }
8542        }
8543    }
8544
8545    void requestTraversalLocked() {
8546        if (!mTraversalScheduled) {
8547            mTraversalScheduled = true;
8548            mH.sendEmptyMessage(H.DO_TRAVERSAL);
8549        }
8550    }
8551
8552    void scheduleAnimationLocked() {
8553        if (!mAnimationScheduled) {
8554            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationRunnable, null);
8555            mAnimationScheduled = true;
8556        }
8557    }
8558
8559    boolean reclaimSomeSurfaceMemoryLocked(WindowStateAnimator winAnimator, String operation,
8560                                           boolean secure) {
8561        final Surface surface = winAnimator.mSurface;
8562        boolean leakedSurface = false;
8563        boolean killedApps = false;
8564
8565        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
8566                winAnimator.mSession.mPid, operation);
8567
8568        if (mForceRemoves == null) {
8569            mForceRemoves = new ArrayList<WindowState>();
8570        }
8571
8572        long callingIdentity = Binder.clearCallingIdentity();
8573        try {
8574            // There was some problem...   first, do a sanity check of the
8575            // window list to make sure we haven't left any dangling surfaces
8576            // around.
8577            int N = mWindows.size();
8578            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
8579            for (int i=0; i<N; i++) {
8580                WindowState ws = mWindows.get(i);
8581                WindowStateAnimator wsa = ws.mWinAnimator;
8582                if (wsa.mSurface != null) {
8583                    if (!mSessions.contains(wsa.mSession)) {
8584                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8585                                + ws + " surface=" + wsa.mSurface
8586                                + " token=" + ws.mToken
8587                                + " pid=" + ws.mSession.mPid
8588                                + " uid=" + ws.mSession.mUid);
8589                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8590                        wsa.mSurface.destroy();
8591                        wsa.mSurfaceShown = false;
8592                        wsa.mSurface = null;
8593                        ws.mHasSurface = false;
8594                        mAnimator.mWinAnimators.remove(wsa);
8595                        mForceRemoves.add(ws);
8596                        i--;
8597                        N--;
8598                        leakedSurface = true;
8599                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
8600                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
8601                                + ws + " surface=" + wsa.mSurface
8602                                + " token=" + ws.mAppToken);
8603                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8604                        wsa.mSurface.destroy();
8605                        wsa.mSurfaceShown = false;
8606                        wsa.mSurface = null;
8607                        ws.mHasSurface = false;
8608                        mAnimator.mWinAnimators.remove(wsa);
8609                        leakedSurface = true;
8610                    }
8611                }
8612            }
8613
8614            if (!leakedSurface) {
8615                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
8616                SparseIntArray pidCandidates = new SparseIntArray();
8617                for (int i=0; i<N; i++) {
8618                    WindowStateAnimator wsa = mWindows.get(i).mWinAnimator;
8619                    if (wsa.mSurface != null) {
8620                        pidCandidates.append(wsa.mSession.mPid, wsa.mSession.mPid);
8621                    }
8622                }
8623                if (pidCandidates.size() > 0) {
8624                    int[] pids = new int[pidCandidates.size()];
8625                    for (int i=0; i<pids.length; i++) {
8626                        pids[i] = pidCandidates.keyAt(i);
8627                    }
8628                    try {
8629                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
8630                            killedApps = true;
8631                        }
8632                    } catch (RemoteException e) {
8633                    }
8634                }
8635            }
8636
8637            if (leakedSurface || killedApps) {
8638                // We managed to reclaim some memory, so get rid of the trouble
8639                // surface and ask the app to request another one.
8640                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8641                if (surface != null) {
8642                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(winAnimator.mWin,
8643                            "RECOVER DESTROY", null);
8644                    surface.destroy();
8645                    winAnimator.mSurfaceShown = false;
8646                    winAnimator.mSurface = null;
8647                    winAnimator.mWin.mHasSurface = false;
8648                    mAnimator.mWinAnimators.remove(winAnimator);
8649                }
8650
8651                try {
8652                    winAnimator.mWin.mClient.dispatchGetNewSurface();
8653                } catch (RemoteException e) {
8654                }
8655            }
8656        } finally {
8657            Binder.restoreCallingIdentity(callingIdentity);
8658        }
8659
8660        return leakedSurface || killedApps;
8661    }
8662
8663    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
8664        WindowState newFocus = computeFocusedWindowLocked();
8665        if (mCurrentFocus != newFocus) {
8666            // This check makes sure that we don't already have the focus
8667            // change message pending.
8668            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
8669            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
8670            if (localLOGV) Slog.v(
8671                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
8672            final WindowState oldFocus = mCurrentFocus;
8673            mCurrentFocus = newFocus;
8674            mAnimator.setCurrentFocus(newFocus);
8675            mLosingFocus.remove(newFocus);
8676            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
8677
8678            final WindowState imWindow = mInputMethodWindow;
8679            if (newFocus != imWindow && oldFocus != imWindow) {
8680                if (moveInputMethodWindowsIfNeededLocked(
8681                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
8682                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
8683                    mLayoutNeeded = true;
8684                }
8685                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8686                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
8687                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
8688                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
8689                    // Client will do the layout, but we need to assign layers
8690                    // for handleNewWindowLocked() below.
8691                    assignLayersLocked();
8692                }
8693            }
8694
8695            if ((focusChanged&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
8696                // The change in focus caused us to need to do a layout.  Okay.
8697                mLayoutNeeded = true;
8698                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8699                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
8700                }
8701            }
8702
8703            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
8704                // If we defer assigning layers, then the caller is responsible for
8705                // doing this part.
8706                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
8707            }
8708            return true;
8709        }
8710        return false;
8711    }
8712
8713    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
8714        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
8715    }
8716
8717    private WindowState computeFocusedWindowLocked() {
8718        WindowState result = null;
8719        WindowState win;
8720
8721        int nextAppIndex = mAppTokens.size()-1;
8722        WindowToken nextApp = nextAppIndex >= 0
8723            ? mAppTokens.get(nextAppIndex) : null;
8724
8725        for (int i = mWindows.size() - 1; i >= 0; i--) {
8726            win = mWindows.get(i);
8727
8728            if (localLOGV || DEBUG_FOCUS) Slog.v(
8729                TAG, "Looking for focus: " + i
8730                + " = " + win
8731                + ", flags=" + win.mAttrs.flags
8732                + ", canReceive=" + win.canReceiveKeys());
8733
8734            AppWindowToken thisApp = win.mAppToken;
8735
8736            // If this window's application has been removed, just skip it.
8737            if (thisApp != null && thisApp.removed) {
8738                continue;
8739            }
8740
8741            // If there is a focused app, don't allow focus to go to any
8742            // windows below it.  If this is an application window, step
8743            // through the app tokens until we find its app.
8744            if (thisApp != null && nextApp != null && thisApp != nextApp
8745                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
8746                int origAppIndex = nextAppIndex;
8747                while (nextAppIndex > 0) {
8748                    if (nextApp == mFocusedApp) {
8749                        // Whoops, we are below the focused app...  no focus
8750                        // for you!
8751                        if (localLOGV || DEBUG_FOCUS) Slog.v(
8752                            TAG, "Reached focused app: " + mFocusedApp);
8753                        return null;
8754                    }
8755                    nextAppIndex--;
8756                    nextApp = mAppTokens.get(nextAppIndex);
8757                    if (nextApp == thisApp) {
8758                        break;
8759                    }
8760                }
8761                if (thisApp != nextApp) {
8762                    // Uh oh, the app token doesn't exist!  This shouldn't
8763                    // happen, but if it does we can get totally hosed...
8764                    // so restart at the original app.
8765                    nextAppIndex = origAppIndex;
8766                    nextApp = mAppTokens.get(nextAppIndex);
8767                }
8768            }
8769
8770            // Dispatch to this window if it is wants key events.
8771            if (win.canReceiveKeys()) {
8772                if (DEBUG_FOCUS) Slog.v(
8773                        TAG, "Found focus @ " + i + " = " + win);
8774                result = win;
8775                break;
8776            }
8777        }
8778
8779        return result;
8780    }
8781
8782    private void startFreezingDisplayLocked(boolean inTransaction) {
8783        if (mDisplayFrozen) {
8784            return;
8785        }
8786
8787        if (mDisplay == null || !mPolicy.isScreenOnFully()) {
8788            // No need to freeze the screen before the system is ready or if
8789            // the screen is off.
8790            return;
8791        }
8792
8793        mScreenFrozenLock.acquire();
8794
8795        mDisplayFrozen = true;
8796
8797        mInputMonitor.freezeInputDispatchingLw();
8798
8799        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
8800            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
8801            mNextAppTransitionPackage = null;
8802            mNextAppTransitionThumbnail = null;
8803            mAppTransitionReady = true;
8804        }
8805
8806        if (PROFILE_ORIENTATION) {
8807            File file = new File("/data/system/frozen");
8808            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
8809        }
8810
8811        if (CUSTOM_SCREEN_ROTATION) {
8812            if (mAnimator.mScreenRotationAnimation != null) {
8813                mAnimator.mScreenRotationAnimation.kill();
8814                mAnimator.mScreenRotationAnimation = null;
8815            }
8816
8817            mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
8818                    mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight,
8819                    mDisplay.getRotation());
8820
8821            if (!mAnimator.mScreenRotationAnimation.hasScreenshot()) {
8822                Surface.freezeDisplay(0);
8823            }
8824        } else {
8825            Surface.freezeDisplay(0);
8826        }
8827    }
8828
8829    private void stopFreezingDisplayLocked() {
8830        if (!mDisplayFrozen) {
8831            return;
8832        }
8833
8834        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
8835            if (DEBUG_ORIENTATION) Slog.d(TAG,
8836                "stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
8837                + ", mAppsFreezingScreen=" + mAppsFreezingScreen
8838                + ", mWindowsFreezingScreen=" + mWindowsFreezingScreen);
8839            return;
8840        }
8841
8842        mDisplayFrozen = false;
8843        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
8844        if (PROFILE_ORIENTATION) {
8845            Debug.stopMethodTracing();
8846        }
8847
8848        boolean updateRotation = false;
8849
8850        if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
8851                && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
8852            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
8853            if (mAnimator.mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
8854                    mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
8855                scheduleAnimationLocked();
8856            } else {
8857                mAnimator.mScreenRotationAnimation = null;
8858                updateRotation = true;
8859            }
8860        } else {
8861            if (mAnimator.mScreenRotationAnimation != null) {
8862                mAnimator.mScreenRotationAnimation.kill();
8863                mAnimator.mScreenRotationAnimation = null;
8864            }
8865            updateRotation = true;
8866        }
8867        Surface.unfreezeDisplay(0);
8868
8869        mInputMonitor.thawInputDispatchingLw();
8870
8871        boolean configChanged;
8872
8873        // While the display is frozen we don't re-compute the orientation
8874        // to avoid inconsistent states.  However, something interesting
8875        // could have actually changed during that time so re-evaluate it
8876        // now to catch that.
8877        configChanged = updateOrientationFromAppTokensLocked(false);
8878
8879        // A little kludge: a lot could have happened while the
8880        // display was frozen, so now that we are coming back we
8881        // do a gc so that any remote references the system
8882        // processes holds on others can be released if they are
8883        // no longer needed.
8884        mH.removeMessages(H.FORCE_GC);
8885        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
8886                2000);
8887
8888        mScreenFrozenLock.release();
8889
8890        if (updateRotation) {
8891            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8892            configChanged |= updateRotationUncheckedLocked(false);
8893        }
8894
8895        if (configChanged) {
8896            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8897        }
8898    }
8899
8900    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
8901            DisplayMetrics dm) {
8902        if (index < tokens.length) {
8903            String str = tokens[index];
8904            if (str != null && str.length() > 0) {
8905                try {
8906                    int val = Integer.parseInt(str);
8907                    return val;
8908                } catch (Exception e) {
8909                }
8910            }
8911        }
8912        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
8913            return defDps;
8914        }
8915        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
8916        return val;
8917    }
8918
8919    void createWatermark() {
8920        if (mWatermark != null) {
8921            return;
8922        }
8923
8924        File file = new File("/system/etc/setup.conf");
8925        FileInputStream in = null;
8926        try {
8927            in = new FileInputStream(file);
8928            DataInputStream ind = new DataInputStream(in);
8929            String line = ind.readLine();
8930            if (line != null) {
8931                String[] toks = line.split("%");
8932                if (toks != null && toks.length > 0) {
8933                    mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks);
8934                }
8935            }
8936        } catch (FileNotFoundException e) {
8937        } catch (IOException e) {
8938        } finally {
8939            if (in != null) {
8940                try {
8941                    in.close();
8942                } catch (IOException e) {
8943                }
8944            }
8945        }
8946    }
8947
8948    @Override
8949    public void statusBarVisibilityChanged(int visibility) {
8950        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
8951                != PackageManager.PERMISSION_GRANTED) {
8952            throw new SecurityException("Caller does not hold permission "
8953                    + android.Manifest.permission.STATUS_BAR);
8954        }
8955
8956        synchronized (mWindowMap) {
8957            mLastStatusBarVisibility = visibility;
8958            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
8959            updateStatusBarVisibilityLocked(visibility);
8960        }
8961    }
8962
8963    void updateStatusBarVisibilityLocked(int visibility) {
8964        mInputManager.setSystemUiVisibility(visibility);
8965        final int N = mWindows.size();
8966        for (int i = 0; i < N; i++) {
8967            WindowState ws = mWindows.get(i);
8968            try {
8969                int curValue = ws.mSystemUiVisibility;
8970                int diff = curValue ^ visibility;
8971                // We are only interested in differences of one of the
8972                // clearable flags...
8973                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
8974                // ...if it has actually been cleared.
8975                diff &= ~visibility;
8976                int newValue = (curValue&~diff) | (visibility&diff);
8977                if (newValue != curValue) {
8978                    ws.mSeq++;
8979                    ws.mSystemUiVisibility = newValue;
8980                }
8981                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
8982                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
8983                            visibility, newValue, diff);
8984                }
8985            } catch (RemoteException e) {
8986                // so sorry
8987            }
8988        }
8989    }
8990
8991    @Override
8992    public void reevaluateStatusBarVisibility() {
8993        synchronized (mWindowMap) {
8994            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
8995            updateStatusBarVisibilityLocked(visibility);
8996            performLayoutAndPlaceSurfacesLocked();
8997        }
8998    }
8999
9000    @Override
9001    public FakeWindow addFakeWindow(Looper looper,
9002            InputEventReceiver.Factory inputEventReceiverFactory,
9003            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
9004            boolean hasFocus, boolean touchFullscreen) {
9005        synchronized (mWindowMap) {
9006            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
9007                    name, windowType,
9008                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
9009            int i=0;
9010            while (i<mFakeWindows.size()) {
9011                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
9012                    break;
9013                }
9014            }
9015            mFakeWindows.add(i, fw);
9016            mInputMonitor.updateInputWindowsLw(true);
9017            return fw;
9018        }
9019    }
9020
9021    boolean removeFakeWindowLocked(FakeWindow window) {
9022        synchronized (mWindowMap) {
9023            if (mFakeWindows.remove(window)) {
9024                mInputMonitor.updateInputWindowsLw(true);
9025                return true;
9026            }
9027            return false;
9028        }
9029    }
9030
9031    @Override
9032    public boolean hasNavigationBar() {
9033        return mPolicy.hasNavigationBar();
9034    }
9035
9036    public void lockNow() {
9037        mPolicy.lockNow();
9038    }
9039
9040    void dumpPolicyLocked(FileDescriptor fd, PrintWriter pw, String[] args, boolean dumpAll) {
9041        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
9042        mPolicy.dump("    ", fd, pw, args);
9043    }
9044
9045    void dumpTokensLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9046        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
9047        if (mTokenMap.size() > 0) {
9048            pw.println("  All tokens:");
9049            Iterator<WindowToken> it = mTokenMap.values().iterator();
9050            while (it.hasNext()) {
9051                WindowToken token = it.next();
9052                pw.print("  Token "); pw.print(token.token);
9053                if (dumpAll) {
9054                    pw.println(':');
9055                    token.dump(pw, "    ");
9056                } else {
9057                    pw.println();
9058                }
9059            }
9060        }
9061        if (mWallpaperTokens.size() > 0) {
9062            pw.println();
9063            pw.println("  Wallpaper tokens:");
9064            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
9065                WindowToken token = mWallpaperTokens.get(i);
9066                pw.print("  Wallpaper #"); pw.print(i);
9067                        pw.print(' '); pw.print(token);
9068                if (dumpAll) {
9069                    pw.println(':');
9070                    token.dump(pw, "    ");
9071                } else {
9072                    pw.println();
9073                }
9074            }
9075        }
9076        if (mAppTokens.size() > 0) {
9077            pw.println();
9078            pw.println("  Application tokens in Z order:");
9079            for (int i=mAppTokens.size()-1; i>=0; i--) {
9080                pw.print("  App #"); pw.print(i); pw.println(": ");
9081                        mAppTokens.get(i).dump(pw, "    ");
9082            }
9083        }
9084        if (mFinishedStarting.size() > 0) {
9085            pw.println();
9086            pw.println("  Finishing start of application tokens:");
9087            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9088                WindowToken token = mFinishedStarting.get(i);
9089                pw.print("  Finished Starting #"); 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 (mExitingTokens.size() > 0) {
9100            pw.println();
9101            pw.println("  Exiting tokens:");
9102            for (int i=mExitingTokens.size()-1; i>=0; i--) {
9103                WindowToken token = mExitingTokens.get(i);
9104                pw.print("  Exiting #"); 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        if (mExitingAppTokens.size() > 0) {
9115            pw.println();
9116            pw.println("  Exiting application tokens:");
9117            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9118                WindowToken token = mExitingAppTokens.get(i);
9119                pw.print("  Exiting App #"); pw.print(i);
9120                        pw.print(' '); pw.print(token);
9121                if (dumpAll) {
9122                    pw.println(':');
9123                    token.dump(pw, "    ");
9124                } else {
9125                    pw.println();
9126                }
9127            }
9128        }
9129        pw.println();
9130        if (mOpeningApps.size() > 0) {
9131            pw.print("  mOpeningApps="); pw.println(mOpeningApps);
9132        }
9133        if (mClosingApps.size() > 0) {
9134            pw.print("  mClosingApps="); pw.println(mClosingApps);
9135        }
9136        if (mToTopApps.size() > 0) {
9137            pw.print("  mToTopApps="); pw.println(mToTopApps);
9138        }
9139        if (mToBottomApps.size() > 0) {
9140            pw.print("  mToBottomApps="); pw.println(mToBottomApps);
9141        }
9142    }
9143
9144    void dumpSessionsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9145        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
9146        if (mSessions.size() > 0) {
9147            Iterator<Session> it = mSessions.iterator();
9148            while (it.hasNext()) {
9149                Session s = it.next();
9150                pw.print("  Session "); pw.print(s); pw.println(':');
9151                s.dump(pw, "    ");
9152            }
9153        }
9154    }
9155
9156    void dumpWindowsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
9157            ArrayList<WindowState> windows) {
9158        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
9159        for (int i=mWindows.size()-1; i>=0; i--) {
9160            WindowState w = mWindows.get(i);
9161            if (windows == null || windows.contains(w)) {
9162                pw.print("  Window #"); pw.print(i); pw.print(' ');
9163                        pw.print(w); pw.println(":");
9164                w.dump(pw, "    ", dumpAll || windows != null);
9165            }
9166        }
9167        if (mInputMethodDialogs.size() > 0) {
9168            pw.println();
9169            pw.println("  Input method dialogs:");
9170            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
9171                WindowState w = mInputMethodDialogs.get(i);
9172                if (windows == null || windows.contains(w)) {
9173                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
9174                }
9175            }
9176        }
9177        if (mPendingRemove.size() > 0) {
9178            pw.println();
9179            pw.println("  Remove pending for:");
9180            for (int i=mPendingRemove.size()-1; i>=0; i--) {
9181                WindowState w = mPendingRemove.get(i);
9182                if (windows == null || windows.contains(w)) {
9183                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
9184                            pw.print(w);
9185                    if (dumpAll) {
9186                        pw.println(":");
9187                        w.dump(pw, "    ", true);
9188                    } else {
9189                        pw.println();
9190                    }
9191                }
9192            }
9193        }
9194        if (mForceRemoves != null && mForceRemoves.size() > 0) {
9195            pw.println();
9196            pw.println("  Windows force removing:");
9197            for (int i=mForceRemoves.size()-1; i>=0; i--) {
9198                WindowState w = mForceRemoves.get(i);
9199                pw.print("  Removing #"); pw.print(i); pw.print(' ');
9200                        pw.print(w);
9201                if (dumpAll) {
9202                    pw.println(":");
9203                    w.dump(pw, "    ", true);
9204                } else {
9205                    pw.println();
9206                }
9207            }
9208        }
9209        if (mDestroySurface.size() > 0) {
9210            pw.println();
9211            pw.println("  Windows waiting to destroy their surface:");
9212            for (int i=mDestroySurface.size()-1; i>=0; i--) {
9213                WindowState w = mDestroySurface.get(i);
9214                if (windows == null || windows.contains(w)) {
9215                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
9216                            pw.print(w);
9217                    if (dumpAll) {
9218                        pw.println(":");
9219                        w.dump(pw, "    ", true);
9220                    } else {
9221                        pw.println();
9222                    }
9223                }
9224            }
9225        }
9226        if (mLosingFocus.size() > 0) {
9227            pw.println();
9228            pw.println("  Windows losing focus:");
9229            for (int i=mLosingFocus.size()-1; i>=0; i--) {
9230                WindowState w = mLosingFocus.get(i);
9231                if (windows == null || windows.contains(w)) {
9232                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
9233                            pw.print(w);
9234                    if (dumpAll) {
9235                        pw.println(":");
9236                        w.dump(pw, "    ", true);
9237                    } else {
9238                        pw.println();
9239                    }
9240                }
9241            }
9242        }
9243        if (mResizingWindows.size() > 0) {
9244            pw.println();
9245            pw.println("  Windows waiting to resize:");
9246            for (int i=mResizingWindows.size()-1; i>=0; i--) {
9247                WindowState w = mResizingWindows.get(i);
9248                if (windows == null || windows.contains(w)) {
9249                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
9250                            pw.print(w);
9251                    if (dumpAll) {
9252                        pw.println(":");
9253                        w.dump(pw, "    ", true);
9254                    } else {
9255                        pw.println();
9256                    }
9257                }
9258            }
9259        }
9260        if (mWaitingForDrawn.size() > 0) {
9261            pw.println();
9262            pw.println("  Clients waiting for these windows to be drawn:");
9263            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
9264                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
9265                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
9266                        pw.print(": "); pw.println(pair.second);
9267            }
9268        }
9269        pw.println();
9270        if (mDisplay != null) {
9271            pw.print("  Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
9272                    pw.print(mInitialDisplayHeight); pw.print(" base=");
9273                    pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
9274                    pw.print(" cur=");
9275                    pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
9276                    pw.print(" app=");
9277                    pw.print(mAppDisplayWidth); pw.print("x"); pw.print(mAppDisplayHeight);
9278                    pw.print(" raw="); pw.print(mDisplay.getRawWidth());
9279                    pw.print("x"); pw.println(mDisplay.getRawHeight());
9280        } else {
9281            pw.println("  NO DISPLAY");
9282        }
9283        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
9284        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
9285        if (mLastFocus != mCurrentFocus) {
9286            pw.print("  mLastFocus="); pw.println(mLastFocus);
9287        }
9288        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
9289        if (mInputMethodTarget != null) {
9290            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
9291        }
9292        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
9293                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
9294        if (dumpAll) {
9295            if (mLastStatusBarVisibility != 0) {
9296                pw.print("  mLastStatusBarVisibility=0x");
9297                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
9298            }
9299            if (mInputMethodWindow != null) {
9300                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
9301            }
9302            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
9303            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
9304                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
9305                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
9306            }
9307            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
9308                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
9309            if (mInputMethodAnimLayerAdjustment != 0 ||
9310                    mWallpaperAnimLayerAdjustment != 0) {
9311                pw.print("  mInputMethodAnimLayerAdjustment=");
9312                        pw.print(mInputMethodAnimLayerAdjustment);
9313                        pw.print("  mWallpaperAnimLayerAdjustment=");
9314                        pw.println(mWallpaperAnimLayerAdjustment);
9315            }
9316            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
9317                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9318            pw.print("  mLayoutNeeded="); pw.println(mLayoutNeeded);
9319            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
9320                    pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9321                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
9322                    pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
9323            pw.print("  mRotation="); pw.print(mRotation);
9324                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
9325            pw.print("  mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
9326                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
9327            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
9328            if (mAnimator.mScreenRotationAnimation != null) {
9329                pw.println("  mScreenRotationAnimation:");
9330                mAnimator.mScreenRotationAnimation.printTo("    ", pw);
9331            }
9332            pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9333                    pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
9334                    pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
9335            pw.print("  mTraversalScheduled="); pw.print(mTraversalScheduled);
9336                    pw.print("  mNextAppTransition=0x");
9337                    pw.print(Integer.toHexString(mNextAppTransition));
9338                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
9339            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
9340                    pw.print(" mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
9341            if (mNextAppTransitionPackage != null) {
9342                pw.print("  mNextAppTransitionPackage=");
9343                    pw.print(mNextAppTransitionPackage);
9344                    pw.print(" mNextAppTransitionEnter=0x");
9345                    pw.print(Integer.toHexString(mNextAppTransitionEnter));
9346                    pw.print(" mNextAppTransitionExit=0x");
9347                    pw.print(Integer.toHexString(mNextAppTransitionExit));
9348            }
9349            if (mNextAppTransitionThumbnail != null) {
9350                pw.print("  mNextAppTransitionThumbnail=");
9351                    pw.print(mNextAppTransitionThumbnail);
9352                    pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX);
9353                    pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY);
9354            }
9355            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9356                    pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9357        }
9358    }
9359
9360    boolean dumpWindows(FileDescriptor fd, PrintWriter pw, String name, String[] args,
9361            int opti, boolean dumpAll) {
9362        ArrayList<WindowState> windows = new ArrayList<WindowState>();
9363        if ("visible".equals(name)) {
9364            synchronized(mWindowMap) {
9365                for (int i=mWindows.size()-1; i>=0; i--) {
9366                    WindowState w = mWindows.get(i);
9367                    if (w.mWinAnimator.mSurfaceShown) {
9368                        windows.add(w);
9369                    }
9370                }
9371            }
9372        } else {
9373            int objectId = 0;
9374            // See if this is an object ID.
9375            try {
9376                objectId = Integer.parseInt(name, 16);
9377                name = null;
9378            } catch (RuntimeException e) {
9379            }
9380            synchronized(mWindowMap) {
9381                for (int i=mWindows.size()-1; i>=0; i--) {
9382                    WindowState w = mWindows.get(i);
9383                    if (name != null) {
9384                        if (w.mAttrs.getTitle().toString().contains(name)) {
9385                            windows.add(w);
9386                        }
9387                    } else if (System.identityHashCode(w) == objectId) {
9388                        windows.add(w);
9389                    }
9390                }
9391            }
9392        }
9393
9394        if (windows.size() <= 0) {
9395            return false;
9396        }
9397
9398        synchronized(mWindowMap) {
9399            dumpWindowsLocked(fd, pw, dumpAll, windows);
9400        }
9401        return true;
9402    }
9403
9404    @Override
9405    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9406        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
9407                != PackageManager.PERMISSION_GRANTED) {
9408            pw.println("Permission Denial: can't dump WindowManager from from pid="
9409                    + Binder.getCallingPid()
9410                    + ", uid=" + Binder.getCallingUid());
9411            return;
9412        }
9413
9414        boolean dumpAll = false;
9415
9416        int opti = 0;
9417        while (opti < args.length) {
9418            String opt = args[opti];
9419            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9420                break;
9421            }
9422            opti++;
9423            if ("-a".equals(opt)) {
9424                dumpAll = true;
9425            } else if ("-h".equals(opt)) {
9426                pw.println("Window manager dump options:");
9427                pw.println("  [-a] [-h] [cmd] ...");
9428                pw.println("  cmd may be one of:");
9429                pw.println("    p[policy]: policy state");
9430                pw.println("    s[essions]: active sessions");
9431                pw.println("    t[okens]: token list");
9432                pw.println("    w[indows]: window list");
9433                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
9434                pw.println("    be a partial substring in a window name, a");
9435                pw.println("    Window hex object identifier, or");
9436                pw.println("    \"all\" for all windows, or");
9437                pw.println("    \"visible\" for the visible windows.");
9438                pw.println("  -a: include all available server state.");
9439                return;
9440            } else {
9441                pw.println("Unknown argument: " + opt + "; use -h for help");
9442            }
9443        }
9444
9445        // Is the caller requesting to dump a particular piece of data?
9446        if (opti < args.length) {
9447            String cmd = args[opti];
9448            opti++;
9449            if ("policy".equals(cmd) || "p".equals(cmd)) {
9450                synchronized(mWindowMap) {
9451                    dumpPolicyLocked(fd, pw, args, true);
9452                }
9453                return;
9454            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
9455                synchronized(mWindowMap) {
9456                    dumpSessionsLocked(fd, pw, true);
9457                }
9458                return;
9459            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
9460                synchronized(mWindowMap) {
9461                    dumpTokensLocked(fd, pw, true);
9462                }
9463                return;
9464            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
9465                synchronized(mWindowMap) {
9466                    dumpWindowsLocked(fd, pw, true, null);
9467                }
9468                return;
9469            } else if ("all".equals(cmd) || "a".equals(cmd)) {
9470                synchronized(mWindowMap) {
9471                    dumpWindowsLocked(fd, pw, true, null);
9472                }
9473                return;
9474            } else {
9475                // Dumping a single name?
9476                if (!dumpWindows(fd, pw, cmd, args, opti, dumpAll)) {
9477                    pw.println("Bad window command, or no windows match: " + cmd);
9478                    pw.println("Use -h for help.");
9479                }
9480                return;
9481            }
9482        }
9483
9484        synchronized(mWindowMap) {
9485            if (dumpAll) {
9486                pw.println("-------------------------------------------------------------------------------");
9487            }
9488            dumpPolicyLocked(fd, pw, args, dumpAll);
9489            pw.println();
9490            if (dumpAll) {
9491                pw.println("-------------------------------------------------------------------------------");
9492            }
9493            dumpSessionsLocked(fd, pw, dumpAll);
9494            pw.println();
9495            if (dumpAll) {
9496                pw.println("-------------------------------------------------------------------------------");
9497            }
9498            dumpTokensLocked(fd, pw, dumpAll);
9499            pw.println();
9500            if (dumpAll) {
9501                pw.println("-------------------------------------------------------------------------------");
9502            }
9503            dumpWindowsLocked(fd, pw, dumpAll, null);
9504        }
9505    }
9506
9507    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
9508    public void monitor() {
9509        synchronized (mWindowMap) { }
9510        synchronized (mKeyguardTokenWatcher) { }
9511    }
9512
9513    public interface OnHardKeyboardStatusChangeListener {
9514        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
9515    }
9516
9517    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
9518        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
9519            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
9520                    Integer.toHexString(pendingLayoutChanges));
9521        }
9522    }
9523
9524    void bulkSetParameters(final int bulkUpdateParams) {
9525        mH.sendMessage(mH.obtainMessage(H.BULK_UPDATE_PARAMETERS, bulkUpdateParams, 0));
9526    }
9527}
9528