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