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