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