Merge "Wire user info and use user context for text toasts" into rvc-dev
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 08b3293..fb96210 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -43,7 +43,7 @@
 import android.util.Log;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -610,10 +610,10 @@
          */
         TN(Context context, String packageName, Binder token, List<Callback> callbacks,
                 @Nullable Looper looper) {
-            WindowManager windowManager = context.getSystemService(WindowManager.class);
-            AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context);
-            mPresenter = new ToastPresenter(context, windowManager, accessibilityManager,
-                    getService(), packageName);
+            IAccessibilityManager accessibilityManager = IAccessibilityManager.Stub.asInterface(
+                    ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+            mPresenter = new ToastPresenter(context, accessibilityManager, getService(),
+                    packageName);
             mParams = mPresenter.getLayoutParams();
             mPackageName = packageName;
             mToken = token;
diff --git a/core/java/android/widget/ToastPresenter.java b/core/java/android/widget/ToastPresenter.java
index e9d4aa6..2679c69 100644
--- a/core/java/android/widget/ToastPresenter.java
+++ b/core/java/android/widget/ToastPresenter.java
@@ -27,6 +27,7 @@
 import android.graphics.PixelFormat;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -34,8 +35,10 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
 /**
@@ -49,12 +52,14 @@
     private static final long SHORT_DURATION_TIMEOUT = 4000;
     private static final long LONG_DURATION_TIMEOUT = 7000;
 
+    @VisibleForTesting
+    public static final int TEXT_TOAST_LAYOUT = R.layout.transient_notification;
+
     /**
      * Returns the default text toast view for message {@code text}.
      */
     public static View getTextToastView(Context context, CharSequence text) {
-        View view = LayoutInflater.from(context).inflate(
-                R.layout.transient_notification, null);
+        View view = LayoutInflater.from(context).inflate(TEXT_TOAST_LAYOUT, null);
         TextView textView = view.findViewById(com.android.internal.R.id.message);
         textView.setText(text);
         return view;
@@ -70,15 +75,23 @@
     @Nullable private View mView;
     @Nullable private IBinder mToken;
 
-    public ToastPresenter(Context context, WindowManager windowManager,
-            AccessibilityManager accessibilityManager,
+    public ToastPresenter(Context context, IAccessibilityManager accessibilityManager,
             INotificationManager notificationManager, String packageName) {
         mContext = context;
         mResources = context.getResources();
-        mWindowManager = windowManager;
-        mAccessibilityManager = accessibilityManager;
+        mWindowManager = context.getSystemService(WindowManager.class);
         mNotificationManager = notificationManager;
         mPackageName = packageName;
+
+        // We obtain AccessibilityManager manually via its constructor instead of using method
+        // AccessibilityManager.getInstance() for 2 reasons:
+        //   1. We want to be able to inject IAccessibilityManager in tests to verify behavior.
+        //   2. getInstance() caches the instance for the process even if we pass a different
+        //      context to it. This is problematic for multi-user because callers can pass a context
+        //      created via Context.createContextAsUser().
+        mAccessibilityManager = new AccessibilityManager(context, accessibilityManager,
+                UserHandle.getCallingUserId());
+
         mParams = createLayoutParams();
     }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 5b79b18..38f5f32 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -204,8 +204,8 @@
     /**
      * Displays a text toast.
      */
-    void showToast(String packageName, IBinder token, CharSequence text, IBinder windowToken,
-            int duration, @nullable ITransientNotificationCallback callback);
+    void showToast(int uid, String packageName, IBinder token, CharSequence text,
+            IBinder windowToken, int duration, @nullable ITransientNotificationCallback callback);
 
     /**
      * Cancels toast with token {@code token} in {@code packageName}.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 94afde78..2419515 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -322,10 +322,10 @@
         default void suppressAmbientDisplay(boolean suppress) { }
 
         /**
-         * @see IStatusBar#showToast(String, IBinder, CharSequence, IBinder, int,
+         * @see IStatusBar#showToast(int, String, IBinder, CharSequence, IBinder, int,
          * ITransientNotificationCallback)
          */
-        default void showToast(String packageName, IBinder token, CharSequence text,
+        default void showToast(int uid, String packageName, IBinder token, CharSequence text,
                 IBinder windowToken, int duration,
                 @Nullable ITransientNotificationCallback callback) { }
 
@@ -798,7 +798,7 @@
     }
 
     @Override
-    public void showToast(String packageName, IBinder token, CharSequence text,
+    public void showToast(int uid, String packageName, IBinder token, CharSequence text,
             IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
         synchronized (mLock) {
             SomeArgs args = SomeArgs.obtain();
@@ -807,7 +807,8 @@
             args.arg3 = text;
             args.arg4 = windowToken;
             args.arg5 = callback;
-            args.argi1 = duration;
+            args.argi1 = uid;
+            args.argi2 = duration;
             mHandler.obtainMessage(MSG_SHOW_TOAST, args).sendToTarget();
         }
     }
@@ -1276,9 +1277,10 @@
                     IBinder windowToken = (IBinder) args.arg4;
                     ITransientNotificationCallback callback =
                             (ITransientNotificationCallback) args.arg5;
-                    int duration = args.argi1;
+                    int uid = args.argi1;
+                    int duration = args.argi2;
                     for (Callbacks callbacks : mCallbacks) {
-                        callbacks.showToast(packageName, token, text, windowToken, duration,
+                        callbacks.showToast(uid, packageName, token, text, windowToken, duration,
                                 callback);
                     }
                     break;
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index 9ccb9bf..9b465ae 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -24,10 +24,10 @@
 import android.content.res.Resources;
 import android.os.IBinder;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.View;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
 import android.widget.ToastPresenter;
 
 import com.android.internal.R;
@@ -48,9 +48,8 @@
     private static final String TAG = "ToastUI";
 
     private final CommandQueue mCommandQueue;
-    private final WindowManager mWindowManager;
     private final INotificationManager mNotificationManager;
-    private final AccessibilityManager mAccessibilityManager;
+    private final IAccessibilityManager mAccessibilityManager;
     private final int mGravity;
     private final int mY;
     @Nullable private ToastPresenter mPresenter;
@@ -59,18 +58,17 @@
     @Inject
     public ToastUI(Context context, CommandQueue commandQueue) {
         this(context, commandQueue,
-                (WindowManager) context.getSystemService(Context.WINDOW_SERVICE),
                 INotificationManager.Stub.asInterface(
                         ServiceManager.getService(Context.NOTIFICATION_SERVICE)),
-                AccessibilityManager.getInstance(context));
+                IAccessibilityManager.Stub.asInterface(
+                        ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)));
     }
 
     @VisibleForTesting
-    ToastUI(Context context, CommandQueue commandQueue, WindowManager windowManager,
-            INotificationManager notificationManager, AccessibilityManager accessibilityManager) {
+    ToastUI(Context context, CommandQueue commandQueue, INotificationManager notificationManager,
+            @Nullable IAccessibilityManager accessibilityManager) {
         super(context);
         mCommandQueue = commandQueue;
-        mWindowManager = windowManager;
         mNotificationManager = notificationManager;
         mAccessibilityManager = accessibilityManager;
         Resources resources = mContext.getResources();
@@ -85,15 +83,16 @@
 
     @Override
     @MainThread
-    public void showToast(String packageName, IBinder token, CharSequence text,
+    public void showToast(int uid, String packageName, IBinder token, CharSequence text,
             IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
         if (mPresenter != null) {
             hideCurrentToast();
         }
-        View view = ToastPresenter.getTextToastView(mContext, text);
+        Context context = mContext.createContextAsUser(UserHandle.getUserHandleForUid(uid), 0);
+        View view = ToastPresenter.getTextToastView(context, text);
         mCallback = callback;
-        mPresenter = new ToastPresenter(mContext, mWindowManager, mAccessibilityManager,
-                mNotificationManager, packageName);
+        mPresenter = new ToastPresenter(context, mAccessibilityManager, mNotificationManager,
+                packageName);
         mPresenter.show(view, token, windowToken, duration, mGravity, 0, mY, 0, 0, mCallback);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index 65fbe79..0a10ab2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -16,29 +16,43 @@
 
 package com.android.systemui.toast;
 
+import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
+import static android.widget.ToastPresenter.TEXT_TOAST_LAYOUT;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.INotificationManager;
 import android.app.ITransientNotificationCallback;
+import android.content.Context;
 import android.os.Binder;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.testing.AndroidTestingRunner;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
 import android.widget.FrameLayout;
 import android.widget.TextView;
 import android.widget.Toast;
+import android.widget.ToastPresenter;
 
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.R;
+import com.android.internal.util.IntPair;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.CommandQueue;
 
@@ -49,32 +63,53 @@
 import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 public class ToastUITest extends SysuiTestCase {
+    private static final int ANDROID_UID = 1000;
+    private static final int SYSTEMUI_UID = 10140;
+
+    private static final int UID_1 = 10255;
     private static final String PACKAGE_NAME_1 = "com.example1.test";
     private static final Binder TOKEN_1 = new Binder();
     private static final Binder WINDOW_TOKEN_1 = new Binder();
+
+    private static final int UID_2 = 10256;
     private static final String PACKAGE_NAME_2 = "com.example2.test";
     private static final Binder TOKEN_2 = new Binder();
     private static final Binder WINDOW_TOKEN_2 = new Binder();
+
     private static final String TEXT = "Hello World";
     private static final int MESSAGE_RES_ID = R.id.message;
 
+    private Context mContextSpy;
+    private ToastUI mToastUI;
+    @Mock private LayoutInflater mLayoutInflater;
     @Mock private CommandQueue mCommandQueue;
     @Mock private WindowManager mWindowManager;
     @Mock private INotificationManager mNotificationManager;
-    @Mock private AccessibilityManager mAccessibilityManager;
+    @Mock private IAccessibilityManager mAccessibilityManager;
     @Mock private ITransientNotificationCallback mCallback;
     @Captor private ArgumentCaptor<View> mViewCaptor;
     @Captor private ArgumentCaptor<ViewGroup.LayoutParams> mParamsCaptor;
-    private ToastUI mToastUI;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mToastUI = new ToastUI(mContext, mCommandQueue, mWindowManager, mNotificationManager,
+
+        // This is because inflate will result in WindowManager (WM) calls, which will fail since we
+        // are mocking it, so we mock LayoutInflater with the view obtained before mocking WM.
+        View view = ToastPresenter.getTextToastView(mContext, TEXT);
+        when(mLayoutInflater.inflate(eq(TEXT_TOAST_LAYOUT), any())).thenReturn(view);
+        mContext.addMockSystemService(LayoutInflater.class, mLayoutInflater);
+
+        mContext.addMockSystemService(WindowManager.class, mWindowManager);
+        mContextSpy = spy(mContext);
+        doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
+
+        mToastUI = new ToastUI(mContextSpy, mCommandQueue, mNotificationManager,
                 mAccessibilityManager);
     }
 
@@ -87,7 +122,8 @@
 
     @Test
     public void testShowToast_addsCorrectViewToWindowManager() throws Exception {
-        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);
+        mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+                null);
 
         verify(mWindowManager).addView(mViewCaptor.capture(), any());
         View view = mViewCaptor.getValue();
@@ -96,13 +132,14 @@
 
     @Test
     public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() throws Exception {
-        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);
+        mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+                null);
 
         verify(mWindowManager).addView(any(), mParamsCaptor.capture());
         ViewGroup.LayoutParams params = mParamsCaptor.getValue();
         assertThat(params).isInstanceOf(WindowManager.LayoutParams.class);
         WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
-        assertThat(windowParams.packageName).isEqualTo(mContext.getPackageName());
+        assertThat(windowParams.packageName).isEqualTo(mContextSpy.getPackageName());
         assertThat(windowParams.getTitle()).isEqualTo("Toast");
         assertThat(windowParams.token).isEqualTo(WINDOW_TOKEN_1);
         assertThat(windowParams.privateFlags
@@ -111,19 +148,7 @@
 
     @Test
     public void testShowToast_forAndroidPackage_addsAllUserFlag() throws Exception {
-        mToastUI.showToast("android", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);
-
-        verify(mWindowManager).addView(any(), mParamsCaptor.capture());
-        ViewGroup.LayoutParams params = mParamsCaptor.getValue();
-        assertThat(params).isInstanceOf(WindowManager.LayoutParams.class);
-        WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
-        assertThat(windowParams.privateFlags
-                & WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS).isNotEqualTo(0);
-    }
-
-    @Test
-    public void testShowToast_forSystemUiPackage_addsAllUserFlag() throws Exception {
-        mToastUI.showToast("com.android.systemui", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+        mToastUI.showToast(ANDROID_UID, "android", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                 null);
 
         verify(mWindowManager).addView(any(), mParamsCaptor.capture());
@@ -135,8 +160,21 @@
     }
 
     @Test
+    public void testShowToast_forSystemUiPackage_addsAllUserFlag() throws Exception {
+        mToastUI.showToast(SYSTEMUI_UID, "com.android.systemui", TOKEN_1, TEXT, WINDOW_TOKEN_1,
+                Toast.LENGTH_LONG, null);
+
+        verify(mWindowManager).addView(any(), mParamsCaptor.capture());
+        ViewGroup.LayoutParams params = mParamsCaptor.getValue();
+        assertThat(params).isInstanceOf(WindowManager.LayoutParams.class);
+        WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
+        assertThat(windowParams.privateFlags
+                & WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS).isNotEqualTo(0);
+    }
+
+    @Test
     public void testShowToast_callsCallback() throws Exception {
-        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+        mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                 mCallback);
 
         verify(mCallback).onToastShown();
@@ -144,14 +182,24 @@
 
     @Test
     public void testShowToast_sendsAccessibilityEvent() throws Exception {
-        when(mAccessibilityManager.isEnabled()).thenReturn(true);
+        // Enable accessibility
+        when(mAccessibilityManager.addClient(any(), anyInt())).thenReturn(
+                IntPair.of(STATE_FLAG_ACCESSIBILITY_ENABLED, AccessibilityEvent.TYPES_ALL_MASK));
+        // AccessibilityManager recycles the event that goes over the wire after making the binder
+        // call to the service. Since we are mocking the service, that call is local, so if we use
+        // ArgumentCaptor or ArgumentMatcher it will retain a reference to the recycled event, which
+        // will already have its state reset by the time we verify its contents. So, instead, we
+        // serialize it at call-time and later on deserialize it to verity its contents.
+        Parcel eventParcel = Parcel.obtain();
+        doAnswer(writeArgumentToParcel(0, eventParcel)).when(
+                mAccessibilityManager).sendAccessibilityEvent(any(), anyInt());
 
-        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);
+        mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+                null);
 
-        ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(
-                AccessibilityEvent.class);
-        verify(mAccessibilityManager).sendAccessibilityEvent(eventCaptor.capture());
-        AccessibilityEvent event = eventCaptor.getValue();
+        eventParcel.setDataPosition(0);
+        assertThat(eventParcel.dataSize()).isGreaterThan(0);
+        AccessibilityEvent event = AccessibilityEvent.CREATOR.createFromParcel(eventParcel);
         assertThat(event.getEventType()).isEqualTo(
                 AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
         assertThat(event.getClassName()).isEqualTo(Toast.class.getName());
@@ -160,7 +208,7 @@
 
     @Test
     public void testHideToast_removesView() throws Exception {
-        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+        mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                 mCallback);
         View view = verifyWmAddViewAndAttachToParent();
 
@@ -171,7 +219,7 @@
 
     @Test
     public void testHideToast_finishesToken() throws Exception {
-        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+        mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                 mCallback);
 
         mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
@@ -181,7 +229,7 @@
 
     @Test
     public void testHideToast_callsCallback() throws Exception {
-        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+        mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                 mCallback);
 
         mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
@@ -191,7 +239,7 @@
 
     @Test
     public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws Exception {
-        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+        mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                 mCallback);
 
         mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_2);
@@ -201,7 +249,7 @@
 
     @Test
     public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws Exception {
-        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+        mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                 mCallback);
 
         mToastUI.hideToast(PACKAGE_NAME_2, TOKEN_1);
@@ -211,11 +259,12 @@
 
     @Test
     public void testShowToast_afterShowToast_hidesCurrentToast() throws Exception {
-        mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+        mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
                 mCallback);
         View view = verifyWmAddViewAndAttachToParent();
 
-        mToastUI.showToast(PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG, null);
+        mToastUI.showToast(UID_2, PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG,
+                null);
 
         verify(mWindowManager).removeViewImmediate(view);
         verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1);
@@ -227,8 +276,15 @@
         verify(mWindowManager).addView(viewCaptor.capture(), any());
         View view = viewCaptor.getValue();
         // Simulate attaching to view hierarchy
-        ViewGroup parent = new FrameLayout(mContext);
+        ViewGroup parent = new FrameLayout(mContextSpy);
         parent.addView(view);
         return view;
     }
+
+    private Answer<Void> writeArgumentToParcel(int i, Parcel dest) {
+        return inv -> {
+            inv.<Parcelable>getArgument(i).writeToParcel(dest, 0);
+            return null;
+        };
+    }
 }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ed3b9f1..776db63 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2745,15 +2745,15 @@
         return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
     }
 
-    private ToastRecord getToastRecord(int pid, String packageName, IBinder token,
+    private ToastRecord getToastRecord(int uid, int pid, String packageName, IBinder token,
             @Nullable CharSequence text, @Nullable ITransientNotification callback, int duration,
             Binder windowToken, int displayId,
             @Nullable ITransientNotificationCallback textCallback) {
         if (callback == null) {
-            return new TextToastRecord(this, mStatusBar, pid, packageName, token, text, duration,
-                    windowToken, displayId, textCallback);
+            return new TextToastRecord(this, mStatusBar, uid, pid, packageName, token, text,
+                    duration, windowToken, displayId, textCallback);
         } else {
-            return new CustomToastRecord(this, pid, packageName, token, callback, duration,
+            return new CustomToastRecord(this, uid, pid, packageName, token, callback, duration,
                     windowToken, displayId);
         }
     }
@@ -2878,8 +2878,8 @@
 
                         Binder windowToken = new Binder();
                         mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId);
-                        record = getToastRecord(callingPid, pkg, token, text, callback, duration,
-                                windowToken, displayId, textCallback);
+                        record = getToastRecord(callingUid, callingPid, pkg, token, text, callback,
+                                duration, windowToken, displayId, textCallback);
                         mToastQueue.add(record);
                         index = mToastQueue.size() - 1;
                         keepProcessAliveForToastIfNeededLocked(callingPid);
diff --git a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java
index aca6f48..2b91a00 100644
--- a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java
+++ b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java
@@ -23,6 +23,7 @@
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.Slog;
 
 import com.android.server.notification.NotificationManagerService;
@@ -35,11 +36,10 @@
 
     public final ITransientNotification callback;
 
-    public CustomToastRecord(
-            NotificationManagerService notificationManager, int pid, String packageName,
-            IBinder token, ITransientNotification callback, int duration, Binder windowToken,
-            int displayId) {
-        super(notificationManager, pid, packageName, token, duration, windowToken, displayId);
+    public CustomToastRecord(NotificationManagerService notificationManager, int uid, int pid,
+            String packageName, IBinder token, ITransientNotification callback, int duration,
+            Binder windowToken, int displayId) {
+        super(notificationManager, uid, pid, packageName, token, duration, windowToken, displayId);
         this.callback = checkNotNull(callback);
     }
 
@@ -74,8 +74,8 @@
     public String toString() {
         return "CustomToastRecord{"
                 + Integer.toHexString(System.identityHashCode(this))
+                + " " + pid + ":" +  pkg + "/" + UserHandle.formatUid(uid)
                 + " token=" + token
-                + " packageName=" + pkg
                 + " callback=" + callback
                 + " duration=" + getDuration()
                 + "}";
diff --git a/services/core/java/com/android/server/notification/toast/TextToastRecord.java b/services/core/java/com/android/server/notification/toast/TextToastRecord.java
index 3c231b4..544520e 100644
--- a/services/core/java/com/android/server/notification/toast/TextToastRecord.java
+++ b/services/core/java/com/android/server/notification/toast/TextToastRecord.java
@@ -23,6 +23,7 @@
 import android.app.ITransientNotificationCallback;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.UserHandle;
 import android.util.Slog;
 
 import com.android.server.notification.NotificationManagerService;
@@ -41,10 +42,10 @@
     private final ITransientNotificationCallback mCallback;
 
     public TextToastRecord(NotificationManagerService notificationManager,
-            @Nullable StatusBarManagerInternal statusBarManager, int pid, String packageName,
-            IBinder token, CharSequence text, int duration, Binder windowToken, int displayId,
-            @Nullable ITransientNotificationCallback callback) {
-        super(notificationManager, pid, packageName, token, duration, windowToken, displayId);
+            @Nullable StatusBarManagerInternal statusBarManager, int uid, int pid,
+            String packageName, IBinder token, CharSequence text, int duration, Binder windowToken,
+            int displayId, @Nullable ITransientNotificationCallback callback) {
+        super(notificationManager, uid, pid, packageName, token, duration, windowToken, displayId);
         mStatusBar = statusBarManager;
         mCallback = callback;
         this.text = checkNotNull(text);
@@ -59,7 +60,7 @@
             Slog.w(TAG, "StatusBar not available to show text toast for package " + pkg);
             return false;
         }
-        mStatusBar.showToast(pkg, token, text, windowToken, getDuration(), mCallback);
+        mStatusBar.showToast(uid, pkg, token, text, windowToken, getDuration(), mCallback);
         return true;
     }
 
@@ -75,8 +76,8 @@
     public String toString() {
         return "TextToastRecord{"
                 + Integer.toHexString(System.identityHashCode(this))
+                + " " + pid + ":" +  pkg + "/" + UserHandle.formatUid(uid)
                 + " token=" + token
-                + " packageName=" + pkg
                 + " text=" + text
                 + " duration=" + getDuration()
                 + "}";
diff --git a/services/core/java/com/android/server/notification/toast/ToastRecord.java b/services/core/java/com/android/server/notification/toast/ToastRecord.java
index ef75a6f..7915f70 100644
--- a/services/core/java/com/android/server/notification/toast/ToastRecord.java
+++ b/services/core/java/com/android/server/notification/toast/ToastRecord.java
@@ -28,6 +28,7 @@
  * Represents a toast, a transient notification.
  */
 public abstract class ToastRecord {
+    public final int uid;
     public final int pid;
     public final String pkg;
     public final IBinder token;
@@ -36,11 +37,10 @@
     protected final NotificationManagerService mNotificationManager;
     private int mDuration;
 
-    protected ToastRecord(
-            NotificationManagerService notificationManager,
-            int pid, String pkg, IBinder token, int duration,
-            Binder windowToken, int displayId) {
+    protected ToastRecord(NotificationManagerService notificationManager, int uid, int pid,
+            String pkg, IBinder token, int duration, Binder windowToken, int displayId) {
         this.mNotificationManager = notificationManager;
+        this.uid = uid;
         this.pid = pid;
         this.pkg = pkg;
         this.token = token;
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index d88dccb..26497d8 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -131,7 +131,7 @@
      * @see com.android.internal.statusbar.IStatusBar#showToast(String, IBinder, CharSequence,
      * IBinder, int, ITransientNotificationCallback)
      */
-    void showToast(String packageName, IBinder token, CharSequence text,
+    void showToast(int uid, String packageName, IBinder token, CharSequence text,
             IBinder windowToken, int duration,
             @Nullable ITransientNotificationCallback textCallback);
 
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 78ef68c..d7a0c987 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -502,12 +502,12 @@
         }
 
         @Override
-        public void showToast(String packageName, IBinder token, CharSequence text,
+        public void showToast(int uid, String packageName, IBinder token, CharSequence text,
                 IBinder windowToken, int duration,
                 @Nullable ITransientNotificationCallback callback) {
             if (mBar != null) {
                 try {
-                    mBar.showToast(packageName, token, text, windowToken, duration, callback);
+                    mBar.showToast(uid, packageName, token, text, windowToken, duration, callback);
                 } catch (RemoteException ex) { }
             }
         }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index f9596b5..15220e1 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4791,7 +4791,7 @@
         // enqueue toast -> no toasts enqueued
         ((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(),
                 "Text", 2000, 0, null);
-        verify(mStatusBar).showToast(any(), any(), any(), any(), anyInt(), any());
+        verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
     }
 
     @Test