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