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