WindowManagerService.java revision eda775cc89b862e0637af132d78168e1b28820f8
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 (computeScreenConfigurationLocked(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        // We need to update our screen size information to match the new
5366        // rotation.  Note that this is redundant with the later call to
5367        // sendNewConfiguration() that must be called after this function
5368        // returns...  however we need to do the screen size part of that
5369        // before then so we have the correct size to use when initializiation
5370        // the rotation animation for the new rotation.
5371        computeScreenConfigurationLocked(null);
5372
5373        if (!inTransaction) {
5374            if (SHOW_TRANSACTIONS)  Slog.i(TAG,
5375                    ">>> OPEN TRANSACTION setRotationUnchecked");
5376            Surface.openTransaction();
5377        }
5378        try {
5379            // NOTE: We disable the rotation in the emulator because
5380            //       it doesn't support hardware OpenGL emulation yet.
5381            if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
5382                    && mScreenRotationAnimation.hasScreenshot()) {
5383                if (mScreenRotationAnimation.setRotation(rotation, mFxSession,
5384                        MAX_ANIMATION_DURATION, mTransitionAnimationScale,
5385                        mCurDisplayWidth, mCurDisplayHeight)) {
5386                    requestAnimationLocked(0);
5387                }
5388            }
5389            Surface.setOrientation(0, rotation);
5390        } finally {
5391            if (!inTransaction) {
5392                Surface.closeTransaction();
5393                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
5394                        "<<< CLOSE TRANSACTION setRotationUnchecked");
5395            }
5396        }
5397
5398        rebuildBlackFrame(inTransaction);
5399
5400        for (int i=mWindows.size()-1; i>=0; i--) {
5401            WindowState w = mWindows.get(i);
5402            if (w.mSurface != null) {
5403                if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
5404                w.mOrientationChanging = true;
5405            }
5406        }
5407        for (int i=mRotationWatchers.size()-1; i>=0; i--) {
5408            try {
5409                mRotationWatchers.get(i).onRotationChanged(rotation);
5410            } catch (RemoteException e) {
5411            }
5412        }
5413        return true;
5414    }
5415
5416    public int getRotation() {
5417        return mRotation;
5418    }
5419
5420    public int watchRotation(IRotationWatcher watcher) {
5421        final IBinder watcherBinder = watcher.asBinder();
5422        IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
5423            public void binderDied() {
5424                synchronized (mWindowMap) {
5425                    for (int i=0; i<mRotationWatchers.size(); i++) {
5426                        if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
5427                            IRotationWatcher removed = mRotationWatchers.remove(i);
5428                            if (removed != null) {
5429                                removed.asBinder().unlinkToDeath(this, 0);
5430                            }
5431                            i--;
5432                        }
5433                    }
5434                }
5435            }
5436        };
5437
5438        synchronized (mWindowMap) {
5439            try {
5440                watcher.asBinder().linkToDeath(dr, 0);
5441                mRotationWatchers.add(watcher);
5442            } catch (RemoteException e) {
5443                // Client died, no cleanup needed.
5444            }
5445
5446            return mRotation;
5447        }
5448    }
5449
5450    /**
5451     * Apps that use the compact menu panel (as controlled by the panelMenuIsCompact
5452     * theme attribute) on devices that feature a physical options menu key attempt to position
5453     * their menu panel window along the edge of the screen nearest the physical menu key.
5454     * This lowers the travel distance between invoking the menu panel and selecting
5455     * a menu option.
5456     *
5457     * This method helps control where that menu is placed. Its current implementation makes
5458     * assumptions about the menu key and its relationship to the screen based on whether
5459     * the device's natural orientation is portrait (width < height) or landscape.
5460     *
5461     * The menu key is assumed to be located along the bottom edge of natural-portrait
5462     * devices and along the right edge of natural-landscape devices. If these assumptions
5463     * do not hold for the target device, this method should be changed to reflect that.
5464     *
5465     * @return A {@link Gravity} value for placing the options menu window
5466     */
5467    public int getPreferredOptionsPanelGravity() {
5468        synchronized (mWindowMap) {
5469            final int rotation = getRotation();
5470
5471            if (mInitialDisplayWidth < mInitialDisplayHeight) {
5472                // On devices with a natural orientation of portrait
5473                switch (rotation) {
5474                    default:
5475                    case Surface.ROTATION_0:
5476                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5477                    case Surface.ROTATION_90:
5478                        return Gravity.RIGHT | Gravity.BOTTOM;
5479                    case Surface.ROTATION_180:
5480                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5481                    case Surface.ROTATION_270:
5482                        return Gravity.LEFT | Gravity.BOTTOM;
5483                }
5484            } else {
5485                // On devices with a natural orientation of landscape
5486                switch (rotation) {
5487                    default:
5488                    case Surface.ROTATION_0:
5489                        return Gravity.RIGHT | Gravity.BOTTOM;
5490                    case Surface.ROTATION_90:
5491                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5492                    case Surface.ROTATION_180:
5493                        return Gravity.LEFT | Gravity.BOTTOM;
5494                    case Surface.ROTATION_270:
5495                        return Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
5496                }
5497            }
5498        }
5499    }
5500
5501    /**
5502     * Starts the view server on the specified port.
5503     *
5504     * @param port The port to listener to.
5505     *
5506     * @return True if the server was successfully started, false otherwise.
5507     *
5508     * @see com.android.server.wm.ViewServer
5509     * @see com.android.server.wm.ViewServer#VIEW_SERVER_DEFAULT_PORT
5510     */
5511    public boolean startViewServer(int port) {
5512        if (isSystemSecure()) {
5513            return false;
5514        }
5515
5516        if (!checkCallingPermission(Manifest.permission.DUMP, "startViewServer")) {
5517            return false;
5518        }
5519
5520        if (port < 1024) {
5521            return false;
5522        }
5523
5524        if (mViewServer != null) {
5525            if (!mViewServer.isRunning()) {
5526                try {
5527                    return mViewServer.start();
5528                } catch (IOException e) {
5529                    Slog.w(TAG, "View server did not start");
5530                }
5531            }
5532            return false;
5533        }
5534
5535        try {
5536            mViewServer = new ViewServer(this, port);
5537            return mViewServer.start();
5538        } catch (IOException e) {
5539            Slog.w(TAG, "View server did not start");
5540        }
5541        return false;
5542    }
5543
5544    private boolean isSystemSecure() {
5545        return "1".equals(SystemProperties.get(SYSTEM_SECURE, "1")) &&
5546                "0".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
5547    }
5548
5549    /**
5550     * Stops the view server if it exists.
5551     *
5552     * @return True if the server stopped, false if it wasn't started or
5553     *         couldn't be stopped.
5554     *
5555     * @see com.android.server.wm.ViewServer
5556     */
5557    public boolean stopViewServer() {
5558        if (isSystemSecure()) {
5559            return false;
5560        }
5561
5562        if (!checkCallingPermission(Manifest.permission.DUMP, "stopViewServer")) {
5563            return false;
5564        }
5565
5566        if (mViewServer != null) {
5567            return mViewServer.stop();
5568        }
5569        return false;
5570    }
5571
5572    /**
5573     * Indicates whether the view server is running.
5574     *
5575     * @return True if the server is running, false otherwise.
5576     *
5577     * @see com.android.server.wm.ViewServer
5578     */
5579    public boolean isViewServerRunning() {
5580        if (isSystemSecure()) {
5581            return false;
5582        }
5583
5584        if (!checkCallingPermission(Manifest.permission.DUMP, "isViewServerRunning")) {
5585            return false;
5586        }
5587
5588        return mViewServer != null && mViewServer.isRunning();
5589    }
5590
5591    /**
5592     * Lists all availble windows in the system. The listing is written in the
5593     * specified Socket's output stream with the following syntax:
5594     * windowHashCodeInHexadecimal windowName
5595     * Each line of the ouput represents a different window.
5596     *
5597     * @param client The remote client to send the listing to.
5598     * @return False if an error occured, true otherwise.
5599     */
5600    boolean viewServerListWindows(Socket client) {
5601        if (isSystemSecure()) {
5602            return false;
5603        }
5604
5605        boolean result = true;
5606
5607        WindowState[] windows;
5608        synchronized (mWindowMap) {
5609            //noinspection unchecked
5610            windows = mWindows.toArray(new WindowState[mWindows.size()]);
5611        }
5612
5613        BufferedWriter out = null;
5614
5615        // Any uncaught exception will crash the system process
5616        try {
5617            OutputStream clientStream = client.getOutputStream();
5618            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
5619
5620            final int count = windows.length;
5621            for (int i = 0; i < count; i++) {
5622                final WindowState w = windows[i];
5623                out.write(Integer.toHexString(System.identityHashCode(w)));
5624                out.write(' ');
5625                out.append(w.mAttrs.getTitle());
5626                out.write('\n');
5627            }
5628
5629            out.write("DONE.\n");
5630            out.flush();
5631        } catch (Exception e) {
5632            result = false;
5633        } finally {
5634            if (out != null) {
5635                try {
5636                    out.close();
5637                } catch (IOException e) {
5638                    result = false;
5639                }
5640            }
5641        }
5642
5643        return result;
5644    }
5645
5646    /**
5647     * Returns the focused window in the following format:
5648     * windowHashCodeInHexadecimal windowName
5649     *
5650     * @param client The remote client to send the listing to.
5651     * @return False if an error occurred, true otherwise.
5652     */
5653    boolean viewServerGetFocusedWindow(Socket client) {
5654        if (isSystemSecure()) {
5655            return false;
5656        }
5657
5658        boolean result = true;
5659
5660        WindowState focusedWindow = getFocusedWindow();
5661
5662        BufferedWriter out = null;
5663
5664        // Any uncaught exception will crash the system process
5665        try {
5666            OutputStream clientStream = client.getOutputStream();
5667            out = new BufferedWriter(new OutputStreamWriter(clientStream), 8 * 1024);
5668
5669            if(focusedWindow != null) {
5670                out.write(Integer.toHexString(System.identityHashCode(focusedWindow)));
5671                out.write(' ');
5672                out.append(focusedWindow.mAttrs.getTitle());
5673            }
5674            out.write('\n');
5675            out.flush();
5676        } catch (Exception e) {
5677            result = false;
5678        } finally {
5679            if (out != null) {
5680                try {
5681                    out.close();
5682                } catch (IOException e) {
5683                    result = false;
5684                }
5685            }
5686        }
5687
5688        return result;
5689    }
5690
5691    /**
5692     * Sends a command to a target window. The result of the command, if any, will be
5693     * written in the output stream of the specified socket.
5694     *
5695     * The parameters must follow this syntax:
5696     * windowHashcode extra
5697     *
5698     * Where XX is the length in characeters of the windowTitle.
5699     *
5700     * The first parameter is the target window. The window with the specified hashcode
5701     * will be the target. If no target can be found, nothing happens. The extra parameters
5702     * will be delivered to the target window and as parameters to the command itself.
5703     *
5704     * @param client The remote client to sent the result, if any, to.
5705     * @param command The command to execute.
5706     * @param parameters The command parameters.
5707     *
5708     * @return True if the command was successfully delivered, false otherwise. This does
5709     *         not indicate whether the command itself was successful.
5710     */
5711    boolean viewServerWindowCommand(Socket client, String command, String parameters) {
5712        if (isSystemSecure()) {
5713            return false;
5714        }
5715
5716        boolean success = true;
5717        Parcel data = null;
5718        Parcel reply = null;
5719
5720        BufferedWriter out = null;
5721
5722        // Any uncaught exception will crash the system process
5723        try {
5724            // Find the hashcode of the window
5725            int index = parameters.indexOf(' ');
5726            if (index == -1) {
5727                index = parameters.length();
5728            }
5729            final String code = parameters.substring(0, index);
5730            int hashCode = (int) Long.parseLong(code, 16);
5731
5732            // Extract the command's parameter after the window description
5733            if (index < parameters.length()) {
5734                parameters = parameters.substring(index + 1);
5735            } else {
5736                parameters = "";
5737            }
5738
5739            final WindowState window = findWindow(hashCode);
5740            if (window == null) {
5741                return false;
5742            }
5743
5744            data = Parcel.obtain();
5745            data.writeInterfaceToken("android.view.IWindow");
5746            data.writeString(command);
5747            data.writeString(parameters);
5748            data.writeInt(1);
5749            ParcelFileDescriptor.fromSocket(client).writeToParcel(data, 0);
5750
5751            reply = Parcel.obtain();
5752
5753            final IBinder binder = window.mClient.asBinder();
5754            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
5755            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
5756
5757            reply.readException();
5758
5759            if (!client.isOutputShutdown()) {
5760                out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
5761                out.write("DONE\n");
5762                out.flush();
5763            }
5764
5765        } catch (Exception e) {
5766            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
5767            success = false;
5768        } finally {
5769            if (data != null) {
5770                data.recycle();
5771            }
5772            if (reply != null) {
5773                reply.recycle();
5774            }
5775            if (out != null) {
5776                try {
5777                    out.close();
5778                } catch (IOException e) {
5779
5780                }
5781            }
5782        }
5783
5784        return success;
5785    }
5786
5787    public void addWindowChangeListener(WindowChangeListener listener) {
5788        synchronized(mWindowMap) {
5789            mWindowChangeListeners.add(listener);
5790        }
5791    }
5792
5793    public void removeWindowChangeListener(WindowChangeListener listener) {
5794        synchronized(mWindowMap) {
5795            mWindowChangeListeners.remove(listener);
5796        }
5797    }
5798
5799    private void notifyWindowsChanged() {
5800        WindowChangeListener[] windowChangeListeners;
5801        synchronized(mWindowMap) {
5802            if(mWindowChangeListeners.isEmpty()) {
5803                return;
5804            }
5805            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
5806            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
5807        }
5808        int N = windowChangeListeners.length;
5809        for(int i = 0; i < N; i++) {
5810            windowChangeListeners[i].windowsChanged();
5811        }
5812    }
5813
5814    private void notifyFocusChanged() {
5815        WindowChangeListener[] windowChangeListeners;
5816        synchronized(mWindowMap) {
5817            if(mWindowChangeListeners.isEmpty()) {
5818                return;
5819            }
5820            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
5821            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
5822        }
5823        int N = windowChangeListeners.length;
5824        for(int i = 0; i < N; i++) {
5825            windowChangeListeners[i].focusChanged();
5826        }
5827    }
5828
5829    private WindowState findWindow(int hashCode) {
5830        if (hashCode == -1) {
5831            return getFocusedWindow();
5832        }
5833
5834        synchronized (mWindowMap) {
5835            final ArrayList<WindowState> windows = mWindows;
5836            final int count = windows.size();
5837
5838            for (int i = 0; i < count; i++) {
5839                WindowState w = windows.get(i);
5840                if (System.identityHashCode(w) == hashCode) {
5841                    return w;
5842                }
5843            }
5844        }
5845
5846        return null;
5847    }
5848
5849    /*
5850     * Instruct the Activity Manager to fetch the current configuration and broadcast
5851     * that to config-changed listeners if appropriate.
5852     */
5853    void sendNewConfiguration() {
5854        try {
5855            mActivityManager.updateConfiguration(null);
5856        } catch (RemoteException e) {
5857        }
5858    }
5859
5860    public Configuration computeNewConfiguration() {
5861        synchronized (mWindowMap) {
5862            Configuration config = computeNewConfigurationLocked();
5863            if (config == null && mWaitingForConfig) {
5864                // Nothing changed but we are waiting for something... stop that!
5865                mWaitingForConfig = false;
5866                performLayoutAndPlaceSurfacesLocked();
5867            }
5868            return config;
5869        }
5870    }
5871
5872    Configuration computeNewConfigurationLocked() {
5873        Configuration config = new Configuration();
5874        config.fontScale = 0;
5875        if (!computeScreenConfigurationLocked(config)) {
5876            return null;
5877        }
5878        return config;
5879    }
5880
5881    private int reduceConfigWidthSize(int curSize, int rotation, float density, int dw, int dh) {
5882        int size = (int)(mPolicy.getConfigDisplayWidth(dw, dh, rotation) / density);
5883        if (size < curSize) {
5884            curSize = size;
5885        }
5886        return curSize;
5887    }
5888
5889    private int reduceConfigLayout(int curLayout, int rotation, float density,
5890            int dw, int dh) {
5891        // Get the app screen size at this rotation.
5892        int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
5893        int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
5894
5895        // Compute the screen layout size class for this rotation.
5896        int screenLayoutSize;
5897        boolean screenLayoutLong;
5898        boolean screenLayoutCompatNeeded;
5899        int longSize = w;
5900        int shortSize = h;
5901        if (longSize < shortSize) {
5902            int tmp = longSize;
5903            longSize = shortSize;
5904            shortSize = tmp;
5905        }
5906        longSize = (int)(longSize/density);
5907        shortSize = (int)(shortSize/density);
5908
5909        // These semi-magic numbers define our compatibility modes for
5910        // applications with different screens.  These are guarantees to
5911        // app developers about the space they can expect for a particular
5912        // configuration.  DO NOT CHANGE!
5913        if (longSize < 470) {
5914            // This is shorter than an HVGA normal density screen (which
5915            // is 480 pixels on its long side).
5916            screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_SMALL;
5917            screenLayoutLong = false;
5918            screenLayoutCompatNeeded = false;
5919        } else {
5920            // What size is this screen screen?
5921            if (longSize >= 960 && shortSize >= 720) {
5922                // 1.5xVGA or larger screens at medium density are the point
5923                // at which we consider it to be an extra large screen.
5924                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_XLARGE;
5925            } else if (longSize >= 640 && shortSize >= 480) {
5926                // VGA or larger screens at medium density are the point
5927                // at which we consider it to be a large screen.
5928                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_LARGE;
5929            } else {
5930                screenLayoutSize = Configuration.SCREENLAYOUT_SIZE_NORMAL;
5931            }
5932
5933            // If this screen is wider than normal HVGA, or taller
5934            // than FWVGA, then for old apps we want to run in size
5935            // compatibility mode.
5936            if (shortSize > 321 || longSize > 570) {
5937                screenLayoutCompatNeeded = true;
5938            } else {
5939                screenLayoutCompatNeeded = false;
5940            }
5941
5942            // Is this a long screen?
5943            if (((longSize*3)/5) >= (shortSize-1)) {
5944                // Anything wider than WVGA (5:3) is considering to be long.
5945                screenLayoutLong = true;
5946            } else {
5947                screenLayoutLong = false;
5948            }
5949        }
5950
5951        // Now reduce the last screenLayout to not be better than what we
5952        // have found.
5953        if (!screenLayoutLong) {
5954            curLayout = (curLayout&~Configuration.SCREENLAYOUT_LONG_MASK)
5955                    | Configuration.SCREENLAYOUT_LONG_NO;
5956        }
5957        if (screenLayoutCompatNeeded) {
5958            curLayout |= Configuration.SCREENLAYOUT_COMPAT_NEEDED;
5959        }
5960        int curSize = curLayout&Configuration.SCREENLAYOUT_SIZE_MASK;
5961        if (screenLayoutSize < curSize) {
5962            curLayout = (curLayout&~Configuration.SCREENLAYOUT_SIZE_MASK)
5963                    | screenLayoutSize;
5964        }
5965        return curLayout;
5966    }
5967
5968    private void computeSmallestWidthAndScreenLayout(boolean rotated, int dw, int dh,
5969            float density, Configuration outConfig) {
5970        // We need to determine the smallest width that will occur under normal
5971        // operation.  To this, start with the base screen size and compute the
5972        // width under the different possible rotations.  We need to un-rotate
5973        // the current screen dimensions before doing this.
5974        int unrotDw, unrotDh;
5975        if (rotated) {
5976            unrotDw = dh;
5977            unrotDh = dw;
5978        } else {
5979            unrotDw = dw;
5980            unrotDh = dh;
5981        }
5982        int sw = reduceConfigWidthSize(unrotDw, Surface.ROTATION_0, density, unrotDw, unrotDh);
5983        sw = reduceConfigWidthSize(sw, Surface.ROTATION_90, density, unrotDh, unrotDw);
5984        sw = reduceConfigWidthSize(sw, Surface.ROTATION_180, density, unrotDw, unrotDh);
5985        sw = reduceConfigWidthSize(sw, Surface.ROTATION_270, density, unrotDh, unrotDw);
5986        int sl = Configuration.SCREENLAYOUT_SIZE_XLARGE
5987                | Configuration.SCREENLAYOUT_LONG_YES;
5988        sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh);
5989        sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw);
5990        sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh);
5991        sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw);
5992        outConfig.smallestScreenWidthDp = sw;
5993        outConfig.screenLayout = sl;
5994    }
5995
5996    private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm,
5997            int dw, int dh) {
5998        dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation);
5999        dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation);
6000        float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
6001        int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
6002        if (curSize == 0 || size < curSize) {
6003            curSize = size;
6004        }
6005        return curSize;
6006    }
6007
6008    private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) {
6009        mTmpDisplayMetrics.setTo(dm);
6010        dm = mTmpDisplayMetrics;
6011        int unrotDw, unrotDh;
6012        if (rotated) {
6013            unrotDw = dh;
6014            unrotDh = dw;
6015        } else {
6016            unrotDw = dw;
6017            unrotDh = dh;
6018        }
6019        int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, dm, unrotDw, unrotDh);
6020        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, dm, unrotDh, unrotDw);
6021        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, dm, unrotDw, unrotDh);
6022        sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, dm, unrotDh, unrotDw);
6023        return sw;
6024    }
6025
6026    boolean computeScreenConfigurationLocked(Configuration config) {
6027        if (mDisplay == null) {
6028            return false;
6029        }
6030
6031        // Use the effective "visual" dimensions based on current rotation
6032        final boolean rotated = (mRotation == Surface.ROTATION_90
6033                || mRotation == Surface.ROTATION_270);
6034        final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
6035        final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
6036
6037        synchronized(mDisplaySizeLock) {
6038            if (mAltOrientation) {
6039                mCurDisplayWidth = realdw;
6040                mCurDisplayHeight = realdh;
6041                if (realdw > realdh) {
6042                    // Turn landscape into portrait.
6043                    int maxw = (int)(realdh/1.3f);
6044                    if (maxw < realdw) {
6045                        mCurDisplayWidth = maxw;
6046                    }
6047                } else {
6048                    // Turn portrait into landscape.
6049                    int maxh = (int)(realdw/1.3f);
6050                    if (maxh < realdh) {
6051                        mCurDisplayHeight = maxh;
6052                    }
6053                }
6054            } else {
6055                mCurDisplayWidth = realdw;
6056                mCurDisplayHeight = realdh;
6057            }
6058        }
6059
6060        final int dw = mCurDisplayWidth;
6061        final int dh = mCurDisplayHeight;
6062
6063        if (config != null) {
6064            mInputManager.getInputConfiguration(config);
6065
6066            int orientation = Configuration.ORIENTATION_SQUARE;
6067            if (dw < dh) {
6068                orientation = Configuration.ORIENTATION_PORTRAIT;
6069            } else if (dw > dh) {
6070                orientation = Configuration.ORIENTATION_LANDSCAPE;
6071            }
6072            config.orientation = orientation;
6073        }
6074
6075        // Update real display metrics.
6076        mDisplay.getMetricsWithSize(mRealDisplayMetrics, mCurDisplayWidth, mCurDisplayHeight);
6077
6078        // Update application display metrics.
6079        final DisplayMetrics dm = mDisplayMetrics;
6080        final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation);
6081        final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation);
6082        synchronized(mDisplaySizeLock) {
6083            mAppDisplayWidth = appWidth;
6084            mAppDisplayHeight = appHeight;
6085        }
6086        if (false) {
6087            Slog.i(TAG, "Set app display size: " + mAppDisplayWidth
6088                    + " x " + mAppDisplayHeight);
6089        }
6090        mDisplay.getMetricsWithSize(dm, mAppDisplayWidth, mAppDisplayHeight);
6091
6092        mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(dm,
6093                mCompatDisplayMetrics);
6094
6095        if (config != null) {
6096            config.screenWidthDp = (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation)
6097                    / dm.density);
6098            config.screenHeightDp = (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation)
6099                    / dm.density);
6100            computeSmallestWidthAndScreenLayout(rotated, dw, dh, dm.density, config);
6101
6102            config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
6103            config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
6104            config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, dm, dw, dh);
6105
6106            // Determine whether a hard keyboard is available and enabled.
6107            boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
6108            if (hardKeyboardAvailable != mHardKeyboardAvailable) {
6109                mHardKeyboardAvailable = hardKeyboardAvailable;
6110                mHardKeyboardEnabled = hardKeyboardAvailable;
6111
6112                mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6113                mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
6114            }
6115            if (!mHardKeyboardEnabled) {
6116                config.keyboard = Configuration.KEYBOARD_NOKEYS;
6117            }
6118
6119            // Update value of keyboardHidden, hardKeyboardHidden and navigationHidden
6120            // based on whether a hard or soft keyboard is present, whether navigation keys
6121            // are present and the lid switch state.
6122            config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
6123            config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
6124            config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
6125            mPolicy.adjustConfigurationLw(config);
6126        }
6127
6128        return true;
6129    }
6130
6131    public boolean isHardKeyboardAvailable() {
6132        synchronized (mWindowMap) {
6133            return mHardKeyboardAvailable;
6134        }
6135    }
6136
6137    public boolean isHardKeyboardEnabled() {
6138        synchronized (mWindowMap) {
6139            return mHardKeyboardEnabled;
6140        }
6141    }
6142
6143    public void setHardKeyboardEnabled(boolean enabled) {
6144        synchronized (mWindowMap) {
6145            if (mHardKeyboardEnabled != enabled) {
6146                mHardKeyboardEnabled = enabled;
6147                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
6148            }
6149        }
6150    }
6151
6152    public void setOnHardKeyboardStatusChangeListener(
6153            OnHardKeyboardStatusChangeListener listener) {
6154        synchronized (mWindowMap) {
6155            mHardKeyboardStatusChangeListener = listener;
6156        }
6157    }
6158
6159    void notifyHardKeyboardStatusChange() {
6160        final boolean available, enabled;
6161        final OnHardKeyboardStatusChangeListener listener;
6162        synchronized (mWindowMap) {
6163            listener = mHardKeyboardStatusChangeListener;
6164            available = mHardKeyboardAvailable;
6165            enabled = mHardKeyboardEnabled;
6166        }
6167        if (listener != null) {
6168            listener.onHardKeyboardStatusChange(available, enabled);
6169        }
6170    }
6171
6172    // -------------------------------------------------------------
6173    // Drag and drop
6174    // -------------------------------------------------------------
6175
6176    IBinder prepareDragSurface(IWindow window, SurfaceSession session,
6177            int flags, int width, int height, Surface outSurface) {
6178        if (DEBUG_DRAG) {
6179            Slog.d(TAG, "prepare drag surface: w=" + width + " h=" + height
6180                    + " flags=" + Integer.toHexString(flags) + " win=" + window
6181                    + " asbinder=" + window.asBinder());
6182        }
6183
6184        final int callerPid = Binder.getCallingPid();
6185        final long origId = Binder.clearCallingIdentity();
6186        IBinder token = null;
6187
6188        try {
6189            synchronized (mWindowMap) {
6190                try {
6191                    if (mDragState == null) {
6192                        Surface surface = new Surface(session, callerPid, "drag surface", 0,
6193                                width, height, PixelFormat.TRANSLUCENT, Surface.HIDDEN);
6194                        if (SHOW_TRANSACTIONS) Slog.i(TAG, "  DRAG "
6195                                + surface + ": CREATE");
6196                        outSurface.copyFrom(surface);
6197                        final IBinder winBinder = window.asBinder();
6198                        token = new Binder();
6199                        mDragState = new DragState(this, token, surface, /*flags*/ 0, winBinder);
6200                        mDragState.mSurface = surface;
6201                        token = mDragState.mToken = new Binder();
6202
6203                        // 5 second timeout for this window to actually begin the drag
6204                        mH.removeMessages(H.DRAG_START_TIMEOUT, winBinder);
6205                        Message msg = mH.obtainMessage(H.DRAG_START_TIMEOUT, winBinder);
6206                        mH.sendMessageDelayed(msg, 5000);
6207                    } else {
6208                        Slog.w(TAG, "Drag already in progress");
6209                    }
6210                } catch (Surface.OutOfResourcesException e) {
6211                    Slog.e(TAG, "Can't allocate drag surface w=" + width + " h=" + height, e);
6212                    if (mDragState != null) {
6213                        mDragState.reset();
6214                        mDragState = null;
6215                    }
6216                }
6217            }
6218        } finally {
6219            Binder.restoreCallingIdentity(origId);
6220        }
6221
6222        return token;
6223    }
6224
6225    // -------------------------------------------------------------
6226    // Input Events and Focus Management
6227    // -------------------------------------------------------------
6228
6229    final InputMonitor mInputMonitor = new InputMonitor(this);
6230
6231    public void pauseKeyDispatching(IBinder _token) {
6232        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6233                "pauseKeyDispatching()")) {
6234            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6235        }
6236
6237        synchronized (mWindowMap) {
6238            WindowToken token = mTokenMap.get(_token);
6239            if (token != null) {
6240                mInputMonitor.pauseDispatchingLw(token);
6241            }
6242        }
6243    }
6244
6245    public void resumeKeyDispatching(IBinder _token) {
6246        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6247                "resumeKeyDispatching()")) {
6248            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6249        }
6250
6251        synchronized (mWindowMap) {
6252            WindowToken token = mTokenMap.get(_token);
6253            if (token != null) {
6254                mInputMonitor.resumeDispatchingLw(token);
6255            }
6256        }
6257    }
6258
6259    public void setEventDispatching(boolean enabled) {
6260        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
6261                "resumeKeyDispatching()")) {
6262            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
6263        }
6264
6265        synchronized (mWindowMap) {
6266            mInputMonitor.setEventDispatchingLw(enabled);
6267        }
6268    }
6269
6270    /**
6271     * Injects a keystroke event into the UI.
6272     * Even when sync is false, this method may block while waiting for current
6273     * input events to be dispatched.
6274     *
6275     * @param ev A motion event describing the keystroke action.  (Be sure to use
6276     * {@link SystemClock#uptimeMillis()} as the timebase.)
6277     * @param sync If true, wait for the event to be completed before returning to the caller.
6278     * @return Returns true if event was dispatched, false if it was dropped for any reason
6279     */
6280    public boolean injectKeyEvent(KeyEvent ev, boolean sync) {
6281        long downTime = ev.getDownTime();
6282        long eventTime = ev.getEventTime();
6283
6284        int action = ev.getAction();
6285        int code = ev.getKeyCode();
6286        int repeatCount = ev.getRepeatCount();
6287        int metaState = ev.getMetaState();
6288        int deviceId = ev.getDeviceId();
6289        int scancode = ev.getScanCode();
6290        int source = ev.getSource();
6291        int flags = ev.getFlags();
6292
6293        if (source == InputDevice.SOURCE_UNKNOWN) {
6294            source = InputDevice.SOURCE_KEYBOARD;
6295        }
6296
6297        if (eventTime == 0) eventTime = SystemClock.uptimeMillis();
6298        if (downTime == 0) downTime = eventTime;
6299
6300        KeyEvent newEvent = new KeyEvent(downTime, eventTime, action, code, repeatCount, metaState,
6301                deviceId, scancode, flags | KeyEvent.FLAG_FROM_SYSTEM, source);
6302
6303        final int pid = Binder.getCallingPid();
6304        final int uid = Binder.getCallingUid();
6305        final long ident = Binder.clearCallingIdentity();
6306
6307        final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
6308                sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
6309                        : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
6310                INJECTION_TIMEOUT_MILLIS);
6311
6312        Binder.restoreCallingIdentity(ident);
6313        return reportInjectionResult(result);
6314    }
6315
6316    /**
6317     * Inject a pointer (touch) event into the UI.
6318     * Even when sync is false, this method may block while waiting for current
6319     * input events to be dispatched.
6320     *
6321     * @param ev A motion event describing the pointer (touch) action.  (As noted in
6322     * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
6323     * {@link SystemClock#uptimeMillis()} as the timebase.)
6324     * @param sync If true, wait for the event to be completed before returning to the caller.
6325     * @return Returns true if event was dispatched, false if it was dropped for any reason
6326     */
6327    public boolean injectPointerEvent(MotionEvent ev, boolean sync) {
6328        final int pid = Binder.getCallingPid();
6329        final int uid = Binder.getCallingUid();
6330        final long ident = Binder.clearCallingIdentity();
6331
6332        MotionEvent newEvent = MotionEvent.obtain(ev);
6333        if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0) {
6334            newEvent.setSource(InputDevice.SOURCE_TOUCHSCREEN);
6335        }
6336
6337        final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
6338                sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
6339                        : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
6340                INJECTION_TIMEOUT_MILLIS);
6341
6342        Binder.restoreCallingIdentity(ident);
6343        return reportInjectionResult(result);
6344    }
6345
6346    /**
6347     * Inject a trackball (navigation device) event into the UI.
6348     * Even when sync is false, this method may block while waiting for current
6349     * input events to be dispatched.
6350     *
6351     * @param ev A motion event describing the trackball action.  (As noted in
6352     * {@link MotionEvent#obtain(long, long, int, float, float, int)}, be sure to use
6353     * {@link SystemClock#uptimeMillis()} as the timebase.)
6354     * @param sync If true, wait for the event to be completed before returning to the caller.
6355     * @return Returns true if event was dispatched, false if it was dropped for any reason
6356     */
6357    public boolean injectTrackballEvent(MotionEvent ev, boolean sync) {
6358        final int pid = Binder.getCallingPid();
6359        final int uid = Binder.getCallingUid();
6360        final long ident = Binder.clearCallingIdentity();
6361
6362        MotionEvent newEvent = MotionEvent.obtain(ev);
6363        if ((newEvent.getSource() & InputDevice.SOURCE_CLASS_TRACKBALL) == 0) {
6364            newEvent.setSource(InputDevice.SOURCE_TRACKBALL);
6365        }
6366
6367        final int result = mInputManager.injectInputEvent(newEvent, pid, uid,
6368                sync ? InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISH
6369                        : InputManager.INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT,
6370                INJECTION_TIMEOUT_MILLIS);
6371
6372        Binder.restoreCallingIdentity(ident);
6373        return reportInjectionResult(result);
6374    }
6375
6376    /**
6377     * Inject an input event into the UI without waiting for dispatch to commence.
6378     * This variant is useful for fire-and-forget input event injection.  It does not
6379     * block any longer than it takes to enqueue the input event.
6380     *
6381     * @param ev An input event.  (Be sure to set the input source correctly.)
6382     * @return Returns true if event was dispatched, false if it was dropped for any reason
6383     */
6384    public boolean injectInputEventNoWait(InputEvent ev) {
6385        final int pid = Binder.getCallingPid();
6386        final int uid = Binder.getCallingUid();
6387        final long ident = Binder.clearCallingIdentity();
6388
6389        final int result = mInputManager.injectInputEvent(ev, pid, uid,
6390                InputManager.INPUT_EVENT_INJECTION_SYNC_NONE,
6391                INJECTION_TIMEOUT_MILLIS);
6392
6393        Binder.restoreCallingIdentity(ident);
6394        return reportInjectionResult(result);
6395    }
6396
6397    private boolean reportInjectionResult(int result) {
6398        switch (result) {
6399            case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
6400                Slog.w(TAG, "Input event injection permission denied.");
6401                throw new SecurityException(
6402                        "Injecting to another application requires INJECT_EVENTS permission");
6403            case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
6404                //Slog.v(TAG, "Input event injection succeeded.");
6405                return true;
6406            case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
6407                Slog.w(TAG, "Input event injection timed out.");
6408                return false;
6409            case InputManager.INPUT_EVENT_INJECTION_FAILED:
6410            default:
6411                Slog.w(TAG, "Input event injection failed.");
6412                return false;
6413        }
6414    }
6415
6416    /**
6417     * Temporarily set the pointer speed.  Does not save the new setting.
6418     * Used by the settings application.
6419     */
6420    public void setPointerSpeed(int speed) {
6421        if (!checkCallingPermission(android.Manifest.permission.SET_POINTER_SPEED,
6422                "setPointerSpeed()")) {
6423            throw new SecurityException("Requires SET_POINTER_SPEED permission");
6424        }
6425
6426        mInputManager.setPointerSpeed(speed);
6427    }
6428
6429    private WindowState getFocusedWindow() {
6430        synchronized (mWindowMap) {
6431            return getFocusedWindowLocked();
6432        }
6433    }
6434
6435    private WindowState getFocusedWindowLocked() {
6436        return mCurrentFocus;
6437    }
6438
6439    public boolean detectSafeMode() {
6440        if (!mInputMonitor.waitForInputDevicesReady(
6441                INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS)) {
6442            Slog.w(TAG, "Devices still not ready after waiting "
6443                    + INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS
6444                    + " milliseconds before attempting to detect safe mode.");
6445        }
6446
6447        mSafeMode = mPolicy.detectSafeMode();
6448        return mSafeMode;
6449    }
6450
6451    public void displayReady() {
6452        synchronized(mWindowMap) {
6453            if (mDisplay != null) {
6454                throw new IllegalStateException("Display already initialized");
6455            }
6456            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
6457            mDisplay = wm.getDefaultDisplay();
6458            synchronized(mDisplaySizeLock) {
6459                mInitialDisplayWidth = mDisplay.getRawWidth();
6460                mInitialDisplayHeight = mDisplay.getRawHeight();
6461                int rot = mDisplay.getRotation();
6462                if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
6463                    // If the screen is currently rotated, we need to swap the
6464                    // initial width and height to get the true natural values.
6465                    int tmp = mInitialDisplayWidth;
6466                    mInitialDisplayWidth = mInitialDisplayHeight;
6467                    mInitialDisplayHeight = tmp;
6468                }
6469                mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth;
6470                mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight;
6471            }
6472            mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
6473                    mDisplay.getRawWidth(), mDisplay.getRawHeight(),
6474                    mDisplay.getRawExternalWidth(), mDisplay.getRawExternalHeight());
6475            mPolicy.setInitialDisplaySize(mInitialDisplayWidth, mInitialDisplayHeight);
6476        }
6477
6478        try {
6479            mActivityManager.updateConfiguration(null);
6480        } catch (RemoteException e) {
6481        }
6482
6483        synchronized (mWindowMap) {
6484            readForcedDisplaySizeLocked();
6485        }
6486    }
6487
6488    public void systemReady() {
6489        mPolicy.systemReady();
6490    }
6491
6492    // This is an animation that does nothing: it just immediately finishes
6493    // itself every time it is called.  It is used as a stub animation in cases
6494    // where we want to synchronize multiple things that may be animating.
6495    static final class DummyAnimation extends Animation {
6496        public boolean getTransformation(long currentTime, Transformation outTransformation) {
6497            return false;
6498        }
6499    }
6500    static final Animation sDummyAnimation = new DummyAnimation();
6501
6502    // -------------------------------------------------------------
6503    // Async Handler
6504    // -------------------------------------------------------------
6505
6506    final class H extends Handler {
6507        public static final int REPORT_FOCUS_CHANGE = 2;
6508        public static final int REPORT_LOSING_FOCUS = 3;
6509        public static final int ANIMATE = 4;
6510        public static final int ADD_STARTING = 5;
6511        public static final int REMOVE_STARTING = 6;
6512        public static final int FINISHED_STARTING = 7;
6513        public static final int REPORT_APPLICATION_TOKEN_WINDOWS = 8;
6514        public static final int REPORT_APPLICATION_TOKEN_DRAWN = 9;
6515        public static final int WINDOW_FREEZE_TIMEOUT = 11;
6516        public static final int HOLD_SCREEN_CHANGED = 12;
6517        public static final int APP_TRANSITION_TIMEOUT = 13;
6518        public static final int PERSIST_ANIMATION_SCALE = 14;
6519        public static final int FORCE_GC = 15;
6520        public static final int ENABLE_SCREEN = 16;
6521        public static final int APP_FREEZE_TIMEOUT = 17;
6522        public static final int SEND_NEW_CONFIGURATION = 18;
6523        public static final int REPORT_WINDOWS_CHANGE = 19;
6524        public static final int DRAG_START_TIMEOUT = 20;
6525        public static final int DRAG_END_TIMEOUT = 21;
6526        public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22;
6527        public static final int BOOT_TIMEOUT = 23;
6528        public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
6529
6530        private Session mLastReportedHold;
6531
6532        public H() {
6533        }
6534
6535        @Override
6536        public void handleMessage(Message msg) {
6537            switch (msg.what) {
6538                case REPORT_FOCUS_CHANGE: {
6539                    WindowState lastFocus;
6540                    WindowState newFocus;
6541
6542                    synchronized(mWindowMap) {
6543                        lastFocus = mLastFocus;
6544                        newFocus = mCurrentFocus;
6545                        if (lastFocus == newFocus) {
6546                            // Focus is not changing, so nothing to do.
6547                            return;
6548                        }
6549                        mLastFocus = newFocus;
6550                        //Slog.i(TAG, "Focus moving from " + lastFocus
6551                        //        + " to " + newFocus);
6552                        if (newFocus != null && lastFocus != null
6553                                && !newFocus.isDisplayedLw()) {
6554                            //Slog.i(TAG, "Delaying loss of focus...");
6555                            mLosingFocus.add(lastFocus);
6556                            lastFocus = null;
6557                        }
6558                    }
6559
6560                    if (lastFocus != newFocus) {
6561                        //System.out.println("Changing focus from " + lastFocus
6562                        //                   + " to " + newFocus);
6563                        if (newFocus != null) {
6564                            try {
6565                                //Slog.i(TAG, "Gaining focus: " + newFocus);
6566                                newFocus.mClient.windowFocusChanged(true, mInTouchMode);
6567                            } catch (RemoteException e) {
6568                                // Ignore if process has died.
6569                            }
6570                            notifyFocusChanged();
6571                        }
6572
6573                        if (lastFocus != null) {
6574                            try {
6575                                //Slog.i(TAG, "Losing focus: " + lastFocus);
6576                                lastFocus.mClient.windowFocusChanged(false, mInTouchMode);
6577                            } catch (RemoteException e) {
6578                                // Ignore if process has died.
6579                            }
6580                        }
6581                    }
6582                } break;
6583
6584                case REPORT_LOSING_FOCUS: {
6585                    ArrayList<WindowState> losers;
6586
6587                    synchronized(mWindowMap) {
6588                        losers = mLosingFocus;
6589                        mLosingFocus = new ArrayList<WindowState>();
6590                    }
6591
6592                    final int N = losers.size();
6593                    for (int i=0; i<N; i++) {
6594                        try {
6595                            //Slog.i(TAG, "Losing delayed focus: " + losers.get(i));
6596                            losers.get(i).mClient.windowFocusChanged(false, mInTouchMode);
6597                        } catch (RemoteException e) {
6598                             // Ignore if process has died.
6599                        }
6600                    }
6601                } break;
6602
6603                case ANIMATE: {
6604                    synchronized(mWindowMap) {
6605                        mAnimationPending = false;
6606                        performLayoutAndPlaceSurfacesLocked();
6607                    }
6608                } break;
6609
6610                case ADD_STARTING: {
6611                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6612                    final StartingData sd = wtoken.startingData;
6613
6614                    if (sd == null) {
6615                        // Animation has been canceled... do nothing.
6616                        return;
6617                    }
6618
6619                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Add starting "
6620                            + wtoken + ": pkg=" + sd.pkg);
6621
6622                    View view = null;
6623                    try {
6624                        view = mPolicy.addStartingWindow(
6625                            wtoken.token, sd.pkg, sd.theme, sd.compatInfo,
6626                            sd.nonLocalizedLabel, sd.labelRes, sd.icon, sd.windowFlags);
6627                    } catch (Exception e) {
6628                        Slog.w(TAG, "Exception when adding starting window", e);
6629                    }
6630
6631                    if (view != null) {
6632                        boolean abort = false;
6633
6634                        synchronized(mWindowMap) {
6635                            if (wtoken.removed || wtoken.startingData == null) {
6636                                // If the window was successfully added, then
6637                                // we need to remove it.
6638                                if (wtoken.startingWindow != null) {
6639                                    if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6640                                            "Aborted starting " + wtoken
6641                                            + ": removed=" + wtoken.removed
6642                                            + " startingData=" + wtoken.startingData);
6643                                    wtoken.startingWindow = null;
6644                                    wtoken.startingData = null;
6645                                    abort = true;
6646                                }
6647                            } else {
6648                                wtoken.startingView = view;
6649                            }
6650                            if (DEBUG_STARTING_WINDOW && !abort) Slog.v(TAG,
6651                                    "Added starting " + wtoken
6652                                    + ": startingWindow="
6653                                    + wtoken.startingWindow + " startingView="
6654                                    + wtoken.startingView);
6655                        }
6656
6657                        if (abort) {
6658                            try {
6659                                mPolicy.removeStartingWindow(wtoken.token, view);
6660                            } catch (Exception e) {
6661                                Slog.w(TAG, "Exception when removing starting window", e);
6662                            }
6663                        }
6664                    }
6665                } break;
6666
6667                case REMOVE_STARTING: {
6668                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6669                    IBinder token = null;
6670                    View view = null;
6671                    synchronized (mWindowMap) {
6672                        if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Remove starting "
6673                                + wtoken + ": startingWindow="
6674                                + wtoken.startingWindow + " startingView="
6675                                + wtoken.startingView);
6676                        if (wtoken.startingWindow != null) {
6677                            view = wtoken.startingView;
6678                            token = wtoken.token;
6679                            wtoken.startingData = null;
6680                            wtoken.startingView = null;
6681                            wtoken.startingWindow = null;
6682                        }
6683                    }
6684                    if (view != null) {
6685                        try {
6686                            mPolicy.removeStartingWindow(token, view);
6687                        } catch (Exception e) {
6688                            Slog.w(TAG, "Exception when removing starting window", e);
6689                        }
6690                    }
6691                } break;
6692
6693                case FINISHED_STARTING: {
6694                    IBinder token = null;
6695                    View view = null;
6696                    while (true) {
6697                        synchronized (mWindowMap) {
6698                            final int N = mFinishedStarting.size();
6699                            if (N <= 0) {
6700                                break;
6701                            }
6702                            AppWindowToken wtoken = mFinishedStarting.remove(N-1);
6703
6704                            if (DEBUG_STARTING_WINDOW) Slog.v(TAG,
6705                                    "Finished starting " + wtoken
6706                                    + ": startingWindow=" + wtoken.startingWindow
6707                                    + " startingView=" + wtoken.startingView);
6708
6709                            if (wtoken.startingWindow == null) {
6710                                continue;
6711                            }
6712
6713                            view = wtoken.startingView;
6714                            token = wtoken.token;
6715                            wtoken.startingData = null;
6716                            wtoken.startingView = null;
6717                            wtoken.startingWindow = null;
6718                        }
6719
6720                        try {
6721                            mPolicy.removeStartingWindow(token, view);
6722                        } catch (Exception e) {
6723                            Slog.w(TAG, "Exception when removing starting window", e);
6724                        }
6725                    }
6726                } break;
6727
6728                case REPORT_APPLICATION_TOKEN_DRAWN: {
6729                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6730
6731                    try {
6732                        if (DEBUG_VISIBILITY) Slog.v(
6733                                TAG, "Reporting drawn in " + wtoken);
6734                        wtoken.appToken.windowsDrawn();
6735                    } catch (RemoteException ex) {
6736                    }
6737                } break;
6738
6739                case REPORT_APPLICATION_TOKEN_WINDOWS: {
6740                    final AppWindowToken wtoken = (AppWindowToken)msg.obj;
6741
6742                    boolean nowVisible = msg.arg1 != 0;
6743                    boolean nowGone = msg.arg2 != 0;
6744
6745                    try {
6746                        if (DEBUG_VISIBILITY) Slog.v(
6747                                TAG, "Reporting visible in " + wtoken
6748                                + " visible=" + nowVisible
6749                                + " gone=" + nowGone);
6750                        if (nowVisible) {
6751                            wtoken.appToken.windowsVisible();
6752                        } else {
6753                            wtoken.appToken.windowsGone();
6754                        }
6755                    } catch (RemoteException ex) {
6756                    }
6757                } break;
6758
6759                case WINDOW_FREEZE_TIMEOUT: {
6760                    synchronized (mWindowMap) {
6761                        Slog.w(TAG, "Window freeze timeout expired.");
6762                        int i = mWindows.size();
6763                        while (i > 0) {
6764                            i--;
6765                            WindowState w = mWindows.get(i);
6766                            if (w.mOrientationChanging) {
6767                                w.mOrientationChanging = false;
6768                                Slog.w(TAG, "Force clearing orientation change: " + w);
6769                            }
6770                        }
6771                        performLayoutAndPlaceSurfacesLocked();
6772                    }
6773                    break;
6774                }
6775
6776                case HOLD_SCREEN_CHANGED: {
6777                    Session oldHold;
6778                    Session newHold;
6779                    synchronized (mWindowMap) {
6780                        oldHold = mLastReportedHold;
6781                        newHold = (Session)msg.obj;
6782                        mLastReportedHold = newHold;
6783                    }
6784
6785                    if (oldHold != newHold) {
6786                        try {
6787                            if (oldHold != null) {
6788                                mBatteryStats.noteStopWakelock(oldHold.mUid, -1,
6789                                        "window",
6790                                        BatteryStats.WAKE_TYPE_WINDOW);
6791                            }
6792                            if (newHold != null) {
6793                                mBatteryStats.noteStartWakelock(newHold.mUid, -1,
6794                                        "window",
6795                                        BatteryStats.WAKE_TYPE_WINDOW);
6796                            }
6797                        } catch (RemoteException e) {
6798                        }
6799                    }
6800                    break;
6801                }
6802
6803                case APP_TRANSITION_TIMEOUT: {
6804                    synchronized (mWindowMap) {
6805                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
6806                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
6807                                    "*** APP TRANSITION TIMEOUT");
6808                            mAppTransitionReady = true;
6809                            mAppTransitionTimeout = true;
6810                            performLayoutAndPlaceSurfacesLocked();
6811                        }
6812                    }
6813                    break;
6814                }
6815
6816                case PERSIST_ANIMATION_SCALE: {
6817                    Settings.System.putFloat(mContext.getContentResolver(),
6818                            Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);
6819                    Settings.System.putFloat(mContext.getContentResolver(),
6820                            Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);
6821                    break;
6822                }
6823
6824                case FORCE_GC: {
6825                    synchronized(mWindowMap) {
6826                        if (mAnimationPending) {
6827                            // If we are animating, don't do the gc now but
6828                            // delay a bit so we don't interrupt the animation.
6829                            mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
6830                                    2000);
6831                            return;
6832                        }
6833                        // If we are currently rotating the display, it will
6834                        // schedule a new message when done.
6835                        if (mDisplayFrozen) {
6836                            return;
6837                        }
6838                    }
6839                    Runtime.getRuntime().gc();
6840                    break;
6841                }
6842
6843                case ENABLE_SCREEN: {
6844                    performEnableScreen();
6845                    break;
6846                }
6847
6848                case APP_FREEZE_TIMEOUT: {
6849                    synchronized (mWindowMap) {
6850                        Slog.w(TAG, "App freeze timeout expired.");
6851                        int i = mAppTokens.size();
6852                        while (i > 0) {
6853                            i--;
6854                            AppWindowToken tok = mAppTokens.get(i);
6855                            if (tok.freezingScreen) {
6856                                Slog.w(TAG, "Force clearing freeze: " + tok);
6857                                unsetAppFreezingScreenLocked(tok, true, true);
6858                            }
6859                        }
6860                    }
6861                    break;
6862                }
6863
6864                case SEND_NEW_CONFIGURATION: {
6865                    removeMessages(SEND_NEW_CONFIGURATION);
6866                    sendNewConfiguration();
6867                    break;
6868                }
6869
6870                case REPORT_WINDOWS_CHANGE: {
6871                    if (mWindowsChanged) {
6872                        synchronized (mWindowMap) {
6873                            mWindowsChanged = false;
6874                        }
6875                        notifyWindowsChanged();
6876                    }
6877                    break;
6878                }
6879
6880                case DRAG_START_TIMEOUT: {
6881                    IBinder win = (IBinder)msg.obj;
6882                    if (DEBUG_DRAG) {
6883                        Slog.w(TAG, "Timeout starting drag by win " + win);
6884                    }
6885                    synchronized (mWindowMap) {
6886                        // !!! TODO: ANR the app that has failed to start the drag in time
6887                        if (mDragState != null) {
6888                            mDragState.unregister();
6889                            mInputMonitor.updateInputWindowsLw(true /*force*/);
6890                            mDragState.reset();
6891                            mDragState = null;
6892                        }
6893                    }
6894                    break;
6895                }
6896
6897                case DRAG_END_TIMEOUT: {
6898                    IBinder win = (IBinder)msg.obj;
6899                    if (DEBUG_DRAG) {
6900                        Slog.w(TAG, "Timeout ending drag to win " + win);
6901                    }
6902                    synchronized (mWindowMap) {
6903                        // !!! TODO: ANR the drag-receiving app
6904                        if (mDragState != null) {
6905                            mDragState.mDragResult = false;
6906                            mDragState.endDragLw();
6907                        }
6908                    }
6909                    break;
6910                }
6911
6912                case REPORT_HARD_KEYBOARD_STATUS_CHANGE: {
6913                    notifyHardKeyboardStatusChange();
6914                    break;
6915                }
6916
6917                case BOOT_TIMEOUT: {
6918                    performBootTimeout();
6919                    break;
6920                }
6921
6922                case WAITING_FOR_DRAWN_TIMEOUT: {
6923                    Pair<WindowState, IRemoteCallback> pair;
6924                    synchronized (mWindowMap) {
6925                        pair = (Pair<WindowState, IRemoteCallback>)msg.obj;
6926                        Slog.w(TAG, "Timeout waiting for drawn: " + pair.first);
6927                        if (!mWaitingForDrawn.remove(pair)) {
6928                            return;
6929                        }
6930                    }
6931                    try {
6932                        pair.second.sendResult(null);
6933                    } catch (RemoteException e) {
6934                    }
6935                    break;
6936                }
6937            }
6938        }
6939    }
6940
6941    // -------------------------------------------------------------
6942    // IWindowManager API
6943    // -------------------------------------------------------------
6944
6945    public IWindowSession openSession(IInputMethodClient client,
6946            IInputContext inputContext) {
6947        if (client == null) throw new IllegalArgumentException("null client");
6948        if (inputContext == null) throw new IllegalArgumentException("null inputContext");
6949        Session session = new Session(this, client, inputContext);
6950        return session;
6951    }
6952
6953    public boolean inputMethodClientHasFocus(IInputMethodClient client) {
6954        synchronized (mWindowMap) {
6955            // The focus for the client is the window immediately below
6956            // where we would place the input method window.
6957            int idx = findDesiredInputMethodWindowIndexLocked(false);
6958            WindowState imFocus;
6959            if (idx > 0) {
6960                imFocus = mWindows.get(idx-1);
6961                //Log.i(TAG, "Desired input method target: " + imFocus);
6962                //Log.i(TAG, "Current focus: " + this.mCurrentFocus);
6963                //Log.i(TAG, "Last focus: " + this.mLastFocus);
6964                if (imFocus != null) {
6965                    // This may be a starting window, in which case we still want
6966                    // to count it as okay.
6967                    if (imFocus.mAttrs.type == LayoutParams.TYPE_APPLICATION_STARTING
6968                            && imFocus.mAppToken != null) {
6969                        // The client has definitely started, so it really should
6970                        // have a window in this app token.  Let's look for it.
6971                        for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
6972                            WindowState w = imFocus.mAppToken.windows.get(i);
6973                            if (w != imFocus) {
6974                                //Log.i(TAG, "Switching to real app window: " + w);
6975                                imFocus = w;
6976                                break;
6977                            }
6978                        }
6979                    }
6980                    //Log.i(TAG, "IM target client: " + imFocus.mSession.mClient);
6981                    //if (imFocus.mSession.mClient != null) {
6982                    //    Log.i(TAG, "IM target client binder: " + imFocus.mSession.mClient.asBinder());
6983                    //    Log.i(TAG, "Requesting client binder: " + client.asBinder());
6984                    //}
6985                    if (imFocus.mSession.mClient != null &&
6986                            imFocus.mSession.mClient.asBinder() == client.asBinder()) {
6987                        return true;
6988                    }
6989
6990                    // Okay, how about this...  what is the current focus?
6991                    // It seems in some cases we may not have moved the IM
6992                    // target window, such as when it was in a pop-up window,
6993                    // so let's also look at the current focus.  (An example:
6994                    // go to Gmail, start searching so the keyboard goes up,
6995                    // press home.  Sometimes the IME won't go down.)
6996                    // Would be nice to fix this more correctly, but it's
6997                    // way at the end of a release, and this should be good enough.
6998                    if (mCurrentFocus != null && mCurrentFocus.mSession.mClient != null &&
6999                            mCurrentFocus.mSession.mClient.asBinder() == client.asBinder()) {
7000                        return true;
7001                    }
7002                }
7003            }
7004        }
7005        return false;
7006    }
7007
7008    public void getDisplaySize(Point size) {
7009        synchronized(mDisplaySizeLock) {
7010            size.x = mAppDisplayWidth;
7011            size.y = mAppDisplayHeight;
7012        }
7013    }
7014
7015    public void getRealDisplaySize(Point size) {
7016        synchronized(mDisplaySizeLock) {
7017            size.x = mCurDisplayWidth;
7018            size.y = mCurDisplayHeight;
7019        }
7020    }
7021
7022    public void getInitialDisplaySize(Point size) {
7023        synchronized(mDisplaySizeLock) {
7024            size.x = mInitialDisplayWidth;
7025            size.y = mInitialDisplayHeight;
7026        }
7027    }
7028
7029    public int getMaximumSizeDimension() {
7030        synchronized(mDisplaySizeLock) {
7031            // Do this based on the raw screen size, until we are smarter.
7032            return mBaseDisplayWidth > mBaseDisplayHeight
7033                    ? mBaseDisplayWidth : mBaseDisplayHeight;
7034        }
7035    }
7036
7037    public void setForcedDisplaySize(int longDimen, int shortDimen) {
7038        synchronized(mWindowMap) {
7039            int width, height;
7040            if (mInitialDisplayWidth < mInitialDisplayHeight) {
7041                width = shortDimen < mInitialDisplayWidth
7042                        ? shortDimen : mInitialDisplayWidth;
7043                height = longDimen < mInitialDisplayHeight
7044                        ? longDimen : mInitialDisplayHeight;
7045            } else {
7046                width = longDimen < mInitialDisplayWidth
7047                        ? longDimen : mInitialDisplayWidth;
7048                height = shortDimen < mInitialDisplayHeight
7049                        ? shortDimen : mInitialDisplayHeight;
7050            }
7051            setForcedDisplaySizeLocked(width, height);
7052            Settings.Secure.putString(mContext.getContentResolver(),
7053                    Settings.Secure.DISPLAY_SIZE_FORCED, width + "," + height);
7054        }
7055    }
7056
7057    private void rebuildBlackFrame(boolean inTransaction) {
7058        if (!inTransaction) {
7059            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
7060                    ">>> OPEN TRANSACTION rebuildBlackFrame");
7061            Surface.openTransaction();
7062        }
7063        try {
7064            if (mBlackFrame != null) {
7065                mBlackFrame.kill();
7066                mBlackFrame = null;
7067            }
7068            if (mBaseDisplayWidth < mInitialDisplayWidth
7069                    || mBaseDisplayHeight < mInitialDisplayHeight) {
7070                int initW, initH, baseW, baseH;
7071                final boolean rotated = (mRotation == Surface.ROTATION_90
7072                        || mRotation == Surface.ROTATION_270);
7073                if (rotated) {
7074                    initW = mInitialDisplayHeight;
7075                    initH = mInitialDisplayWidth;
7076                    baseW = mBaseDisplayHeight;
7077                    baseH = mBaseDisplayWidth;
7078                } else {
7079                    initW = mInitialDisplayWidth;
7080                    initH = mInitialDisplayHeight;
7081                    baseW = mBaseDisplayWidth;
7082                    baseH = mBaseDisplayHeight;
7083                }
7084                Rect outer = new Rect(0, 0, initW, initH);
7085                Rect inner = new Rect(0, 0, baseW, baseH);
7086                try {
7087                    mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER);
7088                } catch (Surface.OutOfResourcesException e) {
7089                }
7090            }
7091        } finally {
7092            if (!inTransaction) {
7093                Surface.closeTransaction();
7094                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
7095                        "<<< CLOSE TRANSACTION rebuildBlackFrame");
7096            }
7097        }
7098    }
7099
7100    private void readForcedDisplaySizeLocked() {
7101        final String str = Settings.Secure.getString(mContext.getContentResolver(),
7102                Settings.Secure.DISPLAY_SIZE_FORCED);
7103        if (str == null || str.length() == 0) {
7104            return;
7105        }
7106        final int pos = str.indexOf(',');
7107        if (pos <= 0 || str.lastIndexOf(',') != pos) {
7108            return;
7109        }
7110        int width, height;
7111        try {
7112            width = Integer.parseInt(str.substring(0, pos));
7113            height = Integer.parseInt(str.substring(pos+1));
7114        } catch (NumberFormatException ex) {
7115            return;
7116        }
7117        setForcedDisplaySizeLocked(width, height);
7118    }
7119
7120    private void setForcedDisplaySizeLocked(int width, int height) {
7121        Slog.i(TAG, "Using new display size: " + width + "x" + height);
7122
7123        synchronized(mDisplaySizeLock) {
7124            mBaseDisplayWidth = width;
7125            mBaseDisplayHeight = height;
7126        }
7127        mPolicy.setInitialDisplaySize(mBaseDisplayWidth, mBaseDisplayHeight);
7128
7129        mLayoutNeeded = true;
7130
7131        boolean configChanged = updateOrientationFromAppTokensLocked(false);
7132        mTempConfiguration.setToDefaults();
7133        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
7134        if (computeScreenConfigurationLocked(mTempConfiguration)) {
7135            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
7136                configChanged = true;
7137            }
7138        }
7139
7140        if (configChanged) {
7141            mWaitingForConfig = true;
7142            startFreezingDisplayLocked(false);
7143            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7144        }
7145
7146        rebuildBlackFrame(false);
7147
7148        performLayoutAndPlaceSurfacesLocked();
7149    }
7150
7151    public void clearForcedDisplaySize() {
7152        synchronized(mWindowMap) {
7153            setForcedDisplaySizeLocked(mInitialDisplayWidth, mInitialDisplayHeight);
7154            Settings.Secure.putString(mContext.getContentResolver(),
7155                    Settings.Secure.DISPLAY_SIZE_FORCED, "");
7156        }
7157    }
7158
7159    public boolean canStatusBarHide() {
7160        return mPolicy.canStatusBarHide();
7161    }
7162
7163    // -------------------------------------------------------------
7164    // Internals
7165    // -------------------------------------------------------------
7166
7167    final WindowState windowForClientLocked(Session session, IWindow client,
7168            boolean throwOnError) {
7169        return windowForClientLocked(session, client.asBinder(), throwOnError);
7170    }
7171
7172    final WindowState windowForClientLocked(Session session, IBinder client,
7173            boolean throwOnError) {
7174        WindowState win = mWindowMap.get(client);
7175        if (localLOGV) Slog.v(
7176            TAG, "Looking up client " + client + ": " + win);
7177        if (win == null) {
7178            RuntimeException ex = new IllegalArgumentException(
7179                    "Requested window " + client + " does not exist");
7180            if (throwOnError) {
7181                throw ex;
7182            }
7183            Slog.w(TAG, "Failed looking up window", ex);
7184            return null;
7185        }
7186        if (session != null && win.mSession != session) {
7187            RuntimeException ex = new IllegalArgumentException(
7188                    "Requested window " + client + " is in session " +
7189                    win.mSession + ", not " + session);
7190            if (throwOnError) {
7191                throw ex;
7192            }
7193            Slog.w(TAG, "Failed looking up window", ex);
7194            return null;
7195        }
7196
7197        return win;
7198    }
7199
7200    final void rebuildAppWindowListLocked() {
7201        int NW = mWindows.size();
7202        int i;
7203        int lastWallpaper = -1;
7204        int numRemoved = 0;
7205
7206        if (mRebuildTmp.length < NW) {
7207            mRebuildTmp = new WindowState[NW+10];
7208        }
7209
7210        // First remove all existing app windows.
7211        i=0;
7212        while (i < NW) {
7213            WindowState w = mWindows.get(i);
7214            if (w.mAppToken != null) {
7215                WindowState win = mWindows.remove(i);
7216                win.mRebuilding = true;
7217                mRebuildTmp[numRemoved] = win;
7218                mWindowsChanged = true;
7219                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
7220                        "Rebuild removing window: " + win);
7221                NW--;
7222                numRemoved++;
7223                continue;
7224            } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER
7225                    && lastWallpaper == i-1) {
7226                lastWallpaper = i;
7227            }
7228            i++;
7229        }
7230
7231        // The wallpaper window(s) typically live at the bottom of the stack,
7232        // so skip them before adding app tokens.
7233        lastWallpaper++;
7234        i = lastWallpaper;
7235
7236        // First add all of the exiting app tokens...  these are no longer
7237        // in the main app list, but still have windows shown.  We put them
7238        // in the back because now that the animation is over we no longer
7239        // will care about them.
7240        int NT = mExitingAppTokens.size();
7241        for (int j=0; j<NT; j++) {
7242            i = reAddAppWindowsLocked(i, mExitingAppTokens.get(j));
7243        }
7244
7245        // And add in the still active app tokens in Z order.
7246        NT = mAppTokens.size();
7247        for (int j=0; j<NT; j++) {
7248            i = reAddAppWindowsLocked(i, mAppTokens.get(j));
7249        }
7250
7251        i -= lastWallpaper;
7252        if (i != numRemoved) {
7253            Slog.w(TAG, "Rebuild removed " + numRemoved
7254                    + " windows but added " + i);
7255            for (i=0; i<numRemoved; i++) {
7256                WindowState ws = mRebuildTmp[i];
7257                if (ws.mRebuilding) {
7258                    StringWriter sw = new StringWriter();
7259                    PrintWriter pw = new PrintWriter(sw);
7260                    ws.dump(pw, "", true);
7261                    pw.flush();
7262                    Slog.w(TAG, "This window was lost: " + ws);
7263                    Slog.w(TAG, sw.toString());
7264                }
7265            }
7266            Slog.w(TAG, "Current app token list:");
7267            dumpAppTokensLocked();
7268            Slog.w(TAG, "Final window list:");
7269            dumpWindowsLocked();
7270        }
7271    }
7272
7273    private final void assignLayersLocked() {
7274        int N = mWindows.size();
7275        int curBaseLayer = 0;
7276        int curLayer = 0;
7277        int i;
7278
7279        if (DEBUG_LAYERS) {
7280            RuntimeException here = new RuntimeException("here");
7281            here.fillInStackTrace();
7282            Slog.v(TAG, "Assigning layers", here);
7283        }
7284
7285        for (i=0; i<N; i++) {
7286            WindowState w = mWindows.get(i);
7287            if (w.mBaseLayer == curBaseLayer || w.mIsImWindow
7288                    || (i > 0 && w.mIsWallpaper)) {
7289                curLayer += WINDOW_LAYER_MULTIPLIER;
7290                w.mLayer = curLayer;
7291            } else {
7292                curBaseLayer = curLayer = w.mBaseLayer;
7293                w.mLayer = curLayer;
7294            }
7295            if (w.mTargetAppToken != null) {
7296                w.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
7297            } else if (w.mAppToken != null) {
7298                w.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
7299            } else {
7300                w.mAnimLayer = w.mLayer;
7301            }
7302            if (w.mIsImWindow) {
7303                w.mAnimLayer += mInputMethodAnimLayerAdjustment;
7304            } else if (w.mIsWallpaper) {
7305                w.mAnimLayer += mWallpaperAnimLayerAdjustment;
7306            }
7307            if (DEBUG_LAYERS) Slog.v(TAG, "Assign layer " + w + ": "
7308                    + w.mAnimLayer);
7309            //System.out.println(
7310            //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
7311        }
7312    }
7313
7314    private boolean mInLayout = false;
7315    private final void performLayoutAndPlaceSurfacesLocked() {
7316        if (mInLayout) {
7317            if (DEBUG) {
7318                throw new RuntimeException("Recursive call!");
7319            }
7320            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
7321            return;
7322        }
7323
7324        if (mWaitingForConfig) {
7325            // Our configuration has changed (most likely rotation), but we
7326            // don't yet have the complete configuration to report to
7327            // applications.  Don't do any window layout until we have it.
7328            return;
7329        }
7330
7331        if (mDisplay == null) {
7332            // Not yet initialized, nothing to do.
7333            return;
7334        }
7335
7336        mInLayout = true;
7337        boolean recoveringMemory = false;
7338
7339        try {
7340            if (mForceRemoves != null) {
7341                recoveringMemory = true;
7342                // Wait a little bit for things to settle down, and off we go.
7343                for (int i=0; i<mForceRemoves.size(); i++) {
7344                    WindowState ws = mForceRemoves.get(i);
7345                    Slog.i(TAG, "Force removing: " + ws);
7346                    removeWindowInnerLocked(ws.mSession, ws);
7347                }
7348                mForceRemoves = null;
7349                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
7350                Object tmp = new Object();
7351                synchronized (tmp) {
7352                    try {
7353                        tmp.wait(250);
7354                    } catch (InterruptedException e) {
7355                    }
7356                }
7357            }
7358        } catch (RuntimeException e) {
7359            Log.wtf(TAG, "Unhandled exception while force removing for memory", e);
7360        }
7361
7362        try {
7363            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
7364
7365            int N = mPendingRemove.size();
7366            if (N > 0) {
7367                if (mPendingRemoveTmp.length < N) {
7368                    mPendingRemoveTmp = new WindowState[N+10];
7369                }
7370                mPendingRemove.toArray(mPendingRemoveTmp);
7371                mPendingRemove.clear();
7372                for (int i=0; i<N; i++) {
7373                    WindowState w = mPendingRemoveTmp[i];
7374                    removeWindowInnerLocked(w.mSession, w);
7375                }
7376
7377                mInLayout = false;
7378                assignLayersLocked();
7379                mLayoutNeeded = true;
7380                performLayoutAndPlaceSurfacesLocked();
7381
7382            } else {
7383                mInLayout = false;
7384                if (mLayoutNeeded) {
7385                    requestAnimationLocked(0);
7386                }
7387            }
7388            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
7389                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
7390                mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE));
7391            }
7392        } catch (RuntimeException e) {
7393            mInLayout = false;
7394            Log.wtf(TAG, "Unhandled exception while laying out windows", e);
7395        }
7396    }
7397
7398    private final int performLayoutLockedInner(boolean initial, boolean updateInputWindows) {
7399        if (!mLayoutNeeded) {
7400            return 0;
7401        }
7402
7403        mLayoutNeeded = false;
7404
7405        final int dw = mCurDisplayWidth;
7406        final int dh = mCurDisplayHeight;
7407
7408        final int NFW = mFakeWindows.size();
7409        for (int i=0; i<NFW; i++) {
7410            mFakeWindows.get(i).layout(dw, dh);
7411        }
7412
7413        final int N = mWindows.size();
7414        int i;
7415
7416        if (DEBUG_LAYOUT) {
7417            Slog.v(TAG, "-------------------------------------");
7418            Slog.v(TAG, "performLayout: needed="
7419                    + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
7420        }
7421
7422        mPolicy.beginLayoutLw(dw, dh, mRotation);
7423
7424        int seq = mLayoutSeq+1;
7425        if (seq < 0) seq = 0;
7426        mLayoutSeq = seq;
7427
7428        // First perform layout of any root windows (not attached
7429        // to another window).
7430        int topAttached = -1;
7431        for (i = N-1; i >= 0; i--) {
7432            WindowState win = mWindows.get(i);
7433
7434            // Don't do layout of a window if it is not visible, or
7435            // soon won't be visible, to avoid wasting time and funky
7436            // changes while a window is animating away.
7437            final boolean gone = win.isGoneForLayoutLw();
7438
7439            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
7440                Slog.v(TAG, "1ST PASS " + win
7441                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
7442                        + " mLayoutAttached=" + win.mLayoutAttached);
7443                final AppWindowToken atoken = win.mAppToken;
7444                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
7445                        + win.mViewVisibility + " mRelayoutCalled="
7446                        + win.mRelayoutCalled + " hidden="
7447                        + win.mRootToken.hidden + " hiddenRequested="
7448                        + (atoken != null && atoken.hiddenRequested)
7449                        + " mAttachedHidden=" + win.mAttachedHidden);
7450                else Slog.v(TAG, "  VIS: mViewVisibility="
7451                        + win.mViewVisibility + " mRelayoutCalled="
7452                        + win.mRelayoutCalled + " hidden="
7453                        + win.mRootToken.hidden + " hiddenRequested="
7454                        + (atoken != null && atoken.hiddenRequested)
7455                        + " mAttachedHidden=" + win.mAttachedHidden);
7456            }
7457
7458            // If this view is GONE, then skip it -- keep the current
7459            // frame, and let the caller know so they can ignore it
7460            // if they want.  (We do the normal layout for INVISIBLE
7461            // windows, since that means "perform layout as normal,
7462            // just don't display").
7463            if (!gone || !win.mHaveFrame) {
7464                if (!win.mLayoutAttached) {
7465                    if (initial) {
7466                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7467                        win.mContentChanged = false;
7468                    }
7469                    win.prelayout();
7470                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
7471                    win.mLayoutSeq = seq;
7472                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7473                            + win.mFrame + " mContainingFrame="
7474                            + win.mContainingFrame + " mDisplayFrame="
7475                            + win.mDisplayFrame);
7476                } else {
7477                    if (topAttached < 0) topAttached = i;
7478                }
7479            }
7480        }
7481
7482        // Now perform layout of attached windows, which usually
7483        // depend on the position of the window they are attached to.
7484        // XXX does not deal with windows that are attached to windows
7485        // that are themselves attached.
7486        for (i = topAttached; i >= 0; i--) {
7487            WindowState win = mWindows.get(i);
7488
7489            if (win.mLayoutAttached) {
7490                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
7491                        + " mHaveFrame=" + win.mHaveFrame
7492                        + " mViewVisibility=" + win.mViewVisibility
7493                        + " mRelayoutCalled=" + win.mRelayoutCalled);
7494                // If this view is GONE, then skip it -- keep the current
7495                // frame, and let the caller know so they can ignore it
7496                // if they want.  (We do the normal layout for INVISIBLE
7497                // windows, since that means "perform layout as normal,
7498                // just don't display").
7499                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7500                        || !win.mHaveFrame) {
7501                    if (initial) {
7502                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7503                        win.mContentChanged = false;
7504                    }
7505                    win.prelayout();
7506                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7507                    win.mLayoutSeq = seq;
7508                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
7509                            + win.mFrame + " mContainingFrame="
7510                            + win.mContainingFrame + " mDisplayFrame="
7511                            + win.mDisplayFrame);
7512                }
7513            }
7514        }
7515
7516        // Window frames may have changed.  Tell the input dispatcher about it.
7517        mInputMonitor.setUpdateInputWindowsNeededLw();
7518        if (updateInputWindows) {
7519            mInputMonitor.updateInputWindowsLw(false /*force*/);
7520        }
7521
7522        return mPolicy.finishLayoutLw();
7523    }
7524
7525    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
7526        // If the screen is currently frozen or off, then keep
7527        // it frozen/off until this window draws at its new
7528        // orientation.
7529        if (mDisplayFrozen || !mPolicy.isScreenOnFully()) {
7530            if (DEBUG_ORIENTATION) Slog.v(TAG,
7531                    "Changing surface while display frozen: " + w);
7532            w.mOrientationChanging = true;
7533            if (!mWindowsFreezingScreen) {
7534                mWindowsFreezingScreen = true;
7535                // XXX should probably keep timeout from
7536                // when we first froze the display.
7537                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
7538                mH.sendMessageDelayed(mH.obtainMessage(
7539                        H.WINDOW_FREEZE_TIMEOUT), 2000);
7540            }
7541        }
7542    }
7543
7544    // "Something has changed!  Let's make it correct now."
7545    private final void performLayoutAndPlaceSurfacesLockedInner(
7546            boolean recoveringMemory) {
7547        if (mDisplay == null) {
7548            Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
7549            return;
7550        }
7551
7552        final long currentTime = SystemClock.uptimeMillis();
7553        final int dw = mCurDisplayWidth;
7554        final int dh = mCurDisplayHeight;
7555        final int innerDw = mAppDisplayWidth;
7556        final int innerDh = mAppDisplayHeight;
7557
7558        int i;
7559
7560        if (mFocusMayChange) {
7561            mFocusMayChange = false;
7562            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
7563                    false /*updateInputWindows*/);
7564        }
7565
7566        // Initialize state of exiting tokens.
7567        for (i=mExitingTokens.size()-1; i>=0; i--) {
7568            mExitingTokens.get(i).hasVisible = false;
7569        }
7570
7571        // Initialize state of exiting applications.
7572        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
7573            mExitingAppTokens.get(i).hasVisible = false;
7574        }
7575
7576        boolean orientationChangeComplete = true;
7577        Session holdScreen = null;
7578        float screenBrightness = -1;
7579        float buttonBrightness = -1;
7580        boolean focusDisplayed = false;
7581        boolean animating = false;
7582        boolean createWatermark = false;
7583        boolean updateRotation = false;
7584        boolean screenRotationFinished = false;
7585
7586        if (mFxSession == null) {
7587            mFxSession = new SurfaceSession();
7588            createWatermark = true;
7589        }
7590
7591        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
7592                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
7593
7594        Surface.openTransaction();
7595
7596        if (createWatermark) {
7597            createWatermark();
7598        }
7599        if (mWatermark != null) {
7600            mWatermark.positionSurface(dw, dh);
7601        }
7602        if (mStrictModeFlash != null) {
7603            mStrictModeFlash.positionSurface(dw, dh);
7604        }
7605
7606        try {
7607            boolean wallpaperForceHidingChanged = false;
7608            int repeats = 0;
7609            int changes = 0;
7610
7611            do {
7612                repeats++;
7613                if (repeats > 6) {
7614                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
7615                    mLayoutNeeded = false;
7616                    break;
7617                }
7618
7619                if ((changes&(WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER
7620                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG
7621                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) {
7622                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
7623                        if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
7624                            assignLayersLocked();
7625                            mLayoutNeeded = true;
7626                        }
7627                    }
7628                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
7629                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
7630                        if (updateOrientationFromAppTokensLocked(true)) {
7631                            mLayoutNeeded = true;
7632                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7633                        }
7634                    }
7635                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
7636                        mLayoutNeeded = true;
7637                    }
7638                }
7639
7640                // FIRST LOOP: Perform a layout, if needed.
7641                if (repeats < 4) {
7642                    changes = performLayoutLockedInner(repeats == 0, false /*updateInputWindows*/);
7643                    if (changes != 0) {
7644                        continue;
7645                    }
7646                } else {
7647                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
7648                    changes = 0;
7649                }
7650
7651                final int transactionSequence = ++mTransactionSequence;
7652
7653                // Update animations of all applications, including those
7654                // associated with exiting/removed apps
7655                boolean tokensAnimating = false;
7656                final int NAT = mAppTokens.size();
7657                for (i=0; i<NAT; i++) {
7658                    if (mAppTokens.get(i).stepAnimationLocked(currentTime,
7659                            innerDw, innerDh)) {
7660                        tokensAnimating = true;
7661                    }
7662                }
7663                final int NEAT = mExitingAppTokens.size();
7664                for (i=0; i<NEAT; i++) {
7665                    if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime,
7666                            innerDw, innerDh)) {
7667                        tokensAnimating = true;
7668                    }
7669                }
7670
7671                // SECOND LOOP: Execute animations and update visibility of windows.
7672
7673                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
7674                        + transactionSequence + " tokensAnimating="
7675                        + tokensAnimating);
7676
7677                animating = tokensAnimating;
7678
7679                if (mScreenRotationAnimation != null) {
7680                    if (mScreenRotationAnimation.isAnimating()) {
7681                        if (mScreenRotationAnimation.stepAnimation(currentTime)) {
7682                            animating = true;
7683                        } else {
7684                            screenRotationFinished = true;
7685                            updateRotation = true;
7686                        }
7687                    }
7688                }
7689
7690                boolean tokenMayBeDrawn = false;
7691                boolean wallpaperMayChange = false;
7692                boolean forceHiding = false;
7693                WindowState windowDetachedWallpaper = null;
7694                WindowState windowAnimationBackground = null;
7695                int windowAnimationBackgroundColor = 0;
7696
7697                mPolicy.beginAnimationLw(dw, dh);
7698
7699                final int N = mWindows.size();
7700
7701                for (i=N-1; i>=0; i--) {
7702                    WindowState w = mWindows.get(i);
7703
7704                    final WindowManager.LayoutParams attrs = w.mAttrs;
7705
7706                    if (w.mSurface != null) {
7707                        // Take care of the window being ready to display.
7708                        if (w.commitFinishDrawingLocked(currentTime)) {
7709                            if ((w.mAttrs.flags
7710                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
7711                                if (DEBUG_WALLPAPER) Slog.v(TAG,
7712                                        "First draw done in potential wallpaper target " + w);
7713                                wallpaperMayChange = true;
7714                            }
7715                        }
7716
7717                        final boolean wasAnimating = w.mAnimating;
7718
7719                        int animDw = innerDw;
7720                        int animDh = innerDh;
7721
7722                        // If the window has moved due to its containing
7723                        // content frame changing, then we'd like to animate
7724                        // it.  The checks here are ordered by what is least
7725                        // likely to be true first.
7726                        if (w.shouldAnimateMove()) {
7727                            // Frame has moved, containing content frame
7728                            // has also moved, and we're not currently animating...
7729                            // let's do something.
7730                            Animation a = AnimationUtils.loadAnimation(mContext,
7731                                    com.android.internal.R.anim.window_move_from_decor);
7732                            w.setAnimation(a);
7733                            animDw = w.mLastFrame.left - w.mFrame.left;
7734                            animDh = w.mLastFrame.top - w.mFrame.top;
7735                        }
7736
7737                        // Execute animation.
7738                        final boolean nowAnimating = w.stepAnimationLocked(currentTime,
7739                                animDw, animDh);
7740
7741                        // If this window is animating, make a note that we have
7742                        // an animating window and take care of a request to run
7743                        // a detached wallpaper animation.
7744                        if (nowAnimating) {
7745                            if (w.mAnimation != null) {
7746                                if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
7747                                        && w.mAnimation.getDetachWallpaper()) {
7748                                    windowDetachedWallpaper = w;
7749                                }
7750                                if (w.mAnimation.getBackgroundColor() != 0) {
7751                                    if (windowAnimationBackground == null || w.mAnimLayer <
7752                                            windowAnimationBackground.mAnimLayer) {
7753                                        windowAnimationBackground = w;
7754                                        windowAnimationBackgroundColor =
7755                                                w.mAnimation.getBackgroundColor();
7756                                    }
7757                                }
7758                            }
7759                            animating = true;
7760                        }
7761
7762                        // If this window's app token is running a detached wallpaper
7763                        // animation, make a note so we can ensure the wallpaper is
7764                        // displayed behind it.
7765                        if (w.mAppToken != null && w.mAppToken.animation != null
7766                                && w.mAppToken.animating) {
7767                            if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
7768                                    && w.mAppToken.animation.getDetachWallpaper()) {
7769                                windowDetachedWallpaper = w;
7770                            }
7771                            if (w.mAppToken.animation.getBackgroundColor() != 0) {
7772                                if (windowAnimationBackground == null || w.mAnimLayer <
7773                                        windowAnimationBackground.mAnimLayer) {
7774                                    windowAnimationBackground = w;
7775                                    windowAnimationBackgroundColor =
7776                                            w.mAppToken.animation.getBackgroundColor();
7777                                }
7778                            }
7779                        }
7780
7781                        if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
7782                            wallpaperMayChange = true;
7783                        }
7784
7785                        if (mPolicy.doesForceHide(w, attrs)) {
7786                            if (!wasAnimating && nowAnimating) {
7787                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7788                                        "Animation started that could impact force hide: "
7789                                        + w);
7790                                wallpaperForceHidingChanged = true;
7791                                mFocusMayChange = true;
7792                            } else if (w.isReadyForDisplay() && w.mAnimation == null) {
7793                                forceHiding = true;
7794                            }
7795                        } else if (mPolicy.canBeForceHidden(w, attrs)) {
7796                            boolean changed;
7797                            if (forceHiding) {
7798                                changed = w.hideLw(false, false);
7799                                if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
7800                                        "Now policy hidden: " + w);
7801                            } else {
7802                                changed = w.showLw(false, false);
7803                                if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
7804                                        "Now policy shown: " + w);
7805                                if (changed) {
7806                                    if (wallpaperForceHidingChanged
7807                                            && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
7808                                        // Assume we will need to animate.  If
7809                                        // we don't (because the wallpaper will
7810                                        // stay with the lock screen), then we will
7811                                        // clean up later.
7812                                        Animation a = mPolicy.createForceHideEnterAnimation();
7813                                        if (a != null) {
7814                                            w.setAnimation(a);
7815                                        }
7816                                    }
7817                                    if (mCurrentFocus == null ||
7818                                            mCurrentFocus.mLayer < w.mLayer) {
7819                                        // We are showing on to of the current
7820                                        // focus, so re-evaluate focus to make
7821                                        // sure it is correct.
7822                                        mFocusMayChange = true;
7823                                    }
7824                                }
7825                            }
7826                            if (changed && (attrs.flags
7827                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
7828                                wallpaperMayChange = true;
7829                            }
7830                        }
7831
7832                        mPolicy.animatingWindowLw(w, attrs);
7833                    }
7834
7835                    final AppWindowToken atoken = w.mAppToken;
7836                    if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
7837                        if (atoken.lastTransactionSequence != transactionSequence) {
7838                            atoken.lastTransactionSequence = transactionSequence;
7839                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
7840                            atoken.startingDisplayed = false;
7841                        }
7842                        if ((w.isOnScreen() || w.mAttrs.type
7843                                == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
7844                                && !w.mExiting && !w.mDestroying) {
7845                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
7846                                Slog.v(TAG, "Eval win " + w + ": isDrawn="
7847                                        + w.isDrawnLw()
7848                                        + ", isAnimating=" + w.isAnimating());
7849                                if (!w.isDrawnLw()) {
7850                                    Slog.v(TAG, "Not displayed: s=" + w.mSurface
7851                                            + " pv=" + w.mPolicyVisibility
7852                                            + " dp=" + w.mDrawPending
7853                                            + " cdp=" + w.mCommitDrawPending
7854                                            + " ah=" + w.mAttachedHidden
7855                                            + " th=" + atoken.hiddenRequested
7856                                            + " a=" + w.mAnimating);
7857                                }
7858                            }
7859                            if (w != atoken.startingWindow) {
7860                                if (!atoken.freezingScreen || !w.mAppFreezing) {
7861                                    atoken.numInterestingWindows++;
7862                                    if (w.isDrawnLw()) {
7863                                        atoken.numDrawnWindows++;
7864                                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
7865                                                "tokenMayBeDrawn: " + atoken
7866                                                + " freezingScreen=" + atoken.freezingScreen
7867                                                + " mAppFreezing=" + w.mAppFreezing);
7868                                        tokenMayBeDrawn = true;
7869                                    }
7870                                }
7871                            } else if (w.isDrawnLw()) {
7872                                atoken.startingDisplayed = true;
7873                            }
7874                        }
7875                    } else if (w.mReadyToShow) {
7876                        w.performShowLocked();
7877                    }
7878                }
7879
7880                changes |= mPolicy.finishAnimationLw();
7881
7882                if (tokenMayBeDrawn) {
7883                    // See if any windows have been drawn, so they (and others
7884                    // associated with them) can now be shown.
7885                    final int NT = mAppTokens.size();
7886                    for (i=0; i<NT; i++) {
7887                        AppWindowToken wtoken = mAppTokens.get(i);
7888                        if (wtoken.freezingScreen) {
7889                            int numInteresting = wtoken.numInterestingWindows;
7890                            if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7891                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7892                                        "allDrawn: " + wtoken
7893                                        + " interesting=" + numInteresting
7894                                        + " drawn=" + wtoken.numDrawnWindows);
7895                                wtoken.showAllWindowsLocked();
7896                                unsetAppFreezingScreenLocked(wtoken, false, true);
7897                                if (DEBUG_ORIENTATION) Slog.i(TAG,
7898                                        "Setting orientationChangeComplete=true because wtoken "
7899                                        + wtoken + " numInteresting=" + numInteresting
7900                                        + " numDrawn=" + wtoken.numDrawnWindows);
7901                                orientationChangeComplete = true;
7902                            }
7903                        } else if (!wtoken.allDrawn) {
7904                            int numInteresting = wtoken.numInterestingWindows;
7905                            if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7906                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7907                                        "allDrawn: " + wtoken
7908                                        + " interesting=" + numInteresting
7909                                        + " drawn=" + wtoken.numDrawnWindows);
7910                                wtoken.allDrawn = true;
7911                                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
7912
7913                                // We can now show all of the drawn windows!
7914                                if (!mOpeningApps.contains(wtoken)) {
7915                                    wtoken.showAllWindowsLocked();
7916                                }
7917                            }
7918                        }
7919                    }
7920                }
7921
7922                // If we are ready to perform an app transition, check through
7923                // all of the app tokens to be shown and see if they are ready
7924                // to go.
7925                if (mAppTransitionReady) {
7926                    int NN = mOpeningApps.size();
7927                    boolean goodToGo = true;
7928                    if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7929                            "Checking " + NN + " opening apps (frozen="
7930                            + mDisplayFrozen + " timeout="
7931                            + mAppTransitionTimeout + ")...");
7932                    if (!mDisplayFrozen && !mAppTransitionTimeout) {
7933                        // If the display isn't frozen, wait to do anything until
7934                        // all of the apps are ready.  Otherwise just go because
7935                        // we'll unfreeze the display when everyone is ready.
7936                        for (i=0; i<NN && goodToGo; i++) {
7937                            AppWindowToken wtoken = mOpeningApps.get(i);
7938                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7939                                    "Check opening app" + wtoken + ": allDrawn="
7940                                    + wtoken.allDrawn + " startingDisplayed="
7941                                    + wtoken.startingDisplayed);
7942                            if (!wtoken.allDrawn && !wtoken.startingDisplayed
7943                                    && !wtoken.startingMoved) {
7944                                goodToGo = false;
7945                            }
7946                        }
7947                    }
7948                    if (goodToGo) {
7949                        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
7950                        int transit = mNextAppTransition;
7951                        if (mSkipAppTransitionAnimation) {
7952                            transit = WindowManagerPolicy.TRANSIT_UNSET;
7953                        }
7954                        mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
7955                        mAppTransitionReady = false;
7956                        mAppTransitionRunning = true;
7957                        mAppTransitionTimeout = false;
7958                        mStartingIconInTransition = false;
7959                        mSkipAppTransitionAnimation = false;
7960
7961                        mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
7962
7963                        // If there are applications waiting to come to the
7964                        // top of the stack, now is the time to move their windows.
7965                        // (Note that we don't do apps going to the bottom
7966                        // here -- we want to keep their windows in the old
7967                        // Z-order until the animation completes.)
7968                        if (mToTopApps.size() > 0) {
7969                            NN = mAppTokens.size();
7970                            for (i=0; i<NN; i++) {
7971                                AppWindowToken wtoken = mAppTokens.get(i);
7972                                if (wtoken.sendingToTop) {
7973                                    wtoken.sendingToTop = false;
7974                                    moveAppWindowsLocked(wtoken, NN, false);
7975                                }
7976                            }
7977                            mToTopApps.clear();
7978                        }
7979
7980                        WindowState oldWallpaper = mWallpaperTarget;
7981
7982                        adjustWallpaperWindowsLocked();
7983                        wallpaperMayChange = false;
7984
7985                        // The top-most window will supply the layout params,
7986                        // and we will determine it below.
7987                        LayoutParams animLp = null;
7988                        int bestAnimLayer = -1;
7989                        boolean fullscreenAnim = false;
7990
7991                        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7992                                "New wallpaper target=" + mWallpaperTarget
7993                                + ", lower target=" + mLowerWallpaperTarget
7994                                + ", upper target=" + mUpperWallpaperTarget);
7995                        int foundWallpapers = 0;
7996                        // Do a first pass through the tokens for two
7997                        // things:
7998                        // (1) Determine if both the closing and opening
7999                        // app token sets are wallpaper targets, in which
8000                        // case special animations are needed
8001                        // (since the wallpaper needs to stay static
8002                        // behind them).
8003                        // (2) Find the layout params of the top-most
8004                        // application window in the tokens, which is
8005                        // what will control the animation theme.
8006                        final int NC = mClosingApps.size();
8007                        NN = NC + mOpeningApps.size();
8008                        for (i=0; i<NN; i++) {
8009                            AppWindowToken wtoken;
8010                            int mode;
8011                            if (i < NC) {
8012                                wtoken = mClosingApps.get(i);
8013                                mode = 1;
8014                            } else {
8015                                wtoken = mOpeningApps.get(i-NC);
8016                                mode = 2;
8017                            }
8018                            if (mLowerWallpaperTarget != null) {
8019                                if (mLowerWallpaperTarget.mAppToken == wtoken
8020                                        || mUpperWallpaperTarget.mAppToken == wtoken) {
8021                                    foundWallpapers |= mode;
8022                                }
8023                            }
8024                            if (wtoken.appFullscreen) {
8025                                WindowState ws = wtoken.findMainWindow();
8026                                if (ws != null) {
8027                                    animLp = ws.mAttrs;
8028                                    bestAnimLayer = ws.mLayer;
8029                                    fullscreenAnim = true;
8030                                }
8031                            } else if (!fullscreenAnim) {
8032                                WindowState ws = wtoken.findMainWindow();
8033                                if (ws != null) {
8034                                    if (ws.mLayer > bestAnimLayer) {
8035                                        animLp = ws.mAttrs;
8036                                        bestAnimLayer = ws.mLayer;
8037                                    }
8038                                }
8039                            }
8040                        }
8041
8042                        if (foundWallpapers == 3) {
8043                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8044                                    "Wallpaper animation!");
8045                            switch (transit) {
8046                                case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
8047                                case WindowManagerPolicy.TRANSIT_TASK_OPEN:
8048                                case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
8049                                    transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
8050                                    break;
8051                                case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
8052                                case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
8053                                case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
8054                                    transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
8055                                    break;
8056                            }
8057                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8058                                    "New transit: " + transit);
8059                        } else if (oldWallpaper != null) {
8060                            // We are transitioning from an activity with
8061                            // a wallpaper to one without.
8062                            transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
8063                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8064                                    "New transit away from wallpaper: " + transit);
8065                        } else if (mWallpaperTarget != null) {
8066                            // We are transitioning from an activity without
8067                            // a wallpaper to now showing the wallpaper
8068                            transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
8069                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8070                                    "New transit into wallpaper: " + transit);
8071                        }
8072
8073                        // If all closing windows are obscured, then there is
8074                        // no need to do an animation.  This is the case, for
8075                        // example, when this transition is being done behind
8076                        // the lock screen.
8077                        if (!mPolicy.allowAppAnimationsLw()) {
8078                            animLp = null;
8079                        }
8080
8081                        NN = mOpeningApps.size();
8082                        for (i=0; i<NN; i++) {
8083                            AppWindowToken wtoken = mOpeningApps.get(i);
8084                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8085                                    "Now opening app" + wtoken);
8086                            wtoken.reportedVisible = false;
8087                            wtoken.inPendingTransaction = false;
8088                            wtoken.animation = null;
8089                            setTokenVisibilityLocked(wtoken, animLp, true,
8090                                    transit, false);
8091                            wtoken.updateReportedVisibilityLocked();
8092                            wtoken.waitingToShow = false;
8093                            wtoken.showAllWindowsLocked();
8094                        }
8095                        NN = mClosingApps.size();
8096                        for (i=0; i<NN; i++) {
8097                            AppWindowToken wtoken = mClosingApps.get(i);
8098                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8099                                    "Now closing app" + wtoken);
8100                            wtoken.inPendingTransaction = false;
8101                            wtoken.animation = null;
8102                            setTokenVisibilityLocked(wtoken, animLp, false,
8103                                    transit, false);
8104                            wtoken.updateReportedVisibilityLocked();
8105                            wtoken.waitingToHide = false;
8106                            // Force the allDrawn flag, because we want to start
8107                            // this guy's animations regardless of whether it's
8108                            // gotten drawn.
8109                            wtoken.allDrawn = true;
8110                        }
8111
8112                        mNextAppTransitionPackage = null;
8113
8114                        mOpeningApps.clear();
8115                        mClosingApps.clear();
8116
8117                        // This has changed the visibility of windows, so perform
8118                        // a new layout to get them all up-to-date.
8119                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
8120                                | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8121                        mLayoutNeeded = true;
8122                        if (!moveInputMethodWindowsIfNeededLocked(true)) {
8123                            assignLayersLocked();
8124                        }
8125                        updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8126                                false /*updateInputWindows*/);
8127                        mFocusMayChange = false;
8128                    }
8129                }
8130
8131                int adjResult = 0;
8132
8133                if (!animating && mAppTransitionRunning) {
8134                    // We have finished the animation of an app transition.  To do
8135                    // this, we have delayed a lot of operations like showing and
8136                    // hiding apps, moving apps in Z-order, etc.  The app token list
8137                    // reflects the correct Z-order, but the window list may now
8138                    // be out of sync with it.  So here we will just rebuild the
8139                    // entire app window list.  Fun!
8140                    mAppTransitionRunning = false;
8141                    // Clear information about apps that were moving.
8142                    mToBottomApps.clear();
8143
8144                    rebuildAppWindowListLocked();
8145                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8146                    adjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
8147                    moveInputMethodWindowsIfNeededLocked(false);
8148                    wallpaperMayChange = true;
8149                    // Since the window list has been rebuilt, focus might
8150                    // have to be recomputed since the actual order of windows
8151                    // might have changed again.
8152                    mFocusMayChange = true;
8153                }
8154
8155                if (wallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) {
8156                    // At this point, there was a window with a wallpaper that
8157                    // was force hiding other windows behind it, but now it
8158                    // is going away.  This may be simple -- just animate
8159                    // away the wallpaper and its window -- or it may be
8160                    // hard -- the wallpaper now needs to be shown behind
8161                    // something that was hidden.
8162                    WindowState oldWallpaper = mWallpaperTarget;
8163                    if (mLowerWallpaperTarget != null
8164                            && mLowerWallpaperTarget.mAppToken != null) {
8165                        if (DEBUG_WALLPAPER) Slog.v(TAG,
8166                                "wallpaperForceHiding changed with lower="
8167                                + mLowerWallpaperTarget);
8168                        if (DEBUG_WALLPAPER) Slog.v(TAG,
8169                                "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
8170                                " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
8171                        if (mLowerWallpaperTarget.mAppToken.hidden) {
8172                            // The lower target has become hidden before we
8173                            // actually started the animation...  let's completely
8174                            // re-evaluate everything.
8175                            mLowerWallpaperTarget = mUpperWallpaperTarget = null;
8176                            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8177                        }
8178                    }
8179                    adjResult |= adjustWallpaperWindowsLocked();
8180                    wallpaperMayChange = false;
8181                    wallpaperForceHidingChanged = false;
8182                    if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
8183                            + " NEW: " + mWallpaperTarget
8184                            + " LOWER: " + mLowerWallpaperTarget);
8185                    if (mLowerWallpaperTarget == null) {
8186                        // Whoops, we don't need a special wallpaper animation.
8187                        // Clear them out.
8188                        forceHiding = false;
8189                        for (i=N-1; i>=0; i--) {
8190                            WindowState w = mWindows.get(i);
8191                            if (w.mSurface != null) {
8192                                final WindowManager.LayoutParams attrs = w.mAttrs;
8193                                if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
8194                                    if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
8195                                    forceHiding = true;
8196                                } else if (mPolicy.canBeForceHidden(w, attrs)) {
8197                                    if (!w.mAnimating) {
8198                                        // We set the animation above so it
8199                                        // is not yet running.
8200                                        w.clearAnimation();
8201                                    }
8202                                }
8203                            }
8204                        }
8205                    }
8206                }
8207
8208                if (mWindowDetachedWallpaper != windowDetachedWallpaper) {
8209                    if (DEBUG_WALLPAPER) Slog.v(TAG,
8210                            "Detached wallpaper changed from " + mWindowDetachedWallpaper
8211                            + " to " + windowDetachedWallpaper);
8212                    mWindowDetachedWallpaper = windowDetachedWallpaper;
8213                    wallpaperMayChange = true;
8214                }
8215
8216                if (windowAnimationBackgroundColor != 0) {
8217                    // If the window that wants black is the current wallpaper
8218                    // target, then the black goes *below* the wallpaper so we
8219                    // don't cause the wallpaper to suddenly disappear.
8220                    WindowState target = windowAnimationBackground;
8221                    if (mWallpaperTarget == windowAnimationBackground
8222                            || mLowerWallpaperTarget == windowAnimationBackground
8223                            || mUpperWallpaperTarget == windowAnimationBackground) {
8224                        for (i=0; i<mWindows.size(); i++) {
8225                            WindowState w = mWindows.get(i);
8226                            if (w.mIsWallpaper) {
8227                                target = w;
8228                                break;
8229                            }
8230                        }
8231                    }
8232                    if (mWindowAnimationBackgroundSurface == null) {
8233                        mWindowAnimationBackgroundSurface = new DimSurface(mFxSession);
8234                    }
8235                    mWindowAnimationBackgroundSurface.show(dw, dh,
8236                            target.mAnimLayer - LAYER_OFFSET_DIM,
8237                            windowAnimationBackgroundColor);
8238                } else if (mWindowAnimationBackgroundSurface != null) {
8239                    mWindowAnimationBackgroundSurface.hide();
8240                }
8241
8242                if (wallpaperMayChange) {
8243                    if (DEBUG_WALLPAPER) Slog.v(TAG,
8244                            "Wallpaper may change!  Adjusting");
8245                    adjResult |= adjustWallpaperWindowsLocked();
8246                }
8247
8248                if ((adjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8249                    if (DEBUG_WALLPAPER) Slog.v(TAG,
8250                            "Wallpaper layer changed: assigning layers + relayout");
8251                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8252                    assignLayersLocked();
8253                } else if ((adjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
8254                    if (DEBUG_WALLPAPER) Slog.v(TAG,
8255                            "Wallpaper visibility changed: relayout");
8256                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8257                }
8258
8259                if (mFocusMayChange) {
8260                    mFocusMayChange = false;
8261                    if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8262                            false /*updateInputWindows*/)) {
8263                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8264                        adjResult = 0;
8265                    }
8266                }
8267
8268                if (mLayoutNeeded) {
8269                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8270                }
8271
8272                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
8273                        + Integer.toHexString(changes));
8274            } while (changes != 0);
8275
8276            // THIRD LOOP: Update the surfaces of all windows.
8277
8278            final boolean someoneLosingFocus = mLosingFocus.size() != 0;
8279
8280            boolean obscured = false;
8281            boolean blurring = false;
8282            boolean dimming = false;
8283            boolean covered = false;
8284            boolean syswin = false;
8285
8286            final int N = mWindows.size();
8287
8288            for (i=N-1; i>=0; i--) {
8289                WindowState w = mWindows.get(i);
8290
8291                boolean displayed = false;
8292                final WindowManager.LayoutParams attrs = w.mAttrs;
8293                final int attrFlags = attrs.flags;
8294
8295                if (w.mSurface != null) {
8296                    // XXX NOTE: The logic here could be improved.  We have
8297                    // the decision about whether to resize a window separated
8298                    // from whether to hide the surface.  This can cause us to
8299                    // resize a surface even if we are going to hide it.  You
8300                    // can see this by (1) holding device in landscape mode on
8301                    // home screen; (2) tapping browser icon (device will rotate
8302                    // to landscape; (3) tap home.  The wallpaper will be resized
8303                    // in step 2 but then immediately hidden, causing us to
8304                    // have to resize and then redraw it again in step 3.  It
8305                    // would be nice to figure out how to avoid this, but it is
8306                    // difficult because we do need to resize surfaces in some
8307                    // cases while they are hidden such as when first showing a
8308                    // window.
8309
8310                    w.computeShownFrameLocked();
8311                    if (localLOGV) Slog.v(
8312                            TAG, "Placing surface #" + i + " " + w.mSurface
8313                            + ": new=" + w.mShownFrame);
8314
8315                    if (w.mSurface != null) {
8316                        int width, height;
8317                        if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
8318                            // for a scaled surface, we just want to use
8319                            // the requested size.
8320                            width  = w.mRequestedWidth;
8321                            height = w.mRequestedHeight;
8322                        } else {
8323                            width = w.mCompatFrame.width();
8324                            height = w.mCompatFrame.height();
8325                        }
8326
8327                        if (width < 1) {
8328                            width = 1;
8329                        }
8330                        if (height < 1) {
8331                            height = 1;
8332                        }
8333                        final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
8334                        if (surfaceResized) {
8335                            w.mSurfaceW = width;
8336                            w.mSurfaceH = height;
8337                        }
8338
8339                        if (w.mSurfaceX != w.mShownFrame.left
8340                                || w.mSurfaceY != w.mShownFrame.top) {
8341                            try {
8342                                if (SHOW_TRANSACTIONS) logSurface(w,
8343                                        "POS " + w.mShownFrame.left
8344                                        + ", " + w.mShownFrame.top, null);
8345                                w.mSurfaceX = w.mShownFrame.left;
8346                                w.mSurfaceY = w.mShownFrame.top;
8347                                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
8348                            } catch (RuntimeException e) {
8349                                Slog.w(TAG, "Error positioning surface of " + w
8350                                        + " pos=(" + w.mShownFrame.left
8351                                        + "," + w.mShownFrame.top + ")", e);
8352                                if (!recoveringMemory) {
8353                                    reclaimSomeSurfaceMemoryLocked(w, "position", true);
8354                                }
8355                            }
8356                        }
8357
8358                        if (surfaceResized) {
8359                            try {
8360                                if (SHOW_TRANSACTIONS) logSurface(w,
8361                                        "SIZE " + width + "x" + height, null);
8362                                w.mSurfaceResized = true;
8363                                w.mSurface.setSize(width, height);
8364                            } catch (RuntimeException e) {
8365                                // If something goes wrong with the surface (such
8366                                // as running out of memory), don't take down the
8367                                // entire system.
8368                                Slog.e(TAG, "Error resizing surface of " + w
8369                                        + " size=(" + width + "x" + height + ")", e);
8370                                if (!recoveringMemory) {
8371                                    reclaimSomeSurfaceMemoryLocked(w, "size", true);
8372                                }
8373                            }
8374                        }
8375                    }
8376
8377                    if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
8378                        w.mContentInsetsChanged |=
8379                            !w.mLastContentInsets.equals(w.mContentInsets);
8380                        w.mVisibleInsetsChanged |=
8381                            !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8382                        boolean configChanged =
8383                            w.mConfiguration != mCurConfiguration
8384                            && (w.mConfiguration == null
8385                                    || mCurConfiguration.diff(w.mConfiguration) != 0);
8386                        if (DEBUG_CONFIGURATION && configChanged) {
8387                            Slog.v(TAG, "Win " + w + " config changed: "
8388                                    + mCurConfiguration);
8389                        }
8390                        if (localLOGV) Slog.v(TAG, "Resizing " + w
8391                                + ": configChanged=" + configChanged
8392                                + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8393                        w.mLastFrame.set(w.mFrame);
8394                        if (w.mContentInsetsChanged
8395                                || w.mVisibleInsetsChanged
8396                                || w.mSurfaceResized
8397                                || configChanged) {
8398                            if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8399                                Slog.v(TAG, "Resize reasons: "
8400                                        + " contentInsetsChanged=" + w.mContentInsetsChanged
8401                                        + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8402                                        + " surfaceResized=" + w.mSurfaceResized
8403                                        + " configChanged=" + configChanged);
8404                            }
8405
8406                            w.mLastContentInsets.set(w.mContentInsets);
8407                            w.mLastVisibleInsets.set(w.mVisibleInsets);
8408                            makeWindowFreezingScreenIfNeededLocked(w);
8409                            // If the orientation is changing, then we need to
8410                            // hold off on unfreezing the display until this
8411                            // window has been redrawn; to do that, we need
8412                            // to go through the process of getting informed
8413                            // by the application when it has finished drawing.
8414                            if (w.mOrientationChanging) {
8415                                if (DEBUG_ORIENTATION) Slog.v(TAG,
8416                                        "Orientation start waiting for draw in "
8417                                        + w + ", surface " + w.mSurface);
8418                                w.mDrawPending = true;
8419                                w.mCommitDrawPending = false;
8420                                w.mReadyToShow = false;
8421                                if (w.mAppToken != null) {
8422                                    w.mAppToken.allDrawn = false;
8423                                }
8424                            }
8425                            if (!mResizingWindows.contains(w)) {
8426                                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8427                                        "Resizing window " + w + " to " + w.mSurfaceW
8428                                        + "x" + w.mSurfaceH);
8429                                mResizingWindows.add(w);
8430                            }
8431                        } else if (w.mOrientationChanging) {
8432                            if (!w.mDrawPending && !w.mCommitDrawPending) {
8433                                if (DEBUG_ORIENTATION) Slog.v(TAG,
8434                                        "Orientation not waiting for draw in "
8435                                        + w + ", surface " + w.mSurface);
8436                                w.mOrientationChanging = false;
8437                            }
8438                        }
8439                    }
8440
8441                    if (w.mAttachedHidden || !w.isReadyForDisplay()) {
8442                        if (!w.mLastHidden) {
8443                            //dump();
8444                            w.mLastHidden = true;
8445                            if (SHOW_TRANSACTIONS) logSurface(w,
8446                                    "HIDE (performLayout)", null);
8447                            if (w.mSurface != null) {
8448                                w.mSurfaceShown = false;
8449                                try {
8450                                    w.mSurface.hide();
8451                                } catch (RuntimeException e) {
8452                                    Slog.w(TAG, "Exception hiding surface in " + w);
8453                                }
8454                            }
8455                        }
8456                        // If we are waiting for this window to handle an
8457                        // orientation change, well, it is hidden, so
8458                        // doesn't really matter.  Note that this does
8459                        // introduce a potential glitch if the window
8460                        // becomes unhidden before it has drawn for the
8461                        // new orientation.
8462                        if (w.mOrientationChanging) {
8463                            w.mOrientationChanging = false;
8464                            if (DEBUG_ORIENTATION) Slog.v(TAG,
8465                                    "Orientation change skips hidden " + w);
8466                        }
8467                    } else if (w.mLastLayer != w.mAnimLayer
8468                            || w.mLastAlpha != w.mShownAlpha
8469                            || w.mLastDsDx != w.mDsDx
8470                            || w.mLastDtDx != w.mDtDx
8471                            || w.mLastDsDy != w.mDsDy
8472                            || w.mLastDtDy != w.mDtDy
8473                            || w.mLastHScale != w.mHScale
8474                            || w.mLastVScale != w.mVScale
8475                            || w.mLastHidden) {
8476                        displayed = true;
8477                        w.mLastAlpha = w.mShownAlpha;
8478                        w.mLastLayer = w.mAnimLayer;
8479                        w.mLastDsDx = w.mDsDx;
8480                        w.mLastDtDx = w.mDtDx;
8481                        w.mLastDsDy = w.mDsDy;
8482                        w.mLastDtDy = w.mDtDy;
8483                        w.mLastHScale = w.mHScale;
8484                        w.mLastVScale = w.mVScale;
8485                        if (SHOW_TRANSACTIONS) logSurface(w,
8486                                "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
8487                                + " matrix=[" + (w.mDsDx*w.mHScale)
8488                                + "," + (w.mDtDx*w.mVScale)
8489                                + "][" + (w.mDsDy*w.mHScale)
8490                                + "," + (w.mDtDy*w.mVScale) + "]", null);
8491                        if (w.mSurface != null) {
8492                            try {
8493                                w.mSurfaceAlpha = w.mShownAlpha;
8494                                w.mSurface.setAlpha(w.mShownAlpha);
8495                                w.mSurfaceLayer = w.mAnimLayer;
8496                                w.mSurface.setLayer(w.mAnimLayer);
8497                                w.mSurface.setMatrix(
8498                                        w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
8499                                        w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
8500                            } catch (RuntimeException e) {
8501                                Slog.w(TAG, "Error updating surface in " + w, e);
8502                                if (!recoveringMemory) {
8503                                    reclaimSomeSurfaceMemoryLocked(w, "update", true);
8504                                }
8505                            }
8506                        }
8507
8508                        if (w.mLastHidden && !w.mDrawPending
8509                                && !w.mCommitDrawPending
8510                                && !w.mReadyToShow) {
8511                            if (SHOW_TRANSACTIONS) logSurface(w,
8512                                    "SHOW (performLayout)", null);
8513                            if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
8514                                    + " during relayout");
8515                            if (showSurfaceRobustlyLocked(w)) {
8516                                w.mHasDrawn = true;
8517                                w.mLastHidden = false;
8518                            } else {
8519                                w.mOrientationChanging = false;
8520                            }
8521                        }
8522                        if (w.mSurface != null) {
8523                            w.mToken.hasVisible = true;
8524                        }
8525                    } else {
8526                        displayed = true;
8527                    }
8528
8529                    if (displayed) {
8530                        if (!covered) {
8531                            if (attrs.width == LayoutParams.MATCH_PARENT
8532                                    && attrs.height == LayoutParams.MATCH_PARENT) {
8533                                covered = true;
8534                            }
8535                        }
8536                        if (w.mOrientationChanging) {
8537                            if (w.mDrawPending || w.mCommitDrawPending) {
8538                                orientationChangeComplete = false;
8539                                if (DEBUG_ORIENTATION) Slog.v(TAG,
8540                                        "Orientation continue waiting for draw in " + w);
8541                            } else {
8542                                w.mOrientationChanging = false;
8543                                if (DEBUG_ORIENTATION) Slog.v(TAG,
8544                                        "Orientation change complete in " + w);
8545                            }
8546                        }
8547                        w.mToken.hasVisible = true;
8548                    }
8549                } else if (w.mOrientationChanging) {
8550                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8551                            "Orientation change skips hidden " + w);
8552                    w.mOrientationChanging = false;
8553                }
8554
8555                if (w.mContentChanged) {
8556                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
8557                    w.mContentChanged = false;
8558                }
8559
8560                final boolean canBeSeen = w.isDisplayedLw();
8561
8562                if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
8563                    focusDisplayed = true;
8564                }
8565
8566                final boolean obscuredChanged = w.mObscured != obscured;
8567
8568                // Update effect.
8569                if (!(w.mObscured=obscured)) {
8570                    if (w.mSurface != null) {
8571                        if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8572                            holdScreen = w.mSession;
8573                        }
8574                        if (!syswin && w.mAttrs.screenBrightness >= 0
8575                                && screenBrightness < 0) {
8576                            screenBrightness = w.mAttrs.screenBrightness;
8577                        }
8578                        if (!syswin && w.mAttrs.buttonBrightness >= 0
8579                                && buttonBrightness < 0) {
8580                            buttonBrightness = w.mAttrs.buttonBrightness;
8581                        }
8582                        if (canBeSeen
8583                                && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8584                                 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8585                                 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
8586                            syswin = true;
8587                        }
8588                    }
8589
8590                    boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8591                    if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8592                        // This window completely covers everything behind it,
8593                        // so we want to leave all of them as unblurred (for
8594                        // performance reasons).
8595                        obscured = true;
8596                    } else if (canBeSeen && !obscured &&
8597                            (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
8598                        if (localLOGV) Slog.v(TAG, "Win " + w
8599                                + ": blurring=" + blurring
8600                                + " obscured=" + obscured
8601                                + " displayed=" + displayed);
8602                        if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
8603                            if (!dimming) {
8604                                //Slog.i(TAG, "DIM BEHIND: " + w);
8605                                dimming = true;
8606                                if (mDimAnimator == null) {
8607                                    mDimAnimator = new DimAnimator(mFxSession);
8608                                }
8609                                mDimAnimator.show(innerDw, innerDh);
8610                                mDimAnimator.updateParameters(mContext.getResources(),
8611                                        w, currentTime);
8612                            }
8613                        }
8614                        if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
8615                            if (!blurring) {
8616                                //Slog.i(TAG, "BLUR BEHIND: " + w);
8617                                blurring = true;
8618                                if (mBlurSurface == null) {
8619                                    try {
8620                                        mBlurSurface = new Surface(mFxSession, 0,
8621                                                "BlurSurface",
8622                                                -1, 16, 16,
8623                                                PixelFormat.OPAQUE,
8624                                                Surface.FX_SURFACE_BLUR);
8625                                    } catch (Exception e) {
8626                                        Slog.e(TAG, "Exception creating Blur surface", e);
8627                                    }
8628                                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
8629                                            + mBlurSurface + ": CREATE");
8630                                }
8631                                if (mBlurSurface != null) {
8632                                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
8633                                            + mBlurSurface + ": pos=(0,0) (" +
8634                                            dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8635                                    mBlurSurface.setPosition(0, 0);
8636                                    mBlurSurface.setSize(dw, dh);
8637                                    mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR);
8638                                    if (!mBlurShown) {
8639                                        try {
8640                                            if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
8641                                                    + mBlurSurface + ": SHOW");
8642                                            mBlurSurface.show();
8643                                        } catch (RuntimeException e) {
8644                                            Slog.w(TAG, "Failure showing blur surface", e);
8645                                        }
8646                                        mBlurShown = true;
8647                                    }
8648                                }
8649                            }
8650                        }
8651                    }
8652                }
8653
8654                if (obscuredChanged && mWallpaperTarget == w) {
8655                    // This is the wallpaper target and its obscured state
8656                    // changed... make sure the current wallaper's visibility
8657                    // has been updated accordingly.
8658                    updateWallpaperVisibilityLocked();
8659                }
8660            }
8661
8662            if (mDimAnimator != null && mDimAnimator.mDimShown) {
8663                animating |= mDimAnimator.updateSurface(dimming, currentTime,
8664                        mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully());
8665            }
8666
8667            if (!blurring && mBlurShown) {
8668                if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR " + mBlurSurface
8669                        + ": HIDE");
8670                try {
8671                    mBlurSurface.hide();
8672                } catch (IllegalArgumentException e) {
8673                    Slog.w(TAG, "Illegal argument exception hiding blur surface");
8674                }
8675                mBlurShown = false;
8676            }
8677
8678            if (mBlackFrame != null) {
8679                if (mScreenRotationAnimation != null) {
8680                    mBlackFrame.setMatrix(
8681                            mScreenRotationAnimation.getEnterTransformation().getMatrix());
8682                } else {
8683                    mBlackFrame.clearMatrix();
8684                }
8685            }
8686        } catch (RuntimeException e) {
8687            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
8688        }
8689
8690        Surface.closeTransaction();
8691
8692        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8693                "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
8694
8695        if (mWatermark != null) {
8696            mWatermark.drawIfNeeded();
8697        }
8698
8699        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
8700                "With display frozen, orientationChangeComplete="
8701                + orientationChangeComplete);
8702        if (orientationChangeComplete) {
8703            if (mWindowsFreezingScreen) {
8704                mWindowsFreezingScreen = false;
8705                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8706            }
8707            stopFreezingDisplayLocked();
8708        }
8709
8710        i = mResizingWindows.size();
8711        if (i > 0) {
8712            do {
8713                i--;
8714                WindowState win = mResizingWindows.get(i);
8715                try {
8716                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8717                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
8718                    int diff = 0;
8719                    boolean configChanged =
8720                        win.mConfiguration != mCurConfiguration
8721                        && (win.mConfiguration == null
8722                                || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0);
8723                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
8724                            && configChanged) {
8725                        Slog.i(TAG, "Sending new config to window " + win + ": "
8726                                + win.mSurfaceW + "x" + win.mSurfaceH
8727                                + " / " + mCurConfiguration + " / 0x"
8728                                + Integer.toHexString(diff));
8729                    }
8730                    win.mConfiguration = mCurConfiguration;
8731                    if (DEBUG_ORIENTATION && win.mDrawPending) Slog.i(
8732                            TAG, "Resizing " + win + " WITH DRAW PENDING");
8733                    win.mClient.resized((int)win.mSurfaceW, (int)win.mSurfaceH,
8734                            win.mLastContentInsets, win.mLastVisibleInsets, win.mDrawPending,
8735                            configChanged ? win.mConfiguration : null);
8736                    win.mContentInsetsChanged = false;
8737                    win.mVisibleInsetsChanged = false;
8738                    win.mSurfaceResized = false;
8739                } catch (RemoteException e) {
8740                    win.mOrientationChanging = false;
8741                }
8742            } while (i > 0);
8743            mResizingWindows.clear();
8744        }
8745
8746        // Destroy the surface of any windows that are no longer visible.
8747        boolean wallpaperDestroyed = false;
8748        i = mDestroySurface.size();
8749        if (i > 0) {
8750            do {
8751                i--;
8752                WindowState win = mDestroySurface.get(i);
8753                win.mDestroying = false;
8754                if (mInputMethodWindow == win) {
8755                    mInputMethodWindow = null;
8756                }
8757                if (win == mWallpaperTarget) {
8758                    wallpaperDestroyed = true;
8759                }
8760                win.destroySurfaceLocked();
8761            } while (i > 0);
8762            mDestroySurface.clear();
8763        }
8764
8765        // Time to remove any exiting tokens?
8766        for (i=mExitingTokens.size()-1; i>=0; i--) {
8767            WindowToken token = mExitingTokens.get(i);
8768            if (!token.hasVisible) {
8769                mExitingTokens.remove(i);
8770                if (token.windowType == TYPE_WALLPAPER) {
8771                    mWallpaperTokens.remove(token);
8772                }
8773            }
8774        }
8775
8776        // Time to remove any exiting applications?
8777        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8778            AppWindowToken token = mExitingAppTokens.get(i);
8779            if (!token.hasVisible && !mClosingApps.contains(token)) {
8780                // Make sure there is no animation running on this token,
8781                // so any windows associated with it will be removed as
8782                // soon as their animations are complete
8783                token.animation = null;
8784                token.animating = false;
8785                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
8786                        "performLayout: App token exiting now removed" + token);
8787                mAppTokens.remove(token);
8788                mExitingAppTokens.remove(i);
8789            }
8790        }
8791
8792        boolean needRelayout = false;
8793
8794        if (!animating && mAppTransitionRunning) {
8795            // We have finished the animation of an app transition.  To do
8796            // this, we have delayed a lot of operations like showing and
8797            // hiding apps, moving apps in Z-order, etc.  The app token list
8798            // reflects the correct Z-order, but the window list may now
8799            // be out of sync with it.  So here we will just rebuild the
8800            // entire app window list.  Fun!
8801            mAppTransitionRunning = false;
8802            needRelayout = true;
8803            rebuildAppWindowListLocked();
8804            assignLayersLocked();
8805            // Clear information about apps that were moving.
8806            mToBottomApps.clear();
8807        }
8808
8809        if (focusDisplayed) {
8810            mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8811        }
8812        if (wallpaperDestroyed) {
8813            needRelayout = adjustWallpaperWindowsLocked() != 0;
8814        }
8815        if (needRelayout) {
8816            requestAnimationLocked(0);
8817        } else if (animating) {
8818            final int refreshTimeUs = (int)(1000 / mDisplay.getRefreshRate());
8819            requestAnimationLocked(currentTime + refreshTimeUs - SystemClock.uptimeMillis());
8820        }
8821
8822        // Finally update all input windows now that the window changes have stabilized.
8823        mInputMonitor.updateInputWindowsLw(true /*force*/);
8824
8825        setHoldScreenLocked(holdScreen != null);
8826        if (!mDisplayFrozen) {
8827            if (screenBrightness < 0 || screenBrightness > 1.0f) {
8828                mPowerManager.setScreenBrightnessOverride(-1);
8829            } else {
8830                mPowerManager.setScreenBrightnessOverride((int)
8831                        (screenBrightness * Power.BRIGHTNESS_ON));
8832            }
8833            if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
8834                mPowerManager.setButtonBrightnessOverride(-1);
8835            } else {
8836                mPowerManager.setButtonBrightnessOverride((int)
8837                        (buttonBrightness * Power.BRIGHTNESS_ON));
8838            }
8839        }
8840        if (holdScreen != mHoldingScreenOn) {
8841            mHoldingScreenOn = holdScreen;
8842            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
8843            mH.sendMessage(m);
8844        }
8845
8846        if (mTurnOnScreen) {
8847            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
8848            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
8849                    LocalPowerManager.BUTTON_EVENT, true);
8850            mTurnOnScreen = false;
8851        }
8852
8853        if (screenRotationFinished && mScreenRotationAnimation != null) {
8854            mScreenRotationAnimation.kill();
8855            mScreenRotationAnimation = null;
8856        }
8857
8858        if (updateRotation) {
8859            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8860            boolean changed = updateRotationUncheckedLocked(false);
8861            if (changed) {
8862                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8863            } else {
8864                updateRotation = false;
8865            }
8866        }
8867
8868        if (orientationChangeComplete && !needRelayout && !updateRotation) {
8869            checkDrawnWindowsLocked();
8870        }
8871
8872        // Check to see if we are now in a state where the screen should
8873        // be enabled, because the window obscured flags have changed.
8874        enableScreenIfNeededLocked();
8875    }
8876
8877    void checkDrawnWindowsLocked() {
8878        if (mWaitingForDrawn.size() > 0) {
8879            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
8880                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
8881                WindowState win = pair.first;
8882                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
8883                //        + win.mRemoved + " visible=" + win.isVisibleLw()
8884                //        + " shown=" + win.mSurfaceShown);
8885                if (win.mRemoved || !win.isVisibleLw()) {
8886                    // Window has been removed or made invisible; no draw
8887                    // will now happen, so stop waiting.
8888                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
8889                    try {
8890                        pair.second.sendResult(null);
8891                    } catch (RemoteException e) {
8892                    }
8893                    mWaitingForDrawn.remove(pair);
8894                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8895                } else if (win.mSurfaceShown) {
8896                    // Window is now drawn (and shown).
8897                    try {
8898                        pair.second.sendResult(null);
8899                    } catch (RemoteException e) {
8900                    }
8901                    mWaitingForDrawn.remove(pair);
8902                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8903                }
8904            }
8905        }
8906    }
8907
8908    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
8909        synchronized (mWindowMap) {
8910            WindowState win = windowForClientLocked(null, token, true);
8911            if (win != null) {
8912                Pair<WindowState, IRemoteCallback> pair =
8913                        new Pair<WindowState, IRemoteCallback>(win, callback);
8914                Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8915                mH.sendMessageDelayed(m, 2000);
8916                mWaitingForDrawn.add(pair);
8917                checkDrawnWindowsLocked();
8918            }
8919        }
8920    }
8921
8922    /**
8923     * Must be called with the main window manager lock held.
8924     */
8925    void setHoldScreenLocked(boolean holding) {
8926        boolean state = mHoldingScreenWakeLock.isHeld();
8927        if (holding != state) {
8928            if (holding) {
8929                mPolicy.screenOnStartedLw();
8930                mHoldingScreenWakeLock.acquire();
8931            } else {
8932                mPolicy.screenOnStoppedLw();
8933                mHoldingScreenWakeLock.release();
8934            }
8935        }
8936    }
8937
8938    void requestAnimationLocked(long delay) {
8939        if (!mAnimationPending) {
8940            mAnimationPending = true;
8941            mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
8942        }
8943    }
8944
8945    /**
8946     * Have the surface flinger show a surface, robustly dealing with
8947     * error conditions.  In particular, if there is not enough memory
8948     * to show the surface, then we will try to get rid of other surfaces
8949     * in order to succeed.
8950     *
8951     * @return Returns true if the surface was successfully shown.
8952     */
8953    boolean showSurfaceRobustlyLocked(WindowState win) {
8954        try {
8955            if (win.mSurface != null) {
8956                win.mSurfaceShown = true;
8957                win.mSurface.show();
8958                if (win.mTurnOnScreen) {
8959                    if (DEBUG_VISIBILITY) Slog.v(TAG,
8960                            "Show surface turning screen on: " + win);
8961                    win.mTurnOnScreen = false;
8962                    mTurnOnScreen = true;
8963                }
8964            }
8965            return true;
8966        } catch (RuntimeException e) {
8967            Slog.w(TAG, "Failure showing surface " + win.mSurface + " in " + win, e);
8968        }
8969
8970        reclaimSomeSurfaceMemoryLocked(win, "show", true);
8971
8972        return false;
8973    }
8974
8975    boolean reclaimSomeSurfaceMemoryLocked(WindowState win, String operation, boolean secure) {
8976        final Surface surface = win.mSurface;
8977        boolean leakedSurface = false;
8978        boolean killedApps = false;
8979
8980        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, win.toString(),
8981                win.mSession.mPid, operation);
8982
8983        if (mForceRemoves == null) {
8984            mForceRemoves = new ArrayList<WindowState>();
8985        }
8986
8987        long callingIdentity = Binder.clearCallingIdentity();
8988        try {
8989            // There was some problem...   first, do a sanity check of the
8990            // window list to make sure we haven't left any dangling surfaces
8991            // around.
8992            int N = mWindows.size();
8993            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
8994            for (int i=0; i<N; i++) {
8995                WindowState ws = mWindows.get(i);
8996                if (ws.mSurface != null) {
8997                    if (!mSessions.contains(ws.mSession)) {
8998                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8999                                + ws + " surface=" + ws.mSurface
9000                                + " token=" + win.mToken
9001                                + " pid=" + ws.mSession.mPid
9002                                + " uid=" + ws.mSession.mUid);
9003                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9004                        ws.mSurface.destroy();
9005                        ws.mSurfaceShown = false;
9006                        ws.mSurface = null;
9007                        mForceRemoves.add(ws);
9008                        i--;
9009                        N--;
9010                        leakedSurface = true;
9011                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
9012                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
9013                                + ws + " surface=" + ws.mSurface
9014                                + " token=" + win.mAppToken);
9015                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
9016                        ws.mSurface.destroy();
9017                        ws.mSurfaceShown = false;
9018                        ws.mSurface = null;
9019                        leakedSurface = true;
9020                    }
9021                }
9022            }
9023
9024            if (!leakedSurface) {
9025                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
9026                SparseIntArray pidCandidates = new SparseIntArray();
9027                for (int i=0; i<N; i++) {
9028                    WindowState ws = mWindows.get(i);
9029                    if (ws.mSurface != null) {
9030                        pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
9031                    }
9032                }
9033                if (pidCandidates.size() > 0) {
9034                    int[] pids = new int[pidCandidates.size()];
9035                    for (int i=0; i<pids.length; i++) {
9036                        pids[i] = pidCandidates.keyAt(i);
9037                    }
9038                    try {
9039                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
9040                            killedApps = true;
9041                        }
9042                    } catch (RemoteException e) {
9043                    }
9044                }
9045            }
9046
9047            if (leakedSurface || killedApps) {
9048                // We managed to reclaim some memory, so get rid of the trouble
9049                // surface and ask the app to request another one.
9050                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9051                if (surface != null) {
9052                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(win,
9053                            "RECOVER DESTROY", null);
9054                    surface.destroy();
9055                    win.mSurfaceShown = false;
9056                    win.mSurface = null;
9057                }
9058
9059                try {
9060                    win.mClient.dispatchGetNewSurface();
9061                } catch (RemoteException e) {
9062                }
9063            }
9064        } finally {
9065            Binder.restoreCallingIdentity(callingIdentity);
9066        }
9067
9068        return leakedSurface || killedApps;
9069    }
9070
9071    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9072        WindowState newFocus = computeFocusedWindowLocked();
9073        if (mCurrentFocus != newFocus) {
9074            // This check makes sure that we don't already have the focus
9075            // change message pending.
9076            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9077            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9078            if (localLOGV) Slog.v(
9079                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
9080            final WindowState oldFocus = mCurrentFocus;
9081            mCurrentFocus = newFocus;
9082            mLosingFocus.remove(newFocus);
9083            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9084
9085            final WindowState imWindow = mInputMethodWindow;
9086            if (newFocus != imWindow && oldFocus != imWindow) {
9087                if (moveInputMethodWindowsIfNeededLocked(
9088                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
9089                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
9090                    mLayoutNeeded = true;
9091                }
9092                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9093                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
9094                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9095                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9096                    // Client will do the layout, but we need to assign layers
9097                    // for handleNewWindowLocked() below.
9098                    assignLayersLocked();
9099                }
9100            }
9101
9102            if ((focusChanged&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9103                // The change in focus caused us to need to do a layout.  Okay.
9104                mLayoutNeeded = true;
9105                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9106                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
9107                }
9108            }
9109
9110            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9111                // If we defer assigning layers, then the caller is responsible for
9112                // doing this part.
9113                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9114            }
9115            return true;
9116        }
9117        return false;
9118    }
9119
9120    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9121        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9122    }
9123
9124    private WindowState computeFocusedWindowLocked() {
9125        WindowState result = null;
9126        WindowState win;
9127
9128        int i = mWindows.size() - 1;
9129        int nextAppIndex = mAppTokens.size()-1;
9130        WindowToken nextApp = nextAppIndex >= 0
9131            ? mAppTokens.get(nextAppIndex) : null;
9132
9133        while (i >= 0) {
9134            win = mWindows.get(i);
9135
9136            if (localLOGV || DEBUG_FOCUS) Slog.v(
9137                TAG, "Looking for focus: " + i
9138                + " = " + win
9139                + ", flags=" + win.mAttrs.flags
9140                + ", canReceive=" + win.canReceiveKeys());
9141
9142            AppWindowToken thisApp = win.mAppToken;
9143
9144            // If this window's application has been removed, just skip it.
9145            if (thisApp != null && thisApp.removed) {
9146                i--;
9147                continue;
9148            }
9149
9150            // If there is a focused app, don't allow focus to go to any
9151            // windows below it.  If this is an application window, step
9152            // through the app tokens until we find its app.
9153            if (thisApp != null && nextApp != null && thisApp != nextApp
9154                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
9155                int origAppIndex = nextAppIndex;
9156                while (nextAppIndex > 0) {
9157                    if (nextApp == mFocusedApp) {
9158                        // Whoops, we are below the focused app...  no focus
9159                        // for you!
9160                        if (localLOGV || DEBUG_FOCUS) Slog.v(
9161                            TAG, "Reached focused app: " + mFocusedApp);
9162                        return null;
9163                    }
9164                    nextAppIndex--;
9165                    nextApp = mAppTokens.get(nextAppIndex);
9166                    if (nextApp == thisApp) {
9167                        break;
9168                    }
9169                }
9170                if (thisApp != nextApp) {
9171                    // Uh oh, the app token doesn't exist!  This shouldn't
9172                    // happen, but if it does we can get totally hosed...
9173                    // so restart at the original app.
9174                    nextAppIndex = origAppIndex;
9175                    nextApp = mAppTokens.get(nextAppIndex);
9176                }
9177            }
9178
9179            // Dispatch to this window if it is wants key events.
9180            if (win.canReceiveKeys()) {
9181                if (DEBUG_FOCUS) Slog.v(
9182                        TAG, "Found focus @ " + i + " = " + win);
9183                result = win;
9184                break;
9185            }
9186
9187            i--;
9188        }
9189
9190        return result;
9191    }
9192
9193    private void startFreezingDisplayLocked(boolean inTransaction) {
9194        if (mDisplayFrozen) {
9195            return;
9196        }
9197
9198        if (mDisplay == null || !mPolicy.isScreenOnFully()) {
9199            // No need to freeze the screen before the system is ready or if
9200            // the screen is off.
9201            return;
9202        }
9203
9204        mScreenFrozenLock.acquire();
9205
9206        mDisplayFrozen = true;
9207
9208        mInputMonitor.freezeInputDispatchingLw();
9209
9210        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
9211            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
9212            mNextAppTransitionPackage = null;
9213            mAppTransitionReady = true;
9214        }
9215
9216        if (PROFILE_ORIENTATION) {
9217            File file = new File("/data/system/frozen");
9218            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9219        }
9220
9221        if (CUSTOM_SCREEN_ROTATION) {
9222            if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
9223                mScreenRotationAnimation.kill();
9224                mScreenRotationAnimation = null;
9225            }
9226            if (mScreenRotationAnimation == null) {
9227                mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
9228                        mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight,
9229                        mDisplay.getRotation());
9230            }
9231            if (!mScreenRotationAnimation.hasScreenshot()) {
9232                Surface.freezeDisplay(0);
9233            }
9234        } else {
9235            Surface.freezeDisplay(0);
9236        }
9237    }
9238
9239    private void stopFreezingDisplayLocked() {
9240        if (!mDisplayFrozen) {
9241            return;
9242        }
9243
9244        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
9245            return;
9246        }
9247
9248        mDisplayFrozen = false;
9249        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9250        if (PROFILE_ORIENTATION) {
9251            Debug.stopMethodTracing();
9252        }
9253
9254        boolean updateRotation = false;
9255
9256        if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
9257                && mScreenRotationAnimation.hasScreenshot()) {
9258            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
9259            if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9260                    mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
9261                requestAnimationLocked(0);
9262            } else {
9263                mScreenRotationAnimation = null;
9264                updateRotation = true;
9265            }
9266        } else {
9267            if (mScreenRotationAnimation != null) {
9268                mScreenRotationAnimation.kill();
9269                mScreenRotationAnimation = null;
9270            }
9271            updateRotation = true;
9272        }
9273        Surface.unfreezeDisplay(0);
9274
9275        mInputMonitor.thawInputDispatchingLw();
9276
9277        boolean configChanged;
9278
9279        // While the display is frozen we don't re-compute the orientation
9280        // to avoid inconsistent states.  However, something interesting
9281        // could have actually changed during that time so re-evaluate it
9282        // now to catch that.
9283        configChanged = updateOrientationFromAppTokensLocked(false);
9284
9285        // A little kludge: a lot could have happened while the
9286        // display was frozen, so now that we are coming back we
9287        // do a gc so that any remote references the system
9288        // processes holds on others can be released if they are
9289        // no longer needed.
9290        mH.removeMessages(H.FORCE_GC);
9291        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
9292                2000);
9293
9294        mScreenFrozenLock.release();
9295
9296        if (updateRotation) {
9297            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9298            configChanged |= updateRotationUncheckedLocked(false);
9299        }
9300
9301        if (configChanged) {
9302            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9303        }
9304    }
9305
9306    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
9307            DisplayMetrics dm) {
9308        if (index < tokens.length) {
9309            String str = tokens[index];
9310            if (str != null && str.length() > 0) {
9311                try {
9312                    int val = Integer.parseInt(str);
9313                    return val;
9314                } catch (Exception e) {
9315                }
9316            }
9317        }
9318        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
9319            return defDps;
9320        }
9321        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
9322        return val;
9323    }
9324
9325    void createWatermark() {
9326        if (mWatermark != null) {
9327            return;
9328        }
9329
9330        File file = new File("/system/etc/setup.conf");
9331        FileInputStream in = null;
9332        try {
9333            in = new FileInputStream(file);
9334            DataInputStream ind = new DataInputStream(in);
9335            String line = ind.readLine();
9336            if (line != null) {
9337                String[] toks = line.split("%");
9338                if (toks != null && toks.length > 0) {
9339                    mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks);
9340                }
9341            }
9342        } catch (FileNotFoundException e) {
9343        } catch (IOException e) {
9344        } finally {
9345            if (in != null) {
9346                try {
9347                    in.close();
9348                } catch (IOException e) {
9349                }
9350            }
9351        }
9352    }
9353
9354    @Override
9355    public void statusBarVisibilityChanged(int visibility) {
9356        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
9357                != PackageManager.PERMISSION_GRANTED) {
9358            throw new SecurityException("Caller does not hold permission "
9359                    + android.Manifest.permission.STATUS_BAR);
9360        }
9361
9362        synchronized (mWindowMap) {
9363            mLastStatusBarVisibility = visibility;
9364            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
9365            updateStatusBarVisibilityLocked(visibility);
9366        }
9367    }
9368
9369    void updateStatusBarVisibilityLocked(int visibility) {
9370        mInputManager.setSystemUiVisibility(visibility);
9371        final int N = mWindows.size();
9372        for (int i = 0; i < N; i++) {
9373            WindowState ws = mWindows.get(i);
9374            try {
9375                int curValue = ws.mSystemUiVisibility;
9376                int diff = curValue ^ visibility;
9377                // We are only interested in differences of one of the
9378                // clearable flags...
9379                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
9380                // ...if it has actually been cleared.
9381                diff &= ~visibility;
9382                int newValue = (curValue&~diff) | (visibility&diff);
9383                if (newValue != curValue) {
9384                    ws.mSeq++;
9385                    ws.mSystemUiVisibility = newValue;
9386                }
9387                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
9388                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
9389                            visibility, newValue, diff);
9390                }
9391            } catch (RemoteException e) {
9392                // so sorry
9393            }
9394        }
9395    }
9396
9397    @Override
9398    public void reevaluateStatusBarVisibility() {
9399        synchronized (mWindowMap) {
9400            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
9401            updateStatusBarVisibilityLocked(visibility);
9402            performLayoutAndPlaceSurfacesLocked();
9403        }
9404    }
9405
9406    @Override
9407    public FakeWindow addFakeWindow(Looper looper,
9408            InputEventReceiver.Factory inputEventReceiverFactory,
9409            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
9410            boolean hasFocus, boolean touchFullscreen) {
9411        synchronized (mWindowMap) {
9412            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputEventReceiverFactory,
9413                    name, windowType,
9414                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
9415            int i=0;
9416            while (i<mFakeWindows.size()) {
9417                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
9418                    break;
9419                }
9420            }
9421            mFakeWindows.add(i, fw);
9422            mInputMonitor.updateInputWindowsLw(true);
9423            return fw;
9424        }
9425    }
9426
9427    boolean removeFakeWindowLocked(FakeWindow window) {
9428        synchronized (mWindowMap) {
9429            if (mFakeWindows.remove(window)) {
9430                mInputMonitor.updateInputWindowsLw(true);
9431                return true;
9432            }
9433            return false;
9434        }
9435    }
9436
9437    @Override
9438    public boolean hasNavigationBar() {
9439        return mPolicy.hasNavigationBar();
9440    }
9441
9442    public void lockNow() {
9443        mPolicy.lockNow();
9444    }
9445
9446    void dumpInput(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9447        pw.println("WINDOW MANAGER INPUT (dumpsys window input)");
9448        mInputManager.dump(pw);
9449    }
9450
9451    void dumpPolicyLocked(FileDescriptor fd, PrintWriter pw, String[] args, boolean dumpAll) {
9452        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
9453        mPolicy.dump("    ", fd, pw, args);
9454    }
9455
9456    void dumpTokensLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9457        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
9458        if (mTokenMap.size() > 0) {
9459            pw.println("  All tokens:");
9460            Iterator<WindowToken> it = mTokenMap.values().iterator();
9461            while (it.hasNext()) {
9462                WindowToken token = it.next();
9463                pw.print("  Token "); pw.print(token.token);
9464                if (dumpAll) {
9465                    pw.println(':');
9466                    token.dump(pw, "    ");
9467                } else {
9468                    pw.println();
9469                }
9470            }
9471        }
9472        if (mWallpaperTokens.size() > 0) {
9473            pw.println();
9474            pw.println("  Wallpaper tokens:");
9475            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
9476                WindowToken token = mWallpaperTokens.get(i);
9477                pw.print("  Wallpaper #"); pw.print(i);
9478                        pw.print(' '); pw.print(token);
9479                if (dumpAll) {
9480                    pw.println(':');
9481                    token.dump(pw, "    ");
9482                } else {
9483                    pw.println();
9484                }
9485            }
9486        }
9487        if (mAppTokens.size() > 0) {
9488            pw.println();
9489            pw.println("  Application tokens in Z order:");
9490            for (int i=mAppTokens.size()-1; i>=0; i--) {
9491                pw.print("  App #"); pw.print(i); pw.print(": ");
9492                        pw.println(mAppTokens.get(i));
9493            }
9494        }
9495        if (mFinishedStarting.size() > 0) {
9496            pw.println();
9497            pw.println("  Finishing start of application tokens:");
9498            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9499                WindowToken token = mFinishedStarting.get(i);
9500                pw.print("  Finished Starting #"); pw.print(i);
9501                        pw.print(' '); pw.print(token);
9502                if (dumpAll) {
9503                    pw.println(':');
9504                    token.dump(pw, "    ");
9505                } else {
9506                    pw.println();
9507                }
9508            }
9509        }
9510        if (mExitingTokens.size() > 0) {
9511            pw.println();
9512            pw.println("  Exiting tokens:");
9513            for (int i=mExitingTokens.size()-1; i>=0; i--) {
9514                WindowToken token = mExitingTokens.get(i);
9515                pw.print("  Exiting #"); pw.print(i);
9516                        pw.print(' '); pw.print(token);
9517                if (dumpAll) {
9518                    pw.println(':');
9519                    token.dump(pw, "    ");
9520                } else {
9521                    pw.println();
9522                }
9523            }
9524        }
9525        if (mExitingAppTokens.size() > 0) {
9526            pw.println();
9527            pw.println("  Exiting application tokens:");
9528            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9529                WindowToken token = mExitingAppTokens.get(i);
9530                pw.print("  Exiting App #"); pw.print(i);
9531                        pw.print(' '); pw.print(token);
9532                if (dumpAll) {
9533                    pw.println(':');
9534                    token.dump(pw, "    ");
9535                } else {
9536                    pw.println();
9537                }
9538            }
9539        }
9540        pw.println();
9541        if (mOpeningApps.size() > 0) {
9542            pw.print("  mOpeningApps="); pw.println(mOpeningApps);
9543        }
9544        if (mClosingApps.size() > 0) {
9545            pw.print("  mClosingApps="); pw.println(mClosingApps);
9546        }
9547        if (mToTopApps.size() > 0) {
9548            pw.print("  mToTopApps="); pw.println(mToTopApps);
9549        }
9550        if (mToBottomApps.size() > 0) {
9551            pw.print("  mToBottomApps="); pw.println(mToBottomApps);
9552        }
9553    }
9554
9555    void dumpSessionsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9556        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
9557        if (mSessions.size() > 0) {
9558            Iterator<Session> it = mSessions.iterator();
9559            while (it.hasNext()) {
9560                Session s = it.next();
9561                pw.print("  Session "); pw.print(s); pw.println(':');
9562                s.dump(pw, "    ");
9563            }
9564        }
9565    }
9566
9567    void dumpWindowsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
9568            ArrayList<WindowState> windows) {
9569        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
9570        for (int i=mWindows.size()-1; i>=0; i--) {
9571            WindowState w = mWindows.get(i);
9572            if (windows == null || windows.contains(w)) {
9573                pw.print("  Window #"); pw.print(i); pw.print(' ');
9574                        pw.print(w); pw.println(":");
9575                w.dump(pw, "    ", dumpAll || windows != null);
9576            }
9577        }
9578        if (mInputMethodDialogs.size() > 0) {
9579            pw.println();
9580            pw.println("  Input method dialogs:");
9581            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
9582                WindowState w = mInputMethodDialogs.get(i);
9583                if (windows == null || windows.contains(w)) {
9584                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
9585                }
9586            }
9587        }
9588        if (mPendingRemove.size() > 0) {
9589            pw.println();
9590            pw.println("  Remove pending for:");
9591            for (int i=mPendingRemove.size()-1; i>=0; i--) {
9592                WindowState w = mPendingRemove.get(i);
9593                if (windows == null || windows.contains(w)) {
9594                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
9595                            pw.print(w);
9596                    if (dumpAll) {
9597                        pw.println(":");
9598                        w.dump(pw, "    ", true);
9599                    } else {
9600                        pw.println();
9601                    }
9602                }
9603            }
9604        }
9605        if (mForceRemoves != null && mForceRemoves.size() > 0) {
9606            pw.println();
9607            pw.println("  Windows force removing:");
9608            for (int i=mForceRemoves.size()-1; i>=0; i--) {
9609                WindowState w = mForceRemoves.get(i);
9610                pw.print("  Removing #"); pw.print(i); pw.print(' ');
9611                        pw.print(w);
9612                if (dumpAll) {
9613                    pw.println(":");
9614                    w.dump(pw, "    ", true);
9615                } else {
9616                    pw.println();
9617                }
9618            }
9619        }
9620        if (mDestroySurface.size() > 0) {
9621            pw.println();
9622            pw.println("  Windows waiting to destroy their surface:");
9623            for (int i=mDestroySurface.size()-1; i>=0; i--) {
9624                WindowState w = mDestroySurface.get(i);
9625                if (windows == null || windows.contains(w)) {
9626                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
9627                            pw.print(w);
9628                    if (dumpAll) {
9629                        pw.println(":");
9630                        w.dump(pw, "    ", true);
9631                    } else {
9632                        pw.println();
9633                    }
9634                }
9635            }
9636        }
9637        if (mLosingFocus.size() > 0) {
9638            pw.println();
9639            pw.println("  Windows losing focus:");
9640            for (int i=mLosingFocus.size()-1; i>=0; i--) {
9641                WindowState w = mLosingFocus.get(i);
9642                if (windows == null || windows.contains(w)) {
9643                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
9644                            pw.print(w);
9645                    if (dumpAll) {
9646                        pw.println(":");
9647                        w.dump(pw, "    ", true);
9648                    } else {
9649                        pw.println();
9650                    }
9651                }
9652            }
9653        }
9654        if (mResizingWindows.size() > 0) {
9655            pw.println();
9656            pw.println("  Windows waiting to resize:");
9657            for (int i=mResizingWindows.size()-1; i>=0; i--) {
9658                WindowState w = mResizingWindows.get(i);
9659                if (windows == null || windows.contains(w)) {
9660                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
9661                            pw.print(w);
9662                    if (dumpAll) {
9663                        pw.println(":");
9664                        w.dump(pw, "    ", true);
9665                    } else {
9666                        pw.println();
9667                    }
9668                }
9669            }
9670        }
9671        if (mWaitingForDrawn.size() > 0) {
9672            pw.println();
9673            pw.println("  Clients waiting for these windows to be drawn:");
9674            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
9675                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
9676                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
9677                        pw.print(": "); pw.println(pair.second);
9678            }
9679        }
9680        pw.println();
9681        if (mDisplay != null) {
9682            pw.print("  Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
9683                    pw.print(mInitialDisplayHeight); pw.print(" base=");
9684                    pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
9685                    pw.print(" cur=");
9686                    pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
9687                    pw.print(" app=");
9688                    pw.print(mAppDisplayWidth); pw.print("x"); pw.print(mAppDisplayHeight);
9689                    pw.print(" raw="); pw.print(mDisplay.getRawWidth());
9690                    pw.print("x"); pw.println(mDisplay.getRawHeight());
9691        } else {
9692            pw.println("  NO DISPLAY");
9693        }
9694        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
9695        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
9696        if (mLastFocus != mCurrentFocus) {
9697            pw.print("  mLastFocus="); pw.println(mLastFocus);
9698        }
9699        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
9700        if (mInputMethodTarget != null) {
9701            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
9702        }
9703        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
9704                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
9705        if (dumpAll) {
9706            if (mLastStatusBarVisibility != 0) {
9707                pw.print("  mLastStatusBarVisibility=0x");
9708                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
9709            }
9710            if (mInputMethodWindow != null) {
9711                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
9712            }
9713            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
9714            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
9715                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
9716                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
9717            }
9718            if (mWindowDetachedWallpaper != null) {
9719                pw.print("  mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper);
9720            }
9721            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
9722                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
9723            if (mInputMethodAnimLayerAdjustment != 0 ||
9724                    mWallpaperAnimLayerAdjustment != 0) {
9725                pw.print("  mInputMethodAnimLayerAdjustment=");
9726                        pw.print(mInputMethodAnimLayerAdjustment);
9727                        pw.print("  mWallpaperAnimLayerAdjustment=");
9728                        pw.println(mWallpaperAnimLayerAdjustment);
9729            }
9730            if (mWindowAnimationBackgroundSurface != null) {
9731                pw.println("  mWindowAnimationBackgroundSurface:");
9732                mWindowAnimationBackgroundSurface.printTo("    ", pw);
9733            }
9734            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
9735                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9736            pw.print("  mLayoutNeeded="); pw.print(mLayoutNeeded);
9737                    pw.print(" mBlurShown="); pw.println(mBlurShown);
9738            if (mDimAnimator != null) {
9739                pw.println("  mDimAnimator:");
9740                mDimAnimator.printTo("    ", pw);
9741            } else {
9742                pw.println( "  no DimAnimator ");
9743            }
9744            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
9745                    pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9746                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
9747                    pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
9748            pw.print("  mRotation="); pw.print(mRotation);
9749                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
9750            pw.print("  mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
9751                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
9752            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
9753            pw.print("  mAnimationPending="); pw.print(mAnimationPending);
9754                    pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9755                    pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
9756            pw.print("  mNextAppTransition=0x");
9757                    pw.print(Integer.toHexString(mNextAppTransition));
9758                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
9759            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
9760                    pw.print(" mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
9761            if (mNextAppTransitionPackage != null) {
9762                pw.print("  mNextAppTransitionPackage=");
9763                    pw.print(mNextAppTransitionPackage);
9764                    pw.print(" mNextAppTransitionEnter=0x");
9765                    pw.print(Integer.toHexString(mNextAppTransitionEnter));
9766                    pw.print(" mNextAppTransitionExit=0x");
9767                    pw.print(Integer.toHexString(mNextAppTransitionExit));
9768            }
9769            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9770                    pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9771        }
9772    }
9773
9774    boolean dumpWindows(FileDescriptor fd, PrintWriter pw, String name, String[] args,
9775            int opti, boolean dumpAll) {
9776        ArrayList<WindowState> windows = new ArrayList<WindowState>();
9777        if ("visible".equals(name)) {
9778            synchronized(mWindowMap) {
9779                for (int i=mWindows.size()-1; i>=0; i--) {
9780                    WindowState w = mWindows.get(i);
9781                    if (w.mSurfaceShown) {
9782                        windows.add(w);
9783                    }
9784                }
9785            }
9786        } else {
9787            int objectId = 0;
9788            // See if this is an object ID.
9789            try {
9790                objectId = Integer.parseInt(name, 16);
9791                name = null;
9792            } catch (RuntimeException e) {
9793            }
9794            synchronized(mWindowMap) {
9795                for (int i=mWindows.size()-1; i>=0; i--) {
9796                    WindowState w = mWindows.get(i);
9797                    if (name != null) {
9798                        if (w.mAttrs.getTitle().toString().contains(name)) {
9799                            windows.add(w);
9800                        }
9801                    } else if (System.identityHashCode(w) == objectId) {
9802                        windows.add(w);
9803                    }
9804                }
9805            }
9806        }
9807
9808        if (windows.size() <= 0) {
9809            return false;
9810        }
9811
9812        synchronized(mWindowMap) {
9813            dumpWindowsLocked(fd, pw, dumpAll, windows);
9814        }
9815        return true;
9816    }
9817
9818    @Override
9819    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9820        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
9821                != PackageManager.PERMISSION_GRANTED) {
9822            pw.println("Permission Denial: can't dump WindowManager from from pid="
9823                    + Binder.getCallingPid()
9824                    + ", uid=" + Binder.getCallingUid());
9825            return;
9826        }
9827
9828        boolean dumpAll = false;
9829
9830        int opti = 0;
9831        while (opti < args.length) {
9832            String opt = args[opti];
9833            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9834                break;
9835            }
9836            opti++;
9837            if ("-a".equals(opt)) {
9838                dumpAll = true;
9839            } else if ("-h".equals(opt)) {
9840                pw.println("Window manager dump options:");
9841                pw.println("  [-a] [-h] [cmd] ...");
9842                pw.println("  cmd may be one of:");
9843                pw.println("    i[input]: input subsystem state");
9844                pw.println("    p[policy]: policy state");
9845                pw.println("    s[essions]: active sessions");
9846                pw.println("    t[okens]: token list");
9847                pw.println("    w[indows]: window list");
9848                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
9849                pw.println("    be a partial substring in a window name, a");
9850                pw.println("    Window hex object identifier, or");
9851                pw.println("    \"all\" for all windows, or");
9852                pw.println("    \"visible\" for the visible windows.");
9853                pw.println("  -a: include all available server state.");
9854                return;
9855            } else {
9856                pw.println("Unknown argument: " + opt + "; use -h for help");
9857            }
9858        }
9859
9860        // Is the caller requesting to dump a particular piece of data?
9861        if (opti < args.length) {
9862            String cmd = args[opti];
9863            opti++;
9864            if ("input".equals(cmd) || "i".equals(cmd)) {
9865                dumpInput(fd, pw, true);
9866                return;
9867            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
9868                synchronized(mWindowMap) {
9869                    dumpPolicyLocked(fd, pw, args, true);
9870                }
9871                return;
9872            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
9873                synchronized(mWindowMap) {
9874                    dumpSessionsLocked(fd, pw, true);
9875                }
9876                return;
9877            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
9878                synchronized(mWindowMap) {
9879                    dumpTokensLocked(fd, pw, true);
9880                }
9881                return;
9882            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
9883                synchronized(mWindowMap) {
9884                    dumpWindowsLocked(fd, pw, true, null);
9885                }
9886                return;
9887            } else if ("all".equals(cmd) || "a".equals(cmd)) {
9888                synchronized(mWindowMap) {
9889                    dumpWindowsLocked(fd, pw, true, null);
9890                }
9891                return;
9892            } else {
9893                // Dumping a single name?
9894                if (!dumpWindows(fd, pw, cmd, args, opti, dumpAll)) {
9895                    pw.println("Bad window command, or no windows match: " + cmd);
9896                    pw.println("Use -h for help.");
9897                }
9898                return;
9899            }
9900        }
9901
9902        dumpInput(fd, pw, dumpAll);
9903
9904        synchronized(mWindowMap) {
9905            if (dumpAll) {
9906                pw.println("-------------------------------------------------------------------------------");
9907            }
9908            dumpPolicyLocked(fd, pw, args, dumpAll);
9909            pw.println();
9910            if (dumpAll) {
9911                pw.println("-------------------------------------------------------------------------------");
9912            }
9913            dumpSessionsLocked(fd, pw, dumpAll);
9914            pw.println();
9915            if (dumpAll) {
9916                pw.println("-------------------------------------------------------------------------------");
9917            }
9918            dumpTokensLocked(fd, pw, dumpAll);
9919            pw.println();
9920            if (dumpAll) {
9921                pw.println("-------------------------------------------------------------------------------");
9922            }
9923            dumpWindowsLocked(fd, pw, dumpAll, null);
9924        }
9925    }
9926
9927    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
9928    public void monitor() {
9929        synchronized (mWindowMap) { }
9930        synchronized (mKeyguardTokenWatcher) { }
9931    }
9932
9933    public interface OnHardKeyboardStatusChangeListener {
9934        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
9935    }
9936}
9937