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