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