WindowManagerService.java revision bf30ac71a9bcfc97391dda650176f9a1f7146ecc
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) Slog.v(TAG, "performLayout: needed="
7401                + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
7402
7403        mPolicy.beginLayoutLw(dw, dh, mRotation);
7404
7405        int seq = mLayoutSeq+1;
7406        if (seq < 0) seq = 0;
7407        mLayoutSeq = seq;
7408
7409        // First perform layout of any root windows (not attached
7410        // to another window).
7411        int topAttached = -1;
7412        for (i = N-1; i >= 0; i--) {
7413            WindowState win = mWindows.get(i);
7414
7415            // Don't do layout of a window if it is not visible, or
7416            // soon won't be visible, to avoid wasting time and funky
7417            // changes while a window is animating away.
7418            final AppWindowToken atoken = win.mAppToken;
7419            final boolean gone = win.mViewVisibility == View.GONE
7420                    || !win.mRelayoutCalled
7421                    || (atoken == null && win.mRootToken.hidden)
7422                    || (atoken != null && atoken.hiddenRequested)
7423                    || win.mAttachedHidden
7424                    || win.mExiting || win.mDestroying;
7425
7426            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
7427                Slog.v(TAG, "First pass " + win
7428                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
7429                        + " mLayoutAttached=" + win.mLayoutAttached);
7430                if (gone) Slog.v(TAG, "  (mViewVisibility="
7431                        + win.mViewVisibility + " mRelayoutCalled="
7432                        + win.mRelayoutCalled + " hidden="
7433                        + win.mRootToken.hidden + " hiddenRequested="
7434                        + (atoken != null && atoken.hiddenRequested)
7435                        + " mAttachedHidden=" + win.mAttachedHidden);
7436            }
7437
7438            // If this view is GONE, then skip it -- keep the current
7439            // frame, and let the caller know so they can ignore it
7440            // if they want.  (We do the normal layout for INVISIBLE
7441            // windows, since that means "perform layout as normal,
7442            // just don't display").
7443            if (!gone || !win.mHaveFrame) {
7444                if (!win.mLayoutAttached) {
7445                    if (initial) {
7446                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7447                        win.mContentChanged = false;
7448                    }
7449                    win.prelayout();
7450                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
7451                    win.mLayoutSeq = seq;
7452                    if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
7453                            + win.mFrame + " mContainingFrame="
7454                            + win.mContainingFrame + " mDisplayFrame="
7455                            + win.mDisplayFrame);
7456                } else {
7457                    if (topAttached < 0) topAttached = i;
7458                }
7459            }
7460        }
7461
7462        // Now perform layout of attached windows, which usually
7463        // depend on the position of the window they are attached to.
7464        // XXX does not deal with windows that are attached to windows
7465        // that are themselves attached.
7466        for (i = topAttached; i >= 0; i--) {
7467            WindowState win = mWindows.get(i);
7468
7469            if (win.mLayoutAttached) {
7470                if (DEBUG_LAYOUT) Slog.v(TAG, "Second pass " + win
7471                        + " mHaveFrame=" + win.mHaveFrame
7472                        + " mViewVisibility=" + win.mViewVisibility
7473                        + " mRelayoutCalled=" + win.mRelayoutCalled);
7474                // If this view is GONE, then skip it -- keep the current
7475                // frame, and let the caller know so they can ignore it
7476                // if they want.  (We do the normal layout for INVISIBLE
7477                // windows, since that means "perform layout as normal,
7478                // just don't display").
7479                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
7480                        || !win.mHaveFrame) {
7481                    if (initial) {
7482                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
7483                        win.mContentChanged = false;
7484                    }
7485                    win.prelayout();
7486                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
7487                    win.mLayoutSeq = seq;
7488                    if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
7489                            + win.mFrame + " mContainingFrame="
7490                            + win.mContainingFrame + " mDisplayFrame="
7491                            + win.mDisplayFrame);
7492                }
7493            }
7494        }
7495
7496        // Window frames may have changed.  Tell the input dispatcher about it.
7497        mInputMonitor.setUpdateInputWindowsNeededLw();
7498        if (updateInputWindows) {
7499            mInputMonitor.updateInputWindowsLw(false /*force*/);
7500        }
7501
7502        return mPolicy.finishLayoutLw();
7503    }
7504
7505    void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
7506        // If the screen is currently frozen or off, then keep
7507        // it frozen/off until this window draws at its new
7508        // orientation.
7509        if (mDisplayFrozen || !mPolicy.isScreenOnFully()) {
7510            if (DEBUG_ORIENTATION) Slog.v(TAG,
7511                    "Changing surface while display frozen: " + w);
7512            w.mOrientationChanging = true;
7513            if (!mWindowsFreezingScreen) {
7514                mWindowsFreezingScreen = true;
7515                // XXX should probably keep timeout from
7516                // when we first froze the display.
7517                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
7518                mH.sendMessageDelayed(mH.obtainMessage(
7519                        H.WINDOW_FREEZE_TIMEOUT), 2000);
7520            }
7521        }
7522    }
7523
7524    // "Something has changed!  Let's make it correct now."
7525    private final void performLayoutAndPlaceSurfacesLockedInner(
7526            boolean recoveringMemory) {
7527        if (mDisplay == null) {
7528            Slog.i(TAG, "skipping performLayoutAndPlaceSurfacesLockedInner with no mDisplay");
7529            return;
7530        }
7531
7532        final long currentTime = SystemClock.uptimeMillis();
7533        final int dw = mCurDisplayWidth;
7534        final int dh = mCurDisplayHeight;
7535        final int innerDw = mAppDisplayWidth;
7536        final int innerDh = mAppDisplayHeight;
7537
7538        int i;
7539
7540        if (mFocusMayChange) {
7541            mFocusMayChange = false;
7542            updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
7543                    false /*updateInputWindows*/);
7544        }
7545
7546        // Initialize state of exiting tokens.
7547        for (i=mExitingTokens.size()-1; i>=0; i--) {
7548            mExitingTokens.get(i).hasVisible = false;
7549        }
7550
7551        // Initialize state of exiting applications.
7552        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
7553            mExitingAppTokens.get(i).hasVisible = false;
7554        }
7555
7556        boolean orientationChangeComplete = true;
7557        Session holdScreen = null;
7558        float screenBrightness = -1;
7559        float buttonBrightness = -1;
7560        boolean focusDisplayed = false;
7561        boolean animating = false;
7562        boolean createWatermark = false;
7563        boolean updateRotation = false;
7564        boolean screenRotationFinished = false;
7565
7566        if (mFxSession == null) {
7567            mFxSession = new SurfaceSession();
7568            createWatermark = true;
7569        }
7570
7571        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
7572                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
7573
7574        Surface.openTransaction();
7575
7576        if (createWatermark) {
7577            createWatermark();
7578        }
7579        if (mWatermark != null) {
7580            mWatermark.positionSurface(dw, dh);
7581        }
7582        if (mStrictModeFlash != null) {
7583            mStrictModeFlash.positionSurface(dw, dh);
7584        }
7585
7586        try {
7587            boolean wallpaperForceHidingChanged = false;
7588            int repeats = 0;
7589            int changes = 0;
7590
7591            do {
7592                repeats++;
7593                if (repeats > 6) {
7594                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
7595                    mLayoutNeeded = false;
7596                    break;
7597                }
7598
7599                if ((changes&(WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER
7600                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG
7601                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) {
7602                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
7603                        if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
7604                            assignLayersLocked();
7605                            mLayoutNeeded = true;
7606                        }
7607                    }
7608                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
7609                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
7610                        if (updateOrientationFromAppTokensLocked(true)) {
7611                            mLayoutNeeded = true;
7612                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
7613                        }
7614                    }
7615                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
7616                        mLayoutNeeded = true;
7617                    }
7618                }
7619
7620                // FIRST LOOP: Perform a layout, if needed.
7621                if (repeats < 4) {
7622                    changes = performLayoutLockedInner(repeats == 0, false /*updateInputWindows*/);
7623                    if (changes != 0) {
7624                        continue;
7625                    }
7626                } else {
7627                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
7628                    changes = 0;
7629                }
7630
7631                final int transactionSequence = ++mTransactionSequence;
7632
7633                // Update animations of all applications, including those
7634                // associated with exiting/removed apps
7635                boolean tokensAnimating = false;
7636                final int NAT = mAppTokens.size();
7637                for (i=0; i<NAT; i++) {
7638                    if (mAppTokens.get(i).stepAnimationLocked(currentTime,
7639                            innerDw, innerDh)) {
7640                        tokensAnimating = true;
7641                    }
7642                }
7643                final int NEAT = mExitingAppTokens.size();
7644                for (i=0; i<NEAT; i++) {
7645                    if (mExitingAppTokens.get(i).stepAnimationLocked(currentTime,
7646                            innerDw, innerDh)) {
7647                        tokensAnimating = true;
7648                    }
7649                }
7650
7651                // SECOND LOOP: Execute animations and update visibility of windows.
7652
7653                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
7654                        + transactionSequence + " tokensAnimating="
7655                        + tokensAnimating);
7656
7657                animating = tokensAnimating;
7658
7659                if (mScreenRotationAnimation != null) {
7660                    if (mScreenRotationAnimation.isAnimating()) {
7661                        if (mScreenRotationAnimation.stepAnimation(currentTime)) {
7662                            animating = true;
7663                        } else {
7664                            screenRotationFinished = true;
7665                            updateRotation = true;
7666                        }
7667                    }
7668                }
7669
7670                boolean tokenMayBeDrawn = false;
7671                boolean wallpaperMayChange = false;
7672                boolean forceHiding = false;
7673                WindowState windowDetachedWallpaper = null;
7674                WindowState windowAnimationBackground = null;
7675                int windowAnimationBackgroundColor = 0;
7676
7677                mPolicy.beginAnimationLw(dw, dh);
7678
7679                final int N = mWindows.size();
7680
7681                for (i=N-1; i>=0; i--) {
7682                    WindowState w = mWindows.get(i);
7683
7684                    final WindowManager.LayoutParams attrs = w.mAttrs;
7685
7686                    if (w.mSurface != null) {
7687                        // Take care of the window being ready to display.
7688                        if (w.commitFinishDrawingLocked(currentTime)) {
7689                            if ((w.mAttrs.flags
7690                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
7691                                if (DEBUG_WALLPAPER) Slog.v(TAG,
7692                                        "First draw done in potential wallpaper target " + w);
7693                                wallpaperMayChange = true;
7694                            }
7695                        }
7696
7697                        final boolean wasAnimating = w.mAnimating;
7698
7699                        int animDw = innerDw;
7700                        int animDh = innerDh;
7701
7702                        // If the window has moved due to its containing
7703                        // content frame changing, then we'd like to animate
7704                        // it.  The checks here are ordered by what is least
7705                        // likely to be true first.
7706                        if (w.shouldAnimateMove()) {
7707                            // Frame has moved, containing content frame
7708                            // has also moved, and we're not currently animating...
7709                            // let's do something.
7710                            Animation a = AnimationUtils.loadAnimation(mContext,
7711                                    com.android.internal.R.anim.window_move_from_decor);
7712                            w.setAnimation(a);
7713                            animDw = w.mLastFrame.left - w.mFrame.left;
7714                            animDh = w.mLastFrame.top - w.mFrame.top;
7715                        }
7716
7717                        // Execute animation.
7718                        final boolean nowAnimating = w.stepAnimationLocked(currentTime,
7719                                animDw, animDh);
7720
7721                        // If this window is animating, make a note that we have
7722                        // an animating window and take care of a request to run
7723                        // a detached wallpaper animation.
7724                        if (nowAnimating) {
7725                            if (w.mAnimation != null) {
7726                                if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
7727                                        && w.mAnimation.getDetachWallpaper()) {
7728                                    windowDetachedWallpaper = w;
7729                                }
7730                                if (w.mAnimation.getBackgroundColor() != 0) {
7731                                    if (windowAnimationBackground == null || w.mAnimLayer <
7732                                            windowAnimationBackground.mAnimLayer) {
7733                                        windowAnimationBackground = w;
7734                                        windowAnimationBackgroundColor =
7735                                                w.mAnimation.getBackgroundColor();
7736                                    }
7737                                }
7738                            }
7739                            animating = true;
7740                        }
7741
7742                        // If this window's app token is running a detached wallpaper
7743                        // animation, make a note so we can ensure the wallpaper is
7744                        // displayed behind it.
7745                        if (w.mAppToken != null && w.mAppToken.animation != null
7746                                && w.mAppToken.animating) {
7747                            if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
7748                                    && w.mAppToken.animation.getDetachWallpaper()) {
7749                                windowDetachedWallpaper = w;
7750                            }
7751                            if (w.mAppToken.animation.getBackgroundColor() != 0) {
7752                                if (windowAnimationBackground == null || w.mAnimLayer <
7753                                        windowAnimationBackground.mAnimLayer) {
7754                                    windowAnimationBackground = w;
7755                                    windowAnimationBackgroundColor =
7756                                            w.mAppToken.animation.getBackgroundColor();
7757                                }
7758                            }
7759                        }
7760
7761                        if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
7762                            wallpaperMayChange = true;
7763                        }
7764
7765                        if (mPolicy.doesForceHide(w, attrs)) {
7766                            if (!wasAnimating && nowAnimating) {
7767                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7768                                        "Animation started that could impact force hide: "
7769                                        + w);
7770                                wallpaperForceHidingChanged = true;
7771                                mFocusMayChange = true;
7772                            } else if (w.isReadyForDisplay() && w.mAnimation == null) {
7773                                forceHiding = true;
7774                            }
7775                        } else if (mPolicy.canBeForceHidden(w, attrs)) {
7776                            boolean changed;
7777                            if (forceHiding) {
7778                                changed = w.hideLw(false, false);
7779                                if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
7780                                        "Now policy hidden: " + w);
7781                            } else {
7782                                changed = w.showLw(false, false);
7783                                if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
7784                                        "Now policy shown: " + w);
7785                                if (changed) {
7786                                    if (wallpaperForceHidingChanged
7787                                            && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
7788                                        // Assume we will need to animate.  If
7789                                        // we don't (because the wallpaper will
7790                                        // stay with the lock screen), then we will
7791                                        // clean up later.
7792                                        Animation a = mPolicy.createForceHideEnterAnimation();
7793                                        if (a != null) {
7794                                            w.setAnimation(a);
7795                                        }
7796                                    }
7797                                    if (mCurrentFocus == null ||
7798                                            mCurrentFocus.mLayer < w.mLayer) {
7799                                        // We are showing on to of the current
7800                                        // focus, so re-evaluate focus to make
7801                                        // sure it is correct.
7802                                        mFocusMayChange = true;
7803                                    }
7804                                }
7805                            }
7806                            if (changed && (attrs.flags
7807                                    & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
7808                                wallpaperMayChange = true;
7809                            }
7810                        }
7811
7812                        mPolicy.animatingWindowLw(w, attrs);
7813                    }
7814
7815                    final AppWindowToken atoken = w.mAppToken;
7816                    if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
7817                        if (atoken.lastTransactionSequence != transactionSequence) {
7818                            atoken.lastTransactionSequence = transactionSequence;
7819                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
7820                            atoken.startingDisplayed = false;
7821                        }
7822                        if ((w.isOnScreen() || w.mAttrs.type
7823                                == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
7824                                && !w.mExiting && !w.mDestroying) {
7825                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
7826                                Slog.v(TAG, "Eval win " + w + ": isDrawn="
7827                                        + w.isDrawnLw()
7828                                        + ", isAnimating=" + w.isAnimating());
7829                                if (!w.isDrawnLw()) {
7830                                    Slog.v(TAG, "Not displayed: s=" + w.mSurface
7831                                            + " pv=" + w.mPolicyVisibility
7832                                            + " dp=" + w.mDrawPending
7833                                            + " cdp=" + w.mCommitDrawPending
7834                                            + " ah=" + w.mAttachedHidden
7835                                            + " th=" + atoken.hiddenRequested
7836                                            + " a=" + w.mAnimating);
7837                                }
7838                            }
7839                            if (w != atoken.startingWindow) {
7840                                if (!atoken.freezingScreen || !w.mAppFreezing) {
7841                                    atoken.numInterestingWindows++;
7842                                    if (w.isDrawnLw()) {
7843                                        atoken.numDrawnWindows++;
7844                                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
7845                                                "tokenMayBeDrawn: " + atoken
7846                                                + " freezingScreen=" + atoken.freezingScreen
7847                                                + " mAppFreezing=" + w.mAppFreezing);
7848                                        tokenMayBeDrawn = true;
7849                                    }
7850                                }
7851                            } else if (w.isDrawnLw()) {
7852                                atoken.startingDisplayed = true;
7853                            }
7854                        }
7855                    } else if (w.mReadyToShow) {
7856                        w.performShowLocked();
7857                    }
7858                }
7859
7860                changes |= mPolicy.finishAnimationLw();
7861
7862                if (tokenMayBeDrawn) {
7863                    // See if any windows have been drawn, so they (and others
7864                    // associated with them) can now be shown.
7865                    final int NT = mAppTokens.size();
7866                    for (i=0; i<NT; i++) {
7867                        AppWindowToken wtoken = mAppTokens.get(i);
7868                        if (wtoken.freezingScreen) {
7869                            int numInteresting = wtoken.numInterestingWindows;
7870                            if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7871                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7872                                        "allDrawn: " + wtoken
7873                                        + " interesting=" + numInteresting
7874                                        + " drawn=" + wtoken.numDrawnWindows);
7875                                wtoken.showAllWindowsLocked();
7876                                unsetAppFreezingScreenLocked(wtoken, false, true);
7877                                if (DEBUG_ORIENTATION) Slog.i(TAG,
7878                                        "Setting orientationChangeComplete=true because wtoken "
7879                                        + wtoken + " numInteresting=" + numInteresting
7880                                        + " numDrawn=" + wtoken.numDrawnWindows);
7881                                orientationChangeComplete = true;
7882                            }
7883                        } else if (!wtoken.allDrawn) {
7884                            int numInteresting = wtoken.numInterestingWindows;
7885                            if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
7886                                if (DEBUG_VISIBILITY) Slog.v(TAG,
7887                                        "allDrawn: " + wtoken
7888                                        + " interesting=" + numInteresting
7889                                        + " drawn=" + wtoken.numDrawnWindows);
7890                                wtoken.allDrawn = true;
7891                                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
7892
7893                                // We can now show all of the drawn windows!
7894                                if (!mOpeningApps.contains(wtoken)) {
7895                                    wtoken.showAllWindowsLocked();
7896                                }
7897                            }
7898                        }
7899                    }
7900                }
7901
7902                // If we are ready to perform an app transition, check through
7903                // all of the app tokens to be shown and see if they are ready
7904                // to go.
7905                if (mAppTransitionReady) {
7906                    int NN = mOpeningApps.size();
7907                    boolean goodToGo = true;
7908                    if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7909                            "Checking " + NN + " opening apps (frozen="
7910                            + mDisplayFrozen + " timeout="
7911                            + mAppTransitionTimeout + ")...");
7912                    if (!mDisplayFrozen && !mAppTransitionTimeout) {
7913                        // If the display isn't frozen, wait to do anything until
7914                        // all of the apps are ready.  Otherwise just go because
7915                        // we'll unfreeze the display when everyone is ready.
7916                        for (i=0; i<NN && goodToGo; i++) {
7917                            AppWindowToken wtoken = mOpeningApps.get(i);
7918                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7919                                    "Check opening app" + wtoken + ": allDrawn="
7920                                    + wtoken.allDrawn + " startingDisplayed="
7921                                    + wtoken.startingDisplayed);
7922                            if (!wtoken.allDrawn && !wtoken.startingDisplayed
7923                                    && !wtoken.startingMoved) {
7924                                goodToGo = false;
7925                            }
7926                        }
7927                    }
7928                    if (goodToGo) {
7929                        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
7930                        int transit = mNextAppTransition;
7931                        if (mSkipAppTransitionAnimation) {
7932                            transit = WindowManagerPolicy.TRANSIT_UNSET;
7933                        }
7934                        mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
7935                        mAppTransitionReady = false;
7936                        mAppTransitionRunning = true;
7937                        mAppTransitionTimeout = false;
7938                        mStartingIconInTransition = false;
7939                        mSkipAppTransitionAnimation = false;
7940
7941                        mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
7942
7943                        // If there are applications waiting to come to the
7944                        // top of the stack, now is the time to move their windows.
7945                        // (Note that we don't do apps going to the bottom
7946                        // here -- we want to keep their windows in the old
7947                        // Z-order until the animation completes.)
7948                        if (mToTopApps.size() > 0) {
7949                            NN = mAppTokens.size();
7950                            for (i=0; i<NN; i++) {
7951                                AppWindowToken wtoken = mAppTokens.get(i);
7952                                if (wtoken.sendingToTop) {
7953                                    wtoken.sendingToTop = false;
7954                                    moveAppWindowsLocked(wtoken, NN, false);
7955                                }
7956                            }
7957                            mToTopApps.clear();
7958                        }
7959
7960                        WindowState oldWallpaper = mWallpaperTarget;
7961
7962                        adjustWallpaperWindowsLocked();
7963                        wallpaperMayChange = false;
7964
7965                        // The top-most window will supply the layout params,
7966                        // and we will determine it below.
7967                        LayoutParams animLp = null;
7968                        int bestAnimLayer = -1;
7969                        boolean fullscreenAnim = false;
7970
7971                        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
7972                                "New wallpaper target=" + mWallpaperTarget
7973                                + ", lower target=" + mLowerWallpaperTarget
7974                                + ", upper target=" + mUpperWallpaperTarget);
7975                        int foundWallpapers = 0;
7976                        // Do a first pass through the tokens for two
7977                        // things:
7978                        // (1) Determine if both the closing and opening
7979                        // app token sets are wallpaper targets, in which
7980                        // case special animations are needed
7981                        // (since the wallpaper needs to stay static
7982                        // behind them).
7983                        // (2) Find the layout params of the top-most
7984                        // application window in the tokens, which is
7985                        // what will control the animation theme.
7986                        final int NC = mClosingApps.size();
7987                        NN = NC + mOpeningApps.size();
7988                        for (i=0; i<NN; i++) {
7989                            AppWindowToken wtoken;
7990                            int mode;
7991                            if (i < NC) {
7992                                wtoken = mClosingApps.get(i);
7993                                mode = 1;
7994                            } else {
7995                                wtoken = mOpeningApps.get(i-NC);
7996                                mode = 2;
7997                            }
7998                            if (mLowerWallpaperTarget != null) {
7999                                if (mLowerWallpaperTarget.mAppToken == wtoken
8000                                        || mUpperWallpaperTarget.mAppToken == wtoken) {
8001                                    foundWallpapers |= mode;
8002                                }
8003                            }
8004                            if (wtoken.appFullscreen) {
8005                                WindowState ws = wtoken.findMainWindow();
8006                                if (ws != null) {
8007                                    animLp = ws.mAttrs;
8008                                    bestAnimLayer = ws.mLayer;
8009                                    fullscreenAnim = true;
8010                                }
8011                            } else if (!fullscreenAnim) {
8012                                WindowState ws = wtoken.findMainWindow();
8013                                if (ws != null) {
8014                                    if (ws.mLayer > bestAnimLayer) {
8015                                        animLp = ws.mAttrs;
8016                                        bestAnimLayer = ws.mLayer;
8017                                    }
8018                                }
8019                            }
8020                        }
8021
8022                        if (foundWallpapers == 3) {
8023                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8024                                    "Wallpaper animation!");
8025                            switch (transit) {
8026                                case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN:
8027                                case WindowManagerPolicy.TRANSIT_TASK_OPEN:
8028                                case WindowManagerPolicy.TRANSIT_TASK_TO_FRONT:
8029                                    transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN;
8030                                    break;
8031                                case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE:
8032                                case WindowManagerPolicy.TRANSIT_TASK_CLOSE:
8033                                case WindowManagerPolicy.TRANSIT_TASK_TO_BACK:
8034                                    transit = WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_CLOSE;
8035                                    break;
8036                            }
8037                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8038                                    "New transit: " + transit);
8039                        } else if (oldWallpaper != null) {
8040                            // We are transitioning from an activity with
8041                            // a wallpaper to one without.
8042                            transit = WindowManagerPolicy.TRANSIT_WALLPAPER_CLOSE;
8043                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8044                                    "New transit away from wallpaper: " + transit);
8045                        } else if (mWallpaperTarget != null) {
8046                            // We are transitioning from an activity without
8047                            // a wallpaper to now showing the wallpaper
8048                            transit = WindowManagerPolicy.TRANSIT_WALLPAPER_OPEN;
8049                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8050                                    "New transit into wallpaper: " + transit);
8051                        }
8052
8053                        // If all closing windows are obscured, then there is
8054                        // no need to do an animation.  This is the case, for
8055                        // example, when this transition is being done behind
8056                        // the lock screen.
8057                        if (!mPolicy.allowAppAnimationsLw()) {
8058                            animLp = null;
8059                        }
8060
8061                        NN = mOpeningApps.size();
8062                        for (i=0; i<NN; i++) {
8063                            AppWindowToken wtoken = mOpeningApps.get(i);
8064                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8065                                    "Now opening app" + wtoken);
8066                            wtoken.reportedVisible = false;
8067                            wtoken.inPendingTransaction = false;
8068                            wtoken.animation = null;
8069                            setTokenVisibilityLocked(wtoken, animLp, true,
8070                                    transit, false);
8071                            wtoken.updateReportedVisibilityLocked();
8072                            wtoken.waitingToShow = false;
8073                            wtoken.showAllWindowsLocked();
8074                        }
8075                        NN = mClosingApps.size();
8076                        for (i=0; i<NN; i++) {
8077                            AppWindowToken wtoken = mClosingApps.get(i);
8078                            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
8079                                    "Now closing app" + wtoken);
8080                            wtoken.inPendingTransaction = false;
8081                            wtoken.animation = null;
8082                            setTokenVisibilityLocked(wtoken, animLp, false,
8083                                    transit, false);
8084                            wtoken.updateReportedVisibilityLocked();
8085                            wtoken.waitingToHide = false;
8086                            // Force the allDrawn flag, because we want to start
8087                            // this guy's animations regardless of whether it's
8088                            // gotten drawn.
8089                            wtoken.allDrawn = true;
8090                        }
8091
8092                        mNextAppTransitionPackage = null;
8093
8094                        mOpeningApps.clear();
8095                        mClosingApps.clear();
8096
8097                        // This has changed the visibility of windows, so perform
8098                        // a new layout to get them all up-to-date.
8099                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT
8100                                | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
8101                        mLayoutNeeded = true;
8102                        if (!moveInputMethodWindowsIfNeededLocked(true)) {
8103                            assignLayersLocked();
8104                        }
8105                        updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8106                                false /*updateInputWindows*/);
8107                        mFocusMayChange = false;
8108                    }
8109                }
8110
8111                int adjResult = 0;
8112
8113                if (!animating && mAppTransitionRunning) {
8114                    // We have finished the animation of an app transition.  To do
8115                    // this, we have delayed a lot of operations like showing and
8116                    // hiding apps, moving apps in Z-order, etc.  The app token list
8117                    // reflects the correct Z-order, but the window list may now
8118                    // be out of sync with it.  So here we will just rebuild the
8119                    // entire app window list.  Fun!
8120                    mAppTransitionRunning = false;
8121                    // Clear information about apps that were moving.
8122                    mToBottomApps.clear();
8123
8124                    rebuildAppWindowListLocked();
8125                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8126                    adjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
8127                    moveInputMethodWindowsIfNeededLocked(false);
8128                    wallpaperMayChange = true;
8129                    // Since the window list has been rebuilt, focus might
8130                    // have to be recomputed since the actual order of windows
8131                    // might have changed again.
8132                    mFocusMayChange = true;
8133                }
8134
8135                if (wallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) {
8136                    // At this point, there was a window with a wallpaper that
8137                    // was force hiding other windows behind it, but now it
8138                    // is going away.  This may be simple -- just animate
8139                    // away the wallpaper and its window -- or it may be
8140                    // hard -- the wallpaper now needs to be shown behind
8141                    // something that was hidden.
8142                    WindowState oldWallpaper = mWallpaperTarget;
8143                    if (mLowerWallpaperTarget != null
8144                            && mLowerWallpaperTarget.mAppToken != null) {
8145                        if (DEBUG_WALLPAPER) Slog.v(TAG,
8146                                "wallpaperForceHiding changed with lower="
8147                                + mLowerWallpaperTarget);
8148                        if (DEBUG_WALLPAPER) Slog.v(TAG,
8149                                "hidden=" + mLowerWallpaperTarget.mAppToken.hidden +
8150                                " hiddenRequested=" + mLowerWallpaperTarget.mAppToken.hiddenRequested);
8151                        if (mLowerWallpaperTarget.mAppToken.hidden) {
8152                            // The lower target has become hidden before we
8153                            // actually started the animation...  let's completely
8154                            // re-evaluate everything.
8155                            mLowerWallpaperTarget = mUpperWallpaperTarget = null;
8156                            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8157                        }
8158                    }
8159                    adjResult |= adjustWallpaperWindowsLocked();
8160                    wallpaperMayChange = false;
8161                    wallpaperForceHidingChanged = false;
8162                    if (DEBUG_WALLPAPER) Slog.v(TAG, "****** OLD: " + oldWallpaper
8163                            + " NEW: " + mWallpaperTarget
8164                            + " LOWER: " + mLowerWallpaperTarget);
8165                    if (mLowerWallpaperTarget == null) {
8166                        // Whoops, we don't need a special wallpaper animation.
8167                        // Clear them out.
8168                        forceHiding = false;
8169                        for (i=N-1; i>=0; i--) {
8170                            WindowState w = mWindows.get(i);
8171                            if (w.mSurface != null) {
8172                                final WindowManager.LayoutParams attrs = w.mAttrs;
8173                                if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
8174                                    if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
8175                                    forceHiding = true;
8176                                } else if (mPolicy.canBeForceHidden(w, attrs)) {
8177                                    if (!w.mAnimating) {
8178                                        // We set the animation above so it
8179                                        // is not yet running.
8180                                        w.clearAnimation();
8181                                    }
8182                                }
8183                            }
8184                        }
8185                    }
8186                }
8187
8188                if (mWindowDetachedWallpaper != windowDetachedWallpaper) {
8189                    if (DEBUG_WALLPAPER) Slog.v(TAG,
8190                            "Detached wallpaper changed from " + mWindowDetachedWallpaper
8191                            + " to " + windowDetachedWallpaper);
8192                    mWindowDetachedWallpaper = windowDetachedWallpaper;
8193                    wallpaperMayChange = true;
8194                }
8195
8196                if (windowAnimationBackgroundColor != 0) {
8197                    // If the window that wants black is the current wallpaper
8198                    // target, then the black goes *below* the wallpaper so we
8199                    // don't cause the wallpaper to suddenly disappear.
8200                    WindowState target = windowAnimationBackground;
8201                    if (mWallpaperTarget == windowAnimationBackground
8202                            || mLowerWallpaperTarget == windowAnimationBackground
8203                            || mUpperWallpaperTarget == windowAnimationBackground) {
8204                        for (i=0; i<mWindows.size(); i++) {
8205                            WindowState w = mWindows.get(i);
8206                            if (w.mIsWallpaper) {
8207                                target = w;
8208                                break;
8209                            }
8210                        }
8211                    }
8212                    if (mWindowAnimationBackgroundSurface == null) {
8213                        mWindowAnimationBackgroundSurface = new DimSurface(mFxSession);
8214                    }
8215                    mWindowAnimationBackgroundSurface.show(dw, dh,
8216                            target.mAnimLayer - LAYER_OFFSET_DIM,
8217                            windowAnimationBackgroundColor);
8218                } else if (mWindowAnimationBackgroundSurface != null) {
8219                    mWindowAnimationBackgroundSurface.hide();
8220                }
8221
8222                if (wallpaperMayChange) {
8223                    if (DEBUG_WALLPAPER) Slog.v(TAG,
8224                            "Wallpaper may change!  Adjusting");
8225                    adjResult |= adjustWallpaperWindowsLocked();
8226                }
8227
8228                if ((adjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
8229                    if (DEBUG_WALLPAPER) Slog.v(TAG,
8230                            "Wallpaper layer changed: assigning layers + relayout");
8231                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8232                    assignLayersLocked();
8233                } else if ((adjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
8234                    if (DEBUG_WALLPAPER) Slog.v(TAG,
8235                            "Wallpaper visibility changed: relayout");
8236                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8237                }
8238
8239                if (mFocusMayChange) {
8240                    mFocusMayChange = false;
8241                    if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
8242                            false /*updateInputWindows*/)) {
8243                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
8244                        adjResult = 0;
8245                    }
8246                }
8247
8248                if (mLayoutNeeded) {
8249                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
8250                }
8251
8252                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
8253                        + Integer.toHexString(changes));
8254            } while (changes != 0);
8255
8256            // THIRD LOOP: Update the surfaces of all windows.
8257
8258            final boolean someoneLosingFocus = mLosingFocus.size() != 0;
8259
8260            boolean obscured = false;
8261            boolean blurring = false;
8262            boolean dimming = false;
8263            boolean covered = false;
8264            boolean syswin = false;
8265
8266            final int N = mWindows.size();
8267
8268            for (i=N-1; i>=0; i--) {
8269                WindowState w = mWindows.get(i);
8270
8271                boolean displayed = false;
8272                final WindowManager.LayoutParams attrs = w.mAttrs;
8273                final int attrFlags = attrs.flags;
8274
8275                if (w.mSurface != null) {
8276                    // XXX NOTE: The logic here could be improved.  We have
8277                    // the decision about whether to resize a window separated
8278                    // from whether to hide the surface.  This can cause us to
8279                    // resize a surface even if we are going to hide it.  You
8280                    // can see this by (1) holding device in landscape mode on
8281                    // home screen; (2) tapping browser icon (device will rotate
8282                    // to landscape; (3) tap home.  The wallpaper will be resized
8283                    // in step 2 but then immediately hidden, causing us to
8284                    // have to resize and then redraw it again in step 3.  It
8285                    // would be nice to figure out how to avoid this, but it is
8286                    // difficult because we do need to resize surfaces in some
8287                    // cases while they are hidden such as when first showing a
8288                    // window.
8289
8290                    w.computeShownFrameLocked();
8291                    if (localLOGV) Slog.v(
8292                            TAG, "Placing surface #" + i + " " + w.mSurface
8293                            + ": new=" + w.mShownFrame);
8294
8295                    if (w.mSurface != null) {
8296                        int width, height;
8297                        if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
8298                            // for a scaled surface, we just want to use
8299                            // the requested size.
8300                            width  = w.mRequestedWidth;
8301                            height = w.mRequestedHeight;
8302                        } else {
8303                            width = w.mCompatFrame.width();
8304                            height = w.mCompatFrame.height();
8305                        }
8306
8307                        if (width < 1) {
8308                            width = 1;
8309                        }
8310                        if (height < 1) {
8311                            height = 1;
8312                        }
8313                        final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
8314                        if (surfaceResized) {
8315                            w.mSurfaceW = width;
8316                            w.mSurfaceH = height;
8317                        }
8318
8319                        if (w.mSurfaceX != w.mShownFrame.left
8320                                || w.mSurfaceY != w.mShownFrame.top) {
8321                            try {
8322                                if (SHOW_TRANSACTIONS) logSurface(w,
8323                                        "POS " + w.mShownFrame.left
8324                                        + ", " + w.mShownFrame.top, null);
8325                                w.mSurfaceX = w.mShownFrame.left;
8326                                w.mSurfaceY = w.mShownFrame.top;
8327                                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
8328                            } catch (RuntimeException e) {
8329                                Slog.w(TAG, "Error positioning surface of " + w
8330                                        + " pos=(" + w.mShownFrame.left
8331                                        + "," + w.mShownFrame.top + ")", e);
8332                                if (!recoveringMemory) {
8333                                    reclaimSomeSurfaceMemoryLocked(w, "position", true);
8334                                }
8335                            }
8336                        }
8337
8338                        if (surfaceResized) {
8339                            try {
8340                                if (SHOW_TRANSACTIONS) logSurface(w,
8341                                        "SIZE " + width + "x" + height, null);
8342                                w.mSurfaceResized = true;
8343                                w.mSurface.setSize(width, height);
8344                            } catch (RuntimeException e) {
8345                                // If something goes wrong with the surface (such
8346                                // as running out of memory), don't take down the
8347                                // entire system.
8348                                Slog.e(TAG, "Error resizing surface of " + w
8349                                        + " size=(" + width + "x" + height + ")", e);
8350                                if (!recoveringMemory) {
8351                                    reclaimSomeSurfaceMemoryLocked(w, "size", true);
8352                                }
8353                            }
8354                        }
8355                    }
8356
8357                    if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
8358                        w.mContentInsetsChanged |=
8359                            !w.mLastContentInsets.equals(w.mContentInsets);
8360                        w.mVisibleInsetsChanged |=
8361                            !w.mLastVisibleInsets.equals(w.mVisibleInsets);
8362                        boolean configChanged =
8363                            w.mConfiguration != mCurConfiguration
8364                            && (w.mConfiguration == null
8365                                    || mCurConfiguration.diff(w.mConfiguration) != 0);
8366                        if (DEBUG_CONFIGURATION && configChanged) {
8367                            Slog.v(TAG, "Win " + w + " config changed: "
8368                                    + mCurConfiguration);
8369                        }
8370                        if (localLOGV) Slog.v(TAG, "Resizing " + w
8371                                + ": configChanged=" + configChanged
8372                                + " last=" + w.mLastFrame + " frame=" + w.mFrame);
8373                        w.mLastFrame.set(w.mFrame);
8374                        if (w.mContentInsetsChanged
8375                                || w.mVisibleInsetsChanged
8376                                || w.mSurfaceResized
8377                                || configChanged) {
8378                            if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
8379                                Slog.v(TAG, "Resize reasons: "
8380                                        + " contentInsetsChanged=" + w.mContentInsetsChanged
8381                                        + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
8382                                        + " surfaceResized=" + w.mSurfaceResized
8383                                        + " configChanged=" + configChanged);
8384                            }
8385
8386                            w.mLastContentInsets.set(w.mContentInsets);
8387                            w.mLastVisibleInsets.set(w.mVisibleInsets);
8388                            makeWindowFreezingScreenIfNeededLocked(w);
8389                            // If the orientation is changing, then we need to
8390                            // hold off on unfreezing the display until this
8391                            // window has been redrawn; to do that, we need
8392                            // to go through the process of getting informed
8393                            // by the application when it has finished drawing.
8394                            if (w.mOrientationChanging) {
8395                                if (DEBUG_ORIENTATION) Slog.v(TAG,
8396                                        "Orientation start waiting for draw in "
8397                                        + w + ", surface " + w.mSurface);
8398                                w.mDrawPending = true;
8399                                w.mCommitDrawPending = false;
8400                                w.mReadyToShow = false;
8401                                if (w.mAppToken != null) {
8402                                    w.mAppToken.allDrawn = false;
8403                                }
8404                            }
8405                            if (!mResizingWindows.contains(w)) {
8406                                if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8407                                        "Resizing window " + w + " to " + w.mSurfaceW
8408                                        + "x" + w.mSurfaceH);
8409                                mResizingWindows.add(w);
8410                            }
8411                        } else if (w.mOrientationChanging) {
8412                            if (!w.mDrawPending && !w.mCommitDrawPending) {
8413                                if (DEBUG_ORIENTATION) Slog.v(TAG,
8414                                        "Orientation not waiting for draw in "
8415                                        + w + ", surface " + w.mSurface);
8416                                w.mOrientationChanging = false;
8417                            }
8418                        }
8419                    }
8420
8421                    if (w.mAttachedHidden || !w.isReadyForDisplay()) {
8422                        if (!w.mLastHidden) {
8423                            //dump();
8424                            w.mLastHidden = true;
8425                            if (SHOW_TRANSACTIONS) logSurface(w,
8426                                    "HIDE (performLayout)", null);
8427                            if (w.mSurface != null) {
8428                                w.mSurfaceShown = false;
8429                                try {
8430                                    w.mSurface.hide();
8431                                } catch (RuntimeException e) {
8432                                    Slog.w(TAG, "Exception hiding surface in " + w);
8433                                }
8434                            }
8435                        }
8436                        // If we are waiting for this window to handle an
8437                        // orientation change, well, it is hidden, so
8438                        // doesn't really matter.  Note that this does
8439                        // introduce a potential glitch if the window
8440                        // becomes unhidden before it has drawn for the
8441                        // new orientation.
8442                        if (w.mOrientationChanging) {
8443                            w.mOrientationChanging = false;
8444                            if (DEBUG_ORIENTATION) Slog.v(TAG,
8445                                    "Orientation change skips hidden " + w);
8446                        }
8447                    } else if (w.mLastLayer != w.mAnimLayer
8448                            || w.mLastAlpha != w.mShownAlpha
8449                            || w.mLastDsDx != w.mDsDx
8450                            || w.mLastDtDx != w.mDtDx
8451                            || w.mLastDsDy != w.mDsDy
8452                            || w.mLastDtDy != w.mDtDy
8453                            || w.mLastHScale != w.mHScale
8454                            || w.mLastVScale != w.mVScale
8455                            || w.mLastHidden) {
8456                        displayed = true;
8457                        w.mLastAlpha = w.mShownAlpha;
8458                        w.mLastLayer = w.mAnimLayer;
8459                        w.mLastDsDx = w.mDsDx;
8460                        w.mLastDtDx = w.mDtDx;
8461                        w.mLastDsDy = w.mDsDy;
8462                        w.mLastDtDy = w.mDtDy;
8463                        w.mLastHScale = w.mHScale;
8464                        w.mLastVScale = w.mVScale;
8465                        if (SHOW_TRANSACTIONS) logSurface(w,
8466                                "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
8467                                + " matrix=[" + (w.mDsDx*w.mHScale)
8468                                + "," + (w.mDtDx*w.mVScale)
8469                                + "][" + (w.mDsDy*w.mHScale)
8470                                + "," + (w.mDtDy*w.mVScale) + "]", null);
8471                        if (w.mSurface != null) {
8472                            try {
8473                                w.mSurfaceAlpha = w.mShownAlpha;
8474                                w.mSurface.setAlpha(w.mShownAlpha);
8475                                w.mSurfaceLayer = w.mAnimLayer;
8476                                w.mSurface.setLayer(w.mAnimLayer);
8477                                w.mSurface.setMatrix(
8478                                        w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
8479                                        w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
8480                            } catch (RuntimeException e) {
8481                                Slog.w(TAG, "Error updating surface in " + w, e);
8482                                if (!recoveringMemory) {
8483                                    reclaimSomeSurfaceMemoryLocked(w, "update", true);
8484                                }
8485                            }
8486                        }
8487
8488                        if (w.mLastHidden && !w.mDrawPending
8489                                && !w.mCommitDrawPending
8490                                && !w.mReadyToShow) {
8491                            if (SHOW_TRANSACTIONS) logSurface(w,
8492                                    "SHOW (performLayout)", null);
8493                            if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
8494                                    + " during relayout");
8495                            if (showSurfaceRobustlyLocked(w)) {
8496                                w.mHasDrawn = true;
8497                                w.mLastHidden = false;
8498                            } else {
8499                                w.mOrientationChanging = false;
8500                            }
8501                        }
8502                        if (w.mSurface != null) {
8503                            w.mToken.hasVisible = true;
8504                        }
8505                    } else {
8506                        displayed = true;
8507                    }
8508
8509                    if (displayed) {
8510                        if (!covered) {
8511                            if (attrs.width == LayoutParams.MATCH_PARENT
8512                                    && attrs.height == LayoutParams.MATCH_PARENT) {
8513                                covered = true;
8514                            }
8515                        }
8516                        if (w.mOrientationChanging) {
8517                            if (w.mDrawPending || w.mCommitDrawPending) {
8518                                orientationChangeComplete = false;
8519                                if (DEBUG_ORIENTATION) Slog.v(TAG,
8520                                        "Orientation continue waiting for draw in " + w);
8521                            } else {
8522                                w.mOrientationChanging = false;
8523                                if (DEBUG_ORIENTATION) Slog.v(TAG,
8524                                        "Orientation change complete in " + w);
8525                            }
8526                        }
8527                        w.mToken.hasVisible = true;
8528                    }
8529                } else if (w.mOrientationChanging) {
8530                    if (DEBUG_ORIENTATION) Slog.v(TAG,
8531                            "Orientation change skips hidden " + w);
8532                    w.mOrientationChanging = false;
8533                }
8534
8535                if (w.mContentChanged) {
8536                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
8537                    w.mContentChanged = false;
8538                }
8539
8540                final boolean canBeSeen = w.isDisplayedLw();
8541
8542                if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
8543                    focusDisplayed = true;
8544                }
8545
8546                final boolean obscuredChanged = w.mObscured != obscured;
8547
8548                // Update effect.
8549                if (!(w.mObscured=obscured)) {
8550                    if (w.mSurface != null) {
8551                        if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
8552                            holdScreen = w.mSession;
8553                        }
8554                        if (!syswin && w.mAttrs.screenBrightness >= 0
8555                                && screenBrightness < 0) {
8556                            screenBrightness = w.mAttrs.screenBrightness;
8557                        }
8558                        if (!syswin && w.mAttrs.buttonBrightness >= 0
8559                                && buttonBrightness < 0) {
8560                            buttonBrightness = w.mAttrs.buttonBrightness;
8561                        }
8562                        if (canBeSeen
8563                                && (attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG
8564                                 || attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD
8565                                 || attrs.type == WindowManager.LayoutParams.TYPE_SYSTEM_ERROR)) {
8566                            syswin = true;
8567                        }
8568                    }
8569
8570                    boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
8571                    if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
8572                        // This window completely covers everything behind it,
8573                        // so we want to leave all of them as unblurred (for
8574                        // performance reasons).
8575                        obscured = true;
8576                    } else if (canBeSeen && !obscured &&
8577                            (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
8578                        if (localLOGV) Slog.v(TAG, "Win " + w
8579                                + ": blurring=" + blurring
8580                                + " obscured=" + obscured
8581                                + " displayed=" + displayed);
8582                        if ((attrFlags&FLAG_DIM_BEHIND) != 0) {
8583                            if (!dimming) {
8584                                //Slog.i(TAG, "DIM BEHIND: " + w);
8585                                dimming = true;
8586                                if (mDimAnimator == null) {
8587                                    mDimAnimator = new DimAnimator(mFxSession);
8588                                }
8589                                mDimAnimator.show(innerDw, innerDh);
8590                                mDimAnimator.updateParameters(mContext.getResources(),
8591                                        w, currentTime);
8592                            }
8593                        }
8594                        if ((attrFlags&FLAG_BLUR_BEHIND) != 0) {
8595                            if (!blurring) {
8596                                //Slog.i(TAG, "BLUR BEHIND: " + w);
8597                                blurring = true;
8598                                if (mBlurSurface == null) {
8599                                    try {
8600                                        mBlurSurface = new Surface(mFxSession, 0,
8601                                                "BlurSurface",
8602                                                -1, 16, 16,
8603                                                PixelFormat.OPAQUE,
8604                                                Surface.FX_SURFACE_BLUR);
8605                                    } catch (Exception e) {
8606                                        Slog.e(TAG, "Exception creating Blur surface", e);
8607                                    }
8608                                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
8609                                            + mBlurSurface + ": CREATE");
8610                                }
8611                                if (mBlurSurface != null) {
8612                                    if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
8613                                            + mBlurSurface + ": pos=(0,0) (" +
8614                                            dw + "x" + dh + "), layer=" + (w.mAnimLayer-1));
8615                                    mBlurSurface.setPosition(0, 0);
8616                                    mBlurSurface.setSize(dw, dh);
8617                                    mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR);
8618                                    if (!mBlurShown) {
8619                                        try {
8620                                            if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR "
8621                                                    + mBlurSurface + ": SHOW");
8622                                            mBlurSurface.show();
8623                                        } catch (RuntimeException e) {
8624                                            Slog.w(TAG, "Failure showing blur surface", e);
8625                                        }
8626                                        mBlurShown = true;
8627                                    }
8628                                }
8629                            }
8630                        }
8631                    }
8632                }
8633
8634                if (obscuredChanged && mWallpaperTarget == w) {
8635                    // This is the wallpaper target and its obscured state
8636                    // changed... make sure the current wallaper's visibility
8637                    // has been updated accordingly.
8638                    updateWallpaperVisibilityLocked();
8639                }
8640            }
8641
8642            if (mDimAnimator != null && mDimAnimator.mDimShown) {
8643                animating |= mDimAnimator.updateSurface(dimming, currentTime,
8644                        mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully());
8645            }
8646
8647            if (!blurring && mBlurShown) {
8648                if (SHOW_TRANSACTIONS) Slog.i(TAG, "  BLUR " + mBlurSurface
8649                        + ": HIDE");
8650                try {
8651                    mBlurSurface.hide();
8652                } catch (IllegalArgumentException e) {
8653                    Slog.w(TAG, "Illegal argument exception hiding blur surface");
8654                }
8655                mBlurShown = false;
8656            }
8657
8658            if (mBlackFrame != null) {
8659                if (mScreenRotationAnimation != null) {
8660                    mBlackFrame.setMatrix(
8661                            mScreenRotationAnimation.getEnterTransformation().getMatrix());
8662                } else {
8663                    mBlackFrame.clearMatrix();
8664                }
8665            }
8666        } catch (RuntimeException e) {
8667            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
8668        }
8669
8670        Surface.closeTransaction();
8671
8672        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
8673                "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
8674
8675        if (mWatermark != null) {
8676            mWatermark.drawIfNeeded();
8677        }
8678
8679        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
8680                "With display frozen, orientationChangeComplete="
8681                + orientationChangeComplete);
8682        if (orientationChangeComplete) {
8683            if (mWindowsFreezingScreen) {
8684                mWindowsFreezingScreen = false;
8685                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
8686            }
8687            stopFreezingDisplayLocked();
8688        }
8689
8690        i = mResizingWindows.size();
8691        if (i > 0) {
8692            do {
8693                i--;
8694                WindowState win = mResizingWindows.get(i);
8695                try {
8696                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
8697                            "Reporting new frame to " + win + ": " + win.mCompatFrame);
8698                    int diff = 0;
8699                    boolean configChanged =
8700                        win.mConfiguration != mCurConfiguration
8701                        && (win.mConfiguration == null
8702                                || (diff=mCurConfiguration.diff(win.mConfiguration)) != 0);
8703                    if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION)
8704                            && configChanged) {
8705                        Slog.i(TAG, "Sending new config to window " + win + ": "
8706                                + win.mSurfaceW + "x" + win.mSurfaceH
8707                                + " / " + mCurConfiguration + " / 0x"
8708                                + Integer.toHexString(diff));
8709                    }
8710                    win.mConfiguration = mCurConfiguration;
8711                    if (DEBUG_ORIENTATION && win.mDrawPending) Slog.i(
8712                            TAG, "Resizing " + win + " WITH DRAW PENDING");
8713                    win.mClient.resized((int)win.mSurfaceW, (int)win.mSurfaceH,
8714                            win.mLastContentInsets, win.mLastVisibleInsets, win.mDrawPending,
8715                            configChanged ? win.mConfiguration : null);
8716                    win.mContentInsetsChanged = false;
8717                    win.mVisibleInsetsChanged = false;
8718                    win.mSurfaceResized = false;
8719                } catch (RemoteException e) {
8720                    win.mOrientationChanging = false;
8721                }
8722            } while (i > 0);
8723            mResizingWindows.clear();
8724        }
8725
8726        // Destroy the surface of any windows that are no longer visible.
8727        boolean wallpaperDestroyed = false;
8728        i = mDestroySurface.size();
8729        if (i > 0) {
8730            do {
8731                i--;
8732                WindowState win = mDestroySurface.get(i);
8733                win.mDestroying = false;
8734                if (mInputMethodWindow == win) {
8735                    mInputMethodWindow = null;
8736                }
8737                if (win == mWallpaperTarget) {
8738                    wallpaperDestroyed = true;
8739                }
8740                win.destroySurfaceLocked();
8741            } while (i > 0);
8742            mDestroySurface.clear();
8743        }
8744
8745        // Time to remove any exiting tokens?
8746        for (i=mExitingTokens.size()-1; i>=0; i--) {
8747            WindowToken token = mExitingTokens.get(i);
8748            if (!token.hasVisible) {
8749                mExitingTokens.remove(i);
8750                if (token.windowType == TYPE_WALLPAPER) {
8751                    mWallpaperTokens.remove(token);
8752                }
8753            }
8754        }
8755
8756        // Time to remove any exiting applications?
8757        for (i=mExitingAppTokens.size()-1; i>=0; i--) {
8758            AppWindowToken token = mExitingAppTokens.get(i);
8759            if (!token.hasVisible && !mClosingApps.contains(token)) {
8760                // Make sure there is no animation running on this token,
8761                // so any windows associated with it will be removed as
8762                // soon as their animations are complete
8763                token.animation = null;
8764                token.animating = false;
8765                if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
8766                        "performLayout: App token exiting now removed" + token);
8767                mAppTokens.remove(token);
8768                mExitingAppTokens.remove(i);
8769            }
8770        }
8771
8772        boolean needRelayout = false;
8773
8774        if (!animating && mAppTransitionRunning) {
8775            // We have finished the animation of an app transition.  To do
8776            // this, we have delayed a lot of operations like showing and
8777            // hiding apps, moving apps in Z-order, etc.  The app token list
8778            // reflects the correct Z-order, but the window list may now
8779            // be out of sync with it.  So here we will just rebuild the
8780            // entire app window list.  Fun!
8781            mAppTransitionRunning = false;
8782            needRelayout = true;
8783            rebuildAppWindowListLocked();
8784            assignLayersLocked();
8785            // Clear information about apps that were moving.
8786            mToBottomApps.clear();
8787        }
8788
8789        if (focusDisplayed) {
8790            mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
8791        }
8792        if (wallpaperDestroyed) {
8793            needRelayout = adjustWallpaperWindowsLocked() != 0;
8794        }
8795        if (needRelayout) {
8796            requestAnimationLocked(0);
8797        } else if (animating) {
8798            final int refreshTimeUs = (int)(1000 / mDisplay.getRefreshRate());
8799            requestAnimationLocked(currentTime + refreshTimeUs - SystemClock.uptimeMillis());
8800        }
8801
8802        // Finally update all input windows now that the window changes have stabilized.
8803        mInputMonitor.updateInputWindowsLw(true /*force*/);
8804
8805        setHoldScreenLocked(holdScreen != null);
8806        if (!mDisplayFrozen) {
8807            if (screenBrightness < 0 || screenBrightness > 1.0f) {
8808                mPowerManager.setScreenBrightnessOverride(-1);
8809            } else {
8810                mPowerManager.setScreenBrightnessOverride((int)
8811                        (screenBrightness * Power.BRIGHTNESS_ON));
8812            }
8813            if (buttonBrightness < 0 || buttonBrightness > 1.0f) {
8814                mPowerManager.setButtonBrightnessOverride(-1);
8815            } else {
8816                mPowerManager.setButtonBrightnessOverride((int)
8817                        (buttonBrightness * Power.BRIGHTNESS_ON));
8818            }
8819        }
8820        if (holdScreen != mHoldingScreenOn) {
8821            mHoldingScreenOn = holdScreen;
8822            Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
8823            mH.sendMessage(m);
8824        }
8825
8826        if (mTurnOnScreen) {
8827            if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
8828            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
8829                    LocalPowerManager.BUTTON_EVENT, true);
8830            mTurnOnScreen = false;
8831        }
8832
8833        if (screenRotationFinished && mScreenRotationAnimation != null) {
8834            mScreenRotationAnimation.kill();
8835            mScreenRotationAnimation = null;
8836        }
8837
8838        if (updateRotation) {
8839            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
8840            boolean changed = updateRotationUncheckedLocked(false);
8841            if (changed) {
8842                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
8843            } else {
8844                updateRotation = false;
8845            }
8846        }
8847
8848        if (orientationChangeComplete && !needRelayout && !updateRotation) {
8849            checkDrawnWindowsLocked();
8850        }
8851
8852        // Check to see if we are now in a state where the screen should
8853        // be enabled, because the window obscured flags have changed.
8854        enableScreenIfNeededLocked();
8855    }
8856
8857    void checkDrawnWindowsLocked() {
8858        if (mWaitingForDrawn.size() > 0) {
8859            for (int j=mWaitingForDrawn.size()-1; j>=0; j--) {
8860                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(j);
8861                WindowState win = pair.first;
8862                //Slog.i(TAG, "Waiting for drawn " + win + ": removed="
8863                //        + win.mRemoved + " visible=" + win.isVisibleLw()
8864                //        + " shown=" + win.mSurfaceShown);
8865                if (win.mRemoved || !win.isVisibleLw()) {
8866                    // Window has been removed or made invisible; no draw
8867                    // will now happen, so stop waiting.
8868                    Slog.w(TAG, "Aborted waiting for drawn: " + pair.first);
8869                    try {
8870                        pair.second.sendResult(null);
8871                    } catch (RemoteException e) {
8872                    }
8873                    mWaitingForDrawn.remove(pair);
8874                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8875                } else if (win.mSurfaceShown) {
8876                    // Window is now drawn (and shown).
8877                    try {
8878                        pair.second.sendResult(null);
8879                    } catch (RemoteException e) {
8880                    }
8881                    mWaitingForDrawn.remove(pair);
8882                    mH.removeMessages(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8883                }
8884            }
8885        }
8886    }
8887
8888    public void waitForWindowDrawn(IBinder token, IRemoteCallback callback) {
8889        synchronized (mWindowMap) {
8890            WindowState win = windowForClientLocked(null, token, true);
8891            if (win != null) {
8892                Pair<WindowState, IRemoteCallback> pair =
8893                        new Pair<WindowState, IRemoteCallback>(win, callback);
8894                Message m = mH.obtainMessage(H.WAITING_FOR_DRAWN_TIMEOUT, pair);
8895                mH.sendMessageDelayed(m, 2000);
8896                mWaitingForDrawn.add(pair);
8897                checkDrawnWindowsLocked();
8898            }
8899        }
8900    }
8901
8902    /**
8903     * Must be called with the main window manager lock held.
8904     */
8905    void setHoldScreenLocked(boolean holding) {
8906        boolean state = mHoldingScreenWakeLock.isHeld();
8907        if (holding != state) {
8908            if (holding) {
8909                mPolicy.screenOnStartedLw();
8910                mHoldingScreenWakeLock.acquire();
8911            } else {
8912                mPolicy.screenOnStoppedLw();
8913                mHoldingScreenWakeLock.release();
8914            }
8915        }
8916    }
8917
8918    void requestAnimationLocked(long delay) {
8919        if (!mAnimationPending) {
8920            mAnimationPending = true;
8921            mH.sendMessageDelayed(mH.obtainMessage(H.ANIMATE), delay);
8922        }
8923    }
8924
8925    /**
8926     * Have the surface flinger show a surface, robustly dealing with
8927     * error conditions.  In particular, if there is not enough memory
8928     * to show the surface, then we will try to get rid of other surfaces
8929     * in order to succeed.
8930     *
8931     * @return Returns true if the surface was successfully shown.
8932     */
8933    boolean showSurfaceRobustlyLocked(WindowState win) {
8934        try {
8935            if (win.mSurface != null) {
8936                win.mSurfaceShown = true;
8937                win.mSurface.show();
8938                if (win.mTurnOnScreen) {
8939                    if (DEBUG_VISIBILITY) Slog.v(TAG,
8940                            "Show surface turning screen on: " + win);
8941                    win.mTurnOnScreen = false;
8942                    mTurnOnScreen = true;
8943                }
8944            }
8945            return true;
8946        } catch (RuntimeException e) {
8947            Slog.w(TAG, "Failure showing surface " + win.mSurface + " in " + win, e);
8948        }
8949
8950        reclaimSomeSurfaceMemoryLocked(win, "show", true);
8951
8952        return false;
8953    }
8954
8955    boolean reclaimSomeSurfaceMemoryLocked(WindowState win, String operation, boolean secure) {
8956        final Surface surface = win.mSurface;
8957        boolean leakedSurface = false;
8958        boolean killedApps = false;
8959
8960        EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, win.toString(),
8961                win.mSession.mPid, operation);
8962
8963        if (mForceRemoves == null) {
8964            mForceRemoves = new ArrayList<WindowState>();
8965        }
8966
8967        long callingIdentity = Binder.clearCallingIdentity();
8968        try {
8969            // There was some problem...   first, do a sanity check of the
8970            // window list to make sure we haven't left any dangling surfaces
8971            // around.
8972            int N = mWindows.size();
8973            Slog.i(TAG, "Out of memory for surface!  Looking for leaks...");
8974            for (int i=0; i<N; i++) {
8975                WindowState ws = mWindows.get(i);
8976                if (ws.mSurface != null) {
8977                    if (!mSessions.contains(ws.mSession)) {
8978                        Slog.w(TAG, "LEAKED SURFACE (session doesn't exist): "
8979                                + ws + " surface=" + ws.mSurface
8980                                + " token=" + win.mToken
8981                                + " pid=" + ws.mSession.mPid
8982                                + " uid=" + ws.mSession.mUid);
8983                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8984                        ws.mSurface.destroy();
8985                        ws.mSurfaceShown = false;
8986                        ws.mSurface = null;
8987                        mForceRemoves.add(ws);
8988                        i--;
8989                        N--;
8990                        leakedSurface = true;
8991                    } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
8992                        Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
8993                                + ws + " surface=" + ws.mSurface
8994                                + " token=" + win.mAppToken);
8995                        if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
8996                        ws.mSurface.destroy();
8997                        ws.mSurfaceShown = false;
8998                        ws.mSurface = null;
8999                        leakedSurface = true;
9000                    }
9001                }
9002            }
9003
9004            if (!leakedSurface) {
9005                Slog.w(TAG, "No leaked surfaces; killing applicatons!");
9006                SparseIntArray pidCandidates = new SparseIntArray();
9007                for (int i=0; i<N; i++) {
9008                    WindowState ws = mWindows.get(i);
9009                    if (ws.mSurface != null) {
9010                        pidCandidates.append(ws.mSession.mPid, ws.mSession.mPid);
9011                    }
9012                }
9013                if (pidCandidates.size() > 0) {
9014                    int[] pids = new int[pidCandidates.size()];
9015                    for (int i=0; i<pids.length; i++) {
9016                        pids[i] = pidCandidates.keyAt(i);
9017                    }
9018                    try {
9019                        if (mActivityManager.killPids(pids, "Free memory", secure)) {
9020                            killedApps = true;
9021                        }
9022                    } catch (RemoteException e) {
9023                    }
9024                }
9025            }
9026
9027            if (leakedSurface || killedApps) {
9028                // We managed to reclaim some memory, so get rid of the trouble
9029                // surface and ask the app to request another one.
9030                Slog.w(TAG, "Looks like we have reclaimed some memory, clearing surface for retry.");
9031                if (surface != null) {
9032                    if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) logSurface(win,
9033                            "RECOVER DESTROY", null);
9034                    surface.destroy();
9035                    win.mSurfaceShown = false;
9036                    win.mSurface = null;
9037                }
9038
9039                try {
9040                    win.mClient.dispatchGetNewSurface();
9041                } catch (RemoteException e) {
9042                }
9043            }
9044        } finally {
9045            Binder.restoreCallingIdentity(callingIdentity);
9046        }
9047
9048        return leakedSurface || killedApps;
9049    }
9050
9051    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
9052        WindowState newFocus = computeFocusedWindowLocked();
9053        if (mCurrentFocus != newFocus) {
9054            // This check makes sure that we don't already have the focus
9055            // change message pending.
9056            mH.removeMessages(H.REPORT_FOCUS_CHANGE);
9057            mH.sendEmptyMessage(H.REPORT_FOCUS_CHANGE);
9058            if (localLOGV) Slog.v(
9059                TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
9060            final WindowState oldFocus = mCurrentFocus;
9061            mCurrentFocus = newFocus;
9062            mLosingFocus.remove(newFocus);
9063            int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
9064
9065            final WindowState imWindow = mInputMethodWindow;
9066            if (newFocus != imWindow && oldFocus != imWindow) {
9067                if (moveInputMethodWindowsIfNeededLocked(
9068                        mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS &&
9069                        mode != UPDATE_FOCUS_WILL_PLACE_SURFACES)) {
9070                    mLayoutNeeded = true;
9071                }
9072                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9073                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
9074                    focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
9075                } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
9076                    // Client will do the layout, but we need to assign layers
9077                    // for handleNewWindowLocked() below.
9078                    assignLayersLocked();
9079                }
9080            }
9081
9082            if ((focusChanged&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
9083                // The change in focus caused us to need to do a layout.  Okay.
9084                mLayoutNeeded = true;
9085                if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
9086                    performLayoutLockedInner(true /*initial*/, updateInputWindows);
9087                }
9088            }
9089
9090            if (mode != UPDATE_FOCUS_WILL_ASSIGN_LAYERS) {
9091                // If we defer assigning layers, then the caller is responsible for
9092                // doing this part.
9093                finishUpdateFocusedWindowAfterAssignLayersLocked(updateInputWindows);
9094            }
9095            return true;
9096        }
9097        return false;
9098    }
9099
9100    private void finishUpdateFocusedWindowAfterAssignLayersLocked(boolean updateInputWindows) {
9101        mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
9102    }
9103
9104    private WindowState computeFocusedWindowLocked() {
9105        WindowState result = null;
9106        WindowState win;
9107
9108        int i = mWindows.size() - 1;
9109        int nextAppIndex = mAppTokens.size()-1;
9110        WindowToken nextApp = nextAppIndex >= 0
9111            ? mAppTokens.get(nextAppIndex) : null;
9112
9113        while (i >= 0) {
9114            win = mWindows.get(i);
9115
9116            if (localLOGV || DEBUG_FOCUS) Slog.v(
9117                TAG, "Looking for focus: " + i
9118                + " = " + win
9119                + ", flags=" + win.mAttrs.flags
9120                + ", canReceive=" + win.canReceiveKeys());
9121
9122            AppWindowToken thisApp = win.mAppToken;
9123
9124            // If this window's application has been removed, just skip it.
9125            if (thisApp != null && thisApp.removed) {
9126                i--;
9127                continue;
9128            }
9129
9130            // If there is a focused app, don't allow focus to go to any
9131            // windows below it.  If this is an application window, step
9132            // through the app tokens until we find its app.
9133            if (thisApp != null && nextApp != null && thisApp != nextApp
9134                    && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
9135                int origAppIndex = nextAppIndex;
9136                while (nextAppIndex > 0) {
9137                    if (nextApp == mFocusedApp) {
9138                        // Whoops, we are below the focused app...  no focus
9139                        // for you!
9140                        if (localLOGV || DEBUG_FOCUS) Slog.v(
9141                            TAG, "Reached focused app: " + mFocusedApp);
9142                        return null;
9143                    }
9144                    nextAppIndex--;
9145                    nextApp = mAppTokens.get(nextAppIndex);
9146                    if (nextApp == thisApp) {
9147                        break;
9148                    }
9149                }
9150                if (thisApp != nextApp) {
9151                    // Uh oh, the app token doesn't exist!  This shouldn't
9152                    // happen, but if it does we can get totally hosed...
9153                    // so restart at the original app.
9154                    nextAppIndex = origAppIndex;
9155                    nextApp = mAppTokens.get(nextAppIndex);
9156                }
9157            }
9158
9159            // Dispatch to this window if it is wants key events.
9160            if (win.canReceiveKeys()) {
9161                if (DEBUG_FOCUS) Slog.v(
9162                        TAG, "Found focus @ " + i + " = " + win);
9163                result = win;
9164                break;
9165            }
9166
9167            i--;
9168        }
9169
9170        return result;
9171    }
9172
9173    private void startFreezingDisplayLocked(boolean inTransaction) {
9174        if (mDisplayFrozen) {
9175            return;
9176        }
9177
9178        if (mDisplay == null || !mPolicy.isScreenOnFully()) {
9179            // No need to freeze the screen before the system is ready or if
9180            // the screen is off.
9181            return;
9182        }
9183
9184        mScreenFrozenLock.acquire();
9185
9186        mDisplayFrozen = true;
9187
9188        mInputMonitor.freezeInputDispatchingLw();
9189
9190        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
9191            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
9192            mNextAppTransitionPackage = null;
9193            mAppTransitionReady = true;
9194        }
9195
9196        if (PROFILE_ORIENTATION) {
9197            File file = new File("/data/system/frozen");
9198            Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
9199        }
9200
9201        if (CUSTOM_SCREEN_ROTATION) {
9202            if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
9203                mScreenRotationAnimation.kill();
9204                mScreenRotationAnimation = null;
9205            }
9206            if (mScreenRotationAnimation == null) {
9207                mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
9208                        mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight,
9209                        mDisplay.getRotation());
9210            }
9211            if (!mScreenRotationAnimation.hasScreenshot()) {
9212                Surface.freezeDisplay(0);
9213            }
9214        } else {
9215            Surface.freezeDisplay(0);
9216        }
9217    }
9218
9219    private void stopFreezingDisplayLocked() {
9220        if (!mDisplayFrozen) {
9221            return;
9222        }
9223
9224        if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen) {
9225            return;
9226        }
9227
9228        mDisplayFrozen = false;
9229        mH.removeMessages(H.APP_FREEZE_TIMEOUT);
9230        if (PROFILE_ORIENTATION) {
9231            Debug.stopMethodTracing();
9232        }
9233
9234        boolean updateRotation = false;
9235
9236        if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
9237                && mScreenRotationAnimation.hasScreenshot()) {
9238            if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
9239            if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
9240                    mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
9241                requestAnimationLocked(0);
9242            } else {
9243                mScreenRotationAnimation = null;
9244                updateRotation = true;
9245            }
9246        } else {
9247            if (mScreenRotationAnimation != null) {
9248                mScreenRotationAnimation.kill();
9249                mScreenRotationAnimation = null;
9250            }
9251            updateRotation = true;
9252        }
9253        Surface.unfreezeDisplay(0);
9254
9255        mInputMonitor.thawInputDispatchingLw();
9256
9257        boolean configChanged;
9258
9259        // While the display is frozen we don't re-compute the orientation
9260        // to avoid inconsistent states.  However, something interesting
9261        // could have actually changed during that time so re-evaluate it
9262        // now to catch that.
9263        configChanged = updateOrientationFromAppTokensLocked(false);
9264
9265        // A little kludge: a lot could have happened while the
9266        // display was frozen, so now that we are coming back we
9267        // do a gc so that any remote references the system
9268        // processes holds on others can be released if they are
9269        // no longer needed.
9270        mH.removeMessages(H.FORCE_GC);
9271        mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
9272                2000);
9273
9274        mScreenFrozenLock.release();
9275
9276        if (updateRotation) {
9277            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
9278            configChanged |= updateRotationUncheckedLocked(false);
9279        }
9280
9281        if (configChanged) {
9282            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
9283        }
9284    }
9285
9286    static int getPropertyInt(String[] tokens, int index, int defUnits, int defDps,
9287            DisplayMetrics dm) {
9288        if (index < tokens.length) {
9289            String str = tokens[index];
9290            if (str != null && str.length() > 0) {
9291                try {
9292                    int val = Integer.parseInt(str);
9293                    return val;
9294                } catch (Exception e) {
9295                }
9296            }
9297        }
9298        if (defUnits == TypedValue.COMPLEX_UNIT_PX) {
9299            return defDps;
9300        }
9301        int val = (int)TypedValue.applyDimension(defUnits, defDps, dm);
9302        return val;
9303    }
9304
9305    void createWatermark() {
9306        if (mWatermark != null) {
9307            return;
9308        }
9309
9310        File file = new File("/system/etc/setup.conf");
9311        FileInputStream in = null;
9312        try {
9313            in = new FileInputStream(file);
9314            DataInputStream ind = new DataInputStream(in);
9315            String line = ind.readLine();
9316            if (line != null) {
9317                String[] toks = line.split("%");
9318                if (toks != null && toks.length > 0) {
9319                    mWatermark = new Watermark(mRealDisplayMetrics, mFxSession, toks);
9320                }
9321            }
9322        } catch (FileNotFoundException e) {
9323        } catch (IOException e) {
9324        } finally {
9325            if (in != null) {
9326                try {
9327                    in.close();
9328                } catch (IOException e) {
9329                }
9330            }
9331        }
9332    }
9333
9334    @Override
9335    public void statusBarVisibilityChanged(int visibility) {
9336        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
9337                != PackageManager.PERMISSION_GRANTED) {
9338            throw new SecurityException("Caller does not hold permission "
9339                    + android.Manifest.permission.STATUS_BAR);
9340        }
9341
9342        synchronized (mWindowMap) {
9343            mLastStatusBarVisibility = visibility;
9344            visibility = mPolicy.adjustSystemUiVisibilityLw(visibility);
9345            updateStatusBarVisibilityLocked(visibility);
9346        }
9347    }
9348
9349    void updateStatusBarVisibilityLocked(int visibility) {
9350        mInputManager.setSystemUiVisibility(visibility);
9351        final int N = mWindows.size();
9352        for (int i = 0; i < N; i++) {
9353            WindowState ws = mWindows.get(i);
9354            try {
9355                int curValue = ws.mSystemUiVisibility;
9356                int diff = curValue ^ visibility;
9357                // We are only interested in differences of one of the
9358                // clearable flags...
9359                diff &= View.SYSTEM_UI_CLEARABLE_FLAGS;
9360                // ...if it has actually been cleared.
9361                diff &= ~visibility;
9362                int newValue = (curValue&~diff) | (visibility&diff);
9363                if (newValue != curValue) {
9364                    ws.mSeq++;
9365                    ws.mSystemUiVisibility = newValue;
9366                }
9367                if (newValue != curValue || ws.mAttrs.hasSystemUiListeners) {
9368                    ws.mClient.dispatchSystemUiVisibilityChanged(ws.mSeq,
9369                            visibility, newValue, diff);
9370                }
9371            } catch (RemoteException e) {
9372                // so sorry
9373            }
9374        }
9375    }
9376
9377    @Override
9378    public void reevaluateStatusBarVisibility() {
9379        synchronized (mWindowMap) {
9380            int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
9381            updateStatusBarVisibilityLocked(visibility);
9382            performLayoutAndPlaceSurfacesLocked();
9383        }
9384    }
9385
9386    @Override
9387    public FakeWindow addFakeWindow(Looper looper, InputHandler inputHandler,
9388            String name, int windowType, int layoutParamsFlags, boolean canReceiveKeys,
9389            boolean hasFocus, boolean touchFullscreen) {
9390        synchronized (mWindowMap) {
9391            FakeWindowImpl fw = new FakeWindowImpl(this, looper, inputHandler, name, windowType,
9392                    layoutParamsFlags, canReceiveKeys, hasFocus, touchFullscreen);
9393            int i=0;
9394            while (i<mFakeWindows.size()) {
9395                if (mFakeWindows.get(i).mWindowLayer <= fw.mWindowLayer) {
9396                    break;
9397                }
9398            }
9399            mFakeWindows.add(i, fw);
9400            mInputMonitor.updateInputWindowsLw(true);
9401            return fw;
9402        }
9403    }
9404
9405    boolean removeFakeWindowLocked(FakeWindow window) {
9406        synchronized (mWindowMap) {
9407            if (mFakeWindows.remove(window)) {
9408                mInputMonitor.updateInputWindowsLw(true);
9409                return true;
9410            }
9411            return false;
9412        }
9413    }
9414
9415    @Override
9416    public boolean hasNavigationBar() {
9417        return mPolicy.hasNavigationBar();
9418    }
9419
9420    void dumpInput(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9421        pw.println("WINDOW MANAGER INPUT (dumpsys window input)");
9422        mInputManager.dump(pw);
9423    }
9424
9425    void dumpPolicyLocked(FileDescriptor fd, PrintWriter pw, String[] args, boolean dumpAll) {
9426        pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
9427        mPolicy.dump("    ", fd, pw, args);
9428    }
9429
9430    void dumpTokensLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9431        pw.println("WINDOW MANAGER TOKENS (dumpsys window tokens)");
9432        if (mTokenMap.size() > 0) {
9433            pw.println("  All tokens:");
9434            Iterator<WindowToken> it = mTokenMap.values().iterator();
9435            while (it.hasNext()) {
9436                WindowToken token = it.next();
9437                pw.print("  Token "); pw.print(token.token);
9438                if (dumpAll) {
9439                    pw.println(':');
9440                    token.dump(pw, "    ");
9441                } else {
9442                    pw.println();
9443                }
9444            }
9445        }
9446        if (mWallpaperTokens.size() > 0) {
9447            pw.println();
9448            pw.println("  Wallpaper tokens:");
9449            for (int i=mWallpaperTokens.size()-1; i>=0; i--) {
9450                WindowToken token = mWallpaperTokens.get(i);
9451                pw.print("  Wallpaper #"); pw.print(i);
9452                        pw.print(' '); pw.print(token);
9453                if (dumpAll) {
9454                    pw.println(':');
9455                    token.dump(pw, "    ");
9456                } else {
9457                    pw.println();
9458                }
9459            }
9460        }
9461        if (mAppTokens.size() > 0) {
9462            pw.println();
9463            pw.println("  Application tokens in Z order:");
9464            for (int i=mAppTokens.size()-1; i>=0; i--) {
9465                pw.print("  App #"); pw.print(i); pw.print(": ");
9466                        pw.println(mAppTokens.get(i));
9467            }
9468        }
9469        if (mFinishedStarting.size() > 0) {
9470            pw.println();
9471            pw.println("  Finishing start of application tokens:");
9472            for (int i=mFinishedStarting.size()-1; i>=0; i--) {
9473                WindowToken token = mFinishedStarting.get(i);
9474                pw.print("  Finished Starting #"); pw.print(i);
9475                        pw.print(' '); pw.print(token);
9476                if (dumpAll) {
9477                    pw.println(':');
9478                    token.dump(pw, "    ");
9479                } else {
9480                    pw.println();
9481                }
9482            }
9483        }
9484        if (mExitingTokens.size() > 0) {
9485            pw.println();
9486            pw.println("  Exiting tokens:");
9487            for (int i=mExitingTokens.size()-1; i>=0; i--) {
9488                WindowToken token = mExitingTokens.get(i);
9489                pw.print("  Exiting #"); pw.print(i);
9490                        pw.print(' '); pw.print(token);
9491                if (dumpAll) {
9492                    pw.println(':');
9493                    token.dump(pw, "    ");
9494                } else {
9495                    pw.println();
9496                }
9497            }
9498        }
9499        if (mExitingAppTokens.size() > 0) {
9500            pw.println();
9501            pw.println("  Exiting application tokens:");
9502            for (int i=mExitingAppTokens.size()-1; i>=0; i--) {
9503                WindowToken token = mExitingAppTokens.get(i);
9504                pw.print("  Exiting App #"); pw.print(i);
9505                        pw.print(' '); pw.print(token);
9506                if (dumpAll) {
9507                    pw.println(':');
9508                    token.dump(pw, "    ");
9509                } else {
9510                    pw.println();
9511                }
9512            }
9513        }
9514        pw.println();
9515        if (mOpeningApps.size() > 0) {
9516            pw.print("  mOpeningApps="); pw.println(mOpeningApps);
9517        }
9518        if (mClosingApps.size() > 0) {
9519            pw.print("  mClosingApps="); pw.println(mClosingApps);
9520        }
9521        if (mToTopApps.size() > 0) {
9522            pw.print("  mToTopApps="); pw.println(mToTopApps);
9523        }
9524        if (mToBottomApps.size() > 0) {
9525            pw.print("  mToBottomApps="); pw.println(mToBottomApps);
9526        }
9527    }
9528
9529    void dumpSessionsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
9530        pw.println("WINDOW MANAGER SESSIONS (dumpsys window sessions)");
9531        if (mSessions.size() > 0) {
9532            Iterator<Session> it = mSessions.iterator();
9533            while (it.hasNext()) {
9534                Session s = it.next();
9535                pw.print("  Session "); pw.print(s); pw.println(':');
9536                s.dump(pw, "    ");
9537            }
9538        }
9539    }
9540
9541    void dumpWindowsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
9542            ArrayList<WindowState> windows) {
9543        pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
9544        for (int i=mWindows.size()-1; i>=0; i--) {
9545            WindowState w = mWindows.get(i);
9546            if (windows == null || windows.contains(w)) {
9547                pw.print("  Window #"); pw.print(i); pw.print(' ');
9548                        pw.print(w); pw.println(":");
9549                w.dump(pw, "    ", dumpAll || windows != null);
9550            }
9551        }
9552        if (mInputMethodDialogs.size() > 0) {
9553            pw.println();
9554            pw.println("  Input method dialogs:");
9555            for (int i=mInputMethodDialogs.size()-1; i>=0; i--) {
9556                WindowState w = mInputMethodDialogs.get(i);
9557                if (windows == null || windows.contains(w)) {
9558                    pw.print("  IM Dialog #"); pw.print(i); pw.print(": "); pw.println(w);
9559                }
9560            }
9561        }
9562        if (mPendingRemove.size() > 0) {
9563            pw.println();
9564            pw.println("  Remove pending for:");
9565            for (int i=mPendingRemove.size()-1; i>=0; i--) {
9566                WindowState w = mPendingRemove.get(i);
9567                if (windows == null || windows.contains(w)) {
9568                    pw.print("  Remove #"); pw.print(i); pw.print(' ');
9569                            pw.print(w);
9570                    if (dumpAll) {
9571                        pw.println(":");
9572                        w.dump(pw, "    ", true);
9573                    } else {
9574                        pw.println();
9575                    }
9576                }
9577            }
9578        }
9579        if (mForceRemoves != null && mForceRemoves.size() > 0) {
9580            pw.println();
9581            pw.println("  Windows force removing:");
9582            for (int i=mForceRemoves.size()-1; i>=0; i--) {
9583                WindowState w = mForceRemoves.get(i);
9584                pw.print("  Removing #"); pw.print(i); pw.print(' ');
9585                        pw.print(w);
9586                if (dumpAll) {
9587                    pw.println(":");
9588                    w.dump(pw, "    ", true);
9589                } else {
9590                    pw.println();
9591                }
9592            }
9593        }
9594        if (mDestroySurface.size() > 0) {
9595            pw.println();
9596            pw.println("  Windows waiting to destroy their surface:");
9597            for (int i=mDestroySurface.size()-1; i>=0; i--) {
9598                WindowState w = mDestroySurface.get(i);
9599                if (windows == null || windows.contains(w)) {
9600                    pw.print("  Destroy #"); pw.print(i); pw.print(' ');
9601                            pw.print(w);
9602                    if (dumpAll) {
9603                        pw.println(":");
9604                        w.dump(pw, "    ", true);
9605                    } else {
9606                        pw.println();
9607                    }
9608                }
9609            }
9610        }
9611        if (mLosingFocus.size() > 0) {
9612            pw.println();
9613            pw.println("  Windows losing focus:");
9614            for (int i=mLosingFocus.size()-1; i>=0; i--) {
9615                WindowState w = mLosingFocus.get(i);
9616                if (windows == null || windows.contains(w)) {
9617                    pw.print("  Losing #"); pw.print(i); pw.print(' ');
9618                            pw.print(w);
9619                    if (dumpAll) {
9620                        pw.println(":");
9621                        w.dump(pw, "    ", true);
9622                    } else {
9623                        pw.println();
9624                    }
9625                }
9626            }
9627        }
9628        if (mResizingWindows.size() > 0) {
9629            pw.println();
9630            pw.println("  Windows waiting to resize:");
9631            for (int i=mResizingWindows.size()-1; i>=0; i--) {
9632                WindowState w = mResizingWindows.get(i);
9633                if (windows == null || windows.contains(w)) {
9634                    pw.print("  Resizing #"); pw.print(i); pw.print(' ');
9635                            pw.print(w);
9636                    if (dumpAll) {
9637                        pw.println(":");
9638                        w.dump(pw, "    ", true);
9639                    } else {
9640                        pw.println();
9641                    }
9642                }
9643            }
9644        }
9645        if (mWaitingForDrawn.size() > 0) {
9646            pw.println();
9647            pw.println("  Clients waiting for these windows to be drawn:");
9648            for (int i=mWaitingForDrawn.size()-1; i>=0; i--) {
9649                Pair<WindowState, IRemoteCallback> pair = mWaitingForDrawn.get(i);
9650                pw.print("  Waiting #"); pw.print(i); pw.print(' '); pw.print(pair.first);
9651                        pw.print(": "); pw.println(pair.second);
9652            }
9653        }
9654        pw.println();
9655        if (mDisplay != null) {
9656            pw.print("  Display: init="); pw.print(mInitialDisplayWidth); pw.print("x");
9657                    pw.print(mInitialDisplayHeight); pw.print(" base=");
9658                    pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
9659                    pw.print(" cur=");
9660                    pw.print(mCurDisplayWidth); pw.print("x"); pw.print(mCurDisplayHeight);
9661                    pw.print(" app=");
9662                    pw.print(mAppDisplayWidth); pw.print("x"); pw.print(mAppDisplayHeight);
9663                    pw.print(" raw="); pw.print(mDisplay.getRawWidth());
9664                    pw.print("x"); pw.println(mDisplay.getRawHeight());
9665        } else {
9666            pw.println("  NO DISPLAY");
9667        }
9668        pw.print("  mCurConfiguration="); pw.println(this.mCurConfiguration);
9669        pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
9670        if (mLastFocus != mCurrentFocus) {
9671            pw.print("  mLastFocus="); pw.println(mLastFocus);
9672        }
9673        pw.print("  mFocusedApp="); pw.println(mFocusedApp);
9674        if (mInputMethodTarget != null) {
9675            pw.print("  mInputMethodTarget="); pw.println(mInputMethodTarget);
9676        }
9677        pw.print("  mInTouchMode="); pw.print(mInTouchMode);
9678                pw.print(" mLayoutSeq="); pw.println(mLayoutSeq);
9679        if (dumpAll) {
9680            if (mLastStatusBarVisibility != 0) {
9681                pw.print("  mLastStatusBarVisibility=0x");
9682                        pw.println(Integer.toHexString(mLastStatusBarVisibility));
9683            }
9684            if (mInputMethodWindow != null) {
9685                pw.print("  mInputMethodWindow="); pw.println(mInputMethodWindow);
9686            }
9687            pw.print("  mWallpaperTarget="); pw.println(mWallpaperTarget);
9688            if (mLowerWallpaperTarget != null && mUpperWallpaperTarget != null) {
9689                pw.print("  mLowerWallpaperTarget="); pw.println(mLowerWallpaperTarget);
9690                pw.print("  mUpperWallpaperTarget="); pw.println(mUpperWallpaperTarget);
9691            }
9692            if (mWindowDetachedWallpaper != null) {
9693                pw.print("  mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper);
9694            }
9695            pw.print("  mLastWallpaperX="); pw.print(mLastWallpaperX);
9696                    pw.print(" mLastWallpaperY="); pw.println(mLastWallpaperY);
9697            if (mInputMethodAnimLayerAdjustment != 0 ||
9698                    mWallpaperAnimLayerAdjustment != 0) {
9699                pw.print("  mInputMethodAnimLayerAdjustment=");
9700                        pw.print(mInputMethodAnimLayerAdjustment);
9701                        pw.print("  mWallpaperAnimLayerAdjustment=");
9702                        pw.println(mWallpaperAnimLayerAdjustment);
9703            }
9704            if (mWindowAnimationBackgroundSurface != null) {
9705                pw.println("  mWindowAnimationBackgroundSurface:");
9706                mWindowAnimationBackgroundSurface.printTo("    ", pw);
9707            }
9708            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
9709                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
9710            pw.print("  mLayoutNeeded="); pw.print(mLayoutNeeded);
9711                    pw.print(" mBlurShown="); pw.println(mBlurShown);
9712            if (mDimAnimator != null) {
9713                pw.println("  mDimAnimator:");
9714                mDimAnimator.printTo("    ", pw);
9715            } else {
9716                pw.println( "  no DimAnimator ");
9717            }
9718            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
9719                    pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
9720                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
9721                    pw.print(" mWaitingForConfig="); pw.println(mWaitingForConfig);
9722            pw.print("  mRotation="); pw.print(mRotation);
9723                    pw.print(" mAltOrientation="); pw.println(mAltOrientation);
9724            pw.print("  mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
9725                    pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
9726            pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
9727            pw.print("  mAnimationPending="); pw.print(mAnimationPending);
9728                    pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
9729                    pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
9730            pw.print("  mNextAppTransition=0x");
9731                    pw.print(Integer.toHexString(mNextAppTransition));
9732                    pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
9733            pw.print("  mAppTransitionRunning="); pw.print(mAppTransitionRunning);
9734                    pw.print(" mAppTransitionTimeout="); pw.println( mAppTransitionTimeout);
9735            if (mNextAppTransitionPackage != null) {
9736                pw.print("  mNextAppTransitionPackage=");
9737                    pw.print(mNextAppTransitionPackage);
9738                    pw.print(" mNextAppTransitionEnter=0x");
9739                    pw.print(Integer.toHexString(mNextAppTransitionEnter));
9740                    pw.print(" mNextAppTransitionExit=0x");
9741                    pw.print(Integer.toHexString(mNextAppTransitionExit));
9742            }
9743            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
9744                    pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
9745        }
9746    }
9747
9748    boolean dumpWindows(FileDescriptor fd, PrintWriter pw, String name, String[] args,
9749            int opti, boolean dumpAll) {
9750        ArrayList<WindowState> windows = new ArrayList<WindowState>();
9751        if ("visible".equals(name)) {
9752            synchronized(mWindowMap) {
9753                for (int i=mWindows.size()-1; i>=0; i--) {
9754                    WindowState w = mWindows.get(i);
9755                    if (w.mSurfaceShown) {
9756                        windows.add(w);
9757                    }
9758                }
9759            }
9760        } else {
9761            int objectId = 0;
9762            // See if this is an object ID.
9763            try {
9764                objectId = Integer.parseInt(name, 16);
9765                name = null;
9766            } catch (RuntimeException e) {
9767            }
9768            synchronized(mWindowMap) {
9769                for (int i=mWindows.size()-1; i>=0; i--) {
9770                    WindowState w = mWindows.get(i);
9771                    if (name != null) {
9772                        if (w.mAttrs.getTitle().toString().contains(name)) {
9773                            windows.add(w);
9774                        }
9775                    } else if (System.identityHashCode(w) == objectId) {
9776                        windows.add(w);
9777                    }
9778                }
9779            }
9780        }
9781
9782        if (windows.size() <= 0) {
9783            return false;
9784        }
9785
9786        synchronized(mWindowMap) {
9787            dumpWindowsLocked(fd, pw, dumpAll, windows);
9788        }
9789        return true;
9790    }
9791
9792    @Override
9793    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9794        if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
9795                != PackageManager.PERMISSION_GRANTED) {
9796            pw.println("Permission Denial: can't dump WindowManager from from pid="
9797                    + Binder.getCallingPid()
9798                    + ", uid=" + Binder.getCallingUid());
9799            return;
9800        }
9801
9802        boolean dumpAll = false;
9803
9804        int opti = 0;
9805        while (opti < args.length) {
9806            String opt = args[opti];
9807            if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9808                break;
9809            }
9810            opti++;
9811            if ("-a".equals(opt)) {
9812                dumpAll = true;
9813            } else if ("-h".equals(opt)) {
9814                pw.println("Window manager dump options:");
9815                pw.println("  [-a] [-h] [cmd] ...");
9816                pw.println("  cmd may be one of:");
9817                pw.println("    i[input]: input subsystem state");
9818                pw.println("    p[policy]: policy state");
9819                pw.println("    s[essions]: active sessions");
9820                pw.println("    t[okens]: token list");
9821                pw.println("    w[indows]: window list");
9822                pw.println("  cmd may also be a NAME to dump windows.  NAME may");
9823                pw.println("    be a partial substring in a window name, a");
9824                pw.println("    Window hex object identifier, or");
9825                pw.println("    \"all\" for all windows, or");
9826                pw.println("    \"visible\" for the visible windows.");
9827                pw.println("  -a: include all available server state.");
9828                return;
9829            } else {
9830                pw.println("Unknown argument: " + opt + "; use -h for help");
9831            }
9832        }
9833
9834        // Is the caller requesting to dump a particular piece of data?
9835        if (opti < args.length) {
9836            String cmd = args[opti];
9837            opti++;
9838            if ("input".equals(cmd) || "i".equals(cmd)) {
9839                dumpInput(fd, pw, true);
9840                return;
9841            } else if ("policy".equals(cmd) || "p".equals(cmd)) {
9842                synchronized(mWindowMap) {
9843                    dumpPolicyLocked(fd, pw, args, true);
9844                }
9845                return;
9846            } else if ("sessions".equals(cmd) || "s".equals(cmd)) {
9847                synchronized(mWindowMap) {
9848                    dumpSessionsLocked(fd, pw, true);
9849                }
9850                return;
9851            } else if ("tokens".equals(cmd) || "t".equals(cmd)) {
9852                synchronized(mWindowMap) {
9853                    dumpTokensLocked(fd, pw, true);
9854                }
9855                return;
9856            } else if ("windows".equals(cmd) || "w".equals(cmd)) {
9857                synchronized(mWindowMap) {
9858                    dumpWindowsLocked(fd, pw, true, null);
9859                }
9860                return;
9861            } else if ("all".equals(cmd) || "a".equals(cmd)) {
9862                synchronized(mWindowMap) {
9863                    dumpWindowsLocked(fd, pw, true, null);
9864                }
9865                return;
9866            } else {
9867                // Dumping a single name?
9868                if (!dumpWindows(fd, pw, cmd, args, opti, dumpAll)) {
9869                    pw.println("Bad window command, or no windows match: " + cmd);
9870                    pw.println("Use -h for help.");
9871                }
9872                return;
9873            }
9874        }
9875
9876        dumpInput(fd, pw, dumpAll);
9877
9878        synchronized(mWindowMap) {
9879            if (dumpAll) {
9880                pw.println("-------------------------------------------------------------------------------");
9881            }
9882            dumpPolicyLocked(fd, pw, args, dumpAll);
9883            pw.println();
9884            if (dumpAll) {
9885                pw.println("-------------------------------------------------------------------------------");
9886            }
9887            dumpSessionsLocked(fd, pw, dumpAll);
9888            pw.println();
9889            if (dumpAll) {
9890                pw.println("-------------------------------------------------------------------------------");
9891            }
9892            dumpTokensLocked(fd, pw, dumpAll);
9893            pw.println();
9894            if (dumpAll) {
9895                pw.println("-------------------------------------------------------------------------------");
9896            }
9897            dumpWindowsLocked(fd, pw, dumpAll, null);
9898        }
9899    }
9900
9901    // Called by the heartbeat to ensure locks are not held indefnitely (for deadlock detection).
9902    public void monitor() {
9903        synchronized (mWindowMap) { }
9904        synchronized (mKeyguardTokenWatcher) { }
9905    }
9906
9907    public interface OnHardKeyboardStatusChangeListener {
9908        public void onHardKeyboardStatusChange(boolean available, boolean enabled);
9909    }
9910}
9911