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