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