WindowManagerService.java revision 161e67ff3ba26408eea09221734ad2e29a1eed11
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 void setInputFilter(InputFilter filter) {
4634        mInputManager.setInputFilter(filter);
4635    }
4636
4637    public InputDevice getInputDevice(int deviceId) {
4638        return mInputManager.getInputDevice(deviceId);
4639    }
4640
4641    public int[] getInputDeviceIds() {
4642        return mInputManager.getInputDeviceIds();
4643    }
4644
4645    public void enableScreenAfterBoot() {
4646        synchronized(mWindowMap) {
4647            if (mSystemBooted) {
4648                return;
4649            }
4650            mSystemBooted = true;
4651        }
4652
4653        performEnableScreen();
4654    }
4655
4656    public void enableScreenIfNeededLocked() {
4657        if (mDisplayEnabled) {
4658            return;
4659        }
4660        if (!mSystemBooted) {
4661            return;
4662        }
4663        mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
4664    }
4665
4666    public void performEnableScreen() {
4667        synchronized(mWindowMap) {
4668            if (mDisplayEnabled) {
4669                return;
4670            }
4671            if (!mSystemBooted) {
4672                return;
4673            }
4674
4675            // Don't enable the screen until all existing windows
4676            // have been drawn.
4677            final int N = mWindows.size();
4678            for (int i=0; i<N; i++) {
4679                WindowState w = mWindows.get(i);
4680                if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
4681                    return;
4682                }
4683            }
4684
4685            mDisplayEnabled = true;
4686            if (false) {
4687                Slog.i(TAG, "ENABLING SCREEN!");
4688                StringWriter sw = new StringWriter();
4689                PrintWriter pw = new PrintWriter(sw);
4690                this.dump(null, pw, null);
4691                Slog.i(TAG, sw.toString());
4692            }
4693            try {
4694                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
4695                if (surfaceFlinger != null) {
4696                    //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
4697                    Parcel data = Parcel.obtain();
4698                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
4699                    surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
4700                                            data, null, 0);
4701                    data.recycle();
4702                }
4703            } catch (RemoteException ex) {
4704                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
4705            }
4706        }
4707
4708        mPolicy.enableScreenAfterBoot();
4709
4710        // Make sure the last requested orientation has been applied.
4711        setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false,
4712                mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
4713    }
4714
4715    public void setInTouchMode(boolean mode) {
4716        synchronized(mWindowMap) {
4717            mInTouchMode = mode;
4718        }
4719    }
4720
4721    // TODO: more accounting of which pid(s) turned it on, keep count,
4722    // only allow disables from pids which have count on, etc.
4723    public void showStrictModeViolation(boolean on) {
4724        int pid = Binder.getCallingPid();
4725        synchronized(mWindowMap) {
4726            // Ignoring requests to enable the red border from clients
4727            // which aren't on screen.  (e.g. Broadcast Receivers in
4728            // the background..)
4729            if (on) {
4730                boolean isVisible = false;
4731                for (WindowState ws : mWindows) {
4732                    if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
4733                        isVisible = true;
4734                        break;
4735                    }
4736                }
4737                if (!isVisible) {
4738                    return;
4739                }
4740            }
4741
4742            if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION showStrictModeViolation");
4743            Surface.openTransaction();
4744            try {
4745                if (mStrictModeFlash == null) {
4746                    mStrictModeFlash = new StrictModeFlash(mDisplay, mFxSession);
4747                }
4748                mStrictModeFlash.setVisibility(on);
4749            } finally {
4750                Surface.closeTransaction();
4751                if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION showStrictModeViolation");
4752            }
4753        }
4754    }
4755
4756    public void setStrictModeVisualIndicatorPreference(String value) {
4757        SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
4758    }
4759
4760    /**
4761     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
4762     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
4763     * of the target image.
4764     *
4765     * @param width the width of the target bitmap
4766     * @param height the height of the target bitmap
4767     */
4768    public Bitmap screenshotApplications(IBinder appToken, int width, int height) {
4769        if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
4770                "screenshotApplications()")) {
4771            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
4772        }
4773
4774        Bitmap rawss;
4775
4776        int maxLayer = 0;
4777        final Rect frame = new Rect();
4778
4779        float scale;
4780        int dw, dh;
4781        int rot;
4782
4783        synchronized(mWindowMap) {
4784            long ident = Binder.clearCallingIdentity();
4785
4786            dw = mPolicy.getNonDecorDisplayWidth(mRotation, mCurDisplayWidth);
4787            dh = mPolicy.getNonDecorDisplayHeight(mRotation, mCurDisplayHeight);
4788
4789            int aboveAppLayer = mPolicy.windowTypeToLayerLw(
4790                    WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER
4791                    + TYPE_LAYER_OFFSET;
4792            aboveAppLayer += TYPE_LAYER_MULTIPLIER;
4793
4794            boolean isImeTarget = mInputMethodTarget != null
4795                    && mInputMethodTarget.mAppToken != null
4796                    && mInputMethodTarget.mAppToken.appToken != null
4797                    && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
4798
4799            // Figure out the part of the screen that is actually the app.
4800            boolean including = false;
4801            for (int i=mWindows.size()-1; i>=0; i--) {
4802                WindowState ws = mWindows.get(i);
4803                if (ws.mSurface == null) {
4804                    continue;
4805                }
4806                if (ws.mLayer >= aboveAppLayer) {
4807                    continue;
4808                }
4809                // When we will skip windows: when we are not including
4810                // ones behind a window we didn't skip, and we are actually
4811                // taking a screenshot of a specific app.
4812                if (!including && appToken != null) {
4813                    // Also, we can possibly skip this window if it is not
4814                    // an IME target or the application for the screenshot
4815                    // is not the current IME target.
4816                    if (!ws.mIsImWindow || !isImeTarget) {
4817                        // And finally, this window is of no interest if it
4818                        // is not associated with the screenshot app.
4819                        if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
4820                            continue;
4821                        }
4822                    }
4823                }
4824
4825                // We keep on including windows until we go past a full-screen
4826                // window.
4827                including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
4828
4829                if (maxLayer < ws.mAnimLayer) {
4830                    maxLayer = ws.mAnimLayer;
4831                }
4832
4833                // Don't include wallpaper in bounds calculation
4834                if (!ws.mIsWallpaper) {
4835                    final Rect wf = ws.mFrame;
4836                    final Rect cr = ws.mContentInsets;
4837                    int left = wf.left + cr.left;
4838                    int top = wf.top + cr.top;
4839                    int right = wf.right - cr.right;
4840                    int bottom = wf.bottom - cr.bottom;
4841                    frame.union(left, top, right, bottom);
4842                }
4843            }
4844            Binder.restoreCallingIdentity(ident);
4845
4846            // Constrain frame to the screen size.
4847            frame.intersect(0, 0, dw, dh);
4848
4849            if (frame.isEmpty() || maxLayer == 0) {
4850                return null;
4851            }
4852
4853            // The screenshot API does not apply the current screen rotation.
4854            rot = mDisplay.getRotation();
4855            int fw = frame.width();
4856            int fh = frame.height();
4857
4858            // First try reducing to fit in x dimension.
4859            scale = width/(float)fw;
4860
4861            // The screen shot will contain the entire screen.
4862            dw = (int)(dw*scale);
4863            dh = (int)(dh*scale);
4864            if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
4865                int tmp = dw;
4866                dw = dh;
4867                dh = tmp;
4868                rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
4869            }
4870            rawss = Surface.screenshot(dw, dh, 0, maxLayer);
4871        }
4872
4873        if (rawss == null) {
4874            Log.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh
4875                    + ") to layer " + maxLayer);
4876            return null;
4877        }
4878
4879        Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
4880        Matrix matrix = new Matrix();
4881        ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
4882        matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale));
4883        Canvas canvas = new Canvas(bm);
4884        canvas.drawBitmap(rawss, matrix, null);
4885
4886        rawss.recycle();
4887        return bm;
4888    }
4889
4890    public void freezeRotation() {
4891        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
4892                "freezeRotation()")) {
4893            throw new SecurityException("Requires SET_ORIENTATION permission");
4894        }
4895
4896        if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
4897
4898        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED, mRotation);
4899        setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0);
4900    }
4901
4902    public void thawRotation() {
4903        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
4904                "thawRotation()")) {
4905            throw new SecurityException("Requires SET_ORIENTATION permission");
4906        }
4907
4908        if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
4909
4910        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used
4911        setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0);
4912    }
4913
4914    public void setRotation(int rotation,
4915            boolean alwaysSendConfiguration, int animFlags) {
4916        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
4917                "setRotation()")) {
4918            throw new SecurityException("Requires SET_ORIENTATION permission");
4919        }
4920
4921        setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags);
4922    }
4923
4924    public void setRotationUnchecked(int rotation,
4925            boolean alwaysSendConfiguration, int animFlags) {
4926        if(DEBUG_ORIENTATION) Slog.v(TAG,
4927                   "setRotationUnchecked(rotation=" + rotation +
4928                   " alwaysSendConfiguration=" + alwaysSendConfiguration +
4929                   " animFlags=" + animFlags);
4930
4931        long origId = Binder.clearCallingIdentity();
4932        boolean changed;
4933        synchronized(mWindowMap) {
4934            changed = setRotationUncheckedLocked(rotation, animFlags, false);
4935        }
4936
4937        if (changed || alwaysSendConfiguration) {
4938            sendNewConfiguration();
4939        }
4940
4941        Binder.restoreCallingIdentity(origId);
4942    }
4943
4944    /**
4945     * Apply a new rotation to the screen, respecting the requests of
4946     * applications.  Use WindowManagerPolicy.USE_LAST_ROTATION to simply
4947     * re-evaluate the desired rotation.
4948     *
4949     * Returns null if the rotation has been changed.  In this case YOU
4950     * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN.
4951     */
4952    public boolean setRotationUncheckedLocked(int rotation, int animFlags, boolean inTransaction) {
4953        if (mDragState != null || mScreenRotationAnimation != null) {
4954            // Potential rotation during a drag.  Don't do the rotation now, but make
4955            // a note to perform the rotation later.
4956            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation.");
4957            if (rotation != WindowManagerPolicy.USE_LAST_ROTATION) {
4958                mDeferredRotation = rotation;
4959                mDeferredRotationAnimFlags = animFlags;
4960            }
4961            return false;
4962        }
4963
4964        boolean changed;
4965        if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
4966            if (mDeferredRotation != WindowManagerPolicy.USE_LAST_ROTATION) {
4967                rotation = mDeferredRotation;
4968                mRequestedRotation = rotation;
4969                mLastRotationFlags = mDeferredRotationAnimFlags;
4970            }
4971            rotation = mRequestedRotation;
4972        } else {
4973            mRequestedRotation = rotation;
4974            mLastRotationFlags = animFlags;
4975        }
4976        mDeferredRotation = WindowManagerPolicy.USE_LAST_ROTATION;
4977        if (DEBUG_ORIENTATION) Slog.v(TAG, "Overwriting rotation value from " + rotation);
4978        rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
4979                mRotation, mDisplayEnabled);
4980        if (DEBUG_ORIENTATION) Slog.v(TAG, "new rotation is set to " + rotation);
4981
4982        int desiredRotation = rotation;
4983        int lockedRotation = mPolicy.getLockedRotationLw();
4984        if (lockedRotation >= 0 && rotation != lockedRotation) {
4985            // We are locked in a rotation but something is requesting
4986            // a different rotation...  we will either keep the locked
4987            // rotation if it results in the same orientation, or have to
4988            // switch into an emulated orientation mode.
4989
4990            // First, we know that our rotation is actually going to be
4991            // the locked rotation.
4992            rotation = lockedRotation;
4993
4994            // Now the difference between the desired and lockedRotation
4995            // may mean that the orientation is different...  if that is
4996            // not the case, we can just make the desired rotation be the
4997            // same as the new locked rotation.
4998            switch (lockedRotation) {
4999                case Surface.ROTATION_0:
5000                    if (rotation == Surface.ROTATION_180) {
5001                        desiredRotation = lockedRotation;
5002                    }
5003                    break;
5004                case Surface.ROTATION_90:
5005                    if (rotation == Surface.ROTATION_270) {
5006                        desiredRotation = lockedRotation;
5007                    }
5008                    break;
5009                case Surface.ROTATION_180:
5010                    if (rotation == Surface.ROTATION_0) {
5011                        desiredRotation = lockedRotation;
5012                    }
5013                    break;
5014                case Surface.ROTATION_270:
5015                    if (rotation == Surface.ROTATION_90) {
5016                        desiredRotation = lockedRotation;
5017                    }
5018                    break;
5019            }
5020        }
5021
5022        changed = mDisplayEnabled && mRotation != rotation;
5023        if (mAltOrientation != (rotation != desiredRotation)) {
5024            changed = true;
5025            mAltOrientation = rotation != desiredRotation;
5026        }
5027
5028        if (changed) {
5029            if (DEBUG_ORIENTATION) Slog.v(TAG,
5030                    "Rotation changed to " + rotation
5031                    + " from " + mRotation
5032                    + " (forceApp=" + mForcedAppOrientation
5033                    + ", req=" + mRequestedRotation + ")");
5034            mRotation = rotation;
5035            mWindowsFreezingScreen = true;
5036            mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
5037            mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
5038                    2000);
5039            mWaitingForConfig = true;
5040            mLayoutNeeded = true;
5041            startFreezingDisplayLocked(inTransaction);
5042            Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
5043            mInputManager.setDisplayOrientation(0, rotation);
5044            if (mDisplayEnabled) {
5045                // NOTE: We disable the rotation in the emulator because
5046                //       it doesn't support hardware OpenGL emulation yet.
5047                if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
5048                        && mScreenRotationAnimation.hasScreenshot()) {
5049                    Surface.freezeDisplay(0);
5050                    if (!inTransaction) {
5051                        if (SHOW_TRANSACTIONS) Slog.i(TAG,
5052                                ">>> OPEN TRANSACTION setRotationUnchecked");
5053                        Surface.openTransaction();
5054                    }
5055                    try {
5056                        if (mScreenRotationAnimation != null) {
5057                            mScreenRotationAnimation.setRotation(rotation);
5058                        }
5059                    } finally {
5060                        if (!inTransaction) {
5061                            Surface.closeTransaction();
5062                            if (SHOW_TRANSACTIONS) Slog.i(TAG,
5063                                    "<<< CLOSE TRANSACTION setRotationUnchecked");
5064                        }
5065                    }
5066                    Surface.setOrientation(0, rotation, animFlags);
5067                    Surface.unfreezeDisplay(0);
5068                } else {
5069                    Surface.setOrientation(0, rotation, animFlags);
5070                }
5071                rebuildBlackFrame(inTransaction);
5072            }
5073
5074            for (int i=mWindows.size()-1; i>=0; i--) {
5075                WindowState w = mWindows.get(i);
5076                if (w.mSurface != null) {
5077                    w.mOrientationChanging = true;
5078                }
5079            }
5080            for (int i=mRotationWatchers.size()-1; i>=0; i--) {
5081                try {
5082                    mRotationWatchers.get(i).onRotationChanged(rotation);
5083                } catch (RemoteException e) {
5084                }
5085            }
5086        } //end if changed
5087
5088        return changed;
5089    }
5090
5091    public int getRotation() {
5092        return mRotation;
5093    }
5094
5095    public int watchRotation(IRotationWatcher watcher) {
5096        final IBinder watcherBinder = watcher.asBinder();
5097        IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
5098            public void binderDied() {
5099                synchronized (mWindowMap) {
5100                    for (int i=0; i<mRotationWatchers.size(); i++) {
5101                        if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
5102                            IRotationWatcher removed = mRotationWatchers.remove(i);
5103                            if (removed != null) {
5104                                removed.asBinder().unlinkToDeath(this, 0);
5105                            }
5106                            i--;
5107                        }
5108                    }
5109                }
5110            }
5111        };
5112
5113        synchronized (mWindowMap) {
5114            try {
5115                watcher.asBinder().linkToDeath(dr, 0);
5116                mRotationWatchers.add(watcher);
5117            } catch (RemoteException e) {
5118                // Client died, no cleanup needed.
5119            }
5120
5121            return mRotation;
5122        }
5123    }
5124
5125    /**
5126     * Starts the view server on the specified port.
5127     *
5128     * @param port The port to listener to.
5129     *
5130     * @return True if the server was successfully started, false otherwise.
5131     *
5132     * @see com.android.server.wm.ViewServer
5133     * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
5134     */
5135    public boolean startViewServer(int port) {
5136        if (isSystemSecure()) {
5137            return false;
5138        }
5139
5140        if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
5141            return false;
5142        }
5143
5144        if (port < 1024) {
5145            return false;
5146        }
5147
5148        if (mViewServer != null) {
5149            if (!mViewServer.isRunning()) {
5150                try {
5151                    return mViewServer.start();
5152                } catch (IOException e) {
5153                    Slog.w(TAG, "View server did not start");
5154                }
5155            }
5156            return false;
5157        }
5158
5159        try {
5160            mViewServer = new ViewServer(this, port);
5161            return mViewServer.start();
5162        } catch (IOException e) {
5163            Slog.w(TAG, "View server did not start");
5164        }
5165        return false;
5166    }
5167
5168    private boolean isSystemSecure() {
5169        return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
5170                "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
5171    }
5172
5173    /**
5174     * Stops the view server if it exists.
5175     *
5176     * @return True if the server stopped, false if it wasn't started or
5177     *         couldn't be stopped.
5178     *
5179     * @see com.android.server.wm.ViewServer
5180     */
5181    public boolean stopViewServer() {
5182        if (isSystemSecure()) {
5183            return false;
5184        }
5185
5186        if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
5187            return false;
5188        }
5189
5190        if (mViewServer != null) {
5191            return mViewServer.stop();
5192        }
5193        return false;
5194    }
5195
5196    /**
5197     * Indicates whether the view server is running.
5198     *
5199     * @return True if the server is running, false otherwise.
5200     *
5201     * @see com.android.server.wm.ViewServer
5202     */
5203    public boolean isViewServerRunning() {
5204        if (isSystemSecure()) {
5205            return false;
5206        }
5207
5208        if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
5209            return false;
5210        }
5211
5212        return mViewServer != null && mViewServer.isRunning();
5213    }
5214
5215    /**
5216     * Lists all availble windows in the system. The listing is written in the
5217     * specified Socket's output stream with the following syntax:
5218     * windowHashCodeInHexadecimal windowName
5219     * Each line of the ouput represents a different window.
5220     *
5221     * @param client The remote client to send the listing to.
5222     * @return False if an error occured, true otherwise.
5223     */
5224    boolean viewServerListWindows(Socket client) {
5225        if (isSystemSecure()) {
5226            return false;
5227        }
5228
5229        boolean result = true;
5230
5231        WindowState[] windows;
5232        synchronized (mWindowMap) {
5233            //noinspection unchecked
5234            windows = mWindows.toArray(new WindowState[mWindows.size()]);
5235        }
5236
5237        BufferedWriter out = null;
5238
5239        // Any uncaught exception will crash the system process
5240        try {
5241            OutputStream clientStream = client.getOutputStream();
5242            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
5243
5244            final int count = windows.length;
5245            for (int i = 0; i < count; i++) {
5246                final WindowState w = windows[i];
5247                out.write(Integer.toHexString(System.identityHashCode(w)));
5248                out.write(' ');
5249                out.append(w.mAttrs.getTitle());
5250                out.write('\n');
5251            }
5252
5253            out.write("DONE.\n");
5254            out.flush();
5255        } catch (Exception e) {
5256            result = false;
5257        } finally {
5258            if (out != null) {
5259                try {
5260                    out.close();
5261                } catch (IOException e) {
5262                    result = false;
5263                }
5264            }
5265        }
5266
5267        return result;
5268    }
5269
5270    /**
5271     * Returns the focused window in the following format:
5272     * windowHashCodeInHexadecimal windowName
5273     *
5274     * @param client The remote client to send the listing to.
5275     * @return False if an error occurred, true otherwise.
5276     */
5277    boolean viewServerGetFocusedWindow(Socket client) {
5278        if (isSystemSecure()) {
5279            return false;
5280        }
5281
5282        boolean result = true;
5283
5284        WindowState focusedWindow = getFocusedWindow();
5285
5286        BufferedWriter out = null;
5287
5288        // Any uncaught exception will crash the system process
5289        try {
5290            OutputStream clientStream = client.getOutputStream();
5291            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
5292
5293            if(focusedWindow != null) {
5294                out.write(Integer.toHexString(System.identityHashCode(focusedWindow)));
5295                out.write(' ');
5296                out.append(focusedWindow.mAttrs.getTitle());
5297            }
5298            out.write('\n');
5299            out.flush();
5300        } catch (Exception e) {
5301            result = false;
5302        } finally {
5303            if (out != null) {
5304                try {
5305                    out.close();
5306                } catch (IOException e) {
5307                    result = false;
5308                }
5309            }
5310        }
5311
5312        return result;
5313    }
5314
5315    /**
5316     * Sends a command to a target window. The result of the command, if any, will be
5317     * written in the output stream of the specified socket.
5318     *
5319     * The parameters must follow this syntax:
5320     * windowHashcode extra
5321     *
5322     * Where XX is the length in characeters of the windowTitle.
5323     *
5324     * The first parameter is the target window. The window with the specified hashcode
5325     * will be the target. If no target can be found, nothing happens. The extra parameters
5326     * will be delivered to the target window and as parameters to the command itself.
5327     *
5328     * @param client The remote client to sent the result, if any, to.
5329     * @param command The command to execute.
5330     * @param parameters The command parameters.
5331     *
5332     * @return True if the command was successfully delivered, false otherwise. This does
5333     *         not indicate whether the command itself was successful.
5334     */
5335    boolean viewServerWindowCommand(Socket client, String command, String parameters) {
5336        if (isSystemSecure()) {
5337            return false;
5338        }
5339
5340        boolean success = true;
5341        Parcel data = null;
5342        Parcel reply = null;
5343
5344        BufferedWriter out = null;
5345
5346        // Any uncaught exception will crash the system process
5347        try {
5348            // Find the hashcode of the window
5349            int index = parameters.indexOf(' ');
5350            if (index == -1) {
5351                index = parameters.length();
5352            }
5353            final String code = parameters.substring(0, index);
5354            int hashCode = (int) Long.parseLong(code, 16);
5355
5356            // Extract the command's parameter after the window description
5357            if (index < parameters.length()) {
5358                parameters = parameters.substring(index + 1);
5359            } else {
5360                parameters = "";
5361            }
5362
5363            final WindowState window = findWindow(hashCode);
5364            if (window == null) {
5365                return false;
5366            }
5367
5368            data = Parcel.obtain();
5369            data.writeInterfaceToken("android.view.IWindow");
5370            data.writeString(command);
5371            data.writeString(parameters);
5372            data.writeInt(1);
5373            ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
5374
5375            reply = Parcel.obtain();
5376
5377            final IBinder binder = window.mClient.asBinder();
5378            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
5379            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
5380
5381            reply.readException();
5382
5383            if (!client.isOutputShutdown()) {
5384                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
5385                out.write("DONE\n");
5386                out.flush();
5387            }
5388
5389        } catch (Exception e) {
5390            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
5391            success = false;
5392        } finally {
5393            if (data != null) {
5394                data.recycle();
5395            }
5396            if (reply != null) {
5397                reply.recycle();
5398            }
5399            if (out != null) {
5400                try {
5401                    out.close();
5402                } catch (IOException e) {
5403
5404                }
5405            }
5406        }
5407
5408        return success;
5409    }
5410
5411    public void addWindowChangeListener(WindowChangeListener listener) {
5412        synchronized(mWindowMap) {
5413            mWindowChangeListeners.add(listener);
5414        }
5415    }
5416
5417    public void removeWindowChangeListener(WindowChangeListener listener) {
5418        synchronized(mWindowMap) {
5419            mWindowChangeListeners.remove(listener);
5420        }
5421    }
5422
5423    private void notifyWindowsChanged() {
5424        WindowChangeListener[] windowChangeListeners;
5425        synchronized(mWindowMap) {
5426            if(mWindowChangeListeners.isEmpty()) {
5427                return;
5428            }
5429            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
5430            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
5431        }
5432        int N = windowChangeListeners.length;
5433        for(int i = 0; i < N; i++) {
5434            windowChangeListeners[i].windowsChanged();
5435        }
5436    }
5437
5438    private void notifyFocusChanged() {
5439        WindowChangeListener[] windowChangeListeners;
5440        synchronized(mWindowMap) {
5441            if(mWindowChangeListeners.isEmpty()) {
5442                return;
5443            }
5444            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
5445            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
5446        }
5447        int N = windowChangeListeners.length;
5448        for(int i = 0; i < N; i++) {
5449            windowChangeListeners[i].focusChanged();
5450        }
5451    }
5452
5453    private WindowState findWindow(int hashCode) {
5454        if (hashCode == -1) {
5455            return getFocusedWindow();
5456        }
5457
5458        synchronized (mWindowMap) {
5459            final ArrayList<WindowState> windows = mWindows;
5460            final int count = windows.size();
5461
5462            for (int i = 0; i < count; i++) {
5463                WindowState w = windows.get(i);
5464                if (System.identityHashCode(w) == hashCode) {
5465                    return w;
5466                }
5467            }
5468        }
5469
5470        return null;
5471    }
5472
5473    /*
5474     * Instruct the Activity Manager to fetch the current configuration and broadcast
5475     * that to config-changed listeners if appropriate.
5476     */
5477    void sendNewConfiguration() {
5478        try {
5479            mActivityManager.updateConfiguration(null);
5480        } catch (RemoteException e) {
5481        }
5482    }
5483
5484    public Configuration computeNewConfiguration() {
5485        synchronized (mWindowMap) {
5486            Configuration config = computeNewConfigurationLocked();
5487            if (config == null && mWaitingForConfig) {
5488                // Nothing changed but we are waiting for something... stop that!
5489                mWaitingForConfig = false;
5490                performLayoutAndPlaceSurfacesLocked();
5491            }
5492            return config;
5493        }
5494    }
5495
5496    Configuration computeNewConfigurationLocked() {
5497        Configuration config = new Configuration();
5498        if (!computeNewConfigurationLocked(config)) {
5499            return null;
5500        }
5501        return config;
5502    }
5503
5504    private int reduceConfigWidthSize(int curSize, int rotation, float density, int dw) {
5505        int size = (int)(mPolicy.getConfigDisplayWidth(rotation, dw) / density);
5506        if (size < curSize) {
5507            curSize = size;
5508        }
5509        return curSize;
5510    }
5511
5512    boolean computeNewConfigurationLocked(Configuration config) {
5513        if (mDisplay == null) {
5514            return false;
5515        }
5516
5517        mInputManager.getInputConfiguration(config);
5518
5519        // Use the effective "visual" dimensions based on current rotation
5520        final boolean rotated = (mRotation == Surface.ROTATION_90
5521                || mRotation == Surface.ROTATION_270);
5522        final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
5523        final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
5524
5525        if (mAltOrientation) {
5526            mCurDisplayWidth = realdw;
5527            mCurDisplayHeight = realdh;
5528            if (realdw > realdh) {
5529                // Turn landscape into portrait.
5530                int maxw = (int)(realdh/1.3f);
5531                if (maxw < realdw) {
5532                    mCurDisplayWidth = maxw;
5533                }
5534            } else {
5535                // Turn portrait into landscape.
5536                int maxh = (int)(realdw/1.3f);
5537                if (maxh < realdh) {
5538                    mCurDisplayHeight = maxh;
5539                }
5540            }
5541        } else {
5542            mCurDisplayWidth = realdw;
5543            mCurDisplayHeight = realdh;
5544        }
5545
5546        final int dw = mCurDisplayWidth;
5547        final int dh = mCurDisplayHeight;
5548
5549        int orientation = Configuration.ORIENTATION_SQUARE;
5550        if (dw < dh) {
5551            orientation = Configuration.ORIENTATION_PORTRAIT;
5552        } else if (dw > dh) {
5553            orientation = Configuration.ORIENTATION_LANDSCAPE;
5554        }
5555        config.orientation = orientation;
5556
5557        DisplayMetrics dm = new DisplayMetrics();
5558        mDisplay.getRealMetrics(dm);
5559
5560        // Override display width and height with what we are computing,
5561        // to be sure they remain consistent.
5562        dm.widthPixels = dm.realWidthPixels = mPolicy.getNonDecorDisplayWidth(
5563                mRotation, dw);
5564        dm.heightPixels = dm.realHeightPixels = mPolicy.getNonDecorDisplayHeight(
5565                mRotation, dh);
5566
5567        mCompatibleScreenScale = CompatibilityInfo.updateCompatibleScreenFrame(
5568                dm, mCompatibleScreenFrame, null);
5569
5570        config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(mRotation, dw) / dm.density);
5571        config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(mRotation, dh) / dm.density);
5572
5573        // We need to determine the smallest width that will occur under normal
5574        // operation.  To this, start with the base screen size and compute the
5575        // width under the different possible rotations.  We need to un-rotate
5576        // the current screen dimensions before doing this.
5577        int unrotDw, unrotDh;
5578        if (rotated) {
5579            unrotDw = dh;
5580            unrotDh = dw;
5581        } else {
5582            unrotDw = dw;
5583            unrotDh = dh;
5584        }
5585        config.smallestScreenWidthDp = reduceConfigWidthSize(unrotDw,
5586                Surface.ROTATION_0, dm.density, unrotDw);
5587        config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp,
5588                Surface.ROTATION_90, dm.density, unrotDh);
5589        config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp,
5590                Surface.ROTATION_180, dm.density, unrotDw);
5591        config.smallestScreenWidthDp = reduceConfigWidthSize(config.smallestScreenWidthDp,
5592                Surface.ROTATION_270, dm.density, unrotDh);
5593
5594        // Compute the screen layout size class.
5595        int screenLayout;
5596        int longSize = dw;
5597        int shortSize = dh;
5598        if (longSize < shortSize) {
5599            int tmp = longSize;
5600            longSize = shortSize;
5601            shortSize = tmp;
5602        }
5603        longSize = (int)(longSize/dm.density);
5604        shortSize = (int)(shortSize/dm.density);
5605
5606        // These semi-magic numbers define our compatibility modes for
5607        // applications with different screens.  These are guarantees to
5608        // app developers about the space they can expect for a particular
5609        // configuration.  DO NOT CHANGE!
5610        if (longSize < 470) {
5611            // This is shorter than an HVGA normal density screen (which
5612            // is 480 pixels on its long side).
5613            screenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL
5614                    | Configuration.SCREENLAYOUT_LONG_NO;
5615        } else {
5616            // What size is this screen screen?
5617            if (longSize >= 960 && shortSize >= 720) {
5618                // 1.5xVGA or larger screens at medium density are the point
5619                // at which we consider it to be an extra large screen.
5620                screenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE;
5621            } else if (longSize >= 640 && shortSize >= 480) {
5622                // VGA or larger screens at medium density are the point
5623                // at which we consider it to be a large screen.
5624                screenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
5625            } else {
5626                screenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL;
5627            }
5628
5629            // If this screen is wider than normal HVGA, or taller
5630            // than FWVGA, then for old apps we want to run in size
5631            // compatibility mode.
5632            if (shortSize > 321 || longSize > 570) {
5633                screenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
5634            }
5635
5636            // Is this a long screen?
5637            if (((longSize*3)/5) >= (shortSize-1)) {
5638                // Anything wider than WVGA (5:3) is considering to be long.
5639                screenLayout |= Configuration.SCREENLAYOUT_LONG_YES;
5640            } else {
5641                screenLayout |= Configuration.SCREENLAYOUT_LONG_NO;
5642            }
5643        }
5644        config.screenLayout = screenLayout;
5645
5646        // Determine whether a hard keyboard is available and enabled.
5647        boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
5648        if (hardKeyboardAvailable != mHardKeyboardAvailable) {
5649            mHardKeyboardAvailable = hardKeyboardAvailable;
5650            mHardKeyboardEnabled = hardKeyboardAvailable;
5651
5652            mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
5653            mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
5654        }
5655        if (!mHardKeyboardEnabled) {
5656            config.keyboard = Configuration.KEYBOARD_NOKEYS;
5657        }
5658
5659        // Update value of keyboardHidden, hardKeyboardHidden and navigationHidden
5660        // based on whether a hard or soft keyboard is present, whether navigation keys
5661        // are present and the lid switch state.
5662        config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
5663        config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
5664        config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
5665        mPolicy.adjustConfigurationLw(config);
5666        return true;
5667    }
5668
5669    public boolean isHardKeyboardAvailable() {
5670        synchronized (mWindowMap) {
5671            return mHardKeyboardAvailable;
5672        }
5673    }
5674
5675    public boolean isHardKeyboardEnabled() {
5676        synchronized (mWindowMap) {
5677            return mHardKeyboardEnabled;
5678        }
5679    }
5680
5681    public void setHardKeyboardEnabled(boolean enabled) {
5682        synchronized (mWindowMap) {
5683            if (mHardKeyboardEnabled != enabled) {
5684                mHardKeyboardEnabled = enabled;
5685                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
5686            }
5687        }
5688    }
5689
5690    public void setOnHardKeyboardStatusChangeListener(
5691            OnHardKeyboardStatusChangeListener listener) {
5692        synchronized (mWindowMap) {
5693            mHardKeyboardStatusChangeListener = listener;
5694        }
5695    }
5696
5697    void notifyHardKeyboardStatusChange() {
5698        final boolean available, enabled;
5699        final OnHardKeyboardStatusChangeListener listener;
5700        synchronized (mWindowMap) {
5701            listener = mHardKeyboardStatusChangeListener;
5702            available = mHardKeyboardAvailable;
5703            enabled = mHardKeyboardEnabled;
5704        }
5705        if (listener != null) {
5706            listener.onHardKeyboardStatusChange(available, enabled);
5707        }
5708    }
5709
5710    // -------------------------------------------------------------
5711    // Drag and drop
5712    // -------------------------------------------------------------
5713
5714    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
5715            int flags, int width, int height, Surface outSurface) {
5716        if (DEBUG_DRAG) {
5717            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
5718                    + " flags=" + Integer.toHexString(flags) + " win=" + window
5719                    + " asbinder=" + window.asBinder());
5720        }
5721
5722        final int callerPid = Binder.getCallingPid();
5723        final long origId = Binder.clearCallingIdentity();
5724        IBinder token = null;
5725
5726        try {
5727            synchronized (mWindowMap) {
5728                try {
5729                    if (mDragState == null) {
5730                        Surface surface = new Surface(session, callerPid, "drag surface", 0,
5731                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
5732                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
5733                                + surface + ": CREATE");
5734                        outSurface.copyFrom(surface);
5735                        final IBinder winBinder = window.asBinder();
5736                        token = new Binder();
5737                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
5738                        mDragState.mSurface = surface;
5739                        token = mDragState.mToken = new Binder();
5740
5741                        // 5 second timeout for this window to actually begin the drag
5742                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
5743                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
5744                        mH.sendMessageDelayed(msg, 5000);
5745                    } else {
5746                        Slog.w(TAG, "Drag already in progress");
5747                    }
5748                } catch (Surface.OutOfResourcesException e) {
5749                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
5750                    if (mDragState != null) {
5751                        mDragState.reset();
5752                        mDragState = null;
5753                    }
5754                }
5755            }
5756        } finally {
5757            Binder.restoreCallingIdentity(origId);
5758        }
5759
5760        return token;
5761    }
5762
5763    // -------------------------------------------------------------
5764    // Input Events and Focus Management
5765    // -------------------------------------------------------------
5766
5767    final InputMonitor mInputMonitor = new InputMonitor(this);
5768
5769    public void pauseKeyDispatching(IBinder _token) {
5770        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
5771                "pauseKeyDispatching()")) {
5772            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
5773        }
5774
5775        synchronized (mWindowMap) {
5776            WindowToken token = mTokenMap.get(_token);
5777            if (token != null) {
5778                mInputMonitor.pauseDispatchingLw(token);
5779            }
5780        }
5781    }
5782
5783    public void resumeKeyDispatching(IBinder _token) {
5784        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
5785                "resumeKeyDispatching()")) {
5786            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
5787        }
5788
5789        synchronized (mWindowMap) {
5790            WindowToken token = mTokenMap.get(_token);
5791            if (token != null) {
5792                mInputMonitor.resumeDispatchingLw(token);
5793            }
5794        }
5795    }
5796
5797    public void setEventDispatching(boolean enabled) {
5798        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
5799                "resumeKeyDispatching()")) {
5800            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
5801        }
5802
5803        synchronized (mWindowMap) {
5804            mInputMonitor.setEventDispatchingLw(enabled);
5805        }
5806    }
5807
5808    /**
5809     * Injects a keystroke event into the UI.
5810     * Even when sync is false, this method may block while waiting for current
5811     * input events to be dispatched.
5812     *
5813     * @param ev A motion event describing the keystroke action.  (Be sure to use
5814     * {@link SystemClock#uptimeMillis()} as the timebase.)
5815     * @param sync If true, wait for the event to be completed before returning to the caller.
5816     * @return Returns true if event was dispatched, false if it was dropped for any reason
5817     */
5818    public boolean injectKeyEvent(KeyEvent ev, boolean sync) {
5819        long downTime = ev.getDownTime();
5820        long eventTime = ev.getEventTime();
5821
5822        int action = ev.getAction();
5823        int code = ev.getKeyCode();
5824        int repeatCount = ev.getRepeatCount();
5825        int metaState = ev.getMetaState();
5826        int deviceId = ev.getDeviceId();
5827        int scancode = ev.getScanCode();
5828        int source = ev.getSource();
5829        int flags = ev.getFlags();
5830
5831        if (source == InputDevice.SOURCE_UNKNOWN) {
5832            source = InputDevice.SOURCE_KEYBOARD;
5833        }
5834
5835        if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
5836        if (downTime == 0) downTime = eventTime;
5837
5838        KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
5839                deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source);
5840
5841        final int pid = Binder.getCallingPid();
5842        final int uid = Binder.getCallingUid();
5843        final long ident = Binder.clearCallingIdentity();
5844
5845        final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
5846                sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
5847                        : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
5848                INJECTION_TIMEOUT_MILLIS);
5849
5850        Binder.restoreCallingIdentity(ident);
5851        return reportInjectionResult(result);
5852    }
5853
5854    /**
5855     * Inject a pointer (touch) event into the UI.
5856     * Even when sync is false, this method may block while waiting for current
5857     * input events to be dispatched.
5858     *
5859     * @param ev A motion event describing the pointer (touch) action.  (As noted in
5860     * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
5861     * {@link SystemClock#uptimeMillis()} as the timebase.)
5862     * @param sync If true, wait for the event to be completed before returning to the caller.
5863     * @return Returns true if event was dispatched, false if it was dropped for any reason
5864     */
5865    public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
5866        final int pid = Binder.getCallingPid();
5867        final int uid = Binder.getCallingUid();
5868        final long ident = Binder.clearCallingIdentity();
5869
5870        MotionEvent newEvent = MotionEvent.obtain(ev);
5871        if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
5872            newEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
5873        }
5874
5875        final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
5876                sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
5877                        : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
5878                INJECTION_TIMEOUT_MILLIS);
5879
5880        Binder.restoreCallingIdentity(ident);
5881        return reportInjectionResult(result);
5882    }
5883
5884    /**
5885     * Inject a trackball (navigation device) event into the UI.
5886     * Even when sync is false, this method may block while waiting for current
5887     * input events to be dispatched.
5888     *
5889     * @param ev A motion event describing the trackball action.  (As noted in
5890     * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
5891     * {@link SystemClock#uptimeMillis()} as the timebase.)
5892     * @param sync If true, wait for the event to be completed before returning to the caller.
5893     * @return Returns true if event was dispatched, false if it was dropped for any reason
5894     */
5895    public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
5896        final int pid = Binder.getCallingPid();
5897        final int uid = Binder.getCallingUid();
5898        final long ident = Binder.clearCallingIdentity();
5899
5900        MotionEvent newEvent = MotionEvent.obtain(ev);
5901        if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) {
5902            newEvent.setSource(InputDevice.SOURCE_TRACKBALL);
5903        }
5904
5905        final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
5906                sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
5907                        : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
5908                INJECTION_TIMEOUT_MILLIS);
5909
5910        Binder.restoreCallingIdentity(ident);
5911        return reportInjectionResult(result);
5912    }
5913
5914    /**
5915     * Inject an input event into the UI without waiting for dispatch to commence.
5916     * This variant is useful for fire-and-forget input event injection.  It does not
5917     * block any longer than it takes to enqueue the input event.
5918     *
5919     * @param ev An input event.  (Be sure to set the input source correctly.)
5920     * @return Returns true if event was dispatched, false if it was dropped for any reason
5921     */
5922    public boolean injectInputEventNoWait(InputEvent ev) {
5923        final int pid = Binder.getCallingPid();
5924        final int uid = Binder.getCallingUid();
5925        final long ident = Binder.clearCallingIdentity();
5926
5927        final int result = mInputManager.injectInputEvent(ev, pid, uid,
5928                InputManager.INPUT_EVENT_INJECTION_SYNC_NONE,
5929                INJECTION_TIMEOUT_MILLIS);
5930
5931        Binder.restoreCallingIdentity(ident);
5932        return reportInjectionResult(result);
5933    }
5934
5935    private boolean reportInjectionResult(int result) {
5936        switch (result) {
5937            case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
5938                Slog.w(TAG, "Input event injection permission denied.");
5939                throw new SecurityException(
5940                        "Injecting to another application requires INJECT_EVENTS permission");
5941            case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
5942                //Slog.v(TAG, "Input event injection succeeded.");
5943                return true;
5944            case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
5945                Slog.w(TAG, "Input event injection timed out.");
5946                return false;
5947            case InputManager.INPUT_EVENT_INJECTION_FAILED:
5948            default:
5949                Slog.w(TAG, "Input event injection failed.");
5950                return false;
5951        }
5952    }
5953
5954    private WindowState getFocusedWindow() {
5955        synchronized (mWindowMap) {
5956            return getFocusedWindowLocked();
5957        }
5958    }
5959
5960    private WindowState getFocusedWindowLocked() {
5961        return mCurrentFocus;
5962    }
5963
5964    public boolean detectSafeMode() {
5965        if (!mInputMonitor.waitForInputDevicesReady(
5966                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
5967            Slog.w(TAG, "Devices still not ready after waiting "
5968                    + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
5969                    + " milliseconds before attempting to detect safe mode.");
5970        }
5971
5972        mSafeMode = mPolicy.detectSafeMode();
5973        return mSafeMode;
5974    }
5975
5976    public void systemReady() {
5977        synchronized(mWindowMap) {
5978            if (mDisplay != null) {
5979                throw new IllegalStateException("Display already initialized");
5980            }
5981            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
5982            mDisplay = wm.getDefaultDisplay();
5983            mInitialDisplayWidth = mDisplay.getRealWidth();
5984            mInitialDisplayHeight = mDisplay.getRealHeight();
5985            int rot = mDisplay.getRotation();
5986            if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
5987                // If the screen is currently rotated, we need to swap the
5988                // initial width and height to get the true natural values.
5989                int tmp = mInitialDisplayWidth;
5990                mInitialDisplayWidth = mInitialDisplayHeight;
5991                mInitialDisplayHeight = tmp;
5992            }
5993            mBaseDisplayWidth = mCurDisplayWidth = mInitialDisplayWidth;
5994            mBaseDisplayHeight = mCurDisplayHeight = mInitialDisplayHeight;
5995            mInputManager.setDisplaySize(0, mDisplay.getRawWidth(), mDisplay.getRawHeight());
5996            mPolicy.setInitialDisplaySize(mInitialDisplayWidth, mInitialDisplayHeight);
5997        }
5998
5999        try {
6000            mActivityManager.updateConfiguration(null);
6001        } catch (RemoteException e) {
6002        }
6003
6004        mPolicy.systemReady();
6005    }
6006
6007    // This is an animation that does nothing: it just immediately finishes
6008    // itself every time it is called.  It is used as a stub animation in cases
6009    // where we want to synchronize multiple things that may be animating.
6010    static final class DummyAnimation extends Animation {
6011        public boolean getTransformation(long currentTime, Transformation outTransformation) {
6012            return false;
6013        }
6014    }
6015    static final Animation sDummyAnimation = new DummyAnimation();
6016
6017    // -------------------------------------------------------------
6018    // Async Handler
6019    // -------------------------------------------------------------
6020
6021    final class H extends Handler {
6022        public static final int REPORT_FOCUS_CHANGE = 2;
6023        public static final int REPORT_LOSING_FOCUS = 3;
6024        public static final int ANIMATE = 4;
6025        public static final int ADD_STARTING = 5;
6026        public static final int REMOVE_STARTING = 6;
6027        public static final int FINISHED_STARTING = 7;
6028        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
6029        public static final int WINDOW_FREEZE_TIMEOUT = 11;
6030        public static final int HOLD_SCREEN_CHANGED = 12;
6031        public static final int APP_TRANSITION_TIMEOUT = 13;
6032        public static final int PERSIST_ANIMATION_SCALE = 14;
6033        public static final int FORCE_GC = 15;
6034        public static final int ENABLE_SCREEN = 16;
6035        public static final int APP_FREEZE_TIMEOUT = 17;
6036        public static final int SEND_NEW_CONFIGURATION = 18;
6037        public static final int REPORT_WINDOWS_CHANGE = 19;
6038        public static final int DRAG_START_TIMEOUT = 20;
6039        public static final int DRAG_END_TIMEOUT = 21;
6040        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
6041
6042        private Session mLastReportedHold;
6043
6044        public H() {
6045        }
6046
6047        @Override
6048        public void handleMessage(Message msg) {
6049            switch (msg.what) {
6050                case REPORT_FOCUS_CHANGE: {
6051                    WindowState lastFocus;
6052                    WindowState newFocus;
6053
6054                    synchronized(mWindowMap) {
6055                        lastFocus = mLastFocus;
6056                        newFocus = mCurrentFocus;
6057                        if (lastFocus == newFocus) {
6058                            // Focus is not changing, so nothing to do.
6059                            return;
6060                        }
6061                        mLastFocus = newFocus;
6062                        //Slog.i(TAG, "Focus moving from " + lastFocus
6063                        //        + " to " + newFocus);
6064                        if (newFocus != null && lastFocus != null
6065                                && !newFocus.isDisplayedLw()) {
6066                            //Slog.i(TAG, "Delaying loss of focus...");
6067                            mLosingFocus.add(lastFocus);
6068                            lastFocus = null;
6069                        }
6070                    }
6071
6072                    if (lastFocus != newFocus) {
6073                        //System.out.println("Changing focus from " + lastFocus
6074                        //                   + " to " + newFocus);
6075                        if (newFocus != null) {
6076                            try {
6077                                //Slog.i(TAG, "Gaining focus: " + newFocus);
6078                                newFocus.mClient.windowFocusChanged(true, mInTouchMode);
6079                            } catch (RemoteException e) {
6080                                // Ignore if process has died.
6081                            }
6082                            notifyFocusChanged();
6083                        }
6084
6085                        if (lastFocus != null) {
6086                            try {
6087                                //Slog.i(TAG, "Losing focus: " + lastFocus);
6088                                lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
6089                            } catch (RemoteException e) {
6090                                // Ignore if process has died.
6091                            }
6092                        }
6093
6094                        mPolicy.focusChanged(lastFocus, newFocus);
6095                    }
6096                } break;
6097
6098                case REPORT_LOSING_FOCUS: {
6099                    ArrayList<WindowState> losers;
6100
6101                    synchronized(mWindowMap) {
6102                        losers = mLosingFocus;
6103                        mLosingFocus = new ArrayList<WindowState>();
6104                    }
6105
6106                    final int N = losers.size();
6107                    for (int i=0; i<N; i++) {
6108                        try {
6109                            //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
6110                            losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
6111                        } catch (RemoteException e) {
6112                             // Ignore if process has died.
6113                        }
6114                    }
6115                } break;
6116
6117                case ANIMATE: {
6118                    synchronized(mWindowMap) {
6119                        mAnimationPending = false;
6120                        performLayoutAndPlaceSurfacesLocked();
6121                    }
6122                } break;
6123
6124                case ADD_STARTING: {
6125                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6126                    final StartingData sd = wtoken.startingData;
6127
6128                    if (sd == null) {
6129                        // Animation has been canceled... do nothing.
6130                        return;
6131                    }
6132
6133                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
6134                            + wtoken + ": pkg=" + sd.pkg);
6135
6136                    View view = null;
6137                    try {
6138                        view = mPolicy.addStartingWindow(
6139                            wtoken.token, sd.pkg,
6140                            sd.theme, sd.nonLocalizedLabel, sd.labelRes,
6141                            sd.icon, sd.windowFlags);
6142                    } catch (Exception e) {
6143                        Slog.w(TAG, "Exception when adding starting window", e);
6144                    }
6145
6146                    if (view != null) {
6147                        boolean abort = false;
6148
6149                        synchronized(mWindowMap) {
6150                            if (wtoken.removed || wtoken.startingData == null) {
6151                                // If the window was successfully added, then
6152                                // we need to remove it.
6153                                if (wtoken.startingWindow != null) {
6154                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6155                                            "Aborted starting " + wtoken
6156                                            + ": removed=" + wtoken.removed
6157                                            + " startingData=" + wtoken.startingData);
6158                                    wtoken.startingWindow = null;
6159                                    wtoken.startingData = null;
6160                                    abort = true;
6161                                }
6162                            } else {
6163                                wtoken.startingView = view;
6164                            }
6165                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
6166                                    "Added starting " + wtoken
6167                                    + ": startingWindow="
6168                                    + wtoken.startingWindow + " startingView="
6169                                    + wtoken.startingView);
6170                        }
6171
6172                        if (abort) {
6173                            try {
6174                                mPolicy.removeStartingWindow(wtoken.token, view);
6175                            } catch (Exception e) {
6176                                Slog.w(TAG, "Exception when removing starting window", e);
6177                            }
6178                        }
6179                    }
6180                } break;
6181
6182                case REMOVE_STARTING: {
6183                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6184                    IBinder token = null;
6185                    View view = null;
6186                    synchronized (mWindowMap) {
6187                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
6188                                + wtoken + ": startingWindow="
6189                                + wtoken.startingWindow + " startingView="
6190                                + wtoken.startingView);
6191                        if (wtoken.startingWindow != null) {
6192                            view = wtoken.startingView;
6193                            token = wtoken.token;
6194                            wtoken.startingData = null;
6195                            wtoken.startingView = null;
6196                            wtoken.startingWindow = null;
6197                        }
6198                    }
6199                    if (view != null) {
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 FINISHED_STARTING: {
6209                    IBinder token = null;
6210                    View view = null;
6211                    while (true) {
6212                        synchronized (mWindowMap) {
6213                            final int N = mFinishedStarting.size();
6214                            if (N <= 0) {
6215                                break;
6216                            }
6217                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
6218
6219                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6220                                    "Finished starting " + wtoken
6221                                    + ": startingWindow=" + wtoken.startingWindow
6222                                    + " startingView=" + wtoken.startingView);
6223
6224                            if (wtoken.startingWindow == null) {
6225                                continue;
6226                            }
6227
6228                            view = wtoken.startingView;
6229                            token = wtoken.token;
6230                            wtoken.startingData = null;
6231                            wtoken.startingView = null;
6232                            wtoken.startingWindow = null;
6233                        }
6234
6235                        try {
6236                            mPolicy.removeStartingWindow(token, view);
6237                        } catch (Exception e) {
6238                            Slog.w(TAG, "Exception when removing starting window", e);
6239                        }
6240                    }
6241                } break;
6242
6243                case REPORT_APPLICATION_TOKEN_WINDOWS: {
6244                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6245
6246                    boolean nowVisible = msg.arg1 != 0;
6247                    boolean nowGone = msg.arg2 != 0;
6248
6249                    try {
6250                        if (DEBUG_VISIBILITY) Slog.v(
6251                                TAG, "Reporting visible in " + wtoken
6252                                + " visible=" + nowVisible
6253                                + " gone=" + nowGone);
6254                        if (nowVisible) {
6255                            wtoken.appToken.windowsVisible();
6256                        } else {
6257                            wtoken.appToken.windowsGone();
6258                        }
6259                    } catch (RemoteException ex) {
6260                    }
6261                } break;
6262
6263                case WINDOW_FREEZE_TIMEOUT: {
6264                    synchronized (mWindowMap) {
6265                        Slog.w(TAG, "Window freeze timeout expired.");
6266                        int i = mWindows.size();
6267                        while (i > 0) {
6268                            i--;
6269                            WindowState w = mWindows.get(i);
6270                            if (w.mOrientationChanging) {
6271                                w.mOrientationChanging = false;
6272                                Slog.w(TAG, "Force clearing orientation change: " + w);
6273                            }
6274                        }
6275                        performLayoutAndPlaceSurfacesLocked();
6276                    }
6277                    break;
6278                }
6279
6280                case HOLD_SCREEN_CHANGED: {
6281                    Session oldHold;
6282                    Session newHold;
6283                    synchronized (mWindowMap) {
6284                        oldHold = mLastReportedHold;
6285                        newHold = (Session)msg.obj;
6286                        mLastReportedHold = newHold;
6287                    }
6288
6289                    if (oldHold != newHold) {
6290                        try {
6291                            if (oldHold != null) {
6292                                mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
6293                                        "window",
6294                                        BatteryStats.WAKE_TYPE_WINDOW);
6295                            }
6296                            if (newHold != null) {
6297                                mBatteryStats.noteStartWakelock(newHold.mUid, -1,
6298                                        "window",
6299                                        BatteryStats.WAKE_TYPE_WINDOW);
6300                            }
6301                        } catch (RemoteException e) {
6302                        }
6303                    }
6304                    break;
6305                }
6306
6307                case APP_TRANSITION_TIMEOUT: {
6308                    synchronized (mWindowMap) {
6309                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
6310                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
6311                                    "*** APP TRANSITION TIMEOUT");
6312                            mAppTransitionReady = true;
6313                            mAppTransitionTimeout = true;
6314                            performLayoutAndPlaceSurfacesLocked();
6315                        }
6316                    }
6317                    break;
6318                }
6319
6320                case PERSIST_ANIMATION_SCALE: {
6321                    Settings.System.putFloat(mContext.getContentResolver(),
6322                            Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
6323                    Settings.System.putFloat(mContext.getContentResolver(),
6324                            Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
6325                    break;
6326                }
6327
6328                case FORCE_GC: {
6329                    synchronized(mWindowMap) {
6330                        if (mAnimationPending) {
6331                            // If we are animating, don't do the gc now but
6332                            // delay a bit so we don't interrupt the animation.
6333                            mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
6334                                    2000);
6335                            return;
6336                        }
6337                        // If we are currently rotating the display, it will
6338                        // schedule a new message when done.
6339                        if (mDisplayFrozen) {
6340                            return;
6341                        }
6342                        mFreezeGcPending = 0;
6343                    }
6344                    Runtime.getRuntime().gc();
6345                    break;
6346                }
6347
6348                case ENABLE_SCREEN: {
6349                    performEnableScreen();
6350                    break;
6351                }
6352
6353                case APP_FREEZE_TIMEOUT: {
6354                    synchronized (mWindowMap) {
6355                        Slog.w(TAG, "App freeze timeout expired.");
6356                        int i = mAppTokens.size();
6357                        while (i > 0) {
6358                            i--;
6359                            AppWindowToken tok = mAppTokens.get(i);
6360                            if (tok.freezingScreen) {
6361                                Slog.w(TAG, "Force clearing freeze: " + tok);
6362                                unsetAppFreezingScreenLocked(tok, true, true);
6363                            }
6364                        }
6365                    }
6366                    break;
6367                }
6368
6369                case SEND_NEW_CONFIGURATION: {
6370                    removeMessages(SEND_NEW_CONFIGURATION);
6371                    sendNewConfiguration();
6372                    break;
6373                }
6374
6375                case REPORT_WINDOWS_CHANGE: {
6376                    if (mWindowsChanged) {
6377                        synchronized (mWindowMap) {
6378                            mWindowsChanged = false;
6379                        }
6380                        notifyWindowsChanged();
6381                    }
6382                    break;
6383                }
6384
6385                case DRAG_START_TIMEOUT: {
6386                    IBinder win = (IBinder)msg.obj;
6387                    if (DEBUG_DRAG) {
6388                        Slog.w(TAG, "Timeout starting drag by win " + win);
6389                    }
6390                    synchronized (mWindowMap) {
6391                        // !!! TODO: ANR the app that has failed to start the drag in time
6392                        if (mDragState != null) {
6393                            mDragState.unregister();
6394                            mInputMonitor.updateInputWindowsLw(true /*force*/);
6395                            mDragState.reset();
6396                            mDragState = null;
6397                        }
6398                    }
6399                    break;
6400                }
6401
6402                case DRAG_END_TIMEOUT: {
6403                    IBinder win = (IBinder)msg.obj;
6404                    if (DEBUG_DRAG) {
6405                        Slog.w(TAG, "Timeout ending drag to win " + win);
6406                    }
6407                    synchronized (mWindowMap) {
6408                        // !!! TODO: ANR the drag-receiving app
6409                        mDragState.mDragResult = false;
6410                        mDragState.endDragLw();
6411                    }
6412                    break;
6413                }
6414
6415                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
6416                    notifyHardKeyboardStatusChange();
6417                    break;
6418                }
6419            }
6420        }
6421    }
6422
6423    // -------------------------------------------------------------
6424    // IWindowManager API
6425    // -------------------------------------------------------------
6426
6427    public IWindowSession openSession(IInputMethodClient client,
6428            IInputContext inputContext) {
6429        if (client == null) throw new IllegalArgumentException("null client");
6430        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
6431        Session session = new Session(this, client, inputContext);
6432        return session;
6433    }
6434
6435    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
6436        synchronized (mWindowMap) {
6437            // The focus for the client is the window immediately below
6438            // where we would place the input method window.
6439            int idx = findDesiredInputMethodWindowIndexLocked(false);
6440            WindowState imFocus;
6441            if (idx > 0) {
6442                imFocus = mWindows.get(idx-1);
6443                //Log.i(TAG, "Desired input method target: " + imFocus);
6444                //Log.i(TAG, "Current focus: " + this.mCurrentFocus);
6445                //Log.i(TAG, "Last focus: " + this.mLastFocus);
6446                if (imFocus != null) {
6447                    // This may be a starting window, in which case we still want
6448                    // to count it as okay.
6449                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
6450                            && imFocus.mAppToken != null) {
6451                        // The client has definitely started, so it really should
6452                        // have a window in this app token.  Let's look for it.
6453                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
6454                            WindowState w = imFocus.mAppToken.windows.get(i);
6455                            if (w != imFocus) {
6456                                //Log.i(TAG, "Switching to real app window: " + w);
6457                                imFocus = w;
6458                                break;
6459                            }
6460                        }
6461                    }
6462                    //Log.i(TAG, "IM target client: " + imFocus.mSession.mClient);
6463                    //if (imFocus.mSession.mClient != null) {
6464                    //    Log.i(TAG, "IM target client binder: " + imFocus.mSession.mClient.asBinder());
6465                    //    Log.i(TAG, "Requesting client binder: " + client.asBinder());
6466                    //}
6467                    if (imFocus.mSession.mClient != null &&
6468                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
6469                        return true;
6470                    }
6471
6472                    // Okay, how about this...  what is the current focus?
6473                    // It seems in some cases we may not have moved the IM
6474                    // target window, such as when it was in a pop-up window,
6475                    // so let's also look at the current focus.  (An example:
6476                    // go to Gmail, start searching so the keyboard goes up,
6477                    // press home.  Sometimes the IME won't go down.)
6478                    // Would be nice to fix this more correctly, but it's
6479                    // way at the end of a release, and this should be good enough.
6480                    if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null &&
6481                            mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
6482                        return true;
6483                    }
6484                }
6485            }
6486        }
6487        return false;
6488    }
6489
6490    public void getDisplaySize(Point size) {
6491        synchronized(mWindowMap) {
6492            size.x = mCurDisplayWidth;
6493            size.y = mCurDisplayHeight;
6494        }
6495    }
6496
6497    public int getMaximumSizeDimension() {
6498        synchronized(mWindowMap) {
6499            // Do this based on the raw screen size, until we are smarter.
6500            return mBaseDisplayWidth > mBaseDisplayHeight
6501                    ? mBaseDisplayWidth : mBaseDisplayHeight;
6502        }
6503    }
6504
6505    public void setForcedDisplaySize(int longDimen, int shortDimen) {
6506        synchronized(mWindowMap) {
6507            int width, height;
6508            if (mInitialDisplayWidth < mInitialDisplayHeight) {
6509                width = shortDimen < mInitialDisplayWidth
6510                        ? shortDimen : mInitialDisplayWidth;
6511                height = longDimen < mInitialDisplayHeight
6512                        ? longDimen : mInitialDisplayHeight;
6513            } else {
6514                width = longDimen < mInitialDisplayWidth
6515                        ? longDimen : mInitialDisplayWidth;
6516                height = shortDimen < mInitialDisplayHeight
6517                        ? shortDimen : mInitialDisplayHeight;
6518            }
6519            setForcedDisplaySizeLocked(width, height);
6520        }
6521    }
6522
6523    private void rebuildBlackFrame(boolean inTransaction) {
6524        if (!inTransaction) {
6525            if (SHOW_TRANSACTIONS) Slog.i(TAG,
6526                    ">>> OPEN TRANSACTION rebuildBlackFrame");
6527            Surface.openTransaction();
6528        }
6529        try {
6530            if (mBlackFrame != null) {
6531                mBlackFrame.kill();
6532                mBlackFrame = null;
6533            }
6534            if (mBaseDisplayWidth < mInitialDisplayWidth
6535                    || mBaseDisplayHeight < mInitialDisplayHeight) {
6536                int initW, initH, baseW, baseH;
6537                final boolean rotated = (mRotation == Surface.ROTATION_90
6538                        || mRotation == Surface.ROTATION_270);
6539                if (rotated) {
6540                    initW = mInitialDisplayHeight;
6541                    initH = mInitialDisplayWidth;
6542                    baseW = mBaseDisplayHeight;
6543                    baseH = mBaseDisplayWidth;
6544                } else {
6545                    initW = mInitialDisplayWidth;
6546                    initH = mInitialDisplayHeight;
6547                    baseW = mBaseDisplayWidth;
6548                    baseH = mBaseDisplayHeight;
6549                }
6550                Rect outer = new Rect(0, 0, initW, initH);
6551                Rect inner = new Rect(0, 0, baseW, baseH);
6552                try {
6553                    mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
6554                } catch (Surface.OutOfResourcesException e) {
6555                }
6556            }
6557        } finally {
6558            if (!inTransaction) {
6559                Surface.closeTransaction();
6560                if (SHOW_TRANSACTIONS) Slog.i(TAG,
6561                        "<<< CLOSE TRANSACTION rebuildBlackFrame");
6562            }
6563        }
6564    }
6565
6566    private void setForcedDisplaySizeLocked(int width, int height) {
6567        mBaseDisplayWidth = width;
6568        mBaseDisplayHeight = height;
6569        mPolicy.setInitialDisplaySize(mBaseDisplayWidth, mBaseDisplayHeight);
6570
6571        mLayoutNeeded = true;
6572
6573        boolean configChanged = updateOrientationFromAppTokensLocked(false);
6574        mTempConfiguration.setToDefaults();
6575        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
6576        if (computeNewConfigurationLocked(mTempConfiguration)) {
6577            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
6578                configChanged = true;
6579            }
6580        }
6581
6582        if (configChanged) {
6583            mWaitingForConfig = true;
6584            startFreezingDisplayLocked(false);
6585            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6586        }
6587
6588        rebuildBlackFrame(false);
6589
6590        performLayoutAndPlaceSurfacesLocked();
6591    }
6592
6593    public void clearForcedDisplaySize() {
6594        synchronized(mWindowMap) {
6595            setForcedDisplaySizeLocked(mInitialDisplayWidth, mInitialDisplayHeight);
6596        }
6597    }
6598
6599    // -------------------------------------------------------------
6600    // Internals
6601    // -------------------------------------------------------------
6602
6603    final WindowState windowForClientLocked(Session session, IWindow client,
6604            boolean throwOnError) {
6605        return windowForClientLocked(session, client.asBinder(), throwOnError);
6606    }
6607
6608    final WindowState windowForClientLocked(Session session, IBinder client,
6609            boolean throwOnError) {
6610        WindowState win = mWindowMap.get(client);
6611        if (localLOGV) Slog.v(
6612            TAG, "Looking up client " + client + ": " + win);
6613        if (win == null) {
6614            RuntimeException ex = new IllegalArgumentException(
6615                    "Requested window " + client + " does not exist");
6616            if (throwOnError) {
6617                throw ex;
6618            }
6619            Slog.w(TAG, "Failed looking up window", ex);
6620            return null;
6621        }
6622        if (session != null && win.mSession != session) {
6623            RuntimeException ex = new IllegalArgumentException(
6624                    "Requested window " + client + " is in session " +
6625                    win.mSession + ", not " + session);
6626            if (throwOnError) {
6627                throw ex;
6628            }
6629            Slog.w(TAG, "Failed looking up window", ex);
6630            return null;
6631        }
6632
6633        return win;
6634    }
6635
6636    final void rebuildAppWindowListLocked() {
6637        int NW = mWindows.size();
6638        int i;
6639        int lastWallpaper = -1;
6640        int numRemoved = 0;
6641
6642        if (mRebuildTmp.length < NW) {
6643            mRebuildTmp = new WindowState[NW+10];
6644        }
6645
6646        // First remove all existing app windows.
6647        i=0;
6648        while (i < NW) {
6649            WindowState w = mWindows.get(i);
6650            if (w.mAppToken != null) {
6651                WindowState win = mWindows.remove(i);
6652                win.mRebuilding = true;
6653                mRebuildTmp[numRemoved] = win;
6654                mWindowsChanged = true;
6655                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
6656                        "Rebuild removing window: " + win);
6657                NW--;
6658                numRemoved++;
6659                continue;
6660            } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER
6661                    && lastWallpaper == i-1) {
6662                lastWallpaper = i;
6663            }
6664            i++;
6665        }
6666
6667        // The wallpaper window(s) typically live at the bottom of the stack,
6668        // so skip them before adding app tokens.
6669        lastWallpaper++;
6670        i = lastWallpaper;
6671
6672        // First add all of the exiting app tokens...  these are no longer
6673        // in the main app list, but still have windows shown.  We put them
6674        // in the back because now that the animation is over we no longer
6675        // will care about them.
6676        int NT = mExitingAppTokens.size();
6677        for (int j=0; j<NT; j++) {
6678            i = reAddAppWindowsLocked(i, mExitingAppTokens.get(j));
6679        }
6680
6681        // And add in the still active app tokens in Z order.
6682        NT = mAppTokens.size();
6683        for (int j=0; j<NT; j++) {
6684            i = reAddAppWindowsLocked(i, mAppTokens.get(j));
6685        }
6686
6687        i -= lastWallpaper;
6688        if (i != numRemoved) {
6689            Slog.w(TAG, "Rebuild removed " + numRemoved
6690                    + " windows but added " + i);
6691            for (i=0; i<numRemoved; i++) {
6692                WindowState ws = mRebuildTmp[i];
6693                if (ws.mRebuilding) {
6694                    StringWriter sw = new StringWriter();
6695                    PrintWriter pw = new PrintWriter(sw);
6696                    ws.dump(pw, "");
6697                    pw.flush();
6698                    Slog.w(TAG, "This window was lost: " + ws);
6699                    Slog.w(TAG, sw.toString());
6700                }
6701            }
6702            Slog.w(TAG, "Current app token list:");
6703            dumpAppTokensLocked();
6704            Slog.w(TAG, "Final window list:");
6705            dumpWindowsLocked();
6706        }
6707    }
6708
6709    private final void assignLayersLocked() {
6710        int N = mWindows.size();
6711        int curBaseLayer = 0;
6712        int curLayer = 0;
6713        int i;
6714
6715        if (DEBUG_LAYERS) {
6716            RuntimeException here = new RuntimeException("here");
6717            here.fillInStackTrace();
6718            Log.v(TAG, "Assigning layers", here);
6719        }
6720
6721        for (i=0; i<N; i++) {
6722            WindowState w = mWindows.get(i);
6723            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
6724                    || (i > 0 && w.mIsWallpaper)) {
6725                curLayer += WINDOW_LAYER_MULTIPLIER;
6726                w.mLayer = curLayer;
6727            } else {
6728                curBaseLayer = curLayer = w.mBaseLayer;
6729                w.mLayer = curLayer;
6730            }
6731            if (w.mTargetAppToken != null) {
6732                w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
6733            } else if (w.mAppToken != null) {
6734                w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
6735            } else {
6736                w.mAnimLayer = w.mLayer;
6737            }
6738            if (w.mIsImWindow) {
6739                w.mAnimLayer += mInputMethodAnimLayerAdjustment;
6740            } else if (w.mIsWallpaper) {
6741                w.mAnimLayer += mWallpaperAnimLayerAdjustment;
6742            }
6743            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
6744                    + w.mAnimLayer);
6745            //System.out.println(
6746            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
6747        }
6748    }
6749
6750    private boolean mInLayout = false;
6751    private final void performLayoutAndPlaceSurfacesLocked() {
6752        if (mInLayout) {
6753            if (DEBUG) {
6754                throw new RuntimeException("Recursive call!");
6755            }
6756            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
6757            return;
6758        }
6759
6760        if (mWaitingForConfig) {
6761            // Our configuration has changed (most likely rotation), but we
6762            // don't yet have the complete configuration to report to
6763            // applications.  Don't do any window layout until we have it.
6764            return;
6765        }
6766
6767        if (mDisplay == null) {
6768            // Not yet initialized, nothing to do.
6769            return;
6770        }
6771
6772        mInLayout = true;
6773        boolean recoveringMemory = false;
6774
6775        try {
6776            if (mForceRemoves != null) {
6777                recoveringMemory = true;
6778                // Wait a little bit for things to settle down, and off we go.
6779                for (int i=0; i<mForceRemoves.size(); i++) {
6780                    WindowState ws = mForceRemoves.get(i);
6781                    Slog.i(TAG, "Force removing: " + ws);
6782                    removeWindowInnerLocked(ws.mSession, ws);
6783                }
6784                mForceRemoves = null;
6785                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
6786                Object tmp = new Object();
6787                synchronized (tmp) {
6788                    try {
6789                        tmp.wait(250);
6790                    } catch (InterruptedException e) {
6791                    }
6792                }
6793            }
6794        } catch (RuntimeException e) {
6795            Slog.e(TAG, "Unhandled exception while force removing for memory", e);
6796        }
6797
6798        try {
6799            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
6800
6801            int N = mPendingRemove.size();
6802            if (N > 0) {
6803                if (mPendingRemoveTmp.length < N) {
6804                    mPendingRemoveTmp = new WindowState[N+10];
6805                }
6806                mPendingRemove.toArray(mPendingRemoveTmp);
6807                mPendingRemove.clear();
6808                for (int i=0; i<N; i++) {
6809                    WindowState w = mPendingRemoveTmp[i];
6810                    removeWindowInnerLocked(w.mSession, w);
6811                }
6812
6813                mInLayout = false;
6814                assignLayersLocked();
6815                mLayoutNeeded = true;
6816                performLayoutAndPlaceSurfacesLocked();
6817
6818            } else {
6819                mInLayout = false;
6820                if (mLayoutNeeded) {
6821                    requestAnimationLocked(0);
6822                }
6823            }
6824            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
6825                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
6826                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
6827            }
6828        } catch (RuntimeException e) {
6829            mInLayout = false;
6830            Slog.e(TAG, "Unhandled exception while layout out windows", e);
6831        }
6832    }
6833
6834    private final int performLayoutLockedInner(boolean initial, boolean updateInputWindows) {
6835        if (!mLayoutNeeded) {
6836            return 0;
6837        }
6838
6839        mLayoutNeeded = false;
6840
6841        final int dw = mCurDisplayWidth;
6842        final int dh = mCurDisplayHeight;
6843
6844        final int N = mWindows.size();
6845        int i;
6846
6847        if (DEBUG_LAYOUT) Slog.v(TAG, "performLayout: needed="
6848                + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
6849
6850        mPolicy.beginLayoutLw(dw, dh);
6851
6852        int seq = mLayoutSeq+1;
6853        if (seq < 0) seq = 0;
6854        mLayoutSeq = seq;
6855
6856        // First perform layout of any root windows (not attached
6857        // to another window).
6858        int topAttached = -1;
6859        for (i = N-1; i >= 0; i--) {
6860            WindowState win = mWindows.get(i);
6861
6862            // Don't do layout of a window if it is not visible, or
6863            // soon won't be visible, to avoid wasting time and funky
6864            // changes while a window is animating away.
6865            final AppWindowToken atoken = win.mAppToken;
6866            final boolean gone = win.mViewVisibility == View.GONE
6867                    || !win.mRelayoutCalled
6868                    || (atoken == null && win.mRootToken.hidden)
6869                    || (atoken != null && atoken.hiddenRequested)
6870                    || win.mAttachedHidden
6871                    || win.mExiting || win.mDestroying;
6872
6873            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
6874                Slog.v(TAG, "First pass " + win
6875                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
6876                        + " mLayoutAttached=" + win.mLayoutAttached);
6877                if (gone) Slog.v(TAG, "  (mViewVisibility="
6878                        + win.mViewVisibility + " mRelayoutCalled="
6879                        + win.mRelayoutCalled + " hidden="
6880                        + win.mRootToken.hidden + " hiddenRequested="
6881                        + (atoken != null && atoken.hiddenRequested)
6882                        + " mAttachedHidden=" + win.mAttachedHidden);
6883            }
6884
6885            // If this view is GONE, then skip it -- keep the current
6886            // frame, and let the caller know so they can ignore it
6887            // if they want.  (We do the normal layout for INVISIBLE
6888            // windows, since that means "perform layout as normal,
6889            // just don't display").
6890            if (!gone || !win.mHaveFrame) {
6891                if (!win.mLayoutAttached) {
6892                    if (initial) {
6893                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
6894                        win.mContentChanged = false;
6895                    }
6896                    win.prelayout();
6897                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
6898                    win.mLayoutSeq = seq;
6899                    if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
6900                            + win.mFrame + " mContainingFrame="
6901                            + win.mContainingFrame + " mDisplayFrame="
6902                            + win.mDisplayFrame);
6903                } else {
6904                    if (topAttached < 0) topAttached = i;
6905                }
6906            }
6907        }
6908
6909        // Now perform layout of attached windows, which usually
6910        // depend on the position of the window they are attached to.
6911        // XXX does not deal with windows that are attached to windows
6912        // that are themselves attached.
6913        for (i = topAttached; i >= 0; i--) {
6914            WindowState win = mWindows.get(i);
6915
6916            if (win.mLayoutAttached) {
6917                if (DEBUG_LAYOUT) Slog.v(TAG, "Second pass " + win
6918                        + " mHaveFrame=" + win.mHaveFrame
6919                        + " mViewVisibility=" + win.mViewVisibility
6920                        + " mRelayoutCalled=" + win.mRelayoutCalled);
6921                // If this view is GONE, then skip it -- keep the current
6922                // frame, and let the caller know so they can ignore it
6923                // if they want.  (We do the normal layout for INVISIBLE
6924                // windows, since that means "perform layout as normal,
6925                // just don't display").
6926                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
6927                        || !win.mHaveFrame) {
6928                    if (initial) {
6929                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
6930                        win.mContentChanged = false;
6931                    }
6932                    win.prelayout();
6933                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
6934                    win.mLayoutSeq = seq;
6935                    if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
6936                            + win.mFrame + " mContainingFrame="
6937                            + win.mContainingFrame + " mDisplayFrame="
6938                            + win.mDisplayFrame);
6939                }
6940            }
6941        }
6942
6943        // Window frames may have changed.  Tell the input dispatcher about it.
6944        mInputMonitor.setUpdateInputWindowsNeededLw();
6945        if (updateInputWindows) {
6946            mInputMonitor.updateInputWindowsLw(false /*force*/);
6947        }
6948
6949        return mPolicy.finishLayoutLw();
6950    }
6951
6952    // "Something has changed!  Let's make it correct now."
6953    private final void performLayoutAndPlaceSurfacesLockedInner(
6954            boolean recoveringMemory) {
6955        if (mDisplay == null) {
6956            Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
6957            return;
6958        }
6959
6960        final long currentTime = SystemClock.uptimeMillis();
6961        final int dw = mCurDisplayWidth;
6962        final int dh = mCurDisplayHeight;
6963
6964        final int innerDw = mPolicy.getNonDecorDisplayWidth(mRotation, dw);
6965        final int innerDh = mPolicy.getNonDecorDisplayHeight(mRotation, dh);
6966
6967        int i;
6968
6969        if (mFocusMayChange) {
6970            mFocusMayChange = false;
6971            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
6972                    false /*updateInputWindows*/);
6973        }
6974
6975        // Initialize state of exiting tokens.
6976        for (i=mExitingTokens.size()-1; i>=0; i--) {
6977            mExitingTokens.get(i).hasVisible = false;
6978        }
6979
6980        // Initialize state of exiting applications.
6981        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
6982            mExitingAppTokens.get(i).hasVisible = false;
6983        }
6984
6985        boolean orientationChangeComplete = true;
6986        Session holdScreen = null;
6987        float screenBrightness = -1;
6988        float buttonBrightness = -1;
6989        boolean focusDisplayed = false;
6990        boolean animating = false;
6991        boolean createWatermark = false;
6992        boolean updateRotation = false;
6993        boolean screenRotationFinished = false;
6994
6995        if (mFxSession == null) {
6996            mFxSession = new SurfaceSession();
6997            createWatermark = true;
6998        }
6999
7000        if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
7001
7002        Surface.openTransaction();
7003
7004        if (createWatermark) {
7005            createWatermark();
7006        }
7007        if (mWatermark != null) {
7008            mWatermark.positionSurface(dw, dh);
7009        }
7010        if (mStrictModeFlash != null) {
7011            mStrictModeFlash.positionSurface(dw, dh);
7012        }
7013
7014        try {
7015            boolean wallpaperForceHidingChanged = false;
7016            int repeats = 0;
7017            int changes = 0;
7018
7019            do {
7020                repeats++;
7021                if (repeats > 6) {
7022                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
7023                    mLayoutNeeded = false;
7024                    break;
7025                }
7026
7027                if ((changes&(WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER
7028                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG
7029                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) {
7030                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
7031                        if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
7032                            assignLayersLocked();
7033                            mLayoutNeeded = true;
7034                        }
7035                    }
7036                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
7037                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
7038                        if (updateOrientationFromAppTokensLocked(true)) {
7039                            mLayoutNeeded = true;
7040                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7041                        }
7042                    }
7043                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
7044                        mLayoutNeeded = true;
7045                    }
7046                }
7047
7048                // FIRST LOOP: Perform a layout, if needed.
7049                if (repeats < 4) {
7050                    changes = performLayoutLockedInner(repeats == 0, false /*updateInputWindows*/);
7051                    if (changes != 0) {
7052                        continue;
7053                    }
7054                } else {
7055                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
7056                    changes = 0;
7057                }
7058
7059                final int transactionSequence = ++mTransactionSequence;
7060
7061                // Update animations of all applications, including those
7062                // associated with exiting/removed apps
7063                boolean tokensAnimating = false;
7064                final int NAT = mAppTokens.size();
7065                for (i=0; i<NAT; i++) {
7066                    if (mAppTokens.get(i).stepAnimationLocked(currentTime,
7067                            innerDw, innerDh)) {
7068                        tokensAnimating = true;
7069                    }
7070                }
7071                final int NEAT = mExitingAppTokens.size();
7072                for (i=0; i<NEAT; i++) {
7073                    if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime,
7074                            innerDw, innerDh)) {
7075                        tokensAnimating = true;
7076                    }
7077                }
7078
7079                // SECOND LOOP: Execute animations and update visibility of windows.
7080
7081                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
7082                        + transactionSequence + " tokensAnimating="
7083                        + tokensAnimating);
7084
7085                animating = tokensAnimating;
7086
7087                if (mScreenRotationAnimation != null) {
7088                    if (mScreenRotationAnimation.isAnimating()) {
7089                        if (mScreenRotationAnimation.stepAnimation(currentTime)) {
7090                            animating = true;
7091                        } else {
7092                            screenRotationFinished = true;
7093                            updateRotation = true;
7094                        }
7095                    }
7096                }
7097
7098                boolean tokenMayBeDrawn = false;
7099                boolean wallpaperMayChange = false;
7100                boolean forceHiding = false;
7101                WindowState windowDetachedWallpaper = null;
7102                WindowState windowAnimationBackground = null;
7103                int windowAnimationBackgroundColor = 0;
7104
7105                mPolicy.beginAnimationLw(dw, dh);
7106
7107                final int N = mWindows.size();
7108
7109                for (i=N-1; i>=0; i--) {
7110                    WindowState w = mWindows.get(i);
7111
7112                    final WindowManager.LayoutParams attrs = w.mAttrs;
7113
7114                    if (w.mSurface != null) {
7115                        // Take care of the window being ready to display.
7116                        if (w.commitFinishDrawingLocked(currentTime)) {
7117                            if ((w.mAttrs.flags
7118                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
7119                                if (DEBUG_WALLPAPER) Slog.v(TAG,
7120                                        "First draw done in potential wallpaper target " + w);
7121                                wallpaperMayChange = true;
7122                            }
7123                        }
7124
7125                        final boolean wasAnimating = w.mAnimating;
7126
7127                        int animDw = innerDw;
7128                        int animDh = innerDh;
7129
7130                        // If the window has moved due to its containing
7131                        // content frame changing, then we'd like to animate
7132                        // it.  The checks here are ordered by what is least
7133                        // likely to be true first.
7134                        if (w.shouldAnimateMove()) {
7135                            // Frame has moved, containing content frame
7136                            // has also moved, and we're not currently animating...
7137                            // let's do something.
7138                            Animation a = AnimationUtils.loadAnimation(mContext,
7139                                    com.android.internal.R.anim.window_move_from_decor);
7140                            w.setAnimation(a);
7141                            animDw = w.mLastFrame.left - w.mFrame.left;
7142                            animDh = w.mLastFrame.top - w.mFrame.top;
7143                        }
7144
7145                        // Execute animation.
7146                        final boolean nowAnimating = w.stepAnimationLocked(currentTime,
7147                                animDw, animDh);
7148
7149                        // If this window is animating, make a note that we have
7150                        // an animating window and take care of a request to run
7151                        // a detached wallpaper animation.
7152                        if (nowAnimating) {
7153                            if (w.mAnimation != null) {
7154                                if (w.mAnimation.getDetachWallpaper()) {
7155                                    windowDetachedWallpaper = w;
7156                                }
7157                                if (w.mAnimation.getBackgroundColor() != 0) {
7158                                    windowAnimationBackground = w;
7159                                    windowAnimationBackgroundColor =
7160                                            w.mAnimation.getBackgroundColor();
7161                                }
7162                            }
7163                            animating = true;
7164                        }
7165
7166                        // If this window's app token is running a detached wallpaper
7167                        // animation, make a note so we can ensure the wallpaper is
7168                        // displayed behind it.
7169                        if (w.mAppToken != null && w.mAppToken.animation != null) {
7170                            if (w.mAppToken.animation.getDetachWallpaper()) {
7171                                windowDetachedWallpaper = w;
7172                            }
7173                            if (w.mAppToken.animation.getBackgroundColor() != 0) {
7174                                windowAnimationBackground = w;
7175                                windowAnimationBackgroundColor =
7176                                        w.mAppToken.animation.getBackgroundColor();
7177                            }
7178                        }
7179
7180                        if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
7181                            wallpaperMayChange = true;
7182                        }
7183
7184                        if (mPolicy.doesForceHide(w, attrs)) {
7185                            if (!wasAnimating && nowAnimating) {
7186                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7187                                        "Animation started that could impact force hide: "
7188                                        + w);
7189                                wallpaperForceHidingChanged = true;
7190                                mFocusMayChange = true;
7191                            } else if (w.isReadyForDisplay() && w.mAnimation == null) {
7192                                forceHiding = true;
7193                            }
7194                        } else if (mPolicy.canBeForceHidden(w, attrs)) {
7195                            boolean changed;
7196                            if (forceHiding) {
7197                                changed = w.hideLw(false, false);
7198                                if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
7199                                        "Now policy hidden: " + w);
7200                            } else {
7201                                changed = w.showLw(false, false);
7202                                if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
7203                                        "Now policy shown: " + w);
7204                                if (changed) {
7205                                    if (wallpaperForceHidingChanged
7206                                            && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
7207                                        // Assume we will need to animate.  If
7208                                        // we don't (because the wallpaper will
7209                                        // stay with the lock screen), then we will
7210                                        // clean up later.
7211                                        Animation a = mPolicy.createForceHideEnterAnimation();
7212                                        if (a != null) {
7213                                            w.setAnimation(a);
7214                                        }
7215                                    }
7216                                    if (mCurrentFocus == null ||
7217                                            mCurrentFocus.mLayer < w.mLayer) {
7218                                        // We are showing on to of the current
7219                                        // focus, so re-evaluate focus to make
7220                                        // sure it is correct.
7221                                        mFocusMayChange = true;
7222                                    }
7223                                }
7224                            }
7225                            if (changed && (attrs.flags
7226                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
7227                                wallpaperMayChange = true;
7228                            }
7229                        }
7230
7231                        mPolicy.animatingWindowLw(w, attrs);
7232                    }
7233
7234                    final AppWindowToken atoken = w.mAppToken;
7235                    if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
7236                        if (atoken.lastTransactionSequence != transactionSequence) {
7237                            atoken.lastTransactionSequence = transactionSequence;
7238                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
7239                            atoken.startingDisplayed = false;
7240                        }
7241                        if ((w.isOnScreen() || w.mAttrs.type
7242                                == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
7243                                && !w.mExiting && !w.mDestroying) {
7244                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
7245                                Slog.v(TAG, "Eval win " + w + ": isDrawn="
7246                                        + w.isDrawnLw()
7247                                        + ", isAnimating=" + w.isAnimating());
7248                                if (!w.isDrawnLw()) {
7249                                    Slog.v(TAG, "Not displayed: s=" + w.mSurface
7250                                            + " pv=" + w.mPolicyVisibility
7251                                            + " dp=" + w.mDrawPending
7252                                            + " cdp=" + w.mCommitDrawPending
7253                                            + " ah=" + w.mAttachedHidden
7254                                            + " th=" + atoken.hiddenRequested
7255                                            + " a=" + w.mAnimating);
7256                                }
7257                            }
7258                            if (w != atoken.startingWindow) {
7259                                if (!atoken.freezingScreen || !w.mAppFreezing) {
7260                                    atoken.numInterestingWindows++;
7261                                    if (w.isDrawnLw()) {
7262                                        atoken.numDrawnWindows++;
7263                                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
7264                                                "tokenMayBeDrawn: " + atoken
7265                                                + " freezingScreen=" + atoken.freezingScreen
7266                                                + " mAppFreezing=" + w.mAppFreezing);
7267                                        tokenMayBeDrawn = true;
7268                                    }
7269                                }
7270                            } else if (w.isDrawnLw()) {
7271                                atoken.startingDisplayed = true;
7272                            }
7273                        }
7274                    } else if (w.mReadyToShow) {
7275                        w.performShowLocked();
7276                    }
7277                }
7278
7279                changes |= mPolicy.finishAnimationLw();
7280
7281                if (tokenMayBeDrawn) {
7282                    // See if any windows have been drawn, so they (and others
7283                    // associated with them) can now be shown.
7284                    final int NT = mAppTokens.size();
7285                    for (i=0; i<NT; i++) {
7286                        AppWindowToken wtoken = mAppTokens.get(i);
7287                        if (wtoken.freezingScreen) {
7288                            int numInteresting = wtoken.numInterestingWindows;
7289                            if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7290                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7291                                        "allDrawn: " + wtoken
7292                                        + " interesting=" + numInteresting
7293                                        + " drawn=" + wtoken.numDrawnWindows);
7294                                wtoken.showAllWindowsLocked();
7295                                unsetAppFreezingScreenLocked(wtoken, false, true);
7296                                orientationChangeComplete = true;
7297                            }
7298                        } else if (!wtoken.allDrawn) {
7299                            int numInteresting = wtoken.numInterestingWindows;
7300                            if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7301                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7302                                        "allDrawn: " + wtoken
7303                                        + " interesting=" + numInteresting
7304                                        + " drawn=" + wtoken.numDrawnWindows);
7305                                wtoken.allDrawn = true;
7306                                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
7307
7308                                // We can now show all of the drawn windows!
7309                                if (!mOpeningApps.contains(wtoken)) {
7310                                    wtoken.showAllWindowsLocked();
7311                                }
7312                            }
7313                        }
7314                    }
7315                }
7316
7317                // If we are ready to perform an app transition, check through
7318                // all of the app tokens to be shown and see if they are ready
7319                // to go.
7320                if (mAppTransitionReady) {
7321                    int NN = mOpeningApps.size();
7322                    boolean goodToGo = true;
7323                    if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7324                            "Checking " + NN + " opening apps (frozen="
7325                            + mDisplayFrozen + " timeout="
7326                            + mAppTransitionTimeout + ")...");
7327                    if (!mDisplayFrozen && !mAppTransitionTimeout) {
7328                        // If the display isn't frozen, wait to do anything until
7329                        // all of the apps are ready.  Otherwise just go because
7330                        // we'll unfreeze the display when everyone is ready.
7331                        for (i=0; i<NN && goodToGo; i++) {
7332                            AppWindowToken wtoken = mOpeningApps.get(i);
7333                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7334                                    "Check opening app" + wtoken + ": allDrawn="
7335                                    + wtoken.allDrawn + " startingDisplayed="
7336                                    + wtoken.startingDisplayed);
7337                            if (!wtoken.allDrawn && !wtoken.startingDisplayed
7338                                    && !wtoken.startingMoved) {
7339                                goodToGo = false;
7340                            }
7341                        }
7342                    }
7343                    if (goodToGo) {
7344                        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
7345                        int transit = mNextAppTransition;
7346                        if (mSkipAppTransitionAnimation) {
7347                            transit = WindowManagerPolicy.TRANSIT_UNSET;
7348                        }
7349                        mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
7350                        mAppTransitionReady = false;
7351                        mAppTransitionRunning = true;
7352                        mAppTransitionTimeout = false;
7353                        mStartingIconInTransition = false;
7354                        mSkipAppTransitionAnimation = false;
7355
7356                        mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
7357
7358                        // If there are applications waiting to come to the
7359                        // top of the stack, now is the time to move their windows.
7360                        // (Note that we don't do apps going to the bottom
7361                        // here -- we want to keep their windows in the old
7362                        // Z-order until the animation completes.)
7363                        if (mToTopApps.size() > 0) {
7364                            NN = mAppTokens.size();
7365                            for (i=0; i<NN; i++) {
7366                                AppWindowToken wtoken = mAppTokens.get(i);
7367                                if (wtoken.sendingToTop) {
7368                                    wtoken.sendingToTop = false;
7369                                    moveAppWindowsLocked(wtoken, NN, false);
7370                                }
7371                            }
7372                            mToTopApps.clear();
7373                        }
7374
7375                        WindowState oldWallpaper = mWallpaperTarget;
7376
7377                        adjustWallpaperWindowsLocked();
7378                        wallpaperMayChange = false;
7379
7380                        // The top-most window will supply the layout params,
7381                        // and we will determine it below.
7382                        LayoutParams animLp = null;
7383                        int bestAnimLayer = -1;
7384                        boolean fullscreenAnim = false;
7385
7386                        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7387                                "New wallpaper target=" + mWallpaperTarget
7388                                + ", lower target=" + mLowerWallpaperTarget
7389                                + ", upper target=" + mUpperWallpaperTarget);
7390                        int foundWallpapers = 0;
7391                        // Do a first pass through the tokens for two
7392                        // things:
7393                        // (1) Determine if both the closing and opening
7394                        // app token sets are wallpaper targets, in which
7395                        // case special animations are needed
7396                        // (since the wallpaper needs to stay static
7397                        // behind them).
7398                        // (2) Find the layout params of the top-most
7399                        // application window in the tokens, which is
7400                        // what will control the animation theme.
7401                        final int NC = mClosingApps.size();
7402                        NN = NC + mOpeningApps.size();
7403                        for (i=0; i<NN; i++) {
7404                            AppWindowToken wtoken;
7405                            int mode;
7406                            if (i < NC) {
7407                                wtoken = mClosingApps.get(i);
7408                                mode = 1;
7409                            } else {
7410                                wtoken = mOpeningApps.get(i-NC);
7411                                mode = 2;
7412                            }
7413                            if (mLowerWallpaperTarget != null) {
7414                                if (mLowerWallpaperTarget.mAppToken == wtoken
7415                                        || mUpperWallpaperTarget.mAppToken == wtoken) {
7416                                    foundWallpapers |= mode;
7417                                }
7418                            }
7419                            if (wtoken.appFullscreen) {
7420                                WindowState ws = wtoken.findMainWindow();
7421                                if (ws != null) {
7422                                    animLp = ws.mAttrs;
7423                                    bestAnimLayer = ws.mLayer;
7424                                    fullscreenAnim = true;
7425                                }
7426                            } else if (!fullscreenAnim) {
7427                                WindowState ws = wtoken.findMainWindow();
7428                                if (ws != null) {
7429                                    if (ws.mLayer > bestAnimLayer) {
7430                                        animLp = ws.mAttrs;
7431                                        bestAnimLayer = ws.mLayer;
7432                                    }
7433                                }
7434                            }
7435                        }
7436
7437                        if (foundWallpapers == 3) {
7438                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7439                                    "Wallpaper animation!");
7440                            switch (transit) {
7441                                case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
7442                                case WindowManagerPolicy.TRANSIT_TASK_OPEN:
7443                                case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
7444                                    transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
7445                                    break;
7446                                case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
7447                                case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
7448                                case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
7449                                    transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
7450                                    break;
7451                            }
7452                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7453                                    "New transit: " + transit);
7454                        } else if (oldWallpaper != null) {
7455                            // We are transitioning from an activity with
7456                            // a wallpaper to one without.
7457                            transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
7458                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7459                                    "New transit away from wallpaper: " + transit);
7460                        } else if (mWallpaperTarget != null) {
7461                            // We are transitioning from an activity without
7462                            // a wallpaper to now showing the wallpaper
7463                            transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
7464                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7465                                    "New transit into wallpaper: " + transit);
7466                        }
7467
7468                        // If all closing windows are obscured, then there is
7469                        // no need to do an animation.  This is the case, for
7470                        // example, when this transition is being done behind
7471                        // the lock screen.
7472                        if (!mPolicy.allowAppAnimationsLw()) {
7473                            animLp = null;
7474                        }
7475
7476                        NN = mOpeningApps.size();
7477                        for (i=0; i<NN; i++) {
7478                            AppWindowToken wtoken = mOpeningApps.get(i);
7479                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7480                                    "Now opening app" + wtoken);
7481                            wtoken.reportedVisible = false;
7482                            wtoken.inPendingTransaction = false;
7483                            wtoken.animation = null;
7484                            setTokenVisibilityLocked(wtoken, animLp, true,
7485                                    transit, false);
7486                            wtoken.updateReportedVisibilityLocked();
7487                            wtoken.waitingToShow = false;
7488                            wtoken.showAllWindowsLocked();
7489                        }
7490                        NN = mClosingApps.size();
7491                        for (i=0; i<NN; i++) {
7492                            AppWindowToken wtoken = mClosingApps.get(i);
7493                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7494                                    "Now closing app" + wtoken);
7495                            wtoken.inPendingTransaction = false;
7496                            wtoken.animation = null;
7497                            setTokenVisibilityLocked(wtoken, animLp, false,
7498                                    transit, false);
7499                            wtoken.updateReportedVisibilityLocked();
7500                            wtoken.waitingToHide = false;
7501                            // Force the allDrawn flag, because we want to start
7502                            // this guy's animations regardless of whether it's
7503                            // gotten drawn.
7504                            wtoken.allDrawn = true;
7505                        }
7506
7507                        mNextAppTransitionPackage = null;
7508
7509                        mOpeningApps.clear();
7510                        mClosingApps.clear();
7511
7512                        // This has changed the visibility of windows, so perform
7513                        // a new layout to get them all up-to-date.
7514                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
7515                                | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
7516                        mLayoutNeeded = true;
7517                        if (!moveInputMethodWindowsIfNeededLocked(true)) {
7518                            assignLayersLocked();
7519                        }
7520                        updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
7521                                false /*updateInputWindows*/);
7522                        mFocusMayChange = false;
7523                    }
7524                }
7525
7526                int adjResult = 0;
7527
7528                if (!animating && mAppTransitionRunning) {
7529                    // We have finished the animation of an app transition.  To do
7530                    // this, we have delayed a lot of operations like showing and
7531                    // hiding apps, moving apps in Z-order, etc.  The app token list
7532                    // reflects the correct Z-order, but the window list may now
7533                    // be out of sync with it.  So here we will just rebuild the
7534                    // entire app window list.  Fun!
7535                    mAppTransitionRunning = false;
7536                    // Clear information about apps that were moving.
7537                    mToBottomApps.clear();
7538
7539                    rebuildAppWindowListLocked();
7540                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
7541                    adjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
7542                    moveInputMethodWindowsIfNeededLocked(false);
7543                    wallpaperMayChange = true;
7544                    // Since the window list has been rebuilt, focus might
7545                    // have to be recomputed since the actual order of windows
7546                    // might have changed again.
7547                    mFocusMayChange = true;
7548                }
7549
7550                if (wallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) {
7551                    // At this point, there was a window with a wallpaper that
7552                    // was force hiding other windows behind it, but now it
7553                    // is going away.  This may be simple -- just animate
7554                    // away the wallpaper and its window -- or it may be
7555                    // hard -- the wallpaper now needs to be shown behind
7556                    // something that was hidden.
7557                    WindowState oldWallpaper = mWallpaperTarget;
7558                    if (mLowerWallpaperTarget != null
7559                            && mLowerWallpaperTarget.mAppToken != null) {
7560                        if (DEBUG_WALLPAPER) Slog.v(TAG,
7561                                "wallpaperForceHiding changed with lower="
7562                                + mLowerWallpaperTarget);
7563                        if (DEBUG_WALLPAPER) Slog.v(TAG,
7564                                "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
7565                                " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
7566                        if (mLowerWallpaperTarget.mAppToken.hidden) {
7567                            // The lower target has become hidden before we
7568                            // actually started the animation...  let's completely
7569                            // re-evaluate everything.
7570                            mLowerWallpaperTarget = mUpperWallpaperTarget = null;
7571                            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
7572                        }
7573                    }
7574                    adjResult |= adjustWallpaperWindowsLocked();
7575                    wallpaperMayChange = false;
7576                    wallpaperForceHidingChanged = false;
7577                    if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
7578                            + " NEW: " + mWallpaperTarget
7579                            + " LOWER: " + mLowerWallpaperTarget);
7580                    if (mLowerWallpaperTarget == null) {
7581                        // Whoops, we don't need a special wallpaper animation.
7582                        // Clear them out.
7583                        forceHiding = false;
7584                        for (i=N-1; i>=0; i--) {
7585                            WindowState w = mWindows.get(i);
7586                            if (w.mSurface != null) {
7587                                final WindowManager.LayoutParams attrs = w.mAttrs;
7588                                if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
7589                                    if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
7590                                    forceHiding = true;
7591                                } else if (mPolicy.canBeForceHidden(w, attrs)) {
7592                                    if (!w.mAnimating) {
7593                                        // We set the animation above so it
7594                                        // is not yet running.
7595                                        w.clearAnimation();
7596                                    }
7597                                }
7598                            }
7599                        }
7600                    }
7601                }
7602
7603                if (mWindowDetachedWallpaper != windowDetachedWallpaper) {
7604                    if (DEBUG_WALLPAPER) Slog.v(TAG,
7605                            "Detached wallpaper changed from " + mWindowDetachedWallpaper
7606                            + windowDetachedWallpaper);
7607                    mWindowDetachedWallpaper = windowDetachedWallpaper;
7608                    wallpaperMayChange = true;
7609                }
7610
7611                if (windowAnimationBackgroundColor != 0) {
7612                    if (mWindowAnimationBackgroundSurface == null) {
7613                        mWindowAnimationBackgroundSurface = new DimSurface(mFxSession);
7614                    }
7615                    mWindowAnimationBackgroundSurface.show(dw, dh,
7616                            windowAnimationBackground.mAnimLayer - LAYER_OFFSET_DIM,
7617                            windowAnimationBackgroundColor);
7618                } else if (mWindowAnimationBackgroundSurface != null) {
7619                    mWindowAnimationBackgroundSurface.hide();
7620                }
7621
7622                if (wallpaperMayChange) {
7623                    if (DEBUG_WALLPAPER) Slog.v(TAG,
7624                            "Wallpaper may change!  Adjusting");
7625                    adjResult |= adjustWallpaperWindowsLocked();
7626                }
7627
7628                if ((adjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
7629                    if (DEBUG_WALLPAPER) Slog.v(TAG,
7630                            "Wallpaper layer changed: assigning layers + relayout");
7631                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
7632                    assignLayersLocked();
7633                } else if ((adjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
7634                    if (DEBUG_WALLPAPER) Slog.v(TAG,
7635                            "Wallpaper visibility changed: relayout");
7636                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
7637                }
7638
7639                if (mFocusMayChange) {
7640                    mFocusMayChange = false;
7641                    if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
7642                            false /*updateInputWindows*/)) {
7643                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
7644                        adjResult = 0;
7645                    }
7646                }
7647
7648                if (mLayoutNeeded) {
7649                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
7650                }
7651
7652                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
7653                        + Integer.toHexString(changes));
7654            } while (changes != 0);
7655
7656            // THIRD LOOP: Update the surfaces of all windows.
7657
7658            final boolean someoneLosingFocus = mLosingFocus.size() != 0;
7659
7660            boolean obscured = false;
7661            boolean blurring = false;
7662            boolean dimming = false;
7663            boolean covered = false;
7664            boolean syswin = false;
7665
7666            final int N = mWindows.size();
7667
7668            for (i=N-1; i>=0; i--) {
7669                WindowState w = mWindows.get(i);
7670
7671                boolean displayed = false;
7672                final WindowManager.LayoutParams attrs = w.mAttrs;
7673                final int attrFlags = attrs.flags;
7674
7675                if (w.mSurface != null) {
7676                    // XXX NOTE: The logic here could be improved.  We have
7677                    // the decision about whether to resize a window separated
7678                    // from whether to hide the surface.  This can cause us to
7679                    // resize a surface even if we are going to hide it.  You
7680                    // can see this by (1) holding device in landscape mode on
7681                    // home screen; (2) tapping browser icon (device will rotate
7682                    // to landscape; (3) tap home.  The wallpaper will be resized
7683                    // in step 2 but then immediately hidden, causing us to
7684                    // have to resize and then redraw it again in step 3.  It
7685                    // would be nice to figure out how to avoid this, but it is
7686                    // difficult because we do need to resize surfaces in some
7687                    // cases while they are hidden such as when first showing a
7688                    // window.
7689
7690                    w.computeShownFrameLocked();
7691                    if (localLOGV) Slog.v(
7692                            TAG, "Placing surface #" + i + " " + w.mSurface
7693                            + ": new=" + w.mShownFrame);
7694
7695                    int width, height;
7696                    if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
7697                        // for a scaled surface, we just want to use
7698                        // the requested size.
7699                        width  = w.mRequestedWidth;
7700                        height = w.mRequestedHeight;
7701                    } else {
7702                        width = w.mCompatFrame.width();
7703                        height = w.mCompatFrame.height();
7704                    }
7705
7706                    if (w.mSurface != null) {
7707                        if (w.mSurfaceX != w.mShownFrame.left
7708                                || w.mSurfaceY != w.mShownFrame.top) {
7709                            try {
7710                                if (SHOW_TRANSACTIONS) logSurface(w,
7711                                        "POS " + w.mShownFrame.left
7712                                        + ", " + w.mShownFrame.top, null);
7713                                w.mSurfaceX = w.mShownFrame.left;
7714                                w.mSurfaceY = w.mShownFrame.top;
7715                                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
7716                            } catch (RuntimeException e) {
7717                                Slog.w(TAG, "Error positioning surface of " + w
7718                                        + " pos=(" + w.mShownFrame.left
7719                                        + "," + w.mShownFrame.top + ")", e);
7720                                if (!recoveringMemory) {
7721                                    reclaimSomeSurfaceMemoryLocked(w, "position", true);
7722                                }
7723                            }
7724                        }
7725
7726                        if (width < 1) {
7727                            width = 1;
7728                        }
7729                        if (height < 1) {
7730                            height = 1;
7731                        }
7732
7733                        if (w.mSurfaceW != width || w.mSurfaceH != height) {
7734                            try {
7735                                if (SHOW_TRANSACTIONS) logSurface(w,
7736                                        "SIZE " + w.mShownFrame.width() + "x"
7737                                        + w.mShownFrame.height(), null);
7738                                w.mSurfaceResized = true;
7739                                w.mSurfaceW = width;
7740                                w.mSurfaceH = height;
7741                                w.mSurface.setSize(width, height);
7742                            } catch (RuntimeException e) {
7743                                // If something goes wrong with the surface (such
7744                                // as running out of memory), don't take down the
7745                                // entire system.
7746                                Slog.e(TAG, "Error resizing surface of " + w
7747                                        + " size=(" + width + "x" + height + ")", e);
7748                                if (!recoveringMemory) {
7749                                    reclaimSomeSurfaceMemoryLocked(w, "size", true);
7750                                }
7751                            }
7752                        }
7753                    }
7754
7755                    if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
7756                        w.mContentInsetsChanged =
7757                            !w.mLastContentInsets.equals(w.mContentInsets);
7758                        w.mVisibleInsetsChanged =
7759                            !w.mLastVisibleInsets.equals(w.mVisibleInsets);
7760                        boolean configChanged =
7761                            w.mConfiguration != mCurConfiguration
7762                            && (w.mConfiguration == null
7763                                    || mCurConfiguration.diff(w.mConfiguration) != 0);
7764                        if (DEBUG_CONFIGURATION && configChanged) {
7765                            Slog.v(TAG, "Win " + w + " config changed: "
7766                                    + mCurConfiguration);
7767                        }
7768                        if (localLOGV) Slog.v(TAG, "Resizing " + w
7769                                + ": configChanged=" + configChanged
7770                                + " last=" + w.mLastCompatFrame + " frame=" + w.mCompatFrame);
7771                        boolean frameChanged = !w.mLastCompatFrame.equals(w.mCompatFrame);
7772                        if (frameChanged
7773                                || w.mContentInsetsChanged
7774                                || w.mVisibleInsetsChanged
7775                                || w.mSurfaceResized
7776                                || configChanged) {
7777                            if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
7778                                Slog.v(TAG, "Resize reasons: "
7779                                        + "frameChanged=" + frameChanged
7780                                        + " contentInsetsChanged=" + w.mContentInsetsChanged
7781                                        + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
7782                                        + " surfaceResized=" + w.mSurfaceResized
7783                                        + " configChanged=" + configChanged);
7784                            }
7785
7786                            w.mLastFrame.set(w.mFrame);
7787                            w.mLastCompatFrame.set(w.mCompatFrame);
7788                            w.mLastContentInsets.set(w.mContentInsets);
7789                            w.mLastVisibleInsets.set(w.mVisibleInsets);
7790                            // If the screen is currently frozen, then keep
7791                            // it frozen until this window draws at its new
7792                            // orientation.
7793                            if (mDisplayFrozen) {
7794                                if (DEBUG_ORIENTATION) Slog.v(TAG,
7795                                        "Resizing while display frozen: " + w);
7796                                w.mOrientationChanging = true;
7797                                if (!mWindowsFreezingScreen) {
7798                                    mWindowsFreezingScreen = true;
7799                                    // XXX should probably keep timeout from
7800                                    // when we first froze the display.
7801                                    mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
7802                                    mH.sendMessageDelayed(mH.obtainMessage(
7803                                            H.WINDOW_FREEZE_TIMEOUT), 2000);
7804                                }
7805                            }
7806                            // If the orientation is changing, then we need to
7807                            // hold off on unfreezing the display until this
7808                            // window has been redrawn; to do that, we need
7809                            // to go through the process of getting informed
7810                            // by the application when it has finished drawing.
7811                            if (w.mOrientationChanging) {
7812                                if (DEBUG_ORIENTATION) Slog.v(TAG,
7813                                        "Orientation start waiting for draw in "
7814                                        + w + ", surface " + w.mSurface);
7815                                w.mDrawPending = true;
7816                                w.mCommitDrawPending = false;
7817                                w.mReadyToShow = false;
7818                                if (w.mAppToken != null) {
7819                                    w.mAppToken.allDrawn = false;
7820                                }
7821                            }
7822                            if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
7823                                    "Resizing window " + w + " to " + w.mCompatFrame);
7824                            mResizingWindows.add(w);
7825                        } else if (w.mOrientationChanging) {
7826                            if (!w.mDrawPending && !w.mCommitDrawPending) {
7827                                if (DEBUG_ORIENTATION) Slog.v(TAG,
7828                                        "Orientation not waiting for draw in "
7829                                        + w + ", surface " + w.mSurface);
7830                                w.mOrientationChanging = false;
7831                            }
7832                        }
7833                    }
7834
7835                    if (w.mAttachedHidden || !w.isReadyForDisplay()) {
7836                        if (!w.mLastHidden) {
7837                            //dump();
7838                            w.mLastHidden = true;
7839                            if (SHOW_TRANSACTIONS) logSurface(w,
7840                                    "HIDE (performLayout)", null);
7841                            if (w.mSurface != null) {
7842                                w.mSurfaceShown = false;
7843                                try {
7844                                    w.mSurface.hide();
7845                                } catch (RuntimeException e) {
7846                                    Slog.w(TAG, "Exception hiding surface in " + w);
7847                                }
7848                            }
7849                        }
7850                        // If we are waiting for this window to handle an
7851                        // orientation change, well, it is hidden, so
7852                        // doesn't really matter.  Note that this does
7853                        // introduce a potential glitch if the window
7854                        // becomes unhidden before it has drawn for the
7855                        // new orientation.
7856                        if (w.mOrientationChanging) {
7857                            w.mOrientationChanging = false;
7858                            if (DEBUG_ORIENTATION) Slog.v(TAG,
7859                                    "Orientation change skips hidden " + w);
7860                        }
7861                    } else if (w.mLastLayer != w.mAnimLayer
7862                            || w.mLastAlpha != w.mShownAlpha
7863                            || w.mLastDsDx != w.mDsDx
7864                            || w.mLastDtDx != w.mDtDx
7865                            || w.mLastDsDy != w.mDsDy
7866                            || w.mLastDtDy != w.mDtDy
7867                            || w.mLastHScale != w.mHScale
7868                            || w.mLastVScale != w.mVScale
7869                            || w.mLastHidden) {
7870                        displayed = true;
7871                        w.mLastAlpha = w.mShownAlpha;
7872                        w.mLastLayer = w.mAnimLayer;
7873                        w.mLastDsDx = w.mDsDx;
7874                        w.mLastDtDx = w.mDtDx;
7875                        w.mLastDsDy = w.mDsDy;
7876                        w.mLastDtDy = w.mDtDy;
7877                        w.mLastHScale = w.mHScale;
7878                        w.mLastVScale = w.mVScale;
7879                        if (SHOW_TRANSACTIONS) logSurface(w,
7880                                "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
7881                                + " matrix=[" + (w.mDsDx*w.mHScale)
7882                                + "," + (w.mDtDx*w.mVScale)
7883                                + "][" + (w.mDsDy*w.mHScale)
7884                                + "," + (w.mDtDy*w.mVScale) + "]", null);
7885                        if (w.mSurface != null) {
7886                            try {
7887                                w.mSurfaceAlpha = w.mShownAlpha;
7888                                w.mSurface.setAlpha(w.mShownAlpha);
7889                                w.mSurfaceLayer = w.mAnimLayer;
7890                                w.mSurface.setLayer(w.mAnimLayer);
7891                                w.mSurface.setMatrix(
7892                                        w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
7893                                        w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
7894                            } catch (RuntimeException e) {
7895                                Slog.w(TAG, "Error updating surface in " + w, e);
7896                                if (!recoveringMemory) {
7897                                    reclaimSomeSurfaceMemoryLocked(w, "update", true);
7898                                }
7899                            }
7900                        }
7901
7902                        if (w.mLastHidden && !w.mDrawPending
7903                                && !w.mCommitDrawPending
7904                                && !w.mReadyToShow) {
7905                            if (SHOW_TRANSACTIONS) logSurface(w,
7906                                    "SHOW (performLayout)", null);
7907                            if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
7908                                    + " during relayout");
7909                            if (showSurfaceRobustlyLocked(w)) {
7910                                w.mHasDrawn = true;
7911                                w.mLastHidden = false;
7912                            } else {
7913                                w.mOrientationChanging = false;
7914                            }
7915                        }
7916                        if (w.mSurface != null) {
7917                            w.mToken.hasVisible = true;
7918                        }
7919                    } else {
7920                        displayed = true;
7921                    }
7922
7923                    if (displayed) {
7924                        if (!covered) {
7925                            if (attrs.width == LayoutParams.MATCH_PARENT
7926                                    && attrs.height == LayoutParams.MATCH_PARENT) {
7927                                covered = true;
7928                            }
7929                        }
7930                        if (w.mOrientationChanging) {
7931                            if (w.mDrawPending || w.mCommitDrawPending) {
7932                                orientationChangeComplete = false;
7933                                if (DEBUG_ORIENTATION) Slog.v(TAG,
7934                                        "Orientation continue waiting for draw in " + w);
7935                            } else {
7936                                w.mOrientationChanging = false;
7937                                if (DEBUG_ORIENTATION) Slog.v(TAG,
7938                                        "Orientation change complete in " + w);
7939                            }
7940                        }
7941                        w.mToken.hasVisible = true;
7942                    }
7943                } else if (w.mOrientationChanging) {
7944                    if (DEBUG_ORIENTATION) Slog.v(TAG,
7945                            "Orientation change skips hidden " + w);
7946                    w.mOrientationChanging = false;
7947                }
7948
7949                if (w.mContentChanged) {
7950                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
7951                    w.mContentChanged = false;
7952                }
7953
7954                final boolean canBeSeen = w.isDisplayedLw();
7955
7956                if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
7957                    focusDisplayed = true;
7958                }
7959
7960                final boolean obscuredChanged = w.mObscured != obscured;
7961
7962                // Update effect.
7963                if (!(w.mObscured=obscured)) {
7964                    if (w.mSurface != null) {
7965                        if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
7966                            holdScreen = w.mSession;
7967                        }
7968                        if (!syswin && w.mAttrs.screenBrightness >= 0
7969                                && screenBrightness < 0) {
7970                            screenBrightness = w.mAttrs.screenBrightness;
7971                        }
7972                        if (!syswin && w.mAttrs.buttonBrightness >= 0
7973                                && buttonBrightness < 0) {
7974                            buttonBrightness = w.mAttrs.buttonBrightness;
7975                        }
7976                        if (canBeSeen
7977                                && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
7978                                 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
7979                                 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
7980                            syswin = true;
7981                        }
7982                    }
7983
7984                    boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
7985                    if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
7986                        // This window completely covers everything behind it,
7987                        // so we want to leave all of them as unblurred (for
7988                        // performance reasons).
7989                        obscured = true;
7990                    } else if (canBeSeen && !obscured &&
7991                            (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
7992                        if (localLOGV) Slog.v(TAG, "Win " + w
7993                                + ": blurring=" + blurring
7994                                + " obscured=" + obscured
7995                                + " displayed=" + displayed);
7996                        if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
7997                            if (!dimming) {
7998                                //Slog.i(TAG, "DIM BEHIND: " + w);
7999                                dimming = true;
8000                                if (mDimAnimator == null) {
8001                                    mDimAnimator = new DimAnimator(mFxSession);
8002                                }
8003                                mDimAnimator.show(dw, dh);
8004                                mDimAnimator.updateParameters(mContext.getResources(),
8005                                        w, currentTime);
8006                            }
8007                        }
8008                        if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
8009                            if (!blurring) {
8010                                //Slog.i(TAG, "BLUR BEHIND: " + w);
8011                                blurring = true;
8012                                if (mBlurSurface == null) {
8013                                    try {
8014                                        mBlurSurface = new Surface(mFxSession, 0,
8015                                                "BlurSurface",
8016                                                -1, 16, 16,
8017                                                PixelFormat.OPAQUE,
8018                                                Surface.FX_SURFACE_BLUR);
8019                                    } catch (Exception e) {
8020                                        Slog.e(TAG, "Exception creating Blur surface", e);
8021                                    }
8022                                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
8023                                            + mBlurSurface + ": CREATE");
8024                                }
8025                                if (mBlurSurface != null) {
8026                                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
8027                                            + mBlurSurface + ": pos=(0,0) (" +
8028                                            dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8029                                    mBlurSurface.setPosition(0, 0);
8030                                    mBlurSurface.setSize(dw, dh);
8031                                    mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR);
8032                                    if (!mBlurShown) {
8033                                        try {
8034                                            if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
8035                                                    + mBlurSurface + ": SHOW");
8036                                            mBlurSurface.show();
8037                                        } catch (RuntimeException e) {
8038                                            Slog.w(TAG, "Failure showing blur surface", e);
8039                                        }
8040                                        mBlurShown = true;
8041                                    }
8042                                }
8043                            }
8044                        }
8045                    }
8046                }
8047
8048                if (obscuredChanged && mWallpaperTarget == w) {
8049                    // This is the wallpaper target and its obscured state
8050                    // changed... make sure the current wallaper's visibility
8051                    // has been updated accordingly.
8052                    updateWallpaperVisibilityLocked();
8053                }
8054            }
8055
8056            if (mDimAnimator != null && mDimAnimator.mDimShown) {
8057                animating |= mDimAnimator.updateSurface(dimming, currentTime,
8058                        mDisplayFrozen || !mPolicy.isScreenOn());
8059            }
8060
8061            if (!blurring && mBlurShown) {
8062                if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR " + mBlurSurface
8063                        + ": HIDE");
8064                try {
8065                    mBlurSurface.hide();
8066                } catch (IllegalArgumentException e) {
8067                    Slog.w(TAG, "Illegal argument exception hiding blur surface");
8068                }
8069                mBlurShown = false;
8070            }
8071
8072            if (mBlackFrame != null) {
8073                if (mScreenRotationAnimation != null) {
8074                    mBlackFrame.setMatrix(
8075                            mScreenRotationAnimation.getEnterTransformation().getMatrix());
8076                } else {
8077                    mBlackFrame.clearMatrix();
8078                }
8079            }
8080        } catch (RuntimeException e) {
8081            Slog.e(TAG, "Unhandled exception in Window Manager", e);
8082        }
8083
8084        Surface.closeTransaction();
8085
8086        if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
8087
8088        if (mWatermark != null) {
8089            mWatermark.drawIfNeeded();
8090        }
8091
8092        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
8093                "With display frozen, orientationChangeComplete="
8094                + orientationChangeComplete);
8095        if (orientationChangeComplete) {
8096            if (mWindowsFreezingScreen) {
8097                mWindowsFreezingScreen = false;
8098                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8099            }
8100            stopFreezingDisplayLocked();
8101        }
8102
8103        i = mResizingWindows.size();
8104        if (i > 0) {
8105            do {
8106                i--;
8107                WindowState win = mResizingWindows.get(i);
8108                try {
8109                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8110                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
8111                    int diff = 0;
8112                    boolean configChanged =
8113                        win.mConfiguration != mCurConfiguration
8114                        && (win.mConfiguration == null
8115                                || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0);
8116                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
8117                            && configChanged) {
8118                        Slog.i(TAG, "Sending new config to window " + win + ": "
8119                                + win.mCompatFrame.width() + "x" + win.mCompatFrame.height()
8120                                + " / " + mCurConfiguration + " / 0x"
8121                                + Integer.toHexString(diff));
8122                    }
8123                    win.mConfiguration = mCurConfiguration;
8124                    win.mClient.resized(win.mCompatFrame.width(),
8125                            win.mCompatFrame.height(), win.mLastContentInsets,
8126                            win.mLastVisibleInsets, win.mDrawPending,
8127                            configChanged ? win.mConfiguration : null);
8128                    win.mContentInsetsChanged = false;
8129                    win.mVisibleInsetsChanged = false;
8130                    win.mSurfaceResized = false;
8131                } catch (RemoteException e) {
8132                    win.mOrientationChanging = false;
8133                }
8134            } while (i > 0);
8135            mResizingWindows.clear();
8136        }
8137
8138        // Destroy the surface of any windows that are no longer visible.
8139        boolean wallpaperDestroyed = false;
8140        i = mDestroySurface.size();
8141        if (i > 0) {
8142            do {
8143                i--;
8144                WindowState win = mDestroySurface.get(i);
8145                win.mDestroying = false;
8146                if (mInputMethodWindow == win) {
8147                    mInputMethodWindow = null;
8148                }
8149                if (win == mWallpaperTarget) {
8150                    wallpaperDestroyed = true;
8151                }
8152                win.destroySurfaceLocked();
8153            } while (i > 0);
8154            mDestroySurface.clear();
8155        }
8156
8157        // Time to remove any exiting tokens?
8158        for (i=mExitingTokens.size()-1; i>=0; i--) {
8159            WindowToken token = mExitingTokens.get(i);
8160            if (!token.hasVisible) {
8161                mExitingTokens.remove(i);
8162                if (token.windowType == TYPE_WALLPAPER) {
8163                    mWallpaperTokens.remove(token);
8164                }
8165            }
8166        }
8167
8168        // Time to remove any exiting applications?
8169        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8170            AppWindowToken token = mExitingAppTokens.get(i);
8171            if (!token.hasVisible && !mClosingApps.contains(token)) {
8172                // Make sure there is no animation running on this token,
8173                // so any windows associated with it will be removed as
8174                // soon as their animations are complete
8175                token.animation = null;
8176                token.animating = false;
8177                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
8178                        "performLayout: App token exiting now removed" + token);
8179                mAppTokens.remove(token);
8180                mExitingAppTokens.remove(i);
8181            }
8182        }
8183
8184        boolean needRelayout = false;
8185
8186        if (!animating && mAppTransitionRunning) {
8187            // We have finished the animation of an app transition.  To do
8188            // this, we have delayed a lot of operations like showing and
8189            // hiding apps, moving apps in Z-order, etc.  The app token list
8190            // reflects the correct Z-order, but the window list may now
8191            // be out of sync with it.  So here we will just rebuild the
8192            // entire app window list.  Fun!
8193            mAppTransitionRunning = false;
8194            needRelayout = true;
8195            rebuildAppWindowListLocked();
8196            assignLayersLocked();
8197            // Clear information about apps that were moving.
8198            mToBottomApps.clear();
8199        }
8200
8201        if (focusDisplayed) {
8202            mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8203        }
8204        if (wallpaperDestroyed) {
8205            needRelayout = adjustWallpaperWindowsLocked() != 0;
8206        }
8207        if (needRelayout) {
8208            requestAnimationLocked(0);
8209        } else if (animating) {
8210            requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
8211        }
8212
8213        // Finally update all input windows now that the window changes have stabilized.
8214        mInputMonitor.updateInputWindowsLw(true /*force*/);
8215
8216        setHoldScreenLocked(holdScreen != null);
8217        if (!mDisplayFrozen) {
8218            if (screenBrightness < 0 || screenBrightness > 1.0f) {
8219                mPowerManager.setScreenBrightnessOverride(-1);
8220            } else {
8221                mPowerManager.setScreenBrightnessOverride((int)
8222                        (screenBrightness * Power.BRIGHTNESS_ON));
8223            }
8224            if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
8225                mPowerManager.setButtonBrightnessOverride(-1);
8226            } else {
8227                mPowerManager.setButtonBrightnessOverride((int)
8228                        (buttonBrightness * Power.BRIGHTNESS_ON));
8229            }
8230        }
8231        if (holdScreen != mHoldingScreenOn) {
8232            mHoldingScreenOn = holdScreen;
8233            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
8234            mH.sendMessage(m);
8235        }
8236
8237        if (mTurnOnScreen) {
8238            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
8239            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
8240                    LocalPowerManager.BUTTON_EVENT, true);
8241            mTurnOnScreen = false;
8242        }
8243
8244        if (screenRotationFinished && mScreenRotationAnimation != null) {
8245            mScreenRotationAnimation.kill();
8246            mScreenRotationAnimation = null;
8247        }
8248
8249        if (updateRotation) {
8250            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8251            boolean changed = setRotationUncheckedLocked(
8252                    WindowManagerPolicy.USE_LAST_ROTATION, 0, false);
8253            if (changed) {
8254                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8255            }
8256        }
8257
8258        // Check to see if we are now in a state where the screen should
8259        // be enabled, because the window obscured flags have changed.
8260        enableScreenIfNeededLocked();
8261    }
8262
8263    /**
8264     * Must be called with the main window manager lock held.
8265     */
8266    void setHoldScreenLocked(boolean holding) {
8267        boolean state = mHoldingScreenWakeLock.isHeld();
8268        if (holding != state) {
8269            if (holding) {
8270                mHoldingScreenWakeLock.acquire();
8271            } else {
8272                mPolicy.screenOnStoppedLw();
8273                mHoldingScreenWakeLock.release();
8274            }
8275        }
8276    }
8277
8278    void requestAnimationLocked(long delay) {
8279        if (!mAnimationPending) {
8280            mAnimationPending = true;
8281            mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
8282        }
8283    }
8284
8285    /**
8286     * Have the surface flinger show a surface, robustly dealing with
8287     * error conditions.  In particular, if there is not enough memory
8288     * to show the surface, then we will try to get rid of other surfaces
8289     * in order to succeed.
8290     *
8291     * @return Returns true if the surface was successfully shown.
8292     */
8293    boolean showSurfaceRobustlyLocked(WindowState win) {
8294        try {
8295            if (win.mSurface != null) {
8296                win.mSurfaceShown = true;
8297                win.mSurface.show();
8298                if (win.mTurnOnScreen) {
8299                    if (DEBUG_VISIBILITY) Slog.v(TAG,
8300                            "Show surface turning screen on: " + win);
8301                    win.mTurnOnScreen = false;
8302                    mTurnOnScreen = true;
8303                }
8304            }
8305            return true;
8306        } catch (RuntimeException e) {
8307            Slog.w(TAG, "Failure showing surface " + win.mSurface + " in " + win, e);
8308        }
8309
8310        reclaimSomeSurfaceMemoryLocked(win, "show", true);
8311
8312        return false;
8313    }
8314
8315    boolean reclaimSomeSurfaceMemoryLocked(WindowState win, String operation, boolean secure) {
8316        final Surface surface = win.mSurface;
8317        boolean leakedSurface = false;
8318        boolean killedApps = false;
8319
8320        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, win.toString(),
8321                win.mSession.mPid, operation);
8322
8323        if (mForceRemoves == null) {
8324            mForceRemoves = new ArrayList<WindowState>();
8325        }
8326
8327        long callingIdentity = Binder.clearCallingIdentity();
8328        try {
8329            // There was some problem...   first, do a sanity check of the
8330            // window list to make sure we haven't left any dangling surfaces
8331            // around.
8332            int N = mWindows.size();
8333            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
8334            for (int i=0; i<N; i++) {
8335                WindowState ws = mWindows.get(i);
8336                if (ws.mSurface != null) {
8337                    if (!mSessions.contains(ws.mSession)) {
8338                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8339                                + ws + " surface=" + ws.mSurface
8340                                + " token=" + win.mToken
8341                                + " pid=" + ws.mSession.mPid
8342                                + " uid=" + ws.mSession.mUid);
8343                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8344                        ws.mSurface.destroy();
8345                        ws.mSurfaceShown = false;
8346                        ws.mSurface = null;
8347                        mForceRemoves.add(ws);
8348                        i--;
8349                        N--;
8350                        leakedSurface = true;
8351                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
8352                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
8353                                + ws + " surface=" + ws.mSurface
8354                                + " token=" + win.mAppToken);
8355                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8356                        ws.mSurface.destroy();
8357                        ws.mSurfaceShown = false;
8358                        ws.mSurface = null;
8359                        leakedSurface = true;
8360                    }
8361                }
8362            }
8363
8364            if (!leakedSurface) {
8365                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
8366                SparseIntArray pidCandidates = new SparseIntArray();
8367                for (int i=0; i<N; i++) {
8368                    WindowState ws = mWindows.get(i);
8369                    if (ws.mSurface != null) {
8370                        pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
8371                    }
8372                }
8373                if (pidCandidates.size() > 0) {
8374                    int[] pids = new int[pidCandidates.size()];
8375                    for (int i=0; i<pids.length; i++) {
8376                        pids[i] = pidCandidates.keyAt(i);
8377                    }
8378                    try {
8379                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
8380                            killedApps = true;
8381                        }
8382                    } catch (RemoteException e) {
8383                    }
8384                }
8385            }
8386
8387            if (leakedSurface || killedApps) {
8388                // We managed to reclaim some memory, so get rid of the trouble
8389                // surface and ask the app to request another one.
8390                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8391                if (surface != null) {
8392                    if (SHOW_TRANSACTIONS) logSurface(win, "RECOVER DESTROY", null);
8393                    surface.destroy();
8394                    win.mSurfaceShown = false;
8395                    win.mSurface = null;
8396                }
8397
8398                try {
8399                    win.mClient.dispatchGetNewSurface();
8400                } catch (RemoteException e) {
8401                }
8402            }
8403        } finally {
8404            Binder.restoreCallingIdentity(callingIdentity);
8405        }
8406
8407        return leakedSurface || killedApps;
8408    }
8409
8410    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
8411        WindowState newFocus = computeFocusedWindowLocked();
8412        if (mCurrentFocus != newFocus) {
8413            // This check makes sure that we don't already have the focus
8414            // change message pending.
8415            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
8416            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
8417            if (localLOGV) Slog.v(
8418                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
8419            final WindowState oldFocus = mCurrentFocus;
8420            mCurrentFocus = newFocus;
8421            mLosingFocus.remove(newFocus);
8422
8423            final WindowState imWindow = mInputMethodWindow;
8424            if (newFocus != imWindow && oldFocus != imWindow) {
8425                if (moveInputMethodWindowsIfNeededLocked(
8426                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
8427                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
8428                    mLayoutNeeded = true;
8429                }
8430                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8431                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
8432                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
8433                    // Client will do the layout, but we need to assign layers
8434                    // for handleNewWindowLocked() below.
8435                    assignLayersLocked();
8436                }
8437            }
8438
8439            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
8440                // If we defer assigning layers, then the caller is responsible for
8441                // doing this part.
8442                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
8443            }
8444            return true;
8445        }
8446        return false;
8447    }
8448
8449    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
8450        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
8451    }
8452
8453    private WindowState computeFocusedWindowLocked() {
8454        WindowState result = null;
8455        WindowState win;
8456
8457        int i = mWindows.size() - 1;
8458        int nextAppIndex = mAppTokens.size()-1;
8459        WindowToken nextApp = nextAppIndex >= 0
8460            ? mAppTokens.get(nextAppIndex) : null;
8461
8462        while (i >= 0) {
8463            win = mWindows.get(i);
8464
8465            if (localLOGV || DEBUG_FOCUS) Slog.v(
8466                TAG, "Looking for focus: " + i
8467                + " = " + win
8468                + ", flags=" + win.mAttrs.flags
8469                + ", canReceive=" + win.canReceiveKeys());
8470
8471            AppWindowToken thisApp = win.mAppToken;
8472
8473            // If this window's application has been removed, just skip it.
8474            if (thisApp != null && thisApp.removed) {
8475                i--;
8476                continue;
8477            }
8478
8479            // If there is a focused app, don't allow focus to go to any
8480            // windows below it.  If this is an application window, step
8481            // through the app tokens until we find its app.
8482            if (thisApp != null && nextApp != null && thisApp != nextApp
8483                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
8484                int origAppIndex = nextAppIndex;
8485                while (nextAppIndex > 0) {
8486                    if (nextApp == mFocusedApp) {
8487                        // Whoops, we are below the focused app...  no focus
8488                        // for you!
8489                        if (localLOGV || DEBUG_FOCUS) Slog.v(
8490                            TAG, "Reached focused app: " + mFocusedApp);
8491                        return null;
8492                    }
8493                    nextAppIndex--;
8494                    nextApp = mAppTokens.get(nextAppIndex);
8495                    if (nextApp == thisApp) {
8496                        break;
8497                    }
8498                }
8499                if (thisApp != nextApp) {
8500                    // Uh oh, the app token doesn't exist!  This shouldn't
8501                    // happen, but if it does we can get totally hosed...
8502                    // so restart at the original app.
8503                    nextAppIndex = origAppIndex;
8504                    nextApp = mAppTokens.get(nextAppIndex);
8505                }
8506            }
8507
8508            // Dispatch to this window if it is wants key events.
8509            if (win.canReceiveKeys()) {
8510                if (DEBUG_FOCUS) Slog.v(
8511                        TAG, "Found focus @ " + i + " = " + win);
8512                result = win;
8513                break;
8514            }
8515
8516            i--;
8517        }
8518
8519        return result;
8520    }
8521
8522    private void startFreezingDisplayLocked(boolean inTransaction) {
8523        if (mDisplayFrozen) {
8524            return;
8525        }
8526
8527        mScreenFrozenLock.acquire();
8528
8529        long now = SystemClock.uptimeMillis();
8530        //Slog.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
8531        if (mFreezeGcPending != 0) {
8532            if (now > (mFreezeGcPending+1000)) {
8533                //Slog.i(TAG, "Gc!  " + now + " > " + (mFreezeGcPending+1000));
8534                mH.removeMessages(H.FORCE_GC);
8535                Runtime.getRuntime().gc();
8536                mFreezeGcPending = now;
8537            }
8538        } else {
8539            mFreezeGcPending = now;
8540        }
8541
8542        mDisplayFrozen = true;
8543
8544        mInputMonitor.freezeInputDispatchingLw();
8545
8546        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
8547            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
8548            mNextAppTransitionPackage = null;
8549            mAppTransitionReady = true;
8550        }
8551
8552        if (PROFILE_ORIENTATION) {
8553            File file = new File("/data/system/frozen");
8554            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
8555        }
8556
8557        if (CUSTOM_SCREEN_ROTATION) {
8558            if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
8559                mScreenRotationAnimation.kill();
8560                mScreenRotationAnimation = null;
8561            }
8562            if (mScreenRotationAnimation == null) {
8563                mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
8564                        mDisplay, mFxSession, inTransaction);
8565            }
8566            if (!mScreenRotationAnimation.hasScreenshot()) {
8567                Surface.freezeDisplay(0);
8568            }
8569        } else {
8570            Surface.freezeDisplay(0);
8571        }
8572    }
8573
8574    private void stopFreezingDisplayLocked() {
8575        if (!mDisplayFrozen) {
8576            return;
8577        }
8578
8579        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
8580            return;
8581        }
8582
8583        mDisplayFrozen = false;
8584        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
8585        if (PROFILE_ORIENTATION) {
8586            Debug.stopMethodTracing();
8587        }
8588
8589        boolean updateRotation = false;
8590
8591        if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
8592                && mScreenRotationAnimation.hasScreenshot()) {
8593            if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
8594                    mTransitionAnimationScale)) {
8595                requestAnimationLocked(0);
8596            } else {
8597                mScreenRotationAnimation = null;
8598                updateRotation = true;
8599            }
8600        } else {
8601            if (mScreenRotationAnimation != null) {
8602                mScreenRotationAnimation.kill();
8603                mScreenRotationAnimation = null;
8604            }
8605            updateRotation = true;
8606            Surface.unfreezeDisplay(0);
8607        }
8608
8609        mInputMonitor.thawInputDispatchingLw();
8610
8611        boolean configChanged;
8612
8613        // While the display is frozen we don't re-compute the orientation
8614        // to avoid inconsistent states.  However, something interesting
8615        // could have actually changed during that time so re-evaluate it
8616        // now to catch that.
8617        configChanged = updateOrientationFromAppTokensLocked(false);
8618
8619        // A little kludge: a lot could have happened while the
8620        // display was frozen, so now that we are coming back we
8621        // do a gc so that any remote references the system
8622        // processes holds on others can be released if they are
8623        // no longer needed.
8624        mH.removeMessages(H.FORCE_GC);
8625        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
8626                2000);
8627
8628        mScreenFrozenLock.release();
8629
8630        if (updateRotation) {
8631            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8632            configChanged |= setRotationUncheckedLocked(
8633                    WindowManagerPolicy.USE_LAST_ROTATION, 0, false);
8634        }
8635
8636        if (configChanged) {
8637            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8638        }
8639    }
8640
8641    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
8642            DisplayMetrics dm) {
8643        if (index < tokens.length) {
8644            String str = tokens[index];
8645            if (str != null && str.length() > 0) {
8646                try {
8647                    int val = Integer.parseInt(str);
8648                    return val;
8649                } catch (Exception e) {
8650                }
8651            }
8652        }
8653        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
8654            return defDps;
8655        }
8656        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
8657        return val;
8658    }
8659
8660    void createWatermark() {
8661        if (mWatermark != null) {
8662            return;
8663        }
8664
8665        File file = new File("/system/etc/setup.conf");
8666        FileInputStream in = null;
8667        try {
8668            in = new FileInputStream(file);
8669            DataInputStream ind = new DataInputStream(in);
8670            String line = ind.readLine();
8671            if (line != null) {
8672                String[] toks = line.split("%");
8673                if (toks != null && toks.length > 0) {
8674                    mWatermark = new Watermark(mDisplay, mFxSession, toks);
8675                }
8676            }
8677        } catch (FileNotFoundException e) {
8678        } catch (IOException e) {
8679        } finally {
8680            if (in != null) {
8681                try {
8682                    in.close();
8683                } catch (IOException e) {
8684                }
8685            }
8686        }
8687    }
8688
8689    @Override
8690    public void statusBarVisibilityChanged(int visibility) {
8691        mInputManager.setSystemUiVisibility(visibility);
8692        synchronized (mWindowMap) {
8693            final int N = mWindows.size();
8694            for (int i = 0; i < N; i++) {
8695                WindowState ws = mWindows.get(i);
8696                try {
8697                    if (ws.getAttrs().hasSystemUiListeners) {
8698                        ws.mClient.dispatchSystemUiVisibilityChanged(visibility);
8699                    }
8700                } catch (RemoteException e) {
8701                    // so sorry
8702                }
8703            }
8704        }
8705    }
8706
8707    @Override
8708    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8709        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
8710                != PackageManager.PERMISSION_GRANTED) {
8711            pw.println("Permission Denial: can't dump WindowManager from from pid="
8712                    + Binder.getCallingPid()
8713                    + ", uid=" + Binder.getCallingUid());
8714            return;
8715        }
8716
8717        mInputManager.dump(pw);
8718        pw.println(" ");
8719
8720        synchronized(mWindowMap) {
8721            pw.println("Current Window Manager state:");
8722            for (int i=mWindows.size()-1; i>=0; i--) {
8723                WindowState w = mWindows.get(i);
8724                pw.print("  Window #"); pw.print(i); pw.print(' ');
8725                        pw.print(w); pw.println(":");
8726                w.dump(pw, "    ");
8727            }
8728            if (mInputMethodDialogs.size() > 0) {
8729                pw.println(" ");
8730                pw.println("  Input method dialogs:");
8731                for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
8732                    WindowState w = mInputMethodDialogs.get(i);
8733                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
8734                }
8735            }
8736            if (mPendingRemove.size() > 0) {
8737                pw.println(" ");
8738                pw.println("  Remove pending for:");
8739                for (int i=mPendingRemove.size()-1; i>=0; i--) {
8740                    WindowState w = mPendingRemove.get(i);
8741                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
8742                            pw.print(w); pw.println(":");
8743                    w.dump(pw, "    ");
8744                }
8745            }
8746            if (mForceRemoves != null && mForceRemoves.size() > 0) {
8747                pw.println(" ");
8748                pw.println("  Windows force removing:");
8749                for (int i=mForceRemoves.size()-1; i>=0; i--) {
8750                    WindowState w = mForceRemoves.get(i);
8751                    pw.print("  Removing #"); pw.print(i); pw.print(' ');
8752                            pw.print(w); pw.println(":");
8753                    w.dump(pw, "    ");
8754                }
8755            }
8756            if (mDestroySurface.size() > 0) {
8757                pw.println(" ");
8758                pw.println("  Windows waiting to destroy their surface:");
8759                for (int i=mDestroySurface.size()-1; i>=0; i--) {
8760                    WindowState w = mDestroySurface.get(i);
8761                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
8762                            pw.print(w); pw.println(":");
8763                    w.dump(pw, "    ");
8764                }
8765            }
8766            if (mLosingFocus.size() > 0) {
8767                pw.println(" ");
8768                pw.println("  Windows losing focus:");
8769                for (int i=mLosingFocus.size()-1; i>=0; i--) {
8770                    WindowState w = mLosingFocus.get(i);
8771                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
8772                            pw.print(w); pw.println(":");
8773                    w.dump(pw, "    ");
8774                }
8775            }
8776            if (mResizingWindows.size() > 0) {
8777                pw.println(" ");
8778                pw.println("  Windows waiting to resize:");
8779                for (int i=mResizingWindows.size()-1; i>=0; i--) {
8780                    WindowState w = mResizingWindows.get(i);
8781                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
8782                            pw.print(w); pw.println(":");
8783                    w.dump(pw, "    ");
8784                }
8785            }
8786            if (mSessions.size() > 0) {
8787                pw.println(" ");
8788                pw.println("  All active sessions:");
8789                Iterator<Session> it = mSessions.iterator();
8790                while (it.hasNext()) {
8791                    Session s = it.next();
8792                    pw.print("  Session "); pw.print(s); pw.println(':');
8793                    s.dump(pw, "    ");
8794                }
8795            }
8796            if (mTokenMap.size() > 0) {
8797                pw.println(" ");
8798                pw.println("  All tokens:");
8799                Iterator<WindowToken> it = mTokenMap.values().iterator();
8800                while (it.hasNext()) {
8801                    WindowToken token = it.next();
8802                    pw.print("  Token "); pw.print(token.token); pw.println(':');
8803                    token.dump(pw, "    ");
8804                }
8805            }
8806            if (mWallpaperTokens.size() > 0) {
8807                pw.println(" ");
8808                pw.println("  Wallpaper tokens:");
8809                for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
8810                    WindowToken token = mWallpaperTokens.get(i);
8811                    pw.print("  Wallpaper #"); pw.print(i);
8812                            pw.print(' '); pw.print(token); pw.println(':');
8813                    token.dump(pw, "    ");
8814                }
8815            }
8816            if (mAppTokens.size() > 0) {
8817                pw.println(" ");
8818                pw.println("  Application tokens in Z order:");
8819                for (int i=mAppTokens.size()-1; i>=0; i--) {
8820                    pw.print("  App #"); pw.print(i); pw.print(": ");
8821                            pw.println(mAppTokens.get(i));
8822                }
8823            }
8824            if (mFinishedStarting.size() > 0) {
8825                pw.println(" ");
8826                pw.println("  Finishing start of application tokens:");
8827                for (int i=mFinishedStarting.size()-1; i>=0; i--) {
8828                    WindowToken token = mFinishedStarting.get(i);
8829                    pw.print("  Finished Starting #"); pw.print(i);
8830                            pw.print(' '); pw.print(token); pw.println(':');
8831                    token.dump(pw, "    ");
8832                }
8833            }
8834            if (mExitingTokens.size() > 0) {
8835                pw.println(" ");
8836                pw.println("  Exiting tokens:");
8837                for (int i=mExitingTokens.size()-1; i>=0; i--) {
8838                    WindowToken token = mExitingTokens.get(i);
8839                    pw.print("  Exiting #"); pw.print(i);
8840                            pw.print(' '); pw.print(token); pw.println(':');
8841                    token.dump(pw, "    ");
8842                }
8843            }
8844            if (mExitingAppTokens.size() > 0) {
8845                pw.println(" ");
8846                pw.println("  Exiting application tokens:");
8847                for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
8848                    WindowToken token = mExitingAppTokens.get(i);
8849                    pw.print("  Exiting App #"); pw.print(i);
8850                            pw.print(' '); pw.print(token); pw.println(':');
8851                    token.dump(pw, "    ");
8852                }
8853            }
8854            pw.println(" ");
8855            pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
8856            pw.print("  mLastFocus="); pw.println(mLastFocus);
8857            pw.print("  mFocusedApp="); pw.println(mFocusedApp);
8858            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
8859            pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
8860            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
8861            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
8862                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
8863                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
8864            }
8865            if (mWindowDetachedWallpaper != null) {
8866                pw.print("  mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper);
8867            }
8868            if (mWindowAnimationBackgroundSurface != null) {
8869                pw.println("  mWindowAnimationBackgroundSurface:");
8870                mWindowAnimationBackgroundSurface.printTo("    ", pw);
8871            }
8872            pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
8873            pw.print("  mInTouchMode="); pw.print(mInTouchMode);
8874                    pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
8875            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
8876                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
8877            pw.print("  mLayoutNeeded="); pw.print(mLayoutNeeded);
8878                    pw.print(" mBlurShown="); pw.println(mBlurShown);
8879            if (mDimAnimator != null) {
8880                pw.println("  mDimAnimator:");
8881                mDimAnimator.printTo("    ", pw);
8882            } else {
8883                pw.println( "  no DimAnimator ");
8884            }
8885            pw.print("  mInputMethodAnimLayerAdjustment=");
8886                    pw.print(mInputMethodAnimLayerAdjustment);
8887                    pw.print("  mWallpaperAnimLayerAdjustment=");
8888                    pw.println(mWallpaperAnimLayerAdjustment);
8889            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
8890                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
8891            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
8892                    pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
8893                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
8894                    pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
8895            pw.print("  mRotation="); pw.print(mRotation);
8896                    pw.print(" mForcedAppOrientation="); pw.print(mForcedAppOrientation);
8897                    pw.print(" mRequestedRotation="); pw.print(mRequestedRotation);
8898                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
8899            pw.print("  mDeferredRotation="); pw.print(mDeferredRotation);
8900                    pw.print(", mDeferredRotationAnimFlags="); pw.println(mDeferredRotationAnimFlags);
8901            pw.print("  mAnimationPending="); pw.print(mAnimationPending);
8902                    pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
8903                    pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
8904            pw.print("  mNextAppTransition=0x");
8905                    pw.print(Integer.toHexString(mNextAppTransition));
8906                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
8907            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
8908                    pw.print(" mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
8909            if (mNextAppTransitionPackage != null) {
8910                pw.print("  mNextAppTransitionPackage=");
8911                    pw.print(mNextAppTransitionPackage);
8912                    pw.print(" mNextAppTransitionEnter=0x");
8913                    pw.print(Integer.toHexString(mNextAppTransitionEnter));
8914                    pw.print(" mNextAppTransitionExit=0x");
8915                    pw.print(Integer.toHexString(mNextAppTransitionExit));
8916            }
8917            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
8918                    pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
8919            if (mOpeningApps.size() > 0) {
8920                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
8921            }
8922            if (mClosingApps.size() > 0) {
8923                pw.print("  mClosingApps="); pw.println(mClosingApps);
8924            }
8925            if (mToTopApps.size() > 0) {
8926                pw.print("  mToTopApps="); pw.println(mToTopApps);
8927            }
8928            if (mToBottomApps.size() > 0) {
8929                pw.print("  mToBottomApps="); pw.println(mToBottomApps);
8930            }
8931            if (mDisplay != null) {
8932                pw.print("  Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
8933                        pw.print(mInitialDisplayHeight); pw.print(" base=");
8934                        pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
8935                        pw.print(" cur=");
8936                        pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
8937                        pw.print(" real="); pw.print(mDisplay.getRealWidth());
8938                        pw.print("x"); pw.print(mDisplay.getRealHeight());
8939                        pw.print(" raw="); pw.print(mDisplay.getRawWidth());
8940                        pw.print("x"); pw.println(mDisplay.getRawHeight());
8941            } else {
8942                pw.println("  NO DISPLAY");
8943            }
8944            pw.println("  Policy:");
8945            mPolicy.dump("    ", fd, pw, args);
8946        }
8947    }
8948
8949    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
8950    public void monitor() {
8951        synchronized (mWindowMap) { }
8952        synchronized (mKeyguardTokenWatcher) { }
8953    }
8954
8955    public interface OnHardKeyboardStatusChangeListener {
8956        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
8957    }
8958}
8959