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