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