WindowManagerService.java revision 0029c66203ab9ded4342976bf7a17bb63af8c44a
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 void setInputFilter(InputFilter filter) {
4608        mInputManager.setInputFilter(filter);
4609    }
4610
4611    public InputDevice getInputDevice(int deviceId) {
4612        return mInputManager.getInputDevice(deviceId);
4613    }
4614
4615    public int[] getInputDeviceIds() {
4616        return mInputManager.getInputDeviceIds();
4617    }
4618
4619    public void enableScreenAfterBoot() {
4620        synchronized(mWindowMap) {
4621            if (mSystemBooted) {
4622                return;
4623            }
4624            mSystemBooted = true;
4625        }
4626
4627        performEnableScreen();
4628    }
4629
4630    public void enableScreenIfNeededLocked() {
4631        if (mDisplayEnabled) {
4632            return;
4633        }
4634        if (!mSystemBooted) {
4635            return;
4636        }
4637        mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN));
4638    }
4639
4640    public void performEnableScreen() {
4641        synchronized(mWindowMap) {
4642            if (mDisplayEnabled) {
4643                return;
4644            }
4645            if (!mSystemBooted) {
4646                return;
4647            }
4648
4649            // Don't enable the screen until all existing windows
4650            // have been drawn.
4651            final int N = mWindows.size();
4652            for (int i=0; i<N; i++) {
4653                WindowState w = mWindows.get(i);
4654                if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
4655                    return;
4656                }
4657            }
4658
4659            mDisplayEnabled = true;
4660            if (false) {
4661                Slog.i(TAG, "ENABLING SCREEN!");
4662                StringWriter sw = new StringWriter();
4663                PrintWriter pw = new PrintWriter(sw);
4664                this.dump(null, pw, null);
4665                Slog.i(TAG, sw.toString());
4666            }
4667            try {
4668                IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
4669                if (surfaceFlinger != null) {
4670                    //Slog.i(TAG, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
4671                    Parcel data = Parcel.obtain();
4672                    data.writeInterfaceToken("android.ui.ISurfaceComposer");
4673                    surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
4674                                            data, null, 0);
4675                    data.recycle();
4676                }
4677            } catch (RemoteException ex) {
4678                Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
4679            }
4680        }
4681
4682        mPolicy.enableScreenAfterBoot();
4683
4684        // Make sure the last requested orientation has been applied.
4685        setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false,
4686                mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE);
4687    }
4688
4689    public void setInTouchMode(boolean mode) {
4690        synchronized(mWindowMap) {
4691            mInTouchMode = mode;
4692        }
4693    }
4694
4695    // TODO: more accounting of which pid(s) turned it on, keep count,
4696    // only allow disables from pids which have count on, etc.
4697    public void showStrictModeViolation(boolean on) {
4698        int pid = Binder.getCallingPid();
4699        synchronized(mWindowMap) {
4700            // Ignoring requests to enable the red border from clients
4701            // which aren't on screen.  (e.g. Broadcast Receivers in
4702            // the background..)
4703            if (on) {
4704                boolean isVisible = false;
4705                for (WindowState ws : mWindows) {
4706                    if (ws.mSession.mPid == pid && ws.isVisibleLw()) {
4707                        isVisible = true;
4708                        break;
4709                    }
4710                }
4711                if (!isVisible) {
4712                    return;
4713                }
4714            }
4715
4716            if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION showStrictModeViolation");
4717            Surface.openTransaction();
4718            try {
4719                if (mStrictModeFlash == null) {
4720                    mStrictModeFlash = new StrictModeFlash(mDisplay, mFxSession);
4721                }
4722                mStrictModeFlash.setVisibility(on);
4723            } finally {
4724                Surface.closeTransaction();
4725                if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION showStrictModeViolation");
4726            }
4727        }
4728    }
4729
4730    public void setStrictModeVisualIndicatorPreference(String value) {
4731        SystemProperties.set(StrictMode.VISUAL_PROPERTY, value);
4732    }
4733
4734    /**
4735     * Takes a snapshot of the screen.  In landscape mode this grabs the whole screen.
4736     * In portrait mode, it grabs the upper region of the screen based on the vertical dimension
4737     * of the target image.
4738     *
4739     * @param width the width of the target bitmap
4740     * @param height the height of the target bitmap
4741     */
4742    public Bitmap screenshotApplications(IBinder appToken, int width, int height) {
4743        if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
4744                "screenshotApplications()")) {
4745            throw new SecurityException("Requires READ_FRAME_BUFFER permission");
4746        }
4747
4748        Bitmap rawss;
4749
4750        int maxLayer = 0;
4751        final Rect frame = new Rect();
4752
4753        float scale;
4754        int dw, dh;
4755        int rot;
4756
4757        synchronized(mWindowMap) {
4758            long ident = Binder.clearCallingIdentity();
4759
4760            dw = mDisplay.getWidth();
4761            dh = mDisplay.getHeight();
4762
4763            int aboveAppLayer = mPolicy.windowTypeToLayerLw(
4764                    WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER
4765                    + TYPE_LAYER_OFFSET;
4766            aboveAppLayer += TYPE_LAYER_MULTIPLIER;
4767
4768            boolean isImeTarget = mInputMethodTarget != null
4769                    && mInputMethodTarget.mAppToken != null
4770                    && mInputMethodTarget.mAppToken.appToken != null
4771                    && mInputMethodTarget.mAppToken.appToken.asBinder() == appToken;
4772
4773            // Figure out the part of the screen that is actually the app.
4774            boolean including = false;
4775            for (int i=mWindows.size()-1; i>=0; i--) {
4776                WindowState ws = mWindows.get(i);
4777                if (ws.mSurface == null) {
4778                    continue;
4779                }
4780                if (ws.mLayer >= aboveAppLayer) {
4781                    continue;
4782                }
4783                // When we will skip windows: when we are not including
4784                // ones behind a window we didn't skip, and we are actually
4785                // taking a screenshot of a specific app.
4786                if (!including && appToken != null) {
4787                    // Also, we can possibly skip this window if it is not
4788                    // an IME target or the application for the screenshot
4789                    // is not the current IME target.
4790                    if (!ws.mIsImWindow || !isImeTarget) {
4791                        // And finally, this window is of no interest if it
4792                        // is not associated with the screenshot app.
4793                        if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
4794                            continue;
4795                        }
4796                    }
4797                }
4798
4799                // We keep on including windows until we go past a full-screen
4800                // window.
4801                including = !ws.mIsImWindow && !ws.isFullscreen(dw, dh);
4802
4803                if (maxLayer < ws.mAnimLayer) {
4804                    maxLayer = ws.mAnimLayer;
4805                }
4806
4807                // Don't include wallpaper in bounds calculation
4808                if (!ws.mIsWallpaper) {
4809                    final Rect wf = ws.mFrame;
4810                    final Rect cr = ws.mContentInsets;
4811                    int left = wf.left + cr.left;
4812                    int top = wf.top + cr.top;
4813                    int right = wf.right - cr.right;
4814                    int bottom = wf.bottom - cr.bottom;
4815                    frame.union(left, top, right, bottom);
4816                }
4817            }
4818            Binder.restoreCallingIdentity(ident);
4819
4820            // Constrain frame to the screen size.
4821            frame.intersect(0, 0, dw, dh);
4822
4823            if (frame.isEmpty() || maxLayer == 0) {
4824                return null;
4825            }
4826
4827            // The screenshot API does not apply the current screen rotation.
4828            rot = mDisplay.getRotation();
4829            int fw = frame.width();
4830            int fh = frame.height();
4831
4832            // First try reducing to fit in x dimension.
4833            scale = width/(float)fw;
4834
4835            // The screen shot will contain the entire screen.
4836            dw = (int)(dw*scale);
4837            dh = (int)(dh*scale);
4838            if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
4839                int tmp = dw;
4840                dw = dh;
4841                dh = tmp;
4842                rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90;
4843            }
4844            rawss = Surface.screenshot(dw, dh, 0, maxLayer);
4845        }
4846
4847        if (rawss == null) {
4848            Log.w(TAG, "Failure taking screenshot for (" + dw + "x" + dh
4849                    + ") to layer " + maxLayer);
4850            return null;
4851        }
4852
4853        Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig());
4854        Matrix matrix = new Matrix();
4855        ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix);
4856        matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale));
4857        Canvas canvas = new Canvas(bm);
4858        canvas.drawBitmap(rawss, matrix, null);
4859
4860        rawss.recycle();
4861        return bm;
4862    }
4863
4864    public void freezeRotation() {
4865        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
4866                "freezeRotation()")) {
4867            throw new SecurityException("Requires SET_ORIENTATION permission");
4868        }
4869
4870        if (DEBUG_ORIENTATION) Slog.v(TAG, "freezeRotation: mRotation=" + mRotation);
4871
4872        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_LOCKED, mRotation);
4873        setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0);
4874    }
4875
4876    public void thawRotation() {
4877        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
4878                "thawRotation()")) {
4879            throw new SecurityException("Requires SET_ORIENTATION permission");
4880        }
4881
4882        if (DEBUG_ORIENTATION) Slog.v(TAG, "thawRotation: mRotation=" + mRotation);
4883
4884        mPolicy.setUserRotationMode(WindowManagerPolicy.USER_ROTATION_FREE, 777); // rot not used
4885        setRotationUnchecked(WindowManagerPolicy.USE_LAST_ROTATION, false, 0);
4886    }
4887
4888    public void setRotation(int rotation,
4889            boolean alwaysSendConfiguration, int animFlags) {
4890        if (!checkCallingPermission(android.Manifest.permission.SET_ORIENTATION,
4891                "setRotation()")) {
4892            throw new SecurityException("Requires SET_ORIENTATION permission");
4893        }
4894
4895        setRotationUnchecked(rotation, alwaysSendConfiguration, animFlags);
4896    }
4897
4898    public void setRotationUnchecked(int rotation,
4899            boolean alwaysSendConfiguration, int animFlags) {
4900        if(DEBUG_ORIENTATION) Slog.v(TAG,
4901                   "setRotationUnchecked(rotation=" + rotation +
4902                   " alwaysSendConfiguration=" + alwaysSendConfiguration +
4903                   " animFlags=" + animFlags);
4904
4905        long origId = Binder.clearCallingIdentity();
4906        boolean changed;
4907        synchronized(mWindowMap) {
4908            changed = setRotationUncheckedLocked(rotation, animFlags, false);
4909        }
4910
4911        if (changed || alwaysSendConfiguration) {
4912            sendNewConfiguration();
4913        }
4914
4915        Binder.restoreCallingIdentity(origId);
4916    }
4917
4918    /**
4919     * Apply a new rotation to the screen, respecting the requests of
4920     * applications.  Use WindowManagerPolicy.USE_LAST_ROTATION to simply
4921     * re-evaluate the desired rotation.
4922     *
4923     * Returns null if the rotation has been changed.  In this case YOU
4924     * MUST CALL setNewConfiguration() TO UNFREEZE THE SCREEN.
4925     */
4926    public boolean setRotationUncheckedLocked(int rotation, int animFlags, boolean inTransaction) {
4927        if (mDragState != null || mScreenRotationAnimation != null) {
4928            // Potential rotation during a drag.  Don't do the rotation now, but make
4929            // a note to perform the rotation later.
4930            if (DEBUG_ORIENTATION) Slog.v(TAG, "Deferring rotation.");
4931            if (rotation != WindowManagerPolicy.USE_LAST_ROTATION) {
4932                mDeferredRotation = rotation;
4933                mDeferredRotationAnimFlags = animFlags;
4934            }
4935            return false;
4936        }
4937
4938        boolean changed;
4939        if (rotation == WindowManagerPolicy.USE_LAST_ROTATION) {
4940            if (mDeferredRotation != WindowManagerPolicy.USE_LAST_ROTATION) {
4941                rotation = mDeferredRotation;
4942                mRequestedRotation = rotation;
4943                mLastRotationFlags = mDeferredRotationAnimFlags;
4944            }
4945            rotation = mRequestedRotation;
4946        } else {
4947            mRequestedRotation = rotation;
4948            mLastRotationFlags = animFlags;
4949        }
4950        mDeferredRotation = WindowManagerPolicy.USE_LAST_ROTATION;
4951        if (DEBUG_ORIENTATION) Slog.v(TAG, "Overwriting rotation value from " + rotation);
4952        rotation = mPolicy.rotationForOrientationLw(mForcedAppOrientation,
4953                mRotation, mDisplayEnabled);
4954        if (DEBUG_ORIENTATION) Slog.v(TAG, "new rotation is set to " + rotation);
4955        changed = mDisplayEnabled && mRotation != rotation;
4956
4957        if (changed) {
4958            if (DEBUG_ORIENTATION) Slog.v(TAG,
4959                    "Rotation changed to " + rotation
4960                    + " from " + mRotation
4961                    + " (forceApp=" + mForcedAppOrientation
4962                    + ", req=" + mRequestedRotation + ")");
4963            mRotation = rotation;
4964            mWindowsFreezingScreen = true;
4965            mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
4966            mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_FREEZE_TIMEOUT),
4967                    2000);
4968            mWaitingForConfig = true;
4969            mLayoutNeeded = true;
4970            startFreezingDisplayLocked(inTransaction);
4971            Slog.i(TAG, "Setting rotation to " + rotation + ", animFlags=" + animFlags);
4972            mInputManager.setDisplayOrientation(0, rotation);
4973            if (mDisplayEnabled) {
4974                // NOTE: We disable the rotation in the emulator because
4975                //       it doesn't support hardware OpenGL emulation yet.
4976                if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
4977                        && mScreenRotationAnimation.hasScreenshot()) {
4978                    Surface.freezeDisplay(0);
4979                    if (!inTransaction) {
4980                        if (SHOW_TRANSACTIONS) Slog.i(TAG,
4981                                ">>> OPEN TRANSACTION setRotationUnchecked");
4982                        Surface.openTransaction();
4983                    }
4984                    try {
4985                        if (mScreenRotationAnimation != null) {
4986                            mScreenRotationAnimation.setRotation(rotation);
4987                        }
4988                    } finally {
4989                        if (!inTransaction) {
4990                            Surface.closeTransaction();
4991                            if (SHOW_TRANSACTIONS) Slog.i(TAG,
4992                                    "<<< CLOSE TRANSACTION setRotationUnchecked");
4993                        }
4994                    }
4995                    Surface.setOrientation(0, rotation, animFlags);
4996                    Surface.unfreezeDisplay(0);
4997                } else {
4998                    Surface.setOrientation(0, rotation, animFlags);
4999                }
5000            }
5001            for (int i=mWindows.size()-1; i>=0; i--) {
5002                WindowState w = mWindows.get(i);
5003                if (w.mSurface != null) {
5004                    w.mOrientationChanging = true;
5005                }
5006            }
5007            for (int i=mRotationWatchers.size()-1; i>=0; i--) {
5008                try {
5009                    mRotationWatchers.get(i).onRotationChanged(rotation);
5010                } catch (RemoteException e) {
5011                }
5012            }
5013        } //end if changed
5014
5015        return changed;
5016    }
5017
5018    public int getRotation() {
5019        return mRotation;
5020    }
5021
5022    public int watchRotation(IRotationWatcher watcher) {
5023        final IBinder watcherBinder = watcher.asBinder();
5024        IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
5025            public void binderDied() {
5026                synchronized (mWindowMap) {
5027                    for (int i=0; i<mRotationWatchers.size(); i++) {
5028                        if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
5029                            IRotationWatcher removed = mRotationWatchers.remove(i);
5030                            if (removed != null) {
5031                                removed.asBinder().unlinkToDeath(this, 0);
5032                            }
5033                            i--;
5034                        }
5035                    }
5036                }
5037            }
5038        };
5039
5040        synchronized (mWindowMap) {
5041            try {
5042                watcher.asBinder().linkToDeath(dr, 0);
5043                mRotationWatchers.add(watcher);
5044            } catch (RemoteException e) {
5045                // Client died, no cleanup needed.
5046            }
5047
5048            return mRotation;
5049        }
5050    }
5051
5052    /**
5053     * Starts the view server on the specified port.
5054     *
5055     * @param port The port to listener to.
5056     *
5057     * @return True if the server was successfully started, false otherwise.
5058     *
5059     * @see com.android.server.wm.ViewServer
5060     * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
5061     */
5062    public boolean startViewServer(int port) {
5063        if (isSystemSecure()) {
5064            return false;
5065        }
5066
5067        if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
5068            return false;
5069        }
5070
5071        if (port < 1024) {
5072            return false;
5073        }
5074
5075        if (mViewServer != null) {
5076            if (!mViewServer.isRunning()) {
5077                try {
5078                    return mViewServer.start();
5079                } catch (IOException e) {
5080                    Slog.w(TAG, "View server did not start");
5081                }
5082            }
5083            return false;
5084        }
5085
5086        try {
5087            mViewServer = new ViewServer(this, port);
5088            return mViewServer.start();
5089        } catch (IOException e) {
5090            Slog.w(TAG, "View server did not start");
5091        }
5092        return false;
5093    }
5094
5095    private boolean isSystemSecure() {
5096        return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
5097                "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
5098    }
5099
5100    /**
5101     * Stops the view server if it exists.
5102     *
5103     * @return True if the server stopped, false if it wasn't started or
5104     *         couldn't be stopped.
5105     *
5106     * @see com.android.server.wm.ViewServer
5107     */
5108    public boolean stopViewServer() {
5109        if (isSystemSecure()) {
5110            return false;
5111        }
5112
5113        if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
5114            return false;
5115        }
5116
5117        if (mViewServer != null) {
5118            return mViewServer.stop();
5119        }
5120        return false;
5121    }
5122
5123    /**
5124     * Indicates whether the view server is running.
5125     *
5126     * @return True if the server is running, false otherwise.
5127     *
5128     * @see com.android.server.wm.ViewServer
5129     */
5130    public boolean isViewServerRunning() {
5131        if (isSystemSecure()) {
5132            return false;
5133        }
5134
5135        if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
5136            return false;
5137        }
5138
5139        return mViewServer != null && mViewServer.isRunning();
5140    }
5141
5142    /**
5143     * Lists all availble windows in the system. The listing is written in the
5144     * specified Socket's output stream with the following syntax:
5145     * windowHashCodeInHexadecimal windowName
5146     * Each line of the ouput represents a different window.
5147     *
5148     * @param client The remote client to send the listing to.
5149     * @return False if an error occured, true otherwise.
5150     */
5151    boolean viewServerListWindows(Socket client) {
5152        if (isSystemSecure()) {
5153            return false;
5154        }
5155
5156        boolean result = true;
5157
5158        WindowState[] windows;
5159        synchronized (mWindowMap) {
5160            //noinspection unchecked
5161            windows = mWindows.toArray(new WindowState[mWindows.size()]);
5162        }
5163
5164        BufferedWriter out = null;
5165
5166        // Any uncaught exception will crash the system process
5167        try {
5168            OutputStream clientStream = client.getOutputStream();
5169            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
5170
5171            final int count = windows.length;
5172            for (int i = 0; i < count; i++) {
5173                final WindowState w = windows[i];
5174                out.write(Integer.toHexString(System.identityHashCode(w)));
5175                out.write(' ');
5176                out.append(w.mAttrs.getTitle());
5177                out.write('\n');
5178            }
5179
5180            out.write("DONE.\n");
5181            out.flush();
5182        } catch (Exception e) {
5183            result = false;
5184        } finally {
5185            if (out != null) {
5186                try {
5187                    out.close();
5188                } catch (IOException e) {
5189                    result = false;
5190                }
5191            }
5192        }
5193
5194        return result;
5195    }
5196
5197    /**
5198     * Returns the focused window in the following format:
5199     * windowHashCodeInHexadecimal windowName
5200     *
5201     * @param client The remote client to send the listing to.
5202     * @return False if an error occurred, true otherwise.
5203     */
5204    boolean viewServerGetFocusedWindow(Socket client) {
5205        if (isSystemSecure()) {
5206            return false;
5207        }
5208
5209        boolean result = true;
5210
5211        WindowState focusedWindow = getFocusedWindow();
5212
5213        BufferedWriter out = null;
5214
5215        // Any uncaught exception will crash the system process
5216        try {
5217            OutputStream clientStream = client.getOutputStream();
5218            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
5219
5220            if(focusedWindow != null) {
5221                out.write(Integer.toHexString(System.identityHashCode(focusedWindow)));
5222                out.write(' ');
5223                out.append(focusedWindow.mAttrs.getTitle());
5224            }
5225            out.write('\n');
5226            out.flush();
5227        } catch (Exception e) {
5228            result = false;
5229        } finally {
5230            if (out != null) {
5231                try {
5232                    out.close();
5233                } catch (IOException e) {
5234                    result = false;
5235                }
5236            }
5237        }
5238
5239        return result;
5240    }
5241
5242    /**
5243     * Sends a command to a target window. The result of the command, if any, will be
5244     * written in the output stream of the specified socket.
5245     *
5246     * The parameters must follow this syntax:
5247     * windowHashcode extra
5248     *
5249     * Where XX is the length in characeters of the windowTitle.
5250     *
5251     * The first parameter is the target window. The window with the specified hashcode
5252     * will be the target. If no target can be found, nothing happens. The extra parameters
5253     * will be delivered to the target window and as parameters to the command itself.
5254     *
5255     * @param client The remote client to sent the result, if any, to.
5256     * @param command The command to execute.
5257     * @param parameters The command parameters.
5258     *
5259     * @return True if the command was successfully delivered, false otherwise. This does
5260     *         not indicate whether the command itself was successful.
5261     */
5262    boolean viewServerWindowCommand(Socket client, String command, String parameters) {
5263        if (isSystemSecure()) {
5264            return false;
5265        }
5266
5267        boolean success = true;
5268        Parcel data = null;
5269        Parcel reply = null;
5270
5271        BufferedWriter out = null;
5272
5273        // Any uncaught exception will crash the system process
5274        try {
5275            // Find the hashcode of the window
5276            int index = parameters.indexOf(' ');
5277            if (index == -1) {
5278                index = parameters.length();
5279            }
5280            final String code = parameters.substring(0, index);
5281            int hashCode = (int) Long.parseLong(code, 16);
5282
5283            // Extract the command's parameter after the window description
5284            if (index < parameters.length()) {
5285                parameters = parameters.substring(index + 1);
5286            } else {
5287                parameters = "";
5288            }
5289
5290            final WindowState window = findWindow(hashCode);
5291            if (window == null) {
5292                return false;
5293            }
5294
5295            data = Parcel.obtain();
5296            data.writeInterfaceToken("android.view.IWindow");
5297            data.writeString(command);
5298            data.writeString(parameters);
5299            data.writeInt(1);
5300            ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
5301
5302            reply = Parcel.obtain();
5303
5304            final IBinder binder = window.mClient.asBinder();
5305            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
5306            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
5307
5308            reply.readException();
5309
5310            if (!client.isOutputShutdown()) {
5311                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
5312                out.write("DONE\n");
5313                out.flush();
5314            }
5315
5316        } catch (Exception e) {
5317            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
5318            success = false;
5319        } finally {
5320            if (data != null) {
5321                data.recycle();
5322            }
5323            if (reply != null) {
5324                reply.recycle();
5325            }
5326            if (out != null) {
5327                try {
5328                    out.close();
5329                } catch (IOException e) {
5330
5331                }
5332            }
5333        }
5334
5335        return success;
5336    }
5337
5338    public void addWindowChangeListener(WindowChangeListener listener) {
5339        synchronized(mWindowMap) {
5340            mWindowChangeListeners.add(listener);
5341        }
5342    }
5343
5344    public void removeWindowChangeListener(WindowChangeListener listener) {
5345        synchronized(mWindowMap) {
5346            mWindowChangeListeners.remove(listener);
5347        }
5348    }
5349
5350    private void notifyWindowsChanged() {
5351        WindowChangeListener[] windowChangeListeners;
5352        synchronized(mWindowMap) {
5353            if(mWindowChangeListeners.isEmpty()) {
5354                return;
5355            }
5356            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
5357            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
5358        }
5359        int N = windowChangeListeners.length;
5360        for(int i = 0; i < N; i++) {
5361            windowChangeListeners[i].windowsChanged();
5362        }
5363    }
5364
5365    private void notifyFocusChanged() {
5366        WindowChangeListener[] windowChangeListeners;
5367        synchronized(mWindowMap) {
5368            if(mWindowChangeListeners.isEmpty()) {
5369                return;
5370            }
5371            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
5372            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
5373        }
5374        int N = windowChangeListeners.length;
5375        for(int i = 0; i < N; i++) {
5376            windowChangeListeners[i].focusChanged();
5377        }
5378    }
5379
5380    private WindowState findWindow(int hashCode) {
5381        if (hashCode == -1) {
5382            return getFocusedWindow();
5383        }
5384
5385        synchronized (mWindowMap) {
5386            final ArrayList<WindowState> windows = mWindows;
5387            final int count = windows.size();
5388
5389            for (int i = 0; i < count; i++) {
5390                WindowState w = windows.get(i);
5391                if (System.identityHashCode(w) == hashCode) {
5392                    return w;
5393                }
5394            }
5395        }
5396
5397        return null;
5398    }
5399
5400    /*
5401     * Instruct the Activity Manager to fetch the current configuration and broadcast
5402     * that to config-changed listeners if appropriate.
5403     */
5404    void sendNewConfiguration() {
5405        try {
5406            mActivityManager.updateConfiguration(null);
5407        } catch (RemoteException e) {
5408        }
5409    }
5410
5411    public Configuration computeNewConfiguration() {
5412        synchronized (mWindowMap) {
5413            Configuration config = computeNewConfigurationLocked();
5414            if (config == null && mWaitingForConfig) {
5415                // Nothing changed but we are waiting for something... stop that!
5416                mWaitingForConfig = false;
5417                performLayoutAndPlaceSurfacesLocked();
5418            }
5419            return config;
5420        }
5421    }
5422
5423    Configuration computeNewConfigurationLocked() {
5424        Configuration config = new Configuration();
5425        if (!computeNewConfigurationLocked(config)) {
5426            return null;
5427        }
5428        return config;
5429    }
5430
5431    boolean computeNewConfigurationLocked(Configuration config) {
5432        if (mDisplay == null) {
5433            return false;
5434        }
5435
5436        mInputManager.getInputConfiguration(config);
5437
5438        // Use the effective "visual" dimensions based on current rotation
5439        final boolean rotated = (mRotation == Surface.ROTATION_90
5440                || mRotation == Surface.ROTATION_270);
5441        final int dw = rotated ? mInitialDisplayHeight : mInitialDisplayWidth;
5442        final int dh = rotated ? mInitialDisplayWidth : mInitialDisplayHeight;
5443
5444        int orientation = Configuration.ORIENTATION_SQUARE;
5445        if (dw < dh) {
5446            orientation = Configuration.ORIENTATION_PORTRAIT;
5447        } else if (dw > dh) {
5448            orientation = Configuration.ORIENTATION_LANDSCAPE;
5449        }
5450        config.orientation = orientation;
5451
5452        DisplayMetrics dm = new DisplayMetrics();
5453        mDisplay.getMetrics(dm);
5454        CompatibilityInfo.updateCompatibleScreenFrame(dm, orientation, mCompatibleScreenFrame);
5455
5456        if (mScreenLayout == Configuration.SCREENLAYOUT_SIZE_UNDEFINED) {
5457            // Note we only do this once because at this point we don't
5458            // expect the screen to change in this way at runtime, and want
5459            // to avoid all of this computation for every config change.
5460            int longSize = dw;
5461            int shortSize = dh;
5462            if (longSize < shortSize) {
5463                int tmp = longSize;
5464                longSize = shortSize;
5465                shortSize = tmp;
5466            }
5467            longSize = (int)(longSize/dm.density);
5468            shortSize = (int)(shortSize/dm.density);
5469
5470            // These semi-magic numbers define our compatibility modes for
5471            // applications with different screens.  These are guarantees to
5472            // app developers about the space they can expect for a particular
5473            // configuration.  DO NOT CHANGE!
5474            if (longSize < 470) {
5475                // This is shorter than an HVGA normal density screen (which
5476                // is 480 pixels on its long side).
5477                mScreenLayout = Configuration.SCREENLAYOUT_SIZE_SMALL
5478                        | Configuration.SCREENLAYOUT_LONG_NO;
5479            } else {
5480                // What size is this screen screen?
5481                if (longSize >= 960 && shortSize >= 720) {
5482                    // 1.5xVGA or larger screens at medium density are the point
5483                    // at which we consider it to be an extra large screen.
5484                    mScreenLayout = Configuration.SCREENLAYOUT_SIZE_XLARGE;
5485                } else if (longSize >= 640 && shortSize >= 480) {
5486                    // VGA or larger screens at medium density are the point
5487                    // at which we consider it to be a large screen.
5488                    mScreenLayout = Configuration.SCREENLAYOUT_SIZE_LARGE;
5489                } else {
5490                    mScreenLayout = Configuration.SCREENLAYOUT_SIZE_NORMAL;
5491                }
5492
5493                // If this screen is wider than normal HVGA, or taller
5494                // than FWVGA, then for old apps we want to run in size
5495                // compatibility mode.
5496                if (shortSize > 321 || longSize > 570) {
5497                    mScreenLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
5498                }
5499
5500                // Is this a long screen?
5501                if (((longSize*3)/5) >= (shortSize-1)) {
5502                    // Anything wider than WVGA (5:3) is considering to be long.
5503                    mScreenLayout |= Configuration.SCREENLAYOUT_LONG_YES;
5504                } else {
5505                    mScreenLayout |= Configuration.SCREENLAYOUT_LONG_NO;
5506                }
5507            }
5508        }
5509        config.screenLayout = mScreenLayout;
5510
5511        // Determine whether a hard keyboard is available and enabled.
5512        boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
5513        if (hardKeyboardAvailable != mHardKeyboardAvailable) {
5514            mHardKeyboardAvailable = hardKeyboardAvailable;
5515            mHardKeyboardEnabled = hardKeyboardAvailable;
5516
5517            mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
5518            mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
5519        }
5520        if (!mHardKeyboardEnabled) {
5521            config.keyboard = Configuration.KEYBOARD_NOKEYS;
5522        }
5523
5524        // Update value of keyboardHidden, hardKeyboardHidden and navigationHidden
5525        // based on whether a hard or soft keyboard is present, whether navigation keys
5526        // are present and the lid switch state.
5527        config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
5528        config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
5529        config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
5530        mPolicy.adjustConfigurationLw(config);
5531        return true;
5532    }
5533
5534    public boolean isHardKeyboardAvailable() {
5535        synchronized (mWindowMap) {
5536            return mHardKeyboardAvailable;
5537        }
5538    }
5539
5540    public boolean isHardKeyboardEnabled() {
5541        synchronized (mWindowMap) {
5542            return mHardKeyboardEnabled;
5543        }
5544    }
5545
5546    public void setHardKeyboardEnabled(boolean enabled) {
5547        synchronized (mWindowMap) {
5548            if (mHardKeyboardEnabled != enabled) {
5549                mHardKeyboardEnabled = enabled;
5550                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
5551            }
5552        }
5553    }
5554
5555    public void setOnHardKeyboardStatusChangeListener(
5556            OnHardKeyboardStatusChangeListener listener) {
5557        synchronized (mWindowMap) {
5558            mHardKeyboardStatusChangeListener = listener;
5559        }
5560    }
5561
5562    void notifyHardKeyboardStatusChange() {
5563        final boolean available, enabled;
5564        final OnHardKeyboardStatusChangeListener listener;
5565        synchronized (mWindowMap) {
5566            listener = mHardKeyboardStatusChangeListener;
5567            available = mHardKeyboardAvailable;
5568            enabled = mHardKeyboardEnabled;
5569        }
5570        if (listener != null) {
5571            listener.onHardKeyboardStatusChange(available, enabled);
5572        }
5573    }
5574
5575    // -------------------------------------------------------------
5576    // Drag and drop
5577    // -------------------------------------------------------------
5578
5579    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
5580            int flags, int width, int height, Surface outSurface) {
5581        if (DEBUG_DRAG) {
5582            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
5583                    + " flags=" + Integer.toHexString(flags) + " win=" + window
5584                    + " asbinder=" + window.asBinder());
5585        }
5586
5587        final int callerPid = Binder.getCallingPid();
5588        final long origId = Binder.clearCallingIdentity();
5589        IBinder token = null;
5590
5591        try {
5592            synchronized (mWindowMap) {
5593                try {
5594                    if (mDragState == null) {
5595                        Surface surface = new Surface(session, callerPid, "drag surface", 0,
5596                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
5597                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
5598                                + surface + ": CREATE");
5599                        outSurface.copyFrom(surface);
5600                        final IBinder winBinder = window.asBinder();
5601                        token = new Binder();
5602                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
5603                        mDragState.mSurface = surface;
5604                        token = mDragState.mToken = new Binder();
5605
5606                        // 5 second timeout for this window to actually begin the drag
5607                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
5608                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
5609                        mH.sendMessageDelayed(msg, 5000);
5610                    } else {
5611                        Slog.w(TAG, "Drag already in progress");
5612                    }
5613                } catch (Surface.OutOfResourcesException e) {
5614                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
5615                    if (mDragState != null) {
5616                        mDragState.reset();
5617                        mDragState = null;
5618                    }
5619                }
5620            }
5621        } finally {
5622            Binder.restoreCallingIdentity(origId);
5623        }
5624
5625        return token;
5626    }
5627
5628    // -------------------------------------------------------------
5629    // Input Events and Focus Management
5630    // -------------------------------------------------------------
5631
5632    final InputMonitor mInputMonitor = new InputMonitor(this);
5633
5634    public void pauseKeyDispatching(IBinder _token) {
5635        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
5636                "pauseKeyDispatching()")) {
5637            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
5638        }
5639
5640        synchronized (mWindowMap) {
5641            WindowToken token = mTokenMap.get(_token);
5642            if (token != null) {
5643                mInputMonitor.pauseDispatchingLw(token);
5644            }
5645        }
5646    }
5647
5648    public void resumeKeyDispatching(IBinder _token) {
5649        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
5650                "resumeKeyDispatching()")) {
5651            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
5652        }
5653
5654        synchronized (mWindowMap) {
5655            WindowToken token = mTokenMap.get(_token);
5656            if (token != null) {
5657                mInputMonitor.resumeDispatchingLw(token);
5658            }
5659        }
5660    }
5661
5662    public void setEventDispatching(boolean enabled) {
5663        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
5664                "resumeKeyDispatching()")) {
5665            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
5666        }
5667
5668        synchronized (mWindowMap) {
5669            mInputMonitor.setEventDispatchingLw(enabled);
5670        }
5671    }
5672
5673    /**
5674     * Injects a keystroke event into the UI.
5675     * Even when sync is false, this method may block while waiting for current
5676     * input events to be dispatched.
5677     *
5678     * @param ev A motion event describing the keystroke action.  (Be sure to use
5679     * {@link SystemClock#uptimeMillis()} as the timebase.)
5680     * @param sync If true, wait for the event to be completed before returning to the caller.
5681     * @return Returns true if event was dispatched, false if it was dropped for any reason
5682     */
5683    public boolean injectKeyEvent(KeyEvent ev, boolean sync) {
5684        long downTime = ev.getDownTime();
5685        long eventTime = ev.getEventTime();
5686
5687        int action = ev.getAction();
5688        int code = ev.getKeyCode();
5689        int repeatCount = ev.getRepeatCount();
5690        int metaState = ev.getMetaState();
5691        int deviceId = ev.getDeviceId();
5692        int scancode = ev.getScanCode();
5693        int source = ev.getSource();
5694        int flags = ev.getFlags();
5695
5696        if (source == InputDevice.SOURCE_UNKNOWN) {
5697            source = InputDevice.SOURCE_KEYBOARD;
5698        }
5699
5700        if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
5701        if (downTime == 0) downTime = eventTime;
5702
5703        KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
5704                deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source);
5705
5706        final int pid = Binder.getCallingPid();
5707        final int uid = Binder.getCallingUid();
5708        final long ident = Binder.clearCallingIdentity();
5709
5710        final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
5711                sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
5712                        : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
5713                INJECTION_TIMEOUT_MILLIS);
5714
5715        Binder.restoreCallingIdentity(ident);
5716        return reportInjectionResult(result);
5717    }
5718
5719    /**
5720     * Inject a pointer (touch) event into the UI.
5721     * Even when sync is false, this method may block while waiting for current
5722     * input events to be dispatched.
5723     *
5724     * @param ev A motion event describing the pointer (touch) action.  (As noted in
5725     * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
5726     * {@link SystemClock#uptimeMillis()} as the timebase.)
5727     * @param sync If true, wait for the event to be completed before returning to the caller.
5728     * @return Returns true if event was dispatched, false if it was dropped for any reason
5729     */
5730    public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
5731        final int pid = Binder.getCallingPid();
5732        final int uid = Binder.getCallingUid();
5733        final long ident = Binder.clearCallingIdentity();
5734
5735        MotionEvent newEvent = MotionEvent.obtain(ev);
5736        if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
5737            newEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
5738        }
5739
5740        final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
5741                sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
5742                        : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
5743                INJECTION_TIMEOUT_MILLIS);
5744
5745        Binder.restoreCallingIdentity(ident);
5746        return reportInjectionResult(result);
5747    }
5748
5749    /**
5750     * Inject a trackball (navigation device) event into the UI.
5751     * Even when sync is false, this method may block while waiting for current
5752     * input events to be dispatched.
5753     *
5754     * @param ev A motion event describing the trackball action.  (As noted in
5755     * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
5756     * {@link SystemClock#uptimeMillis()} as the timebase.)
5757     * @param sync If true, wait for the event to be completed before returning to the caller.
5758     * @return Returns true if event was dispatched, false if it was dropped for any reason
5759     */
5760    public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
5761        final int pid = Binder.getCallingPid();
5762        final int uid = Binder.getCallingUid();
5763        final long ident = Binder.clearCallingIdentity();
5764
5765        MotionEvent newEvent = MotionEvent.obtain(ev);
5766        if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) {
5767            newEvent.setSource(InputDevice.SOURCE_TRACKBALL);
5768        }
5769
5770        final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
5771                sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
5772                        : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
5773                INJECTION_TIMEOUT_MILLIS);
5774
5775        Binder.restoreCallingIdentity(ident);
5776        return reportInjectionResult(result);
5777    }
5778
5779    /**
5780     * Inject an input event into the UI without waiting for dispatch to commence.
5781     * This variant is useful for fire-and-forget input event injection.  It does not
5782     * block any longer than it takes to enqueue the input event.
5783     *
5784     * @param ev An input event.  (Be sure to set the input source correctly.)
5785     * @return Returns true if event was dispatched, false if it was dropped for any reason
5786     */
5787    public boolean injectInputEventNoWait(InputEvent ev) {
5788        final int pid = Binder.getCallingPid();
5789        final int uid = Binder.getCallingUid();
5790        final long ident = Binder.clearCallingIdentity();
5791
5792        final int result = mInputManager.injectInputEvent(ev, pid, uid,
5793                InputManager.INPUT_EVENT_INJECTION_SYNC_NONE,
5794                INJECTION_TIMEOUT_MILLIS);
5795
5796        Binder.restoreCallingIdentity(ident);
5797        return reportInjectionResult(result);
5798    }
5799
5800    private boolean reportInjectionResult(int result) {
5801        switch (result) {
5802            case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
5803                Slog.w(TAG, "Input event injection permission denied.");
5804                throw new SecurityException(
5805                        "Injecting to another application requires INJECT_EVENTS permission");
5806            case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
5807                //Slog.v(TAG, "Input event injection succeeded.");
5808                return true;
5809            case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
5810                Slog.w(TAG, "Input event injection timed out.");
5811                return false;
5812            case InputManager.INPUT_EVENT_INJECTION_FAILED:
5813            default:
5814                Slog.w(TAG, "Input event injection failed.");
5815                return false;
5816        }
5817    }
5818
5819    private WindowState getFocusedWindow() {
5820        synchronized (mWindowMap) {
5821            return getFocusedWindowLocked();
5822        }
5823    }
5824
5825    private WindowState getFocusedWindowLocked() {
5826        return mCurrentFocus;
5827    }
5828
5829    public boolean detectSafeMode() {
5830        if (!mInputMonitor.waitForInputDevicesReady(
5831                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
5832            Slog.w(TAG, "Devices still not ready after waiting "
5833                    + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
5834                    + " milliseconds before attempting to detect safe mode.");
5835        }
5836
5837        mSafeMode = mPolicy.detectSafeMode();
5838        return mSafeMode;
5839    }
5840
5841    public void systemReady() {
5842        synchronized(mWindowMap) {
5843            if (mDisplay != null) {
5844                throw new IllegalStateException("Display already initialized");
5845            }
5846            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
5847            mDisplay = wm.getDefaultDisplay();
5848            mInitialDisplayWidth = mDisplay.getWidth();
5849            mInitialDisplayHeight = mDisplay.getHeight();
5850            mInputManager.setDisplaySize(0, mDisplay.getRealWidth(), mDisplay.getRealHeight());
5851        }
5852
5853        try {
5854            mActivityManager.updateConfiguration(null);
5855        } catch (RemoteException e) {
5856        }
5857
5858        mPolicy.systemReady();
5859    }
5860
5861    // This is an animation that does nothing: it just immediately finishes
5862    // itself every time it is called.  It is used as a stub animation in cases
5863    // where we want to synchronize multiple things that may be animating.
5864    static final class DummyAnimation extends Animation {
5865        public boolean getTransformation(long currentTime, Transformation outTransformation) {
5866            return false;
5867        }
5868    }
5869    static final Animation sDummyAnimation = new DummyAnimation();
5870
5871    // -------------------------------------------------------------
5872    // Async Handler
5873    // -------------------------------------------------------------
5874
5875    final class H extends Handler {
5876        public static final int REPORT_FOCUS_CHANGE = 2;
5877        public static final int REPORT_LOSING_FOCUS = 3;
5878        public static final int ANIMATE = 4;
5879        public static final int ADD_STARTING = 5;
5880        public static final int REMOVE_STARTING = 6;
5881        public static final int FINISHED_STARTING = 7;
5882        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
5883        public static final int WINDOW_FREEZE_TIMEOUT = 11;
5884        public static final int HOLD_SCREEN_CHANGED = 12;
5885        public static final int APP_TRANSITION_TIMEOUT = 13;
5886        public static final int PERSIST_ANIMATION_SCALE = 14;
5887        public static final int FORCE_GC = 15;
5888        public static final int ENABLE_SCREEN = 16;
5889        public static final int APP_FREEZE_TIMEOUT = 17;
5890        public static final int SEND_NEW_CONFIGURATION = 18;
5891        public static final int REPORT_WINDOWS_CHANGE = 19;
5892        public static final int DRAG_START_TIMEOUT = 20;
5893        public static final int DRAG_END_TIMEOUT = 21;
5894        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
5895
5896        private Session mLastReportedHold;
5897
5898        public H() {
5899        }
5900
5901        @Override
5902        public void handleMessage(Message msg) {
5903            switch (msg.what) {
5904                case REPORT_FOCUS_CHANGE: {
5905                    WindowState lastFocus;
5906                    WindowState newFocus;
5907
5908                    synchronized(mWindowMap) {
5909                        lastFocus = mLastFocus;
5910                        newFocus = mCurrentFocus;
5911                        if (lastFocus == newFocus) {
5912                            // Focus is not changing, so nothing to do.
5913                            return;
5914                        }
5915                        mLastFocus = newFocus;
5916                        //Slog.i(TAG, "Focus moving from " + lastFocus
5917                        //        + " to " + newFocus);
5918                        if (newFocus != null && lastFocus != null
5919                                && !newFocus.isDisplayedLw()) {
5920                            //Slog.i(TAG, "Delaying loss of focus...");
5921                            mLosingFocus.add(lastFocus);
5922                            lastFocus = null;
5923                        }
5924                    }
5925
5926                    if (lastFocus != newFocus) {
5927                        //System.out.println("Changing focus from " + lastFocus
5928                        //                   + " to " + newFocus);
5929                        if (newFocus != null) {
5930                            try {
5931                                //Slog.i(TAG, "Gaining focus: " + newFocus);
5932                                newFocus.mClient.windowFocusChanged(true, mInTouchMode);
5933                            } catch (RemoteException e) {
5934                                // Ignore if process has died.
5935                            }
5936                            notifyFocusChanged();
5937                        }
5938
5939                        if (lastFocus != null) {
5940                            try {
5941                                //Slog.i(TAG, "Losing focus: " + lastFocus);
5942                                lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
5943                            } catch (RemoteException e) {
5944                                // Ignore if process has died.
5945                            }
5946                        }
5947
5948                        mPolicy.focusChanged(lastFocus, newFocus);
5949                    }
5950                } break;
5951
5952                case REPORT_LOSING_FOCUS: {
5953                    ArrayList<WindowState> losers;
5954
5955                    synchronized(mWindowMap) {
5956                        losers = mLosingFocus;
5957                        mLosingFocus = new ArrayList<WindowState>();
5958                    }
5959
5960                    final int N = losers.size();
5961                    for (int i=0; i<N; i++) {
5962                        try {
5963                            //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
5964                            losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
5965                        } catch (RemoteException e) {
5966                             // Ignore if process has died.
5967                        }
5968                    }
5969                } break;
5970
5971                case ANIMATE: {
5972                    synchronized(mWindowMap) {
5973                        mAnimationPending = false;
5974                        performLayoutAndPlaceSurfacesLocked();
5975                    }
5976                } break;
5977
5978                case ADD_STARTING: {
5979                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
5980                    final StartingData sd = wtoken.startingData;
5981
5982                    if (sd == null) {
5983                        // Animation has been canceled... do nothing.
5984                        return;
5985                    }
5986
5987                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
5988                            + wtoken + ": pkg=" + sd.pkg);
5989
5990                    View view = null;
5991                    try {
5992                        view = mPolicy.addStartingWindow(
5993                            wtoken.token, sd.pkg,
5994                            sd.theme, sd.nonLocalizedLabel, sd.labelRes,
5995                            sd.icon, sd.windowFlags);
5996                    } catch (Exception e) {
5997                        Slog.w(TAG, "Exception when adding starting window", e);
5998                    }
5999
6000                    if (view != null) {
6001                        boolean abort = false;
6002
6003                        synchronized(mWindowMap) {
6004                            if (wtoken.removed || wtoken.startingData == null) {
6005                                // If the window was successfully added, then
6006                                // we need to remove it.
6007                                if (wtoken.startingWindow != null) {
6008                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6009                                            "Aborted starting " + wtoken
6010                                            + ": removed=" + wtoken.removed
6011                                            + " startingData=" + wtoken.startingData);
6012                                    wtoken.startingWindow = null;
6013                                    wtoken.startingData = null;
6014                                    abort = true;
6015                                }
6016                            } else {
6017                                wtoken.startingView = view;
6018                            }
6019                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
6020                                    "Added starting " + wtoken
6021                                    + ": startingWindow="
6022                                    + wtoken.startingWindow + " startingView="
6023                                    + wtoken.startingView);
6024                        }
6025
6026                        if (abort) {
6027                            try {
6028                                mPolicy.removeStartingWindow(wtoken.token, view);
6029                            } catch (Exception e) {
6030                                Slog.w(TAG, "Exception when removing starting window", e);
6031                            }
6032                        }
6033                    }
6034                } break;
6035
6036                case REMOVE_STARTING: {
6037                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6038                    IBinder token = null;
6039                    View view = null;
6040                    synchronized (mWindowMap) {
6041                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
6042                                + wtoken + ": startingWindow="
6043                                + wtoken.startingWindow + " startingView="
6044                                + wtoken.startingView);
6045                        if (wtoken.startingWindow != null) {
6046                            view = wtoken.startingView;
6047                            token = wtoken.token;
6048                            wtoken.startingData = null;
6049                            wtoken.startingView = null;
6050                            wtoken.startingWindow = null;
6051                        }
6052                    }
6053                    if (view != null) {
6054                        try {
6055                            mPolicy.removeStartingWindow(token, view);
6056                        } catch (Exception e) {
6057                            Slog.w(TAG, "Exception when removing starting window", e);
6058                        }
6059                    }
6060                } break;
6061
6062                case FINISHED_STARTING: {
6063                    IBinder token = null;
6064                    View view = null;
6065                    while (true) {
6066                        synchronized (mWindowMap) {
6067                            final int N = mFinishedStarting.size();
6068                            if (N <= 0) {
6069                                break;
6070                            }
6071                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
6072
6073                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6074                                    "Finished starting " + wtoken
6075                                    + ": startingWindow=" + wtoken.startingWindow
6076                                    + " startingView=" + wtoken.startingView);
6077
6078                            if (wtoken.startingWindow == null) {
6079                                continue;
6080                            }
6081
6082                            view = wtoken.startingView;
6083                            token = wtoken.token;
6084                            wtoken.startingData = null;
6085                            wtoken.startingView = null;
6086                            wtoken.startingWindow = null;
6087                        }
6088
6089                        try {
6090                            mPolicy.removeStartingWindow(token, view);
6091                        } catch (Exception e) {
6092                            Slog.w(TAG, "Exception when removing starting window", e);
6093                        }
6094                    }
6095                } break;
6096
6097                case REPORT_APPLICATION_TOKEN_WINDOWS: {
6098                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6099
6100                    boolean nowVisible = msg.arg1 != 0;
6101                    boolean nowGone = msg.arg2 != 0;
6102
6103                    try {
6104                        if (DEBUG_VISIBILITY) Slog.v(
6105                                TAG, "Reporting visible in " + wtoken
6106                                + " visible=" + nowVisible
6107                                + " gone=" + nowGone);
6108                        if (nowVisible) {
6109                            wtoken.appToken.windowsVisible();
6110                        } else {
6111                            wtoken.appToken.windowsGone();
6112                        }
6113                    } catch (RemoteException ex) {
6114                    }
6115                } break;
6116
6117                case WINDOW_FREEZE_TIMEOUT: {
6118                    synchronized (mWindowMap) {
6119                        Slog.w(TAG, "Window freeze timeout expired.");
6120                        int i = mWindows.size();
6121                        while (i > 0) {
6122                            i--;
6123                            WindowState w = mWindows.get(i);
6124                            if (w.mOrientationChanging) {
6125                                w.mOrientationChanging = false;
6126                                Slog.w(TAG, "Force clearing orientation change: " + w);
6127                            }
6128                        }
6129                        performLayoutAndPlaceSurfacesLocked();
6130                    }
6131                    break;
6132                }
6133
6134                case HOLD_SCREEN_CHANGED: {
6135                    Session oldHold;
6136                    Session newHold;
6137                    synchronized (mWindowMap) {
6138                        oldHold = mLastReportedHold;
6139                        newHold = (Session)msg.obj;
6140                        mLastReportedHold = newHold;
6141                    }
6142
6143                    if (oldHold != newHold) {
6144                        try {
6145                            if (oldHold != null) {
6146                                mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
6147                                        "window",
6148                                        BatteryStats.WAKE_TYPE_WINDOW);
6149                            }
6150                            if (newHold != null) {
6151                                mBatteryStats.noteStartWakelock(newHold.mUid, -1,
6152                                        "window",
6153                                        BatteryStats.WAKE_TYPE_WINDOW);
6154                            }
6155                        } catch (RemoteException e) {
6156                        }
6157                    }
6158                    break;
6159                }
6160
6161                case APP_TRANSITION_TIMEOUT: {
6162                    synchronized (mWindowMap) {
6163                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
6164                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
6165                                    "*** APP TRANSITION TIMEOUT");
6166                            mAppTransitionReady = true;
6167                            mAppTransitionTimeout = true;
6168                            performLayoutAndPlaceSurfacesLocked();
6169                        }
6170                    }
6171                    break;
6172                }
6173
6174                case PERSIST_ANIMATION_SCALE: {
6175                    Settings.System.putFloat(mContext.getContentResolver(),
6176                            Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
6177                    Settings.System.putFloat(mContext.getContentResolver(),
6178                            Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
6179                    break;
6180                }
6181
6182                case FORCE_GC: {
6183                    synchronized(mWindowMap) {
6184                        if (mAnimationPending) {
6185                            // If we are animating, don't do the gc now but
6186                            // delay a bit so we don't interrupt the animation.
6187                            mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
6188                                    2000);
6189                            return;
6190                        }
6191                        // If we are currently rotating the display, it will
6192                        // schedule a new message when done.
6193                        if (mDisplayFrozen) {
6194                            return;
6195                        }
6196                        mFreezeGcPending = 0;
6197                    }
6198                    Runtime.getRuntime().gc();
6199                    break;
6200                }
6201
6202                case ENABLE_SCREEN: {
6203                    performEnableScreen();
6204                    break;
6205                }
6206
6207                case APP_FREEZE_TIMEOUT: {
6208                    synchronized (mWindowMap) {
6209                        Slog.w(TAG, "App freeze timeout expired.");
6210                        int i = mAppTokens.size();
6211                        while (i > 0) {
6212                            i--;
6213                            AppWindowToken tok = mAppTokens.get(i);
6214                            if (tok.freezingScreen) {
6215                                Slog.w(TAG, "Force clearing freeze: " + tok);
6216                                unsetAppFreezingScreenLocked(tok, true, true);
6217                            }
6218                        }
6219                    }
6220                    break;
6221                }
6222
6223                case SEND_NEW_CONFIGURATION: {
6224                    removeMessages(SEND_NEW_CONFIGURATION);
6225                    sendNewConfiguration();
6226                    break;
6227                }
6228
6229                case REPORT_WINDOWS_CHANGE: {
6230                    if (mWindowsChanged) {
6231                        synchronized (mWindowMap) {
6232                            mWindowsChanged = false;
6233                        }
6234                        notifyWindowsChanged();
6235                    }
6236                    break;
6237                }
6238
6239                case DRAG_START_TIMEOUT: {
6240                    IBinder win = (IBinder)msg.obj;
6241                    if (DEBUG_DRAG) {
6242                        Slog.w(TAG, "Timeout starting drag by win " + win);
6243                    }
6244                    synchronized (mWindowMap) {
6245                        // !!! TODO: ANR the app that has failed to start the drag in time
6246                        if (mDragState != null) {
6247                            mDragState.unregister();
6248                            mInputMonitor.updateInputWindowsLw(true /*force*/);
6249                            mDragState.reset();
6250                            mDragState = null;
6251                        }
6252                    }
6253                    break;
6254                }
6255
6256                case DRAG_END_TIMEOUT: {
6257                    IBinder win = (IBinder)msg.obj;
6258                    if (DEBUG_DRAG) {
6259                        Slog.w(TAG, "Timeout ending drag to win " + win);
6260                    }
6261                    synchronized (mWindowMap) {
6262                        // !!! TODO: ANR the drag-receiving app
6263                        mDragState.mDragResult = false;
6264                        mDragState.endDragLw();
6265                    }
6266                    break;
6267                }
6268
6269                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
6270                    notifyHardKeyboardStatusChange();
6271                    break;
6272                }
6273            }
6274        }
6275    }
6276
6277    // -------------------------------------------------------------
6278    // IWindowManager API
6279    // -------------------------------------------------------------
6280
6281    public IWindowSession openSession(IInputMethodClient client,
6282            IInputContext inputContext) {
6283        if (client == null) throw new IllegalArgumentException("null client");
6284        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
6285        Session session = new Session(this, client, inputContext);
6286        return session;
6287    }
6288
6289    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
6290        synchronized (mWindowMap) {
6291            // The focus for the client is the window immediately below
6292            // where we would place the input method window.
6293            int idx = findDesiredInputMethodWindowIndexLocked(false);
6294            WindowState imFocus;
6295            if (idx > 0) {
6296                imFocus = mWindows.get(idx-1);
6297                //Log.i(TAG, "Desired input method target: " + imFocus);
6298                //Log.i(TAG, "Current focus: " + this.mCurrentFocus);
6299                //Log.i(TAG, "Last focus: " + this.mLastFocus);
6300                if (imFocus != null) {
6301                    // This may be a starting window, in which case we still want
6302                    // to count it as okay.
6303                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
6304                            && imFocus.mAppToken != null) {
6305                        // The client has definitely started, so it really should
6306                        // have a window in this app token.  Let's look for it.
6307                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
6308                            WindowState w = imFocus.mAppToken.windows.get(i);
6309                            if (w != imFocus) {
6310                                //Log.i(TAG, "Switching to real app window: " + w);
6311                                imFocus = w;
6312                                break;
6313                            }
6314                        }
6315                    }
6316                    //Log.i(TAG, "IM target client: " + imFocus.mSession.mClient);
6317                    //if (imFocus.mSession.mClient != null) {
6318                    //    Log.i(TAG, "IM target client binder: " + imFocus.mSession.mClient.asBinder());
6319                    //    Log.i(TAG, "Requesting client binder: " + client.asBinder());
6320                    //}
6321                    if (imFocus.mSession.mClient != null &&
6322                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
6323                        return true;
6324                    }
6325
6326                    // Okay, how about this...  what is the current focus?
6327                    // It seems in some cases we may not have moved the IM
6328                    // target window, such as when it was in a pop-up window,
6329                    // so let's also look at the current focus.  (An example:
6330                    // go to Gmail, start searching so the keyboard goes up,
6331                    // press home.  Sometimes the IME won't go down.)
6332                    // Would be nice to fix this more correctly, but it's
6333                    // way at the end of a release, and this should be good enough.
6334                    if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null &&
6335                            mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
6336                        return true;
6337                    }
6338                }
6339            }
6340        }
6341        return false;
6342    }
6343
6344    // -------------------------------------------------------------
6345    // Internals
6346    // -------------------------------------------------------------
6347
6348    final WindowState windowForClientLocked(Session session, IWindow client,
6349            boolean throwOnError) {
6350        return windowForClientLocked(session, client.asBinder(), throwOnError);
6351    }
6352
6353    final WindowState windowForClientLocked(Session session, IBinder client,
6354            boolean throwOnError) {
6355        WindowState win = mWindowMap.get(client);
6356        if (localLOGV) Slog.v(
6357            TAG, "Looking up client " + client + ": " + win);
6358        if (win == null) {
6359            RuntimeException ex = new IllegalArgumentException(
6360                    "Requested window " + client + " does not exist");
6361            if (throwOnError) {
6362                throw ex;
6363            }
6364            Slog.w(TAG, "Failed looking up window", ex);
6365            return null;
6366        }
6367        if (session != null && win.mSession != session) {
6368            RuntimeException ex = new IllegalArgumentException(
6369                    "Requested window " + client + " is in session " +
6370                    win.mSession + ", not " + session);
6371            if (throwOnError) {
6372                throw ex;
6373            }
6374            Slog.w(TAG, "Failed looking up window", ex);
6375            return null;
6376        }
6377
6378        return win;
6379    }
6380
6381    final void rebuildAppWindowListLocked() {
6382        int NW = mWindows.size();
6383        int i;
6384        int lastWallpaper = -1;
6385        int numRemoved = 0;
6386
6387        if (mRebuildTmp.length < NW) {
6388            mRebuildTmp = new WindowState[NW+10];
6389        }
6390
6391        // First remove all existing app windows.
6392        i=0;
6393        while (i < NW) {
6394            WindowState w = mWindows.get(i);
6395            if (w.mAppToken != null) {
6396                WindowState win = mWindows.remove(i);
6397                win.mRebuilding = true;
6398                mRebuildTmp[numRemoved] = win;
6399                mWindowsChanged = true;
6400                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
6401                        "Rebuild removing window: " + win);
6402                NW--;
6403                numRemoved++;
6404                continue;
6405            } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER
6406                    && lastWallpaper == i-1) {
6407                lastWallpaper = i;
6408            }
6409            i++;
6410        }
6411
6412        // The wallpaper window(s) typically live at the bottom of the stack,
6413        // so skip them before adding app tokens.
6414        lastWallpaper++;
6415        i = lastWallpaper;
6416
6417        // First add all of the exiting app tokens...  these are no longer
6418        // in the main app list, but still have windows shown.  We put them
6419        // in the back because now that the animation is over we no longer
6420        // will care about them.
6421        int NT = mExitingAppTokens.size();
6422        for (int j=0; j<NT; j++) {
6423            i = reAddAppWindowsLocked(i, mExitingAppTokens.get(j));
6424        }
6425
6426        // And add in the still active app tokens in Z order.
6427        NT = mAppTokens.size();
6428        for (int j=0; j<NT; j++) {
6429            i = reAddAppWindowsLocked(i, mAppTokens.get(j));
6430        }
6431
6432        i -= lastWallpaper;
6433        if (i != numRemoved) {
6434            Slog.w(TAG, "Rebuild removed " + numRemoved
6435                    + " windows but added " + i);
6436            for (i=0; i<numRemoved; i++) {
6437                WindowState ws = mRebuildTmp[i];
6438                if (ws.mRebuilding) {
6439                    StringWriter sw = new StringWriter();
6440                    PrintWriter pw = new PrintWriter(sw);
6441                    ws.dump(pw, "");
6442                    pw.flush();
6443                    Slog.w(TAG, "This window was lost: " + ws);
6444                    Slog.w(TAG, sw.toString());
6445                }
6446            }
6447            Slog.w(TAG, "Current app token list:");
6448            dumpAppTokensLocked();
6449            Slog.w(TAG, "Final window list:");
6450            dumpWindowsLocked();
6451        }
6452    }
6453
6454    private final void assignLayersLocked() {
6455        int N = mWindows.size();
6456        int curBaseLayer = 0;
6457        int curLayer = 0;
6458        int i;
6459
6460        if (DEBUG_LAYERS) {
6461            RuntimeException here = new RuntimeException("here");
6462            here.fillInStackTrace();
6463            Log.v(TAG, "Assigning layers", here);
6464        }
6465
6466        for (i=0; i<N; i++) {
6467            WindowState w = mWindows.get(i);
6468            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
6469                    || (i > 0 && w.mIsWallpaper)) {
6470                curLayer += WINDOW_LAYER_MULTIPLIER;
6471                w.mLayer = curLayer;
6472            } else {
6473                curBaseLayer = curLayer = w.mBaseLayer;
6474                w.mLayer = curLayer;
6475            }
6476            if (w.mTargetAppToken != null) {
6477                w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
6478            } else if (w.mAppToken != null) {
6479                w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
6480            } else {
6481                w.mAnimLayer = w.mLayer;
6482            }
6483            if (w.mIsImWindow) {
6484                w.mAnimLayer += mInputMethodAnimLayerAdjustment;
6485            } else if (w.mIsWallpaper) {
6486                w.mAnimLayer += mWallpaperAnimLayerAdjustment;
6487            }
6488            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
6489                    + w.mAnimLayer);
6490            //System.out.println(
6491            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
6492        }
6493    }
6494
6495    private boolean mInLayout = false;
6496    private final void performLayoutAndPlaceSurfacesLocked() {
6497        if (mInLayout) {
6498            if (DEBUG) {
6499                throw new RuntimeException("Recursive call!");
6500            }
6501            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
6502            return;
6503        }
6504
6505        if (mWaitingForConfig) {
6506            // Our configuration has changed (most likely rotation), but we
6507            // don't yet have the complete configuration to report to
6508            // applications.  Don't do any window layout until we have it.
6509            return;
6510        }
6511
6512        if (mDisplay == null) {
6513            // Not yet initialized, nothing to do.
6514            return;
6515        }
6516
6517        mInLayout = true;
6518        boolean recoveringMemory = false;
6519
6520        try {
6521            if (mForceRemoves != null) {
6522                recoveringMemory = true;
6523                // Wait a little bit for things to settle down, and off we go.
6524                for (int i=0; i<mForceRemoves.size(); i++) {
6525                    WindowState ws = mForceRemoves.get(i);
6526                    Slog.i(TAG, "Force removing: " + ws);
6527                    removeWindowInnerLocked(ws.mSession, ws);
6528                }
6529                mForceRemoves = null;
6530                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
6531                Object tmp = new Object();
6532                synchronized (tmp) {
6533                    try {
6534                        tmp.wait(250);
6535                    } catch (InterruptedException e) {
6536                    }
6537                }
6538            }
6539        } catch (RuntimeException e) {
6540            Slog.e(TAG, "Unhandled exception while force removing for memory", e);
6541        }
6542
6543        try {
6544            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
6545
6546            int N = mPendingRemove.size();
6547            if (N > 0) {
6548                if (mPendingRemoveTmp.length < N) {
6549                    mPendingRemoveTmp = new WindowState[N+10];
6550                }
6551                mPendingRemove.toArray(mPendingRemoveTmp);
6552                mPendingRemove.clear();
6553                for (int i=0; i<N; i++) {
6554                    WindowState w = mPendingRemoveTmp[i];
6555                    removeWindowInnerLocked(w.mSession, w);
6556                }
6557
6558                mInLayout = false;
6559                assignLayersLocked();
6560                mLayoutNeeded = true;
6561                performLayoutAndPlaceSurfacesLocked();
6562
6563            } else {
6564                mInLayout = false;
6565                if (mLayoutNeeded) {
6566                    requestAnimationLocked(0);
6567                }
6568            }
6569            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
6570                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
6571                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
6572            }
6573        } catch (RuntimeException e) {
6574            mInLayout = false;
6575            Slog.e(TAG, "Unhandled exception while layout out windows", e);
6576        }
6577    }
6578
6579    private final int performLayoutLockedInner(boolean initial, boolean updateInputWindows) {
6580        if (!mLayoutNeeded) {
6581            return 0;
6582        }
6583
6584        mLayoutNeeded = false;
6585
6586        final int dw = mDisplay.getWidth();
6587        final int dh = mDisplay.getHeight();
6588
6589        final int N = mWindows.size();
6590        int i;
6591
6592        if (DEBUG_LAYOUT) Slog.v(TAG, "performLayout: needed="
6593                + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
6594
6595        mPolicy.beginLayoutLw(dw, dh);
6596
6597        int seq = mLayoutSeq+1;
6598        if (seq < 0) seq = 0;
6599        mLayoutSeq = seq;
6600
6601        // First perform layout of any root windows (not attached
6602        // to another window).
6603        int topAttached = -1;
6604        for (i = N-1; i >= 0; i--) {
6605            WindowState win = mWindows.get(i);
6606
6607            // Don't do layout of a window if it is not visible, or
6608            // soon won't be visible, to avoid wasting time and funky
6609            // changes while a window is animating away.
6610            final AppWindowToken atoken = win.mAppToken;
6611            final boolean gone = win.mViewVisibility == View.GONE
6612                    || !win.mRelayoutCalled
6613                    || (atoken == null && win.mRootToken.hidden)
6614                    || (atoken != null && atoken.hiddenRequested)
6615                    || win.mAttachedHidden
6616                    || win.mExiting || win.mDestroying;
6617
6618            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
6619                Slog.v(TAG, "First pass " + win
6620                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
6621                        + " mLayoutAttached=" + win.mLayoutAttached);
6622                if (gone) Slog.v(TAG, "  (mViewVisibility="
6623                        + win.mViewVisibility + " mRelayoutCalled="
6624                        + win.mRelayoutCalled + " hidden="
6625                        + win.mRootToken.hidden + " hiddenRequested="
6626                        + (atoken != null && atoken.hiddenRequested)
6627                        + " mAttachedHidden=" + win.mAttachedHidden);
6628            }
6629
6630            // If this view is GONE, then skip it -- keep the current
6631            // frame, and let the caller know so they can ignore it
6632            // if they want.  (We do the normal layout for INVISIBLE
6633            // windows, since that means "perform layout as normal,
6634            // just don't display").
6635            if (!gone || !win.mHaveFrame) {
6636                if (!win.mLayoutAttached) {
6637                    if (initial) {
6638                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
6639                        win.mContentChanged = false;
6640                    }
6641                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
6642                    win.mLayoutSeq = seq;
6643                    if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
6644                            + win.mFrame + " mContainingFrame="
6645                            + win.mContainingFrame + " mDisplayFrame="
6646                            + win.mDisplayFrame);
6647                } else {
6648                    if (topAttached < 0) topAttached = i;
6649                }
6650            }
6651        }
6652
6653        // Now perform layout of attached windows, which usually
6654        // depend on the position of the window they are attached to.
6655        // XXX does not deal with windows that are attached to windows
6656        // that are themselves attached.
6657        for (i = topAttached; i >= 0; i--) {
6658            WindowState win = mWindows.get(i);
6659
6660            if (win.mLayoutAttached) {
6661                if (DEBUG_LAYOUT) Slog.v(TAG, "Second pass " + win
6662                        + " mHaveFrame=" + win.mHaveFrame
6663                        + " mViewVisibility=" + win.mViewVisibility
6664                        + " mRelayoutCalled=" + win.mRelayoutCalled);
6665                // If this view is GONE, then skip it -- keep the current
6666                // frame, and let the caller know so they can ignore it
6667                // if they want.  (We do the normal layout for INVISIBLE
6668                // windows, since that means "perform layout as normal,
6669                // just don't display").
6670                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
6671                        || !win.mHaveFrame) {
6672                    if (initial) {
6673                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
6674                        win.mContentChanged = false;
6675                    }
6676                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
6677                    win.mLayoutSeq = seq;
6678                    if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
6679                            + win.mFrame + " mContainingFrame="
6680                            + win.mContainingFrame + " mDisplayFrame="
6681                            + win.mDisplayFrame);
6682                }
6683            }
6684        }
6685
6686        // Window frames may have changed.  Tell the input dispatcher about it.
6687        mInputMonitor.setUpdateInputWindowsNeededLw();
6688        if (updateInputWindows) {
6689            mInputMonitor.updateInputWindowsLw(false /*force*/);
6690        }
6691
6692        return mPolicy.finishLayoutLw();
6693    }
6694
6695    // "Something has changed!  Let's make it correct now."
6696    private final void performLayoutAndPlaceSurfacesLockedInner(
6697            boolean recoveringMemory) {
6698        if (mDisplay == null) {
6699            Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
6700            return;
6701        }
6702
6703        final long currentTime = SystemClock.uptimeMillis();
6704        final int dw = mDisplay.getWidth();
6705        final int dh = mDisplay.getHeight();
6706
6707        int i;
6708
6709        if (mFocusMayChange) {
6710            mFocusMayChange = false;
6711            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
6712                    false /*updateInputWindows*/);
6713        }
6714
6715        // Initialize state of exiting tokens.
6716        for (i=mExitingTokens.size()-1; i>=0; i--) {
6717            mExitingTokens.get(i).hasVisible = false;
6718        }
6719
6720        // Initialize state of exiting applications.
6721        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
6722            mExitingAppTokens.get(i).hasVisible = false;
6723        }
6724
6725        boolean orientationChangeComplete = true;
6726        Session holdScreen = null;
6727        float screenBrightness = -1;
6728        float buttonBrightness = -1;
6729        boolean focusDisplayed = false;
6730        boolean animating = false;
6731        boolean createWatermark = false;
6732        boolean updateRotation = false;
6733        boolean screenRotationFinished = false;
6734
6735        if (mFxSession == null) {
6736            mFxSession = new SurfaceSession();
6737            createWatermark = true;
6738        }
6739
6740        if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
6741
6742        Surface.openTransaction();
6743
6744        if (createWatermark) {
6745            createWatermark();
6746        }
6747        if (mWatermark != null) {
6748            mWatermark.positionSurface(dw, dh);
6749        }
6750        if (mStrictModeFlash != null) {
6751            mStrictModeFlash.positionSurface(dw, dh);
6752        }
6753
6754        try {
6755            boolean wallpaperForceHidingChanged = false;
6756            int repeats = 0;
6757            int changes = 0;
6758
6759            do {
6760                repeats++;
6761                if (repeats > 6) {
6762                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
6763                    mLayoutNeeded = false;
6764                    break;
6765                }
6766
6767                if ((changes&(WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER
6768                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG
6769                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) {
6770                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
6771                        if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
6772                            assignLayersLocked();
6773                            mLayoutNeeded = true;
6774                        }
6775                    }
6776                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
6777                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
6778                        if (updateOrientationFromAppTokensLocked(true)) {
6779                            mLayoutNeeded = true;
6780                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6781                        }
6782                    }
6783                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
6784                        mLayoutNeeded = true;
6785                    }
6786                }
6787
6788                // FIRST LOOP: Perform a layout, if needed.
6789                if (repeats < 4) {
6790                    changes = performLayoutLockedInner(repeats == 0, false /*updateInputWindows*/);
6791                    if (changes != 0) {
6792                        continue;
6793                    }
6794                } else {
6795                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
6796                    changes = 0;
6797                }
6798
6799                final int transactionSequence = ++mTransactionSequence;
6800
6801                // Update animations of all applications, including those
6802                // associated with exiting/removed apps
6803                boolean tokensAnimating = false;
6804                final int NAT = mAppTokens.size();
6805                for (i=0; i<NAT; i++) {
6806                    if (mAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
6807                        tokensAnimating = true;
6808                    }
6809                }
6810                final int NEAT = mExitingAppTokens.size();
6811                for (i=0; i<NEAT; i++) {
6812                    if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime, dw, dh)) {
6813                        tokensAnimating = true;
6814                    }
6815                }
6816
6817                // SECOND LOOP: Execute animations and update visibility of windows.
6818
6819                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
6820                        + transactionSequence + " tokensAnimating="
6821                        + tokensAnimating);
6822
6823                animating = tokensAnimating;
6824
6825                if (mScreenRotationAnimation != null) {
6826                    if (mScreenRotationAnimation.isAnimating()) {
6827                        if (mScreenRotationAnimation.stepAnimation(currentTime)) {
6828                            animating = true;
6829                        } else {
6830                            screenRotationFinished = true;
6831                            updateRotation = true;
6832                        }
6833                    }
6834                }
6835
6836                boolean tokenMayBeDrawn = false;
6837                boolean wallpaperMayChange = false;
6838                boolean forceHiding = false;
6839                WindowState windowDetachedWallpaper = null;
6840                WindowState windowAnimationBackground = null;
6841                int windowAnimationBackgroundColor = 0;
6842
6843                mPolicy.beginAnimationLw(dw, dh);
6844
6845                final int N = mWindows.size();
6846
6847                for (i=N-1; i>=0; i--) {
6848                    WindowState w = mWindows.get(i);
6849
6850                    final WindowManager.LayoutParams attrs = w.mAttrs;
6851
6852                    if (w.mSurface != null) {
6853                        // Take care of the window being ready to display.
6854                        if (w.commitFinishDrawingLocked(currentTime)) {
6855                            if ((w.mAttrs.flags
6856                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
6857                                if (DEBUG_WALLPAPER) Slog.v(TAG,
6858                                        "First draw done in potential wallpaper target " + w);
6859                                wallpaperMayChange = true;
6860                            }
6861                        }
6862
6863                        final boolean wasAnimating = w.mAnimating;
6864
6865                        int animDw = dw;
6866                        int animDh = dh;
6867
6868                        // If the window has moved due to its containing
6869                        // content frame changing, then we'd like to animate
6870                        // it.  The checks here are ordered by what is least
6871                        // likely to be true first.
6872                        if (w.shouldAnimateMove()) {
6873                            // Frame has moved, containing content frame
6874                            // has also moved, and we're not currently animating...
6875                            // let's do something.
6876                            Animation a = AnimationUtils.loadAnimation(mContext,
6877                                    com.android.internal.R.anim.window_move_from_decor);
6878                            w.setAnimation(a);
6879                            animDw = w.mLastFrame.left - w.mFrame.left;
6880                            animDh = w.mLastFrame.top - w.mFrame.top;
6881                        }
6882
6883                        // Execute animation.
6884                        final boolean nowAnimating = w.stepAnimationLocked(currentTime,
6885                                animDw, animDh);
6886
6887                        // If this window is animating, make a note that we have
6888                        // an animating window and take care of a request to run
6889                        // a detached wallpaper animation.
6890                        if (nowAnimating) {
6891                            if (w.mAnimation != null) {
6892                                if (w.mAnimation.getDetachWallpaper()) {
6893                                    windowDetachedWallpaper = w;
6894                                }
6895                                if (w.mAnimation.getBackgroundColor() != 0) {
6896                                    windowAnimationBackground = w;
6897                                    windowAnimationBackgroundColor =
6898                                            w.mAnimation.getBackgroundColor();
6899                                }
6900                            }
6901                            animating = true;
6902                        }
6903
6904                        // If this window's app token is running a detached wallpaper
6905                        // animation, make a note so we can ensure the wallpaper is
6906                        // displayed behind it.
6907                        if (w.mAppToken != null && w.mAppToken.animation != null) {
6908                            if (w.mAppToken.animation.getDetachWallpaper()) {
6909                                windowDetachedWallpaper = w;
6910                            }
6911                            if (w.mAppToken.animation.getBackgroundColor() != 0) {
6912                                windowAnimationBackground = w;
6913                                windowAnimationBackgroundColor =
6914                                        w.mAppToken.animation.getBackgroundColor();
6915                            }
6916                        }
6917
6918                        if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
6919                            wallpaperMayChange = true;
6920                        }
6921
6922                        if (mPolicy.doesForceHide(w, attrs)) {
6923                            if (!wasAnimating && nowAnimating) {
6924                                if (DEBUG_VISIBILITY) Slog.v(TAG,
6925                                        "Animation started that could impact force hide: "
6926                                        + w);
6927                                wallpaperForceHidingChanged = true;
6928                                mFocusMayChange = true;
6929                            } else if (w.isReadyForDisplay() && w.mAnimation == null) {
6930                                forceHiding = true;
6931                            }
6932                        } else if (mPolicy.canBeForceHidden(w, attrs)) {
6933                            boolean changed;
6934                            if (forceHiding) {
6935                                changed = w.hideLw(false, false);
6936                                if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
6937                                        "Now policy hidden: " + w);
6938                            } else {
6939                                changed = w.showLw(false, false);
6940                                if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
6941                                        "Now policy shown: " + w);
6942                                if (changed) {
6943                                    if (wallpaperForceHidingChanged
6944                                            && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
6945                                        // Assume we will need to animate.  If
6946                                        // we don't (because the wallpaper will
6947                                        // stay with the lock screen), then we will
6948                                        // clean up later.
6949                                        Animation a = mPolicy.createForceHideEnterAnimation();
6950                                        if (a != null) {
6951                                            w.setAnimation(a);
6952                                        }
6953                                    }
6954                                    if (mCurrentFocus == null ||
6955                                            mCurrentFocus.mLayer < w.mLayer) {
6956                                        // We are showing on to of the current
6957                                        // focus, so re-evaluate focus to make
6958                                        // sure it is correct.
6959                                        mFocusMayChange = true;
6960                                    }
6961                                }
6962                            }
6963                            if (changed && (attrs.flags
6964                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
6965                                wallpaperMayChange = true;
6966                            }
6967                        }
6968
6969                        mPolicy.animatingWindowLw(w, attrs);
6970                    }
6971
6972                    final AppWindowToken atoken = w.mAppToken;
6973                    if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
6974                        if (atoken.lastTransactionSequence != transactionSequence) {
6975                            atoken.lastTransactionSequence = transactionSequence;
6976                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
6977                            atoken.startingDisplayed = false;
6978                        }
6979                        if ((w.isOnScreen() || w.mAttrs.type
6980                                == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
6981                                && !w.mExiting && !w.mDestroying) {
6982                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
6983                                Slog.v(TAG, "Eval win " + w + ": isDrawn="
6984                                        + w.isDrawnLw()
6985                                        + ", isAnimating=" + w.isAnimating());
6986                                if (!w.isDrawnLw()) {
6987                                    Slog.v(TAG, "Not displayed: s=" + w.mSurface
6988                                            + " pv=" + w.mPolicyVisibility
6989                                            + " dp=" + w.mDrawPending
6990                                            + " cdp=" + w.mCommitDrawPending
6991                                            + " ah=" + w.mAttachedHidden
6992                                            + " th=" + atoken.hiddenRequested
6993                                            + " a=" + w.mAnimating);
6994                                }
6995                            }
6996                            if (w != atoken.startingWindow) {
6997                                if (!atoken.freezingScreen || !w.mAppFreezing) {
6998                                    atoken.numInterestingWindows++;
6999                                    if (w.isDrawnLw()) {
7000                                        atoken.numDrawnWindows++;
7001                                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
7002                                                "tokenMayBeDrawn: " + atoken
7003                                                + " freezingScreen=" + atoken.freezingScreen
7004                                                + " mAppFreezing=" + w.mAppFreezing);
7005                                        tokenMayBeDrawn = true;
7006                                    }
7007                                }
7008                            } else if (w.isDrawnLw()) {
7009                                atoken.startingDisplayed = true;
7010                            }
7011                        }
7012                    } else if (w.mReadyToShow) {
7013                        w.performShowLocked();
7014                    }
7015                }
7016
7017                changes |= mPolicy.finishAnimationLw();
7018
7019                if (tokenMayBeDrawn) {
7020                    // See if any windows have been drawn, so they (and others
7021                    // associated with them) can now be shown.
7022                    final int NT = mAppTokens.size();
7023                    for (i=0; i<NT; i++) {
7024                        AppWindowToken wtoken = mAppTokens.get(i);
7025                        if (wtoken.freezingScreen) {
7026                            int numInteresting = wtoken.numInterestingWindows;
7027                            if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7028                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7029                                        "allDrawn: " + wtoken
7030                                        + " interesting=" + numInteresting
7031                                        + " drawn=" + wtoken.numDrawnWindows);
7032                                wtoken.showAllWindowsLocked();
7033                                unsetAppFreezingScreenLocked(wtoken, false, true);
7034                                orientationChangeComplete = true;
7035                            }
7036                        } else if (!wtoken.allDrawn) {
7037                            int numInteresting = wtoken.numInterestingWindows;
7038                            if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7039                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7040                                        "allDrawn: " + wtoken
7041                                        + " interesting=" + numInteresting
7042                                        + " drawn=" + wtoken.numDrawnWindows);
7043                                wtoken.allDrawn = true;
7044                                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
7045
7046                                // We can now show all of the drawn windows!
7047                                if (!mOpeningApps.contains(wtoken)) {
7048                                    wtoken.showAllWindowsLocked();
7049                                }
7050                            }
7051                        }
7052                    }
7053                }
7054
7055                // If we are ready to perform an app transition, check through
7056                // all of the app tokens to be shown and see if they are ready
7057                // to go.
7058                if (mAppTransitionReady) {
7059                    int NN = mOpeningApps.size();
7060                    boolean goodToGo = true;
7061                    if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7062                            "Checking " + NN + " opening apps (frozen="
7063                            + mDisplayFrozen + " timeout="
7064                            + mAppTransitionTimeout + ")...");
7065                    if (!mDisplayFrozen && !mAppTransitionTimeout) {
7066                        // If the display isn't frozen, wait to do anything until
7067                        // all of the apps are ready.  Otherwise just go because
7068                        // we'll unfreeze the display when everyone is ready.
7069                        for (i=0; i<NN && goodToGo; i++) {
7070                            AppWindowToken wtoken = mOpeningApps.get(i);
7071                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7072                                    "Check opening app" + wtoken + ": allDrawn="
7073                                    + wtoken.allDrawn + " startingDisplayed="
7074                                    + wtoken.startingDisplayed);
7075                            if (!wtoken.allDrawn && !wtoken.startingDisplayed
7076                                    && !wtoken.startingMoved) {
7077                                goodToGo = false;
7078                            }
7079                        }
7080                    }
7081                    if (goodToGo) {
7082                        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
7083                        int transit = mNextAppTransition;
7084                        if (mSkipAppTransitionAnimation) {
7085                            transit = WindowManagerPolicy.TRANSIT_UNSET;
7086                        }
7087                        mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
7088                        mAppTransitionReady = false;
7089                        mAppTransitionRunning = true;
7090                        mAppTransitionTimeout = false;
7091                        mStartingIconInTransition = false;
7092                        mSkipAppTransitionAnimation = false;
7093
7094                        mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
7095
7096                        // If there are applications waiting to come to the
7097                        // top of the stack, now is the time to move their windows.
7098                        // (Note that we don't do apps going to the bottom
7099                        // here -- we want to keep their windows in the old
7100                        // Z-order until the animation completes.)
7101                        if (mToTopApps.size() > 0) {
7102                            NN = mAppTokens.size();
7103                            for (i=0; i<NN; i++) {
7104                                AppWindowToken wtoken = mAppTokens.get(i);
7105                                if (wtoken.sendingToTop) {
7106                                    wtoken.sendingToTop = false;
7107                                    moveAppWindowsLocked(wtoken, NN, false);
7108                                }
7109                            }
7110                            mToTopApps.clear();
7111                        }
7112
7113                        WindowState oldWallpaper = mWallpaperTarget;
7114
7115                        adjustWallpaperWindowsLocked();
7116                        wallpaperMayChange = false;
7117
7118                        // The top-most window will supply the layout params,
7119                        // and we will determine it below.
7120                        LayoutParams animLp = null;
7121                        int bestAnimLayer = -1;
7122                        boolean fullscreenAnim = false;
7123
7124                        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7125                                "New wallpaper target=" + mWallpaperTarget
7126                                + ", lower target=" + mLowerWallpaperTarget
7127                                + ", upper target=" + mUpperWallpaperTarget);
7128                        int foundWallpapers = 0;
7129                        // Do a first pass through the tokens for two
7130                        // things:
7131                        // (1) Determine if both the closing and opening
7132                        // app token sets are wallpaper targets, in which
7133                        // case special animations are needed
7134                        // (since the wallpaper needs to stay static
7135                        // behind them).
7136                        // (2) Find the layout params of the top-most
7137                        // application window in the tokens, which is
7138                        // what will control the animation theme.
7139                        final int NC = mClosingApps.size();
7140                        NN = NC + mOpeningApps.size();
7141                        for (i=0; i<NN; i++) {
7142                            AppWindowToken wtoken;
7143                            int mode;
7144                            if (i < NC) {
7145                                wtoken = mClosingApps.get(i);
7146                                mode = 1;
7147                            } else {
7148                                wtoken = mOpeningApps.get(i-NC);
7149                                mode = 2;
7150                            }
7151                            if (mLowerWallpaperTarget != null) {
7152                                if (mLowerWallpaperTarget.mAppToken == wtoken
7153                                        || mUpperWallpaperTarget.mAppToken == wtoken) {
7154                                    foundWallpapers |= mode;
7155                                }
7156                            }
7157                            if (wtoken.appFullscreen) {
7158                                WindowState ws = wtoken.findMainWindow();
7159                                if (ws != null) {
7160                                    // If this is a compatibility mode
7161                                    // window, we will always use its anim.
7162                                    if ((ws.mAttrs.flags&FLAG_COMPATIBLE_WINDOW) != 0) {
7163                                        animLp = ws.mAttrs;
7164                                        bestAnimLayer = Integer.MAX_VALUE;
7165                                    } else if (!fullscreenAnim || ws.mLayer > bestAnimLayer) {
7166                                        animLp = ws.mAttrs;
7167                                        bestAnimLayer = ws.mLayer;
7168                                    }
7169                                    fullscreenAnim = true;
7170                                }
7171                            } else if (!fullscreenAnim) {
7172                                WindowState ws = wtoken.findMainWindow();
7173                                if (ws != null) {
7174                                    if (ws.mLayer > bestAnimLayer) {
7175                                        animLp = ws.mAttrs;
7176                                        bestAnimLayer = ws.mLayer;
7177                                    }
7178                                }
7179                            }
7180                        }
7181
7182                        if (foundWallpapers == 3) {
7183                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7184                                    "Wallpaper animation!");
7185                            switch (transit) {
7186                                case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
7187                                case WindowManagerPolicy.TRANSIT_TASK_OPEN:
7188                                case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
7189                                    transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
7190                                    break;
7191                                case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
7192                                case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
7193                                case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
7194                                    transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
7195                                    break;
7196                            }
7197                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7198                                    "New transit: " + transit);
7199                        } else if (oldWallpaper != null) {
7200                            // We are transitioning from an activity with
7201                            // a wallpaper to one without.
7202                            transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
7203                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7204                                    "New transit away from wallpaper: " + transit);
7205                        } else if (mWallpaperTarget != null) {
7206                            // We are transitioning from an activity without
7207                            // a wallpaper to now showing the wallpaper
7208                            transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
7209                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7210                                    "New transit into wallpaper: " + transit);
7211                        }
7212
7213                        // If all closing windows are obscured, then there is
7214                        // no need to do an animation.  This is the case, for
7215                        // example, when this transition is being done behind
7216                        // the lock screen.
7217                        if (!mPolicy.allowAppAnimationsLw()) {
7218                            animLp = null;
7219                        }
7220
7221                        NN = mOpeningApps.size();
7222                        for (i=0; i<NN; i++) {
7223                            AppWindowToken wtoken = mOpeningApps.get(i);
7224                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7225                                    "Now opening app" + wtoken);
7226                            wtoken.reportedVisible = false;
7227                            wtoken.inPendingTransaction = false;
7228                            wtoken.animation = null;
7229                            setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
7230                            wtoken.updateReportedVisibilityLocked();
7231                            wtoken.waitingToShow = false;
7232                            wtoken.showAllWindowsLocked();
7233                        }
7234                        NN = mClosingApps.size();
7235                        for (i=0; i<NN; i++) {
7236                            AppWindowToken wtoken = mClosingApps.get(i);
7237                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7238                                    "Now closing app" + wtoken);
7239                            wtoken.inPendingTransaction = false;
7240                            wtoken.animation = null;
7241                            setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
7242                            wtoken.updateReportedVisibilityLocked();
7243                            wtoken.waitingToHide = false;
7244                            // Force the allDrawn flag, because we want to start
7245                            // this guy's animations regardless of whether it's
7246                            // gotten drawn.
7247                            wtoken.allDrawn = true;
7248                        }
7249
7250                        mNextAppTransitionPackage = null;
7251
7252                        mOpeningApps.clear();
7253                        mClosingApps.clear();
7254
7255                        // This has changed the visibility of windows, so perform
7256                        // a new layout to get them all up-to-date.
7257                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
7258                                | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
7259                        mLayoutNeeded = true;
7260                        if (!moveInputMethodWindowsIfNeededLocked(true)) {
7261                            assignLayersLocked();
7262                        }
7263                        updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
7264                                false /*updateInputWindows*/);
7265                        mFocusMayChange = false;
7266                    }
7267                }
7268
7269                int adjResult = 0;
7270
7271                if (!animating && mAppTransitionRunning) {
7272                    // We have finished the animation of an app transition.  To do
7273                    // this, we have delayed a lot of operations like showing and
7274                    // hiding apps, moving apps in Z-order, etc.  The app token list
7275                    // reflects the correct Z-order, but the window list may now
7276                    // be out of sync with it.  So here we will just rebuild the
7277                    // entire app window list.  Fun!
7278                    mAppTransitionRunning = false;
7279                    // Clear information about apps that were moving.
7280                    mToBottomApps.clear();
7281
7282                    rebuildAppWindowListLocked();
7283                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
7284                    adjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
7285                    moveInputMethodWindowsIfNeededLocked(false);
7286                    wallpaperMayChange = true;
7287                    // Since the window list has been rebuilt, focus might
7288                    // have to be recomputed since the actual order of windows
7289                    // might have changed again.
7290                    mFocusMayChange = true;
7291                }
7292
7293                if (wallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) {
7294                    // At this point, there was a window with a wallpaper that
7295                    // was force hiding other windows behind it, but now it
7296                    // is going away.  This may be simple -- just animate
7297                    // away the wallpaper and its window -- or it may be
7298                    // hard -- the wallpaper now needs to be shown behind
7299                    // something that was hidden.
7300                    WindowState oldWallpaper = mWallpaperTarget;
7301                    if (mLowerWallpaperTarget != null
7302                            && mLowerWallpaperTarget.mAppToken != null) {
7303                        if (DEBUG_WALLPAPER) Slog.v(TAG,
7304                                "wallpaperForceHiding changed with lower="
7305                                + mLowerWallpaperTarget);
7306                        if (DEBUG_WALLPAPER) Slog.v(TAG,
7307                                "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
7308                                " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
7309                        if (mLowerWallpaperTarget.mAppToken.hidden) {
7310                            // The lower target has become hidden before we
7311                            // actually started the animation...  let's completely
7312                            // re-evaluate everything.
7313                            mLowerWallpaperTarget = mUpperWallpaperTarget = null;
7314                            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
7315                        }
7316                    }
7317                    adjResult |= adjustWallpaperWindowsLocked();
7318                    wallpaperMayChange = false;
7319                    wallpaperForceHidingChanged = false;
7320                    if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
7321                            + " NEW: " + mWallpaperTarget
7322                            + " LOWER: " + mLowerWallpaperTarget);
7323                    if (mLowerWallpaperTarget == null) {
7324                        // Whoops, we don't need a special wallpaper animation.
7325                        // Clear them out.
7326                        forceHiding = false;
7327                        for (i=N-1; i>=0; i--) {
7328                            WindowState w = mWindows.get(i);
7329                            if (w.mSurface != null) {
7330                                final WindowManager.LayoutParams attrs = w.mAttrs;
7331                                if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
7332                                    if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
7333                                    forceHiding = true;
7334                                } else if (mPolicy.canBeForceHidden(w, attrs)) {
7335                                    if (!w.mAnimating) {
7336                                        // We set the animation above so it
7337                                        // is not yet running.
7338                                        w.clearAnimation();
7339                                    }
7340                                }
7341                            }
7342                        }
7343                    }
7344                }
7345
7346                if (mWindowDetachedWallpaper != windowDetachedWallpaper) {
7347                    if (DEBUG_WALLPAPER) Slog.v(TAG,
7348                            "Detached wallpaper changed from " + mWindowDetachedWallpaper
7349                            + windowDetachedWallpaper);
7350                    mWindowDetachedWallpaper = windowDetachedWallpaper;
7351                    wallpaperMayChange = true;
7352                }
7353
7354                if (windowAnimationBackgroundColor != 0) {
7355                    if (mWindowAnimationBackgroundSurface == null) {
7356                        mWindowAnimationBackgroundSurface = new DimSurface(mFxSession);
7357                    }
7358                    mWindowAnimationBackgroundSurface.show(dw, dh,
7359                            windowAnimationBackground.mAnimLayer - LAYER_OFFSET_DIM,
7360                            windowAnimationBackgroundColor);
7361                } else if (mWindowAnimationBackgroundSurface != null) {
7362                    mWindowAnimationBackgroundSurface.hide();
7363                }
7364
7365                if (wallpaperMayChange) {
7366                    if (DEBUG_WALLPAPER) Slog.v(TAG,
7367                            "Wallpaper may change!  Adjusting");
7368                    adjResult |= adjustWallpaperWindowsLocked();
7369                }
7370
7371                if ((adjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
7372                    if (DEBUG_WALLPAPER) Slog.v(TAG,
7373                            "Wallpaper layer changed: assigning layers + relayout");
7374                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
7375                    assignLayersLocked();
7376                } else if ((adjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
7377                    if (DEBUG_WALLPAPER) Slog.v(TAG,
7378                            "Wallpaper visibility changed: relayout");
7379                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
7380                }
7381
7382                if (mFocusMayChange) {
7383                    mFocusMayChange = false;
7384                    if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
7385                            false /*updateInputWindows*/)) {
7386                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
7387                        adjResult = 0;
7388                    }
7389                }
7390
7391                if (mLayoutNeeded) {
7392                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
7393                }
7394
7395                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
7396                        + Integer.toHexString(changes));
7397            } while (changes != 0);
7398
7399            // THIRD LOOP: Update the surfaces of all windows.
7400
7401            final boolean someoneLosingFocus = mLosingFocus.size() != 0;
7402
7403            boolean obscured = false;
7404            boolean blurring = false;
7405            boolean dimming = false;
7406            boolean covered = false;
7407            boolean syswin = false;
7408            boolean backgroundFillerWasShown = mBackgroundFillerTarget != null;
7409            mBackgroundFillerTarget = null;
7410
7411            final int N = mWindows.size();
7412
7413            for (i=N-1; i>=0; i--) {
7414                WindowState w = mWindows.get(i);
7415
7416                boolean displayed = false;
7417                final WindowManager.LayoutParams attrs = w.mAttrs;
7418                final int attrFlags = attrs.flags;
7419
7420                if (w.mSurface != null) {
7421                    // XXX NOTE: The logic here could be improved.  We have
7422                    // the decision about whether to resize a window separated
7423                    // from whether to hide the surface.  This can cause us to
7424                    // resize a surface even if we are going to hide it.  You
7425                    // can see this by (1) holding device in landscape mode on
7426                    // home screen; (2) tapping browser icon (device will rotate
7427                    // to landscape; (3) tap home.  The wallpaper will be resized
7428                    // in step 2 but then immediately hidden, causing us to
7429                    // have to resize and then redraw it again in step 3.  It
7430                    // would be nice to figure out how to avoid this, but it is
7431                    // difficult because we do need to resize surfaces in some
7432                    // cases while they are hidden such as when first showing a
7433                    // window.
7434
7435                    w.computeShownFrameLocked();
7436                    if (localLOGV) Slog.v(
7437                            TAG, "Placing surface #" + i + " " + w.mSurface
7438                            + ": new=" + w.mShownFrame + ", old="
7439                            + w.mLastShownFrame);
7440
7441                    int width, height;
7442                    if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
7443                        // for a scaled surface, we just want to use
7444                        // the requested size.
7445                        width  = w.mRequestedWidth;
7446                        height = w.mRequestedHeight;
7447                        w.mLastRequestedWidth = width;
7448                        w.mLastRequestedHeight = height;
7449                        w.mLastShownFrame.set(w.mShownFrame);
7450                    } else {
7451                        width = w.mShownFrame.width();
7452                        height = w.mShownFrame.height();
7453                        w.mLastShownFrame.set(w.mShownFrame);
7454                    }
7455
7456                    if (w.mSurface != null) {
7457                        if (w.mSurfaceX != w.mShownFrame.left
7458                                || w.mSurfaceY != w.mShownFrame.top) {
7459                            try {
7460                                if (SHOW_TRANSACTIONS) logSurface(w,
7461                                        "POS " + w.mShownFrame.left
7462                                        + ", " + w.mShownFrame.top, null);
7463                                w.mSurfaceX = w.mShownFrame.left;
7464                                w.mSurfaceY = w.mShownFrame.top;
7465                                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
7466                            } catch (RuntimeException e) {
7467                                Slog.w(TAG, "Error positioning surface of " + w
7468                                        + " pos=(" + w.mShownFrame.left
7469                                        + "," + w.mShownFrame.top + ")", e);
7470                                if (!recoveringMemory) {
7471                                    reclaimSomeSurfaceMemoryLocked(w, "position", true);
7472                                }
7473                            }
7474                        }
7475
7476                        if (width < 1) {
7477                            width = 1;
7478                        }
7479                        if (height < 1) {
7480                            height = 1;
7481                        }
7482
7483                        if (w.mSurfaceW != width || w.mSurfaceH != height) {
7484                            try {
7485                                if (SHOW_TRANSACTIONS) logSurface(w,
7486                                        "SIZE " + w.mShownFrame.width() + "x"
7487                                        + w.mShownFrame.height(), null);
7488                                w.mSurfaceResized = true;
7489                                w.mSurfaceW = width;
7490                                w.mSurfaceH = height;
7491                                w.mSurface.setSize(width, height);
7492                            } catch (RuntimeException e) {
7493                                // If something goes wrong with the surface (such
7494                                // as running out of memory), don't take down the
7495                                // entire system.
7496                                Slog.e(TAG, "Error resizing surface of " + w
7497                                        + " size=(" + width + "x" + height + ")", e);
7498                                if (!recoveringMemory) {
7499                                    reclaimSomeSurfaceMemoryLocked(w, "size", true);
7500                                }
7501                            }
7502                        }
7503                    }
7504
7505                    if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
7506                        w.mContentInsetsChanged =
7507                            !w.mLastContentInsets.equals(w.mContentInsets);
7508                        w.mVisibleInsetsChanged =
7509                            !w.mLastVisibleInsets.equals(w.mVisibleInsets);
7510                        boolean configChanged =
7511                            w.mConfiguration != mCurConfiguration
7512                            && (w.mConfiguration == null
7513                                    || mCurConfiguration.diff(w.mConfiguration) != 0);
7514                        if (DEBUG_CONFIGURATION && configChanged) {
7515                            Slog.v(TAG, "Win " + w + " config changed: "
7516                                    + mCurConfiguration);
7517                        }
7518                        if (localLOGV) Slog.v(TAG, "Resizing " + w
7519                                + ": configChanged=" + configChanged
7520                                + " last=" + w.mLastFrame + " frame=" + w.mFrame);
7521                        boolean frameChanged = !w.mLastFrame.equals(w.mFrame);
7522                        if (frameChanged
7523                                || w.mContentInsetsChanged
7524                                || w.mVisibleInsetsChanged
7525                                || w.mSurfaceResized
7526                                || configChanged) {
7527                            if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
7528                                Slog.v(TAG, "Resize reasons: "
7529                                        + "frameChanged=" + frameChanged
7530                                        + " contentInsetsChanged=" + w.mContentInsetsChanged
7531                                        + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
7532                                        + " surfaceResized=" + w.mSurfaceResized
7533                                        + " configChanged=" + configChanged);
7534                            }
7535
7536                            w.mLastFrame.set(w.mFrame);
7537                            w.mLastContentInsets.set(w.mContentInsets);
7538                            w.mLastVisibleInsets.set(w.mVisibleInsets);
7539                            // If the screen is currently frozen, then keep
7540                            // it frozen until this window draws at its new
7541                            // orientation.
7542                            if (mDisplayFrozen) {
7543                                if (DEBUG_ORIENTATION) Slog.v(TAG,
7544                                        "Resizing while display frozen: " + w);
7545                                w.mOrientationChanging = true;
7546                                if (!mWindowsFreezingScreen) {
7547                                    mWindowsFreezingScreen = true;
7548                                    // XXX should probably keep timeout from
7549                                    // when we first froze the display.
7550                                    mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
7551                                    mH.sendMessageDelayed(mH.obtainMessage(
7552                                            H.WINDOW_FREEZE_TIMEOUT), 2000);
7553                                }
7554                            }
7555                            // If the orientation is changing, then we need to
7556                            // hold off on unfreezing the display until this
7557                            // window has been redrawn; to do that, we need
7558                            // to go through the process of getting informed
7559                            // by the application when it has finished drawing.
7560                            if (w.mOrientationChanging) {
7561                                if (DEBUG_ORIENTATION) Slog.v(TAG,
7562                                        "Orientation start waiting for draw in "
7563                                        + w + ", surface " + w.mSurface);
7564                                w.mDrawPending = true;
7565                                w.mCommitDrawPending = false;
7566                                w.mReadyToShow = false;
7567                                if (w.mAppToken != null) {
7568                                    w.mAppToken.allDrawn = false;
7569                                }
7570                            }
7571                            if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
7572                                    "Resizing window " + w + " to " + w.mFrame);
7573                            mResizingWindows.add(w);
7574                        } else if (w.mOrientationChanging) {
7575                            if (!w.mDrawPending && !w.mCommitDrawPending) {
7576                                if (DEBUG_ORIENTATION) Slog.v(TAG,
7577                                        "Orientation not waiting for draw in "
7578                                        + w + ", surface " + w.mSurface);
7579                                w.mOrientationChanging = false;
7580                            }
7581                        }
7582                    }
7583
7584                    if (w.mAttachedHidden || !w.isReadyForDisplay()) {
7585                        if (!w.mLastHidden) {
7586                            //dump();
7587                            w.mLastHidden = true;
7588                            if (SHOW_TRANSACTIONS) logSurface(w,
7589                                    "HIDE (performLayout)", null);
7590                            if (w.mSurface != null) {
7591                                w.mSurfaceShown = false;
7592                                try {
7593                                    w.mSurface.hide();
7594                                } catch (RuntimeException e) {
7595                                    Slog.w(TAG, "Exception hiding surface in " + w);
7596                                }
7597                            }
7598                        }
7599                        // If we are waiting for this window to handle an
7600                        // orientation change, well, it is hidden, so
7601                        // doesn't really matter.  Note that this does
7602                        // introduce a potential glitch if the window
7603                        // becomes unhidden before it has drawn for the
7604                        // new orientation.
7605                        if (w.mOrientationChanging) {
7606                            w.mOrientationChanging = false;
7607                            if (DEBUG_ORIENTATION) Slog.v(TAG,
7608                                    "Orientation change skips hidden " + w);
7609                        }
7610                    } else if (w.mLastLayer != w.mAnimLayer
7611                            || w.mLastAlpha != w.mShownAlpha
7612                            || w.mLastDsDx != w.mDsDx
7613                            || w.mLastDtDx != w.mDtDx
7614                            || w.mLastDsDy != w.mDsDy
7615                            || w.mLastDtDy != w.mDtDy
7616                            || w.mLastHScale != w.mHScale
7617                            || w.mLastVScale != w.mVScale
7618                            || w.mLastHidden) {
7619                        displayed = true;
7620                        w.mLastAlpha = w.mShownAlpha;
7621                        w.mLastLayer = w.mAnimLayer;
7622                        w.mLastDsDx = w.mDsDx;
7623                        w.mLastDtDx = w.mDtDx;
7624                        w.mLastDsDy = w.mDsDy;
7625                        w.mLastDtDy = w.mDtDy;
7626                        w.mLastHScale = w.mHScale;
7627                        w.mLastVScale = w.mVScale;
7628                        if (SHOW_TRANSACTIONS) logSurface(w,
7629                                "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
7630                                + " matrix=[" + (w.mDsDx*w.mHScale)
7631                                + "," + (w.mDtDx*w.mVScale)
7632                                + "][" + (w.mDsDy*w.mHScale)
7633                                + "," + (w.mDtDy*w.mVScale) + "]", null);
7634                        if (w.mSurface != null) {
7635                            try {
7636                                w.mSurfaceAlpha = w.mShownAlpha;
7637                                w.mSurface.setAlpha(w.mShownAlpha);
7638                                w.mSurfaceLayer = w.mAnimLayer;
7639                                w.mSurface.setLayer(w.mAnimLayer);
7640                                w.mSurface.setMatrix(
7641                                        w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
7642                                        w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
7643                            } catch (RuntimeException e) {
7644                                Slog.w(TAG, "Error updating surface in " + w, e);
7645                                if (!recoveringMemory) {
7646                                    reclaimSomeSurfaceMemoryLocked(w, "update", true);
7647                                }
7648                            }
7649                        }
7650
7651                        if (w.mLastHidden && !w.mDrawPending
7652                                && !w.mCommitDrawPending
7653                                && !w.mReadyToShow) {
7654                            if (SHOW_TRANSACTIONS) logSurface(w,
7655                                    "SHOW (performLayout)", null);
7656                            if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
7657                                    + " during relayout");
7658                            if (showSurfaceRobustlyLocked(w)) {
7659                                w.mHasDrawn = true;
7660                                w.mLastHidden = false;
7661                            } else {
7662                                w.mOrientationChanging = false;
7663                            }
7664                        }
7665                        if (w.mSurface != null) {
7666                            w.mToken.hasVisible = true;
7667                        }
7668                    } else {
7669                        displayed = true;
7670                    }
7671
7672                    if (displayed) {
7673                        if (!covered) {
7674                            if (attrs.width == LayoutParams.MATCH_PARENT
7675                                    && attrs.height == LayoutParams.MATCH_PARENT) {
7676                                covered = true;
7677                            }
7678                        }
7679                        if (w.mOrientationChanging) {
7680                            if (w.mDrawPending || w.mCommitDrawPending) {
7681                                orientationChangeComplete = false;
7682                                if (DEBUG_ORIENTATION) Slog.v(TAG,
7683                                        "Orientation continue waiting for draw in " + w);
7684                            } else {
7685                                w.mOrientationChanging = false;
7686                                if (DEBUG_ORIENTATION) Slog.v(TAG,
7687                                        "Orientation change complete in " + w);
7688                            }
7689                        }
7690                        w.mToken.hasVisible = true;
7691                    }
7692                } else if (w.mOrientationChanging) {
7693                    if (DEBUG_ORIENTATION) Slog.v(TAG,
7694                            "Orientation change skips hidden " + w);
7695                    w.mOrientationChanging = false;
7696                }
7697
7698                if (w.mContentChanged) {
7699                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
7700                    w.mContentChanged = false;
7701                }
7702
7703                final boolean canBeSeen = w.isDisplayedLw();
7704
7705                if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
7706                    focusDisplayed = true;
7707                }
7708
7709                final boolean obscuredChanged = w.mObscured != obscured;
7710
7711                if (mBackgroundFillerTarget != null) {
7712                    if (w.isAnimating()) {
7713                        // Background filler is below all other windows that
7714                        // are animating.
7715                        mBackgroundFillerTarget = w;
7716                    } else if (w.mIsWallpaper) {
7717                        mBackgroundFillerTarget = w;
7718                    }
7719                }
7720
7721                // Update effect.
7722                if (!(w.mObscured=obscured)) {
7723                    if (w.mSurface != null) {
7724                        if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
7725                            holdScreen = w.mSession;
7726                        }
7727                        if (!syswin && w.mAttrs.screenBrightness >= 0
7728                                && screenBrightness < 0) {
7729                            screenBrightness = w.mAttrs.screenBrightness;
7730                        }
7731                        if (!syswin && w.mAttrs.buttonBrightness >= 0
7732                                && buttonBrightness < 0) {
7733                            buttonBrightness = w.mAttrs.buttonBrightness;
7734                        }
7735                        if (canBeSeen
7736                                && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
7737                                 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
7738                                 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
7739                            syswin = true;
7740                        }
7741                    }
7742
7743                    boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
7744                    if (opaqueDrawn && w.isFullscreen(dw, dh)) {
7745                        // This window completely covers everything behind it,
7746                        // so we want to leave all of them as unblurred (for
7747                        // performance reasons).
7748                        obscured = true;
7749                    } else if (w.needsBackgroundFiller(dw, dh) && (canBeSeen || w.isAnimating())) {
7750                        // This window is in compatibility mode, and needs background filler.
7751                        obscured = true;
7752                        mBackgroundFillerTarget = w;
7753                    } else if (canBeSeen && !obscured &&
7754                            (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
7755                        if (localLOGV) Slog.v(TAG, "Win " + w
7756                                + ": blurring=" + blurring
7757                                + " obscured=" + obscured
7758                                + " displayed=" + displayed);
7759                        if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
7760                            if (!dimming) {
7761                                //Slog.i(TAG, "DIM BEHIND: " + w);
7762                                dimming = true;
7763                                if (mDimAnimator == null) {
7764                                    mDimAnimator = new DimAnimator(mFxSession);
7765                                }
7766                                mDimAnimator.show(dw, dh);
7767                                mDimAnimator.updateParameters(mContext.getResources(),
7768                                        w, currentTime);
7769                            }
7770                        }
7771                        if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
7772                            if (!blurring) {
7773                                //Slog.i(TAG, "BLUR BEHIND: " + w);
7774                                blurring = true;
7775                                if (mBlurSurface == null) {
7776                                    try {
7777                                        mBlurSurface = new Surface(mFxSession, 0,
7778                                                "BlurSurface",
7779                                                -1, 16, 16,
7780                                                PixelFormat.OPAQUE,
7781                                                Surface.FX_SURFACE_BLUR);
7782                                    } catch (Exception e) {
7783                                        Slog.e(TAG, "Exception creating Blur surface", e);
7784                                    }
7785                                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
7786                                            + mBlurSurface + ": CREATE");
7787                                }
7788                                if (mBlurSurface != null) {
7789                                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
7790                                            + mBlurSurface + ": pos=(0,0) (" +
7791                                            dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
7792                                    mBlurSurface.setPosition(0, 0);
7793                                    mBlurSurface.setSize(dw, dh);
7794                                    mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR);
7795                                    if (!mBlurShown) {
7796                                        try {
7797                                            if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
7798                                                    + mBlurSurface + ": SHOW");
7799                                            mBlurSurface.show();
7800                                        } catch (RuntimeException e) {
7801                                            Slog.w(TAG, "Failure showing blur surface", e);
7802                                        }
7803                                        mBlurShown = true;
7804                                    }
7805                                }
7806                            }
7807                        }
7808                    }
7809                }
7810
7811                if (obscuredChanged && mWallpaperTarget == w) {
7812                    // This is the wallpaper target and its obscured state
7813                    // changed... make sure the current wallaper's visibility
7814                    // has been updated accordingly.
7815                    updateWallpaperVisibilityLocked();
7816                }
7817            }
7818
7819            if (mBackgroundFillerTarget != null) {
7820                if (mBackgroundFillerSurface == null) {
7821                    try {
7822                        mBackgroundFillerSurface = new Surface(mFxSession, 0,
7823                                "BackGroundFiller",
7824                                0, dw, dh,
7825                                PixelFormat.OPAQUE,
7826                                Surface.FX_SURFACE_NORMAL);
7827                    } catch (Exception e) {
7828                        Slog.e(TAG, "Exception creating filler surface", e);
7829                    }
7830                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BG FILLER "
7831                            + mBackgroundFillerSurface + ": CREATE");
7832                }
7833                try {
7834                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BG FILLER "
7835                            + mBackgroundFillerSurface + " SHOW: pos=(0,0) ("
7836                            + dw + "x" + dh + ") layer="
7837                            + (mBackgroundFillerTarget.mLayer - 1));
7838                    mBackgroundFillerSurface.setPosition(0, 0);
7839                    mBackgroundFillerSurface.setSize(dw, dh);
7840                    // Using the same layer as Dim because they will never be shown at the
7841                    // same time.  NOTE: we do NOT use mAnimLayer, because we don't
7842                    // want this surface dragged up in front of stuff that is animating.
7843                    mBackgroundFillerSurface.setLayer(mBackgroundFillerTarget.mLayer
7844                            - LAYER_OFFSET_DIM);
7845                    mBackgroundFillerSurface.show();
7846                } catch (RuntimeException e) {
7847                    Slog.e(TAG, "Exception showing filler surface");
7848                }
7849            } else if (backgroundFillerWasShown) {
7850                mBackgroundFillerTarget = null;
7851                if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BG FILLER "
7852                        + mBackgroundFillerSurface + " HIDE");
7853                try {
7854                    mBackgroundFillerSurface.hide();
7855                } catch (RuntimeException e) {
7856                    Slog.e(TAG, "Exception hiding filler surface", e);
7857                }
7858            }
7859
7860            if (mDimAnimator != null && mDimAnimator.mDimShown) {
7861                animating |= mDimAnimator.updateSurface(dimming, currentTime,
7862                        mDisplayFrozen || !mPolicy.isScreenOn());
7863            }
7864
7865            if (!blurring && mBlurShown) {
7866                if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR " + mBlurSurface
7867                        + ": HIDE");
7868                try {
7869                    mBlurSurface.hide();
7870                } catch (IllegalArgumentException e) {
7871                    Slog.w(TAG, "Illegal argument exception hiding blur surface");
7872                }
7873                mBlurShown = false;
7874            }
7875        } catch (RuntimeException e) {
7876            Slog.e(TAG, "Unhandled exception in Window Manager", e);
7877        }
7878
7879        Surface.closeTransaction();
7880
7881        if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
7882
7883        if (mWatermark != null) {
7884            mWatermark.drawIfNeeded();
7885        }
7886
7887        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
7888                "With display frozen, orientationChangeComplete="
7889                + orientationChangeComplete);
7890        if (orientationChangeComplete) {
7891            if (mWindowsFreezingScreen) {
7892                mWindowsFreezingScreen = false;
7893                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
7894            }
7895            stopFreezingDisplayLocked();
7896        }
7897
7898        i = mResizingWindows.size();
7899        if (i > 0) {
7900            do {
7901                i--;
7902                WindowState win = mResizingWindows.get(i);
7903                try {
7904                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
7905                            "Reporting new frame to " + win + ": " + win.mFrame);
7906                    int diff = 0;
7907                    boolean configChanged =
7908                        win.mConfiguration != mCurConfiguration
7909                        && (win.mConfiguration == null
7910                                || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0);
7911                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
7912                            && configChanged) {
7913                        Slog.i(TAG, "Sending new config to window " + win + ": "
7914                                + win.mFrame.width() + "x" + win.mFrame.height()
7915                                + " / " + mCurConfiguration + " / 0x"
7916                                + Integer.toHexString(diff));
7917                    }
7918                    win.mConfiguration = mCurConfiguration;
7919                    win.mClient.resized(win.mFrame.width(),
7920                            win.mFrame.height(), win.mLastContentInsets,
7921                            win.mLastVisibleInsets, win.mDrawPending,
7922                            configChanged ? win.mConfiguration : null);
7923                    win.mContentInsetsChanged = false;
7924                    win.mVisibleInsetsChanged = false;
7925                    win.mSurfaceResized = false;
7926                } catch (RemoteException e) {
7927                    win.mOrientationChanging = false;
7928                }
7929            } while (i > 0);
7930            mResizingWindows.clear();
7931        }
7932
7933        // Destroy the surface of any windows that are no longer visible.
7934        boolean wallpaperDestroyed = false;
7935        i = mDestroySurface.size();
7936        if (i > 0) {
7937            do {
7938                i--;
7939                WindowState win = mDestroySurface.get(i);
7940                win.mDestroying = false;
7941                if (mInputMethodWindow == win) {
7942                    mInputMethodWindow = null;
7943                }
7944                if (win == mWallpaperTarget) {
7945                    wallpaperDestroyed = true;
7946                }
7947                win.destroySurfaceLocked();
7948            } while (i > 0);
7949            mDestroySurface.clear();
7950        }
7951
7952        // Time to remove any exiting tokens?
7953        for (i=mExitingTokens.size()-1; i>=0; i--) {
7954            WindowToken token = mExitingTokens.get(i);
7955            if (!token.hasVisible) {
7956                mExitingTokens.remove(i);
7957                if (token.windowType == TYPE_WALLPAPER) {
7958                    mWallpaperTokens.remove(token);
7959                }
7960            }
7961        }
7962
7963        // Time to remove any exiting applications?
7964        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
7965            AppWindowToken token = mExitingAppTokens.get(i);
7966            if (!token.hasVisible && !mClosingApps.contains(token)) {
7967                // Make sure there is no animation running on this token,
7968                // so any windows associated with it will be removed as
7969                // soon as their animations are complete
7970                token.animation = null;
7971                token.animating = false;
7972                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
7973                        "performLayout: App token exiting now removed" + token);
7974                mAppTokens.remove(token);
7975                mExitingAppTokens.remove(i);
7976            }
7977        }
7978
7979        boolean needRelayout = false;
7980
7981        if (!animating && mAppTransitionRunning) {
7982            // We have finished the animation of an app transition.  To do
7983            // this, we have delayed a lot of operations like showing and
7984            // hiding apps, moving apps in Z-order, etc.  The app token list
7985            // reflects the correct Z-order, but the window list may now
7986            // be out of sync with it.  So here we will just rebuild the
7987            // entire app window list.  Fun!
7988            mAppTransitionRunning = false;
7989            needRelayout = true;
7990            rebuildAppWindowListLocked();
7991            assignLayersLocked();
7992            // Clear information about apps that were moving.
7993            mToBottomApps.clear();
7994        }
7995
7996        if (focusDisplayed) {
7997            mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
7998        }
7999        if (wallpaperDestroyed) {
8000            needRelayout = adjustWallpaperWindowsLocked() != 0;
8001        }
8002        if (needRelayout) {
8003            requestAnimationLocked(0);
8004        } else if (animating) {
8005            requestAnimationLocked(currentTime+(1000/60)-SystemClock.uptimeMillis());
8006        }
8007
8008        // Finally update all input windows now that the window changes have stabilized.
8009        mInputMonitor.updateInputWindowsLw(true /*force*/);
8010
8011        setHoldScreenLocked(holdScreen != null);
8012        if (!mDisplayFrozen) {
8013            if (screenBrightness < 0 || screenBrightness > 1.0f) {
8014                mPowerManager.setScreenBrightnessOverride(-1);
8015            } else {
8016                mPowerManager.setScreenBrightnessOverride((int)
8017                        (screenBrightness * Power.BRIGHTNESS_ON));
8018            }
8019            if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
8020                mPowerManager.setButtonBrightnessOverride(-1);
8021            } else {
8022                mPowerManager.setButtonBrightnessOverride((int)
8023                        (buttonBrightness * Power.BRIGHTNESS_ON));
8024            }
8025        }
8026        if (holdScreen != mHoldingScreenOn) {
8027            mHoldingScreenOn = holdScreen;
8028            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
8029            mH.sendMessage(m);
8030        }
8031
8032        if (mTurnOnScreen) {
8033            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
8034            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
8035                    LocalPowerManager.BUTTON_EVENT, true);
8036            mTurnOnScreen = false;
8037        }
8038
8039        if (screenRotationFinished && mScreenRotationAnimation != null) {
8040            mScreenRotationAnimation.kill();
8041            mScreenRotationAnimation = null;
8042        }
8043
8044        if (updateRotation) {
8045            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8046            boolean changed = setRotationUncheckedLocked(
8047                    WindowManagerPolicy.USE_LAST_ROTATION, 0, false);
8048            if (changed) {
8049                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8050            }
8051        }
8052
8053        // Check to see if we are now in a state where the screen should
8054        // be enabled, because the window obscured flags have changed.
8055        enableScreenIfNeededLocked();
8056    }
8057
8058    /**
8059     * Must be called with the main window manager lock held.
8060     */
8061    void setHoldScreenLocked(boolean holding) {
8062        boolean state = mHoldingScreenWakeLock.isHeld();
8063        if (holding != state) {
8064            if (holding) {
8065                mHoldingScreenWakeLock.acquire();
8066            } else {
8067                mPolicy.screenOnStoppedLw();
8068                mHoldingScreenWakeLock.release();
8069            }
8070        }
8071    }
8072
8073    void requestAnimationLocked(long delay) {
8074        if (!mAnimationPending) {
8075            mAnimationPending = true;
8076            mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
8077        }
8078    }
8079
8080    /**
8081     * Have the surface flinger show a surface, robustly dealing with
8082     * error conditions.  In particular, if there is not enough memory
8083     * to show the surface, then we will try to get rid of other surfaces
8084     * in order to succeed.
8085     *
8086     * @return Returns true if the surface was successfully shown.
8087     */
8088    boolean showSurfaceRobustlyLocked(WindowState win) {
8089        try {
8090            if (win.mSurface != null) {
8091                win.mSurfaceShown = true;
8092                win.mSurface.show();
8093                if (win.mTurnOnScreen) {
8094                    if (DEBUG_VISIBILITY) Slog.v(TAG,
8095                            "Show surface turning screen on: " + win);
8096                    win.mTurnOnScreen = false;
8097                    mTurnOnScreen = true;
8098                }
8099            }
8100            return true;
8101        } catch (RuntimeException e) {
8102            Slog.w(TAG, "Failure showing surface " + win.mSurface + " in " + win, e);
8103        }
8104
8105        reclaimSomeSurfaceMemoryLocked(win, "show", true);
8106
8107        return false;
8108    }
8109
8110    boolean reclaimSomeSurfaceMemoryLocked(WindowState win, String operation, boolean secure) {
8111        final Surface surface = win.mSurface;
8112        boolean leakedSurface = false;
8113        boolean killedApps = false;
8114
8115        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, win.toString(),
8116                win.mSession.mPid, operation);
8117
8118        if (mForceRemoves == null) {
8119            mForceRemoves = new ArrayList<WindowState>();
8120        }
8121
8122        long callingIdentity = Binder.clearCallingIdentity();
8123        try {
8124            // There was some problem...   first, do a sanity check of the
8125            // window list to make sure we haven't left any dangling surfaces
8126            // around.
8127            int N = mWindows.size();
8128            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
8129            for (int i=0; i<N; i++) {
8130                WindowState ws = mWindows.get(i);
8131                if (ws.mSurface != null) {
8132                    if (!mSessions.contains(ws.mSession)) {
8133                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8134                                + ws + " surface=" + ws.mSurface
8135                                + " token=" + win.mToken
8136                                + " pid=" + ws.mSession.mPid
8137                                + " uid=" + ws.mSession.mUid);
8138                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8139                        ws.mSurface.destroy();
8140                        ws.mSurfaceShown = false;
8141                        ws.mSurface = null;
8142                        mForceRemoves.add(ws);
8143                        i--;
8144                        N--;
8145                        leakedSurface = true;
8146                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
8147                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
8148                                + ws + " surface=" + ws.mSurface
8149                                + " token=" + win.mAppToken);
8150                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8151                        ws.mSurface.destroy();
8152                        ws.mSurfaceShown = false;
8153                        ws.mSurface = null;
8154                        leakedSurface = true;
8155                    }
8156                }
8157            }
8158
8159            if (!leakedSurface) {
8160                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
8161                SparseIntArray pidCandidates = new SparseIntArray();
8162                for (int i=0; i<N; i++) {
8163                    WindowState ws = mWindows.get(i);
8164                    if (ws.mSurface != null) {
8165                        pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
8166                    }
8167                }
8168                if (pidCandidates.size() > 0) {
8169                    int[] pids = new int[pidCandidates.size()];
8170                    for (int i=0; i<pids.length; i++) {
8171                        pids[i] = pidCandidates.keyAt(i);
8172                    }
8173                    try {
8174                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
8175                            killedApps = true;
8176                        }
8177                    } catch (RemoteException e) {
8178                    }
8179                }
8180            }
8181
8182            if (leakedSurface || killedApps) {
8183                // We managed to reclaim some memory, so get rid of the trouble
8184                // surface and ask the app to request another one.
8185                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
8186                if (surface != null) {
8187                    if (SHOW_TRANSACTIONS) logSurface(win, "RECOVER DESTROY", null);
8188                    surface.destroy();
8189                    win.mSurfaceShown = false;
8190                    win.mSurface = null;
8191                }
8192
8193                try {
8194                    win.mClient.dispatchGetNewSurface();
8195                } catch (RemoteException e) {
8196                }
8197            }
8198        } finally {
8199            Binder.restoreCallingIdentity(callingIdentity);
8200        }
8201
8202        return leakedSurface || killedApps;
8203    }
8204
8205    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
8206        WindowState newFocus = computeFocusedWindowLocked();
8207        if (mCurrentFocus != newFocus) {
8208            // This check makes sure that we don't already have the focus
8209            // change message pending.
8210            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
8211            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
8212            if (localLOGV) Slog.v(
8213                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
8214            final WindowState oldFocus = mCurrentFocus;
8215            mCurrentFocus = newFocus;
8216            mLosingFocus.remove(newFocus);
8217
8218            final WindowState imWindow = mInputMethodWindow;
8219            if (newFocus != imWindow && oldFocus != imWindow) {
8220                if (moveInputMethodWindowsIfNeededLocked(
8221                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
8222                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
8223                    mLayoutNeeded = true;
8224                }
8225                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
8226                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
8227                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
8228                    // Client will do the layout, but we need to assign layers
8229                    // for handleNewWindowLocked() below.
8230                    assignLayersLocked();
8231                }
8232            }
8233
8234            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
8235                // If we defer assigning layers, then the caller is responsible for
8236                // doing this part.
8237                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
8238            }
8239            return true;
8240        }
8241        return false;
8242    }
8243
8244    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
8245        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
8246    }
8247
8248    private WindowState computeFocusedWindowLocked() {
8249        WindowState result = null;
8250        WindowState win;
8251
8252        int i = mWindows.size() - 1;
8253        int nextAppIndex = mAppTokens.size()-1;
8254        WindowToken nextApp = nextAppIndex >= 0
8255            ? mAppTokens.get(nextAppIndex) : null;
8256
8257        while (i >= 0) {
8258            win = mWindows.get(i);
8259
8260            if (localLOGV || DEBUG_FOCUS) Slog.v(
8261                TAG, "Looking for focus: " + i
8262                + " = " + win
8263                + ", flags=" + win.mAttrs.flags
8264                + ", canReceive=" + win.canReceiveKeys());
8265
8266            AppWindowToken thisApp = win.mAppToken;
8267
8268            // If this window's application has been removed, just skip it.
8269            if (thisApp != null && thisApp.removed) {
8270                i--;
8271                continue;
8272            }
8273
8274            // If there is a focused app, don't allow focus to go to any
8275            // windows below it.  If this is an application window, step
8276            // through the app tokens until we find its app.
8277            if (thisApp != null && nextApp != null && thisApp != nextApp
8278                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
8279                int origAppIndex = nextAppIndex;
8280                while (nextAppIndex > 0) {
8281                    if (nextApp == mFocusedApp) {
8282                        // Whoops, we are below the focused app...  no focus
8283                        // for you!
8284                        if (localLOGV || DEBUG_FOCUS) Slog.v(
8285                            TAG, "Reached focused app: " + mFocusedApp);
8286                        return null;
8287                    }
8288                    nextAppIndex--;
8289                    nextApp = mAppTokens.get(nextAppIndex);
8290                    if (nextApp == thisApp) {
8291                        break;
8292                    }
8293                }
8294                if (thisApp != nextApp) {
8295                    // Uh oh, the app token doesn't exist!  This shouldn't
8296                    // happen, but if it does we can get totally hosed...
8297                    // so restart at the original app.
8298                    nextAppIndex = origAppIndex;
8299                    nextApp = mAppTokens.get(nextAppIndex);
8300                }
8301            }
8302
8303            // Dispatch to this window if it is wants key events.
8304            if (win.canReceiveKeys()) {
8305                if (DEBUG_FOCUS) Slog.v(
8306                        TAG, "Found focus @ " + i + " = " + win);
8307                result = win;
8308                break;
8309            }
8310
8311            i--;
8312        }
8313
8314        return result;
8315    }
8316
8317    private void startFreezingDisplayLocked(boolean inTransaction) {
8318        if (mDisplayFrozen) {
8319            return;
8320        }
8321
8322        mScreenFrozenLock.acquire();
8323
8324        long now = SystemClock.uptimeMillis();
8325        //Slog.i(TAG, "Freezing, gc pending: " + mFreezeGcPending + ", now " + now);
8326        if (mFreezeGcPending != 0) {
8327            if (now > (mFreezeGcPending+1000)) {
8328                //Slog.i(TAG, "Gc!  " + now + " > " + (mFreezeGcPending+1000));
8329                mH.removeMessages(H.FORCE_GC);
8330                Runtime.getRuntime().gc();
8331                mFreezeGcPending = now;
8332            }
8333        } else {
8334            mFreezeGcPending = now;
8335        }
8336
8337        mDisplayFrozen = true;
8338
8339        mInputMonitor.freezeInputDispatchingLw();
8340
8341        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
8342            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
8343            mNextAppTransitionPackage = null;
8344            mAppTransitionReady = true;
8345        }
8346
8347        if (PROFILE_ORIENTATION) {
8348            File file = new File("/data/system/frozen");
8349            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
8350        }
8351
8352        if (CUSTOM_SCREEN_ROTATION) {
8353            if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
8354                mScreenRotationAnimation.kill();
8355                mScreenRotationAnimation = null;
8356            }
8357            if (mScreenRotationAnimation == null) {
8358                mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
8359                        mDisplay, mFxSession, inTransaction);
8360            }
8361            if (!mScreenRotationAnimation.hasScreenshot()) {
8362                Surface.freezeDisplay(0);
8363            }
8364        } else {
8365            Surface.freezeDisplay(0);
8366        }
8367    }
8368
8369    private void stopFreezingDisplayLocked() {
8370        if (!mDisplayFrozen) {
8371            return;
8372        }
8373
8374        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
8375            return;
8376        }
8377
8378        mDisplayFrozen = false;
8379        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
8380        if (PROFILE_ORIENTATION) {
8381            Debug.stopMethodTracing();
8382        }
8383
8384        boolean updateRotation = false;
8385
8386        if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
8387                && mScreenRotationAnimation.hasScreenshot()) {
8388            if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
8389                    mTransitionAnimationScale)) {
8390                requestAnimationLocked(0);
8391            } else {
8392                mScreenRotationAnimation = null;
8393                updateRotation = true;
8394            }
8395        } else {
8396            if (mScreenRotationAnimation != null) {
8397                mScreenRotationAnimation.kill();
8398                mScreenRotationAnimation = null;
8399            }
8400            updateRotation = true;
8401            Surface.unfreezeDisplay(0);
8402        }
8403
8404        mInputMonitor.thawInputDispatchingLw();
8405
8406        boolean configChanged;
8407
8408        // While the display is frozen we don't re-compute the orientation
8409        // to avoid inconsistent states.  However, something interesting
8410        // could have actually changed during that time so re-evaluate it
8411        // now to catch that.
8412        configChanged = updateOrientationFromAppTokensLocked(false);
8413
8414        // A little kludge: a lot could have happened while the
8415        // display was frozen, so now that we are coming back we
8416        // do a gc so that any remote references the system
8417        // processes holds on others can be released if they are
8418        // no longer needed.
8419        mH.removeMessages(H.FORCE_GC);
8420        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
8421                2000);
8422
8423        mScreenFrozenLock.release();
8424
8425        if (updateRotation) {
8426            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8427            configChanged |= setRotationUncheckedLocked(
8428                    WindowManagerPolicy.USE_LAST_ROTATION, 0, false);
8429        }
8430
8431        if (configChanged) {
8432            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8433        }
8434    }
8435
8436    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
8437            DisplayMetrics dm) {
8438        if (index < tokens.length) {
8439            String str = tokens[index];
8440            if (str != null && str.length() > 0) {
8441                try {
8442                    int val = Integer.parseInt(str);
8443                    return val;
8444                } catch (Exception e) {
8445                }
8446            }
8447        }
8448        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
8449            return defDps;
8450        }
8451        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
8452        return val;
8453    }
8454
8455    void createWatermark() {
8456        if (mWatermark != null) {
8457            return;
8458        }
8459
8460        File file = new File("/system/etc/setup.conf");
8461        FileInputStream in = null;
8462        try {
8463            in = new FileInputStream(file);
8464            DataInputStream ind = new DataInputStream(in);
8465            String line = ind.readLine();
8466            if (line != null) {
8467                String[] toks = line.split("%");
8468                if (toks != null && toks.length > 0) {
8469                    mWatermark = new Watermark(mDisplay, mFxSession, toks);
8470                }
8471            }
8472        } catch (FileNotFoundException e) {
8473        } catch (IOException e) {
8474        } finally {
8475            if (in != null) {
8476                try {
8477                    in.close();
8478                } catch (IOException e) {
8479                }
8480            }
8481        }
8482    }
8483
8484    @Override
8485    public void statusBarVisibilityChanged(int visibility) {
8486        mInputManager.setSystemUiVisibility(visibility);
8487        synchronized (mWindowMap) {
8488            final int N = mWindows.size();
8489            for (int i = 0; i < N; i++) {
8490                WindowState ws = mWindows.get(i);
8491                try {
8492                    if (ws.getAttrs().hasSystemUiListeners) {
8493                        ws.mClient.dispatchSystemUiVisibilityChanged(visibility);
8494                    }
8495                } catch (RemoteException e) {
8496                    // so sorry
8497                }
8498            }
8499        }
8500    }
8501
8502    @Override
8503    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8504        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
8505                != PackageManager.PERMISSION_GRANTED) {
8506            pw.println("Permission Denial: can't dump WindowManager from from pid="
8507                    + Binder.getCallingPid()
8508                    + ", uid=" + Binder.getCallingUid());
8509            return;
8510        }
8511
8512        mInputManager.dump(pw);
8513        pw.println(" ");
8514
8515        synchronized(mWindowMap) {
8516            pw.println("Current Window Manager state:");
8517            for (int i=mWindows.size()-1; i>=0; i--) {
8518                WindowState w = mWindows.get(i);
8519                pw.print("  Window #"); pw.print(i); pw.print(' ');
8520                        pw.print(w); pw.println(":");
8521                w.dump(pw, "    ");
8522            }
8523            if (mInputMethodDialogs.size() > 0) {
8524                pw.println(" ");
8525                pw.println("  Input method dialogs:");
8526                for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
8527                    WindowState w = mInputMethodDialogs.get(i);
8528                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
8529                }
8530            }
8531            if (mPendingRemove.size() > 0) {
8532                pw.println(" ");
8533                pw.println("  Remove pending for:");
8534                for (int i=mPendingRemove.size()-1; i>=0; i--) {
8535                    WindowState w = mPendingRemove.get(i);
8536                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
8537                            pw.print(w); pw.println(":");
8538                    w.dump(pw, "    ");
8539                }
8540            }
8541            if (mForceRemoves != null && mForceRemoves.size() > 0) {
8542                pw.println(" ");
8543                pw.println("  Windows force removing:");
8544                for (int i=mForceRemoves.size()-1; i>=0; i--) {
8545                    WindowState w = mForceRemoves.get(i);
8546                    pw.print("  Removing #"); pw.print(i); pw.print(' ');
8547                            pw.print(w); pw.println(":");
8548                    w.dump(pw, "    ");
8549                }
8550            }
8551            if (mDestroySurface.size() > 0) {
8552                pw.println(" ");
8553                pw.println("  Windows waiting to destroy their surface:");
8554                for (int i=mDestroySurface.size()-1; i>=0; i--) {
8555                    WindowState w = mDestroySurface.get(i);
8556                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
8557                            pw.print(w); pw.println(":");
8558                    w.dump(pw, "    ");
8559                }
8560            }
8561            if (mLosingFocus.size() > 0) {
8562                pw.println(" ");
8563                pw.println("  Windows losing focus:");
8564                for (int i=mLosingFocus.size()-1; i>=0; i--) {
8565                    WindowState w = mLosingFocus.get(i);
8566                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
8567                            pw.print(w); pw.println(":");
8568                    w.dump(pw, "    ");
8569                }
8570            }
8571            if (mResizingWindows.size() > 0) {
8572                pw.println(" ");
8573                pw.println("  Windows waiting to resize:");
8574                for (int i=mResizingWindows.size()-1; i>=0; i--) {
8575                    WindowState w = mResizingWindows.get(i);
8576                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
8577                            pw.print(w); pw.println(":");
8578                    w.dump(pw, "    ");
8579                }
8580            }
8581            if (mSessions.size() > 0) {
8582                pw.println(" ");
8583                pw.println("  All active sessions:");
8584                Iterator<Session> it = mSessions.iterator();
8585                while (it.hasNext()) {
8586                    Session s = it.next();
8587                    pw.print("  Session "); pw.print(s); pw.println(':');
8588                    s.dump(pw, "    ");
8589                }
8590            }
8591            if (mTokenMap.size() > 0) {
8592                pw.println(" ");
8593                pw.println("  All tokens:");
8594                Iterator<WindowToken> it = mTokenMap.values().iterator();
8595                while (it.hasNext()) {
8596                    WindowToken token = it.next();
8597                    pw.print("  Token "); pw.print(token.token); pw.println(':');
8598                    token.dump(pw, "    ");
8599                }
8600            }
8601            if (mWallpaperTokens.size() > 0) {
8602                pw.println(" ");
8603                pw.println("  Wallpaper tokens:");
8604                for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
8605                    WindowToken token = mWallpaperTokens.get(i);
8606                    pw.print("  Wallpaper #"); pw.print(i);
8607                            pw.print(' '); pw.print(token); pw.println(':');
8608                    token.dump(pw, "    ");
8609                }
8610            }
8611            if (mAppTokens.size() > 0) {
8612                pw.println(" ");
8613                pw.println("  Application tokens in Z order:");
8614                for (int i=mAppTokens.size()-1; i>=0; i--) {
8615                    pw.print("  App #"); pw.print(i); pw.print(": ");
8616                            pw.println(mAppTokens.get(i));
8617                }
8618            }
8619            if (mFinishedStarting.size() > 0) {
8620                pw.println(" ");
8621                pw.println("  Finishing start of application tokens:");
8622                for (int i=mFinishedStarting.size()-1; i>=0; i--) {
8623                    WindowToken token = mFinishedStarting.get(i);
8624                    pw.print("  Finished Starting #"); pw.print(i);
8625                            pw.print(' '); pw.print(token); pw.println(':');
8626                    token.dump(pw, "    ");
8627                }
8628            }
8629            if (mExitingTokens.size() > 0) {
8630                pw.println(" ");
8631                pw.println("  Exiting tokens:");
8632                for (int i=mExitingTokens.size()-1; i>=0; i--) {
8633                    WindowToken token = mExitingTokens.get(i);
8634                    pw.print("  Exiting #"); pw.print(i);
8635                            pw.print(' '); pw.print(token); pw.println(':');
8636                    token.dump(pw, "    ");
8637                }
8638            }
8639            if (mExitingAppTokens.size() > 0) {
8640                pw.println(" ");
8641                pw.println("  Exiting application tokens:");
8642                for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
8643                    WindowToken token = mExitingAppTokens.get(i);
8644                    pw.print("  Exiting App #"); pw.print(i);
8645                            pw.print(' '); pw.print(token); pw.println(':');
8646                    token.dump(pw, "    ");
8647                }
8648            }
8649            pw.println(" ");
8650            pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
8651            pw.print("  mLastFocus="); pw.println(mLastFocus);
8652            pw.print("  mFocusedApp="); pw.println(mFocusedApp);
8653            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
8654            pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
8655            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
8656            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
8657                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
8658                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
8659            }
8660            if (mWindowDetachedWallpaper != null) {
8661                pw.print("  mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper);
8662            }
8663            if (mWindowAnimationBackgroundSurface != null) {
8664                pw.println("  mWindowAnimationBackgroundSurface:");
8665                mWindowAnimationBackgroundSurface.printTo("    ", pw);
8666            }
8667            pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
8668            pw.print("  mInTouchMode="); pw.print(mInTouchMode);
8669                    pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
8670            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
8671                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
8672            pw.print("  mLayoutNeeded="); pw.print(mLayoutNeeded);
8673                    pw.print(" mBlurShown="); pw.println(mBlurShown);
8674            if (mDimAnimator != null) {
8675                pw.println("  mDimAnimator:");
8676                mDimAnimator.printTo("    ", pw);
8677            } else {
8678                pw.println( "  no DimAnimator ");
8679            }
8680            pw.print("  mInputMethodAnimLayerAdjustment=");
8681                    pw.print(mInputMethodAnimLayerAdjustment);
8682                    pw.print("  mWallpaperAnimLayerAdjustment=");
8683                    pw.println(mWallpaperAnimLayerAdjustment);
8684            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
8685                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
8686            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
8687                    pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
8688                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
8689                    pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
8690            pw.print("  mRotation="); pw.print(mRotation);
8691                    pw.print(", mForcedAppOrientation="); pw.print(mForcedAppOrientation);
8692                    pw.print(", mRequestedRotation="); pw.println(mRequestedRotation);
8693            pw.print("  mDeferredRotation="); pw.print(mDeferredRotation);
8694                    pw.print(", mDeferredRotationAnimFlags="); pw.print(mDeferredRotationAnimFlags);
8695            pw.print("  mAnimationPending="); pw.print(mAnimationPending);
8696                    pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
8697                    pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
8698            pw.print("  mNextAppTransition=0x");
8699                    pw.print(Integer.toHexString(mNextAppTransition));
8700                    pw.print(", mAppTransitionReady="); pw.print(mAppTransitionReady);
8701                    pw.print(", mAppTransitionRunning="); pw.print(mAppTransitionRunning);
8702                    pw.print(", mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
8703            if (mNextAppTransitionPackage != null) {
8704                pw.print("  mNextAppTransitionPackage=");
8705                    pw.print(mNextAppTransitionPackage);
8706                    pw.print(", mNextAppTransitionEnter=0x");
8707                    pw.print(Integer.toHexString(mNextAppTransitionEnter));
8708                    pw.print(", mNextAppTransitionExit=0x");
8709                    pw.print(Integer.toHexString(mNextAppTransitionExit));
8710            }
8711            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
8712                    pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
8713            if (mOpeningApps.size() > 0) {
8714                pw.print("  mOpeningApps="); pw.println(mOpeningApps);
8715            }
8716            if (mClosingApps.size() > 0) {
8717                pw.print("  mClosingApps="); pw.println(mClosingApps);
8718            }
8719            if (mToTopApps.size() > 0) {
8720                pw.print("  mToTopApps="); pw.println(mToTopApps);
8721            }
8722            if (mToBottomApps.size() > 0) {
8723                pw.print("  mToBottomApps="); pw.println(mToBottomApps);
8724            }
8725            if (mDisplay != null) {
8726                pw.print("  DisplayWidth="); pw.print(mDisplay.getWidth());
8727                        pw.print(" DisplayHeight="); pw.println(mDisplay.getHeight());
8728            } else {
8729                pw.println("  NO DISPLAY");
8730            }
8731            pw.println("  Policy:");
8732            mPolicy.dump("    ", fd, pw, args);
8733        }
8734    }
8735
8736    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
8737    public void monitor() {
8738        synchronized (mWindowMap) { }
8739        synchronized (mKeyguardTokenWatcher) { }
8740    }
8741
8742    public interface OnHardKeyboardStatusChangeListener {
8743        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
8744    }
8745}
8746