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