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