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