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