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