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