Merge \\"Prevent apps to overlay other apps via toast windows\\" into nyc-mr1-dev am: e2d148b008
am: cd263d56d2

Change-Id: I4971baf5ef2a522f8acea091023936e033f23cea
diff --git a/core/java/android/app/ITransientNotification.aidl b/core/java/android/app/ITransientNotification.aidl
index 35b53a4..d5b3ed0 100644
--- a/core/java/android/app/ITransientNotification.aidl
+++ b/core/java/android/app/ITransientNotification.aidl
@@ -19,7 +19,7 @@
 
 /** @hide */
 oneway interface ITransientNotification {
-    void show();
+    void show(IBinder windowToken);
     void hide();
 }
 
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 7762675..4074166 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -24,7 +24,10 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.PixelFormat;
+import android.os.Binder;
 import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
@@ -326,13 +329,6 @@
     }
 
     private static class TN extends ITransientNotification.Stub {
-        final Runnable mShow = new Runnable() {
-            @Override
-            public void run() {
-                handleShow();
-            }
-        };
-
         final Runnable mHide = new Runnable() {
             @Override
             public void run() {
@@ -343,7 +339,13 @@
         };
 
         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
-        final Handler mHandler = new Handler();
+        final Handler mHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                IBinder token = (IBinder) msg.obj;
+                handleShow(token);
+            }
+        };
 
         int mGravity;
         int mX, mY;
@@ -379,9 +381,9 @@
          * schedule handleShow into the right thread
          */
         @Override
-        public void show() {
+        public void show(IBinder windowToken) {
             if (localLOGV) Log.v(TAG, "SHOW: " + this);
-            mHandler.post(mShow);
+            mHandler.obtainMessage(0, windowToken).sendToTarget();
         }
 
         /**
@@ -393,7 +395,7 @@
             mHandler.post(mHide);
         }
 
-        public void handleShow() {
+        public void handleShow(IBinder windowToken) {
             if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
                     + " mNextView=" + mNextView);
             if (mView != mNextView) {
@@ -424,6 +426,7 @@
                 mParams.packageName = packageName;
                 mParams.removeTimeoutMilliseconds = mDuration ==
                     Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
+                mParams.token = windowToken;
                 if (mView.getParent() != null) {
                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                     mWM.removeView(mView);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4bc12ff..57cf713 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -58,7 +58,6 @@
 import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
 import android.app.PendingIntent;
-import android.app.RemoteInput;
 import android.app.StatusBarManager;
 import android.app.backup.BackupManager;
 import android.app.usage.UsageEvents;
@@ -93,7 +92,6 @@
 import android.os.IInterface;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -122,6 +120,8 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.Xml;
+import android.view.WindowManager;
+import android.view.WindowManagerInternal;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
@@ -232,6 +232,7 @@
     @Nullable StatusBarManagerInternal mStatusBar;
     Vibrator mVibrator;
     private VrManagerInternal mVrManagerInternal;
+    private WindowManagerInternal mWindowManagerInternal;
 
     final IBinder mForegroundToken = new Binder();
     private Handler mHandler;
@@ -452,13 +453,15 @@
         final String pkg;
         final ITransientNotification callback;
         int duration;
+        Binder token;
 
-        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
-        {
+        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
+                    Binder token) {
             this.pid = pid;
             this.pkg = pkg;
             this.callback = callback;
             this.duration = duration;
+            this.token = token;
         }
 
         void update(int duration) {
@@ -1125,6 +1128,7 @@
             mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
             mVrManagerInternal = getLocalService(VrManagerInternal.class);
+            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
             mZenModeHelper.onSystemReady();
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             // This observer will force an update when observe is called, causing us to
@@ -1325,10 +1329,13 @@
                             }
                         }
 
-                        record = new ToastRecord(callingPid, pkg, callback, duration);
+                        Binder token = new Binder();
+                        mWindowManagerInternal.addWindowToken(token,
+                                WindowManager.LayoutParams.TYPE_TOAST);
+                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
                         mToastQueue.add(record);
                         index = mToastQueue.size() - 1;
-                        keepProcessAliveLocked(callingPid);
+                        keepProcessAliveIfNeededLocked(callingPid);
                     }
                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
                     // new or just been updated.  Call back and tell it to show itself.
@@ -2987,7 +2994,7 @@
         while (record != null) {
             if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
             try {
-                record.callback.show();
+                record.callback.show(record.token);
                 scheduleTimeoutLocked(record);
                 return;
             } catch (RemoteException e) {
@@ -2998,7 +3005,7 @@
                 if (index >= 0) {
                     mToastQueue.remove(index);
                 }
-                keepProcessAliveLocked(record.pid);
+                keepProcessAliveIfNeededLocked(record.pid);
                 if (mToastQueue.size() > 0) {
                     record = mToastQueue.get(0);
                 } else {
@@ -3018,8 +3025,11 @@
             // don't worry about this, we're about to remove it from
             // the list anyway
         }
-        mToastQueue.remove(index);
-        keepProcessAliveLocked(record.pid);
+
+        ToastRecord lastToast = mToastQueue.remove(index);
+        mWindowManagerInternal.removeWindowToken(lastToast.token, true);
+
+        keepProcessAliveIfNeededLocked(record.pid);
         if (mToastQueue.size() > 0) {
             // Show the next one. If the callback fails, this will remove
             // it from the list, so don't assume that the list hasn't changed
@@ -3063,7 +3073,7 @@
     }
 
     // lock on mToastQueue
-    void keepProcessAliveLocked(int pid)
+    void keepProcessAliveIfNeededLocked(int pid)
     {
         int toastCount = 0; // toasts from this pid
         ArrayList<ToastRecord> list = mToastQueue;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 409cf1b..b9f1df4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -200,6 +200,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
@@ -1956,6 +1957,11 @@
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+                if (type == TYPE_TOAST) {
+                    Slog.w(TAG_WM, "Attempted to add a toast 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) {
@@ -2005,6 +2011,12 @@
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+            } else if (type == TYPE_TOAST) {
+                if (token.windowType != TYPE_TOAST) {
+                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
+                            + attrs.token + ".  Aborting.");
+                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+                }
             } else if (type == TYPE_QS_DIALOG) {
                 if (token.windowType != TYPE_QS_DIALOG) {
                     Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "