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