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