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