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