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