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