Merge "APIs for an accessibility service to put interaction tracking overlays." into lmp-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index f14daa7..20cf89c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -34967,6 +34967,7 @@
     field public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0; // 0x0
     field public static final int SOFT_INPUT_STATE_VISIBLE = 4; // 0x4
     field public static final int TITLE_CHANGED = 64; // 0x40
+    field public static final int TYPE_ACCESSIBILITY_OVERLAY = 2032; // 0x7f0
     field public static final int TYPE_APPLICATION = 2; // 0x2
     field public static final int TYPE_APPLICATION_ATTACHED_DIALOG = 1003; // 0x3eb
     field public static final int TYPE_APPLICATION_MEDIA = 1001; // 0x3e9
@@ -35386,6 +35387,7 @@
     method public void recycle();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
+    field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4
     field public static final int TYPE_APPLICATION = 1; // 0x1
     field public static final int TYPE_INPUT_METHOD = 2; // 0x2
     field public static final int TYPE_SYSTEM = 3; // 0x3
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 13ceb4a..1e1b33f 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -24,13 +24,18 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.Display;
 import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityWindowInfo;
 
 import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.SomeArgs;
 
 import java.util.List;
 
@@ -366,7 +371,7 @@
         public void onAccessibilityEvent(AccessibilityEvent event);
         public void onInterrupt();
         public void onServiceConnected();
-        public void onSetConnectionId(int connectionId);
+        public void init(int connectionId, IBinder windowToken);
         public boolean onGesture(int gestureId);
         public boolean onKeyEvent(KeyEvent event);
     }
@@ -375,6 +380,10 @@
 
     private AccessibilityServiceInfo mInfo;
 
+    private IBinder mWindowToken;
+
+    private WindowManager mWindowManager;
+
     /**
      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
      *
@@ -611,6 +620,18 @@
         }
     }
 
+    @Override
+    public Object getSystemService(String name) {
+        if (Context.WINDOW_SERVICE.equals(name)) {
+            if (mWindowManager == null) {
+                WindowManager wrapped = (WindowManager) super.getSystemService(name);
+                mWindowManager = new LocalWindowManager(wrapped);
+            }
+            return mWindowManager;
+        }
+        return super.getSystemService(name);
+    }
+
     /**
      * Implement to return the implementation of the internal accessibility
      * service interface.
@@ -634,8 +655,9 @@
             }
 
             @Override
-            public void onSetConnectionId( int connectionId) {
+            public void init(int connectionId, IBinder windowToken) {
                 mConnectionId = connectionId;
+                mWindowToken = windowToken;
             }
 
             @Override
@@ -658,7 +680,7 @@
      */
     public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub
             implements HandlerCaller.Callback {
-        private static final int DO_SET_SET_CONNECTION = 1;
+        private static final int DO_INIT = 1;
         private static final int DO_ON_INTERRUPT = 2;
         private static final int DO_ON_ACCESSIBILITY_EVENT = 3;
         private static final int DO_ON_GESTURE = 4;
@@ -677,9 +699,10 @@
             mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/);
         }
 
-        public void setConnection(IAccessibilityServiceConnection connection, int connectionId) {
-            Message message = mCaller.obtainMessageIO(DO_SET_SET_CONNECTION, connectionId,
-                    connection);
+        public void init(IAccessibilityServiceConnection connection, int connectionId,
+                IBinder windowToken) {
+            Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId,
+                    connection, windowToken);
             mCaller.sendMessage(message);
         }
 
@@ -730,20 +753,24 @@
                     mCallback.onInterrupt();
                 } return;
 
-                case DO_SET_SET_CONNECTION: {
+                case DO_INIT: {
                     mConnectionId = message.arg1;
+                    SomeArgs args = (SomeArgs) message.obj;
                     IAccessibilityServiceConnection connection =
-                        (IAccessibilityServiceConnection) message.obj;
+                            (IAccessibilityServiceConnection) args.arg1;
+                    IBinder windowToken = (IBinder) args.arg2;
+                    args.recycle();
                     if (connection != null) {
                         AccessibilityInteractionClient.getInstance().addConnection(mConnectionId,
                                 connection);
-                        mCallback.onSetConnectionId(mConnectionId);
+                        mCallback.init(mConnectionId, windowToken);
                         mCallback.onServiceConnected();
                     } else {
                         AccessibilityInteractionClient.getInstance().removeConnection(
                                 mConnectionId);
+                        mConnectionId = AccessibilityInteractionClient.NO_ID;
                         AccessibilityInteractionClient.getInstance().clearCache();
-                        mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID);
+                        mCallback.init(AccessibilityInteractionClient.NO_ID, null);
                     }
                 } return;
 
@@ -785,4 +812,53 @@
             }
         }
     }
+
+    private class LocalWindowManager implements WindowManager {
+        private final WindowManager mImpl;
+
+        private LocalWindowManager(WindowManager impl) {
+            mImpl = impl;
+        }
+
+        @Override
+        public Display getDefaultDisplay() {
+            return mImpl.getDefaultDisplay();
+        }
+
+        @Override
+        public void addView(View view, ViewGroup.LayoutParams params) {
+            if (!(params instanceof WindowManager.LayoutParams)) {
+                throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
+            }
+            WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
+            if (windowParams.type == LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
+                    && windowParams.token == null) {
+                windowParams.token = mWindowToken;
+            }
+            mImpl.addView(view, params);
+        }
+
+        @Override
+        public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
+            if (!(params instanceof WindowManager.LayoutParams)) {
+                throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
+            }
+            WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
+            if (windowParams.type == LayoutParams.TYPE_ACCESSIBILITY_OVERLAY
+                    && windowParams.token == null) {
+                windowParams.token = mWindowToken;
+            }
+            mImpl.updateViewLayout(view, params);
+        }
+
+        @Override
+        public void removeViewImmediate(View view) {
+            mImpl.removeViewImmediate(view);
+        }
+
+        @Override
+        public void removeView(View view) {
+            mImpl.removeView(view);
+        }
+    }
 }
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 6ce0219..8b503dd 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -28,7 +28,7 @@
  */
  oneway interface IAccessibilityServiceClient {
 
-    void setConnection(in IAccessibilityServiceConnection connection, int connectionId);
+    void init(in IAccessibilityServiceConnection connection, int connectionId, IBinder windowToken);
 
     void onAccessibilityEvent(in AccessibilityEvent event);
 
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 4aec9e0..b0dd70f 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -25,6 +25,7 @@
 import android.graphics.Canvas;
 import android.graphics.Point;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -919,7 +920,7 @@
         public IAccessibilityServiceClientImpl(Looper looper) {
             super(null, looper, new Callbacks() {
                 @Override
-                public void onSetConnectionId(int connectionId) {
+                public void init(int connectionId, IBinder windowToken) {
                     synchronized (mLock) {
                         mConnectionId = connectionId;
                         mLock.notifyAll();
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 3f84c9b..5b48c0d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -542,6 +542,19 @@
         public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
 
         /**
+         * Window type: Windows that are overlaid <em>only</em> by an {@link
+         * android.accessibilityservice.AccessibilityService} for interception of
+         * user interactions without changing the windows an accessibility service
+         * can introspect. In particular, an accessibility service can introspect
+         * only windows that a sighted user can interact with which is they can touch
+         * these windows or can type into these windows. For example, if there
+         * is a full screen accessibility overlay that is touchable, the windows
+         * below it will be introspectable by an accessibility service regardless
+         * they are covered by a touchable window.
+         */
+        public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 38e3723..f557b97 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -173,4 +173,20 @@
      * redrawn.
      */
     public abstract void waitForAllWindowsDrawn(Runnable callback, long timeout);
+
+    /**
+     * Adds a window token for a given window type.
+     *
+     * @param token The token to add.
+     * @param type The window type.
+     */
+    public abstract void addWindowToken(android.os.IBinder token, int type);
+
+    /**
+     * Removes a window token.
+     *
+     * @param token The toke to remove.
+     * @param removeWindows Whether to also remove the windows associated with the token.
+     */
+    public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows);
 }
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index ad55f5f..e1942be 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -51,11 +51,24 @@
      */
     public static final int TYPE_SYSTEM = 3;
 
+    /**
+     * Window type: Windows that are overlaid <em>only</em> by an {@link
+     * android.accessibilityservice.AccessibilityService} for interception of
+     * user interactions without changing the windows an accessibility service
+     * can introspect. In particular, an accessibility service can introspect
+     * only windows that a sighted user can interact with which they can touch
+     * these windows or can type into these windows. For example, if there
+     * is a full screen accessibility overlay that is touchable, the windows
+     * below it will be introspectable by an accessibility service regardless
+     * they are covered by a touchable window.
+     */
+    public static final int TYPE_ACCESSIBILITY_OVERLAY = 4;
+
     private static final int UNDEFINED = -1;
 
     private static final int BOOLEAN_PROPERTY_ACTIVE = 1 << 0;
     private static final int BOOLEAN_PROPERTY_FOCUSED = 1 << 1;
-    private static final int BOOLEAN_PROPERTY_ACCESSIBLITY_FOCUSED = 1 << 2;
+    private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 1 << 2;
 
     // Housekeeping.
     private static final int MAX_POOL_SIZE = 10;
@@ -85,6 +98,7 @@
      * @see #TYPE_APPLICATION
      * @see #TYPE_INPUT_METHOD
      * @see #TYPE_SYSTEM
+     * @see #TYPE_ACCESSIBILITY_OVERLAY
      */
     public int getType() {
         return mType;
@@ -93,7 +107,7 @@
     /**
      * Sets the type of the window.
      *
-     * @param The type
+     * @param type The type
      *
      * @hide
      */
@@ -115,7 +129,7 @@
      * Sets the layer which determines the Z-order of the window. Windows
      * with greater layer appear on top of windows with lesser layer.
      *
-     * @param The window layer.
+     * @param layer The window layer.
      *
      * @hide
      */
@@ -174,7 +188,7 @@
     /**
      * Sets the unique window id.
      *
-     * @param windowId The window id.
+     * @param id The window id.
      *
      * @hide
      */
@@ -230,7 +244,7 @@
      * the user is currently touching or the window has input focus
      * and the user is not touching any window.
      *
-     * @param Whether this is the active window.
+     * @param active Whether this is the active window.
      *
      * @hide
      */
@@ -250,7 +264,7 @@
     /**
      * Sets if this window has input focus.
      *
-     * @param Whether has input focus.
+     * @param focused Whether has input focus.
      *
      * @hide
      */
@@ -264,18 +278,18 @@
      * @return Whether has accessibility focus.
      */
     public boolean isAccessibilityFocused() {
-        return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBLITY_FOCUSED);
+        return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED);
     }
 
     /**
      * Sets if this window has accessibility focus.
      *
-     * @param Whether has accessibility focus.
+     * @param focused Whether has accessibility focus.
      *
      * @hide
      */
     public void setAccessibilityFocused(boolean focused) {
-        setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBLITY_FOCUSED, focused);
+        setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused);
     }
 
     /**
@@ -534,6 +548,9 @@
             case TYPE_SYSTEM: {
                 return "TYPE_SYSTEM";
             }
+            case TYPE_ACCESSIBILITY_OVERLAY: {
+                return "TYPE_ACCESSIBILITY_OVERLAY";
+            }
             default:
                 return "<UNKNOWN>";
         }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index e184577..558cf56 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1431,6 +1431,7 @@
             case TYPE_WALLPAPER:
             case TYPE_PRIVATE_PRESENTATION:
             case TYPE_VOICE_INTERACTION:
+            case TYPE_ACCESSIBILITY_OVERLAY:
                 // The window manager will check these.
                 break;
             case TYPE_PHONE:
@@ -1660,15 +1661,18 @@
             // the drag layer: input for drag-and-drop is associated with this window,
             // which sits above all other focusable windows
             return 25;
-        case TYPE_SECURE_SYSTEM_OVERLAY:
+        case TYPE_ACCESSIBILITY_OVERLAY:
+            // overlay put by accessibility services to intercept user interaction
             return 26;
-        case TYPE_BOOT_PROGRESS:
+        case TYPE_SECURE_SYSTEM_OVERLAY:
             return 27;
+        case TYPE_BOOT_PROGRESS:
+            return 28;
         case TYPE_POINTER:
             // the (mouse) pointer layer
-            return 28;
-        case TYPE_HIDDEN_NAV_CONSUMER:
             return 29;
+        case TYPE_HIDDEN_NAV_CONSUMER:
+            return 30;
         }
         Log.e(TAG, "Unknown window type: " + type);
         return 2;
@@ -1972,7 +1976,6 @@
                 }
                 mKeyguardScrim = win;
                 break;
-
         }
         return WindowManagerGlobal.ADD_OKAY;
     }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index e1a74d1..2781890 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1040,7 +1040,7 @@
 
     private void addServiceLocked(Service service, UserState userState) {
         try {
-            service.linkToOwnDeathLocked();
+            service.onAdded();
             userState.mBoundServices.add(service);
             userState.mComponentNameToServiceMap.put(service.mComponentName, service);
         } catch (RemoteException re) {
@@ -1056,7 +1056,7 @@
     private void removeServiceLocked(Service service, UserState userState) {
         userState.mBoundServices.remove(service);
         userState.mComponentNameToServiceMap.remove(service.mComponentName);
-        service.unlinkToOwnDeathLocked();
+        service.onRemoved();
     }
 
     /**
@@ -1931,6 +1931,8 @@
 
         final ResolveInfo mResolveInfo;
 
+        final IBinder mOverlayWindowToken = new Binder();
+
         // the events pending events to be dispatched to this service
         final SparseArray<AccessibilityEvent> mPendingEvents =
             new SparseArray<>();
@@ -2112,7 +2114,7 @@
                     userState.mBindingServices.remove(mComponentName);
                     mWasConnectedAndDied = false;
                     try {
-                       mServiceInterface.setConnection(this, mId);
+                       mServiceInterface.init(this, mId, mOverlayWindowToken);
                        onUserStateChangedLocked(userState);
                     } catch (RemoteException re) {
                         Slog.w(LOG_TAG, "Error while setting connection for service: "
@@ -2602,6 +2604,27 @@
             /* do nothing - #binderDied takes care */
         }
 
+        public void onAdded() throws RemoteException {
+            linkToOwnDeathLocked();
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mWindowManagerService.addWindowToken(mOverlayWindowToken,
+                        WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        public void onRemoved() {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                mWindowManagerService.removeWindowToken(mOverlayWindowToken, true);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+            unlinkToOwnDeathLocked();
+        }
+
         public void linkToOwnDeathLocked() throws RemoteException {
             mService.linkToDeath(this, 0);
         }
@@ -2614,7 +2637,7 @@
             try {
                 // Clear the proxy in the other process so this
                 // IAccessibilityServiceConnection can be garbage collected.
-                mServiceInterface.setConnection(null, mId);
+                mServiceInterface.init(null, mId, null);
             } catch (RemoteException re) {
                 /* ignore */
             }
@@ -3164,6 +3187,10 @@
                     return AccessibilityWindowInfo.TYPE_SYSTEM;
                 }
 
+                case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY: {
+                    return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
+                }
+
                 default: {
                     return -1;
                 }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index fde703d..f947b6a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -992,8 +992,7 @@
 
                     final int flags = windowState.mAttrs.flags;
 
-                    // If the window is not touchable, do not report it but take into account
-                    // the space it takes since the content behind it cannot be touched.
+                    // If the window is not touchable - ignore.
                     if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
                         continue;
                     }
@@ -1014,9 +1013,14 @@
                         }
                     }
 
-                    // Account for the space this window takes.
-                    unaccountedSpace.op(boundsInScreen, unaccountedSpace,
-                            Region.Op.REVERSE_DIFFERENCE);
+                    // Account for the space this window takes if the window
+                    // is not an accessibility overlay which does not change
+                    // the reported windows.
+                    if (windowState.mAttrs.type == WindowManager.LayoutParams
+                            .TYPE_ACCESSIBILITY_OVERLAY) {
+                        unaccountedSpace.op(boundsInScreen, unaccountedSpace,
+                                Region.Op.REVERSE_DIFFERENCE);
+                    }
 
                     // We figured out what is touchable for the entire screen - done.
                     if (unaccountedSpace.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 57d793f..3fee608 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2337,6 +2337,11 @@
                           + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+                if (type == TYPE_ACCESSIBILITY_OVERLAY) {
+                    Slog.w(TAG, "Attempted to add Accessibility overlay window with unknown token "
+                            + attrs.token + ".  Aborting.");
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                }
                 token = new WindowToken(this, attrs.token, -1, false);
                 addToken = true;
             } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
@@ -2380,6 +2385,12 @@
                             + attrs.token + ".  Aborting.");
                       return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+            } else if (type == TYPE_ACCESSIBILITY_OVERLAY) {
+                if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
+                    Slog.w(TAG, "Attempted to add Accessibility overlay window with bad token "
+                            + attrs.token + ".  Aborting.");
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                }
             } else if (token.appWindowToken != null) {
                 Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type);
                 // It is not valid to use an app token with other system types; we will
@@ -11627,5 +11638,23 @@
                 checkDrawnWindowsLocked();
             }
         }
+
+        @Override
+        public void addWindowToken(IBinder token, int type) {
+            WindowManagerService.this.addWindowToken(token, type);
+        }
+
+        @Override
+        public void removeWindowToken(IBinder token, boolean removeWindows) {
+            synchronized(mWindowMap) {
+                if (removeWindows) {
+                    WindowToken wtoken = mTokenMap.remove(token);
+                    if (wtoken != null) {
+                        wtoken.removeAllWindows();
+                    }
+                }
+                WindowManagerService.this.removeWindowToken(token);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 2267123..1a672e68 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import android.os.IBinder;
+import android.util.Slog;
 
 import java.io.PrintWriter;
 
@@ -29,7 +30,7 @@
 class WindowToken {
     // The window manager!
     final WindowManagerService service;
-    
+
     // The actual token.
     final IBinder token;
 
@@ -77,6 +78,15 @@
         explicit = _explicit;
     }
 
+    void removeAllWindows() {
+        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+            WindowState win = windows.get(winNdx);
+            if (WindowManagerService.DEBUG_WINDOW_MOVEMENT) Slog.w(WindowManagerService.TAG,
+                    "removeAllWindows: removing win=" + win);
+            win.mService.removeWindowLocked(win.mSession, win);
+        }
+    }
+
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("windows="); pw.println(windows);
         pw.print(prefix); pw.print("windowType="); pw.print(windowType);