Resolve message/conversation image Uris with the correct user id
Bug: 317503801
Test: atest ExpandableNotificationRowTest
Flag: ACONFIG com.android.systemui.notification_row_user_context DEVELOPMENT
Change-Id: I11c5b39f2d9d8f0788acab43640a6d4abcd5a179
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 2ad7192..ba0cc68 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -405,3 +405,14 @@
bug: "282007590"
}
+flag {
+ name: "notification_row_user_context"
+ namespace: "systemui"
+ description: "Create a user-specific Context for the ImageResolver in ExpandableNotificationRow"
+ " (based on the NotificationEntry's user)."
+ bug: "317503801"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 5eeb066..859ce70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -40,6 +40,7 @@
import android.os.Bundle;
import android.os.SystemProperties;
import android.os.Trace;
+import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.IndentingPrintWriter;
@@ -382,7 +383,7 @@
private boolean mUseIncreasedHeadsUpHeight;
private float mTranslationWhenRemoved;
private boolean mWasChildInGroupWhenRemoved;
- private NotificationInlineImageResolver mImageResolver;
+ private final NotificationInlineImageResolver mImageResolver;
private BigPictureIconManager mBigPictureIconManager;
@Nullable
private OnExpansionChangedListener mExpansionChangedListener;
@@ -1700,13 +1701,43 @@
}
/**
- * Constructs an ExpandableNotificationRow.
- * @param context context passed to image resolver
+ * Constructs an ExpandableNotificationRow. Used by layout inflation.
+ *
+ * @param context passed to image resolver
* @param attrs attributes used to initialize parent view
*/
public ExpandableNotificationRow(Context context, AttributeSet attrs) {
- super(context, attrs);
- mImageResolver = new NotificationInlineImageResolver(context,
+ this(context, attrs, context);
+ if (com.android.systemui.Flags.notificationRowUserContext()) {
+ Log.wtf(TAG, "This constructor shouldn't be called");
+ }
+ }
+
+ /**
+ * Constructs an ExpandableNotificationRow. Used by layout inflation (with a custom {@code
+ * AsyncLayoutFactory} in {@link RowInflaterTask}.
+ *
+ * @param context context context of the view
+ * @param attrs attributes used to initialize parent view
+ * @param entry notification that the row will be associated to (determines the user for the
+ * ImageResolver)
+ */
+ public ExpandableNotificationRow(Context context, AttributeSet attrs, NotificationEntry entry) {
+ this(context, attrs, userContextForEntry(context, entry));
+ }
+
+ private static Context userContextForEntry(Context base, NotificationEntry entry) {
+ if (base.getUserId() == entry.getSbn().getNormalizedUserId()) {
+ return base;
+ }
+ return base.createContextAsUser(
+ UserHandle.of(entry.getSbn().getNormalizedUserId()), /* flags= */ 0);
+ }
+
+ private ExpandableNotificationRow(Context sysUiContext, AttributeSet attrs,
+ Context userContext) {
+ super(sysUiContext, attrs);
+ mImageResolver = new NotificationInlineImageResolver(userContext,
new NotificationInlineImageCache());
float radius = getResources().getDimension(R.dimen.notification_corner_radius_small);
mSmallRoundness = radius / getMaxRadius();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
index c620f44..609b15e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInlineImageResolver.java
@@ -31,6 +31,7 @@
import com.android.internal.widget.ImageResolver;
import com.android.internal.widget.LocalImageResolver;
import com.android.internal.widget.MessagingMessage;
+import com.android.systemui.Flags;
import java.util.HashSet;
import java.util.List;
@@ -66,7 +67,11 @@
* @param imageCache The implementation of internal cache.
*/
public NotificationInlineImageResolver(Context context, ImageCache imageCache) {
- mContext = context.getApplicationContext();
+ if (Flags.notificationRowUserContext()) {
+ mContext = context;
+ } else {
+ mContext = context.getApplicationContext();
+ }
mImageCache = imageCache;
if (mImageCache != null) {
@@ -76,6 +81,11 @@
updateMaxImageSizes();
}
+ @VisibleForTesting
+ public Context getContext() {
+ return mContext;
+ }
+
/**
* Check if this resolver has its internal cache implementation.
* @return True if has its internal cache, false otherwise.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
index 8e974c2..9445d56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowInflaterTask.java
@@ -17,10 +17,15 @@
package com.android.systemui.statusbar.notification.row;
import android.content.Context;
+import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
+import androidx.asynclayoutinflater.view.AsyncLayoutFactory;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
import com.android.systemui.res.R;
@@ -55,12 +60,40 @@
mInflateOrigin = new Throwable("inflate requested here");
}
mListener = listener;
- AsyncLayoutInflater inflater = new AsyncLayoutInflater(context);
+ AsyncLayoutInflater inflater = com.android.systemui.Flags.notificationRowUserContext()
+ ? new AsyncLayoutInflater(context, new RowAsyncLayoutInflater(entry))
+ : new AsyncLayoutInflater(context);
mEntry = entry;
entry.setInflationTask(this);
inflater.inflate(R.layout.status_bar_notification_row, parent, this);
}
+ @VisibleForTesting
+ static class RowAsyncLayoutInflater implements AsyncLayoutFactory {
+ private final NotificationEntry mEntry;
+
+ RowAsyncLayoutInflater(NotificationEntry entry) {
+ mEntry = entry;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@Nullable View parent, @NonNull String name,
+ @NonNull Context context, @NonNull AttributeSet attrs) {
+ if (name.equals(ExpandableNotificationRow.class.getName())) {
+ return new ExpandableNotificationRow(context, attrs, mEntry);
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(@NonNull String name, @NonNull Context context,
+ @NonNull AttributeSet attrs) {
+ return null;
+ }
+ }
+
@Override
public void abort() {
mCancelled = true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index e373143..49ba915 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -16,10 +16,9 @@
package com.android.systemui.statusbar.notification.row;
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-
-import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_ALL;
+import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.PKG;
+import static com.android.systemui.statusbar.notification.row.NotificationTestHelper.USER_HANDLE;
import static com.google.common.truth.Truth.assertThat;
@@ -40,11 +39,13 @@
import static org.mockito.Mockito.when;
import android.app.Notification;
-import android.app.NotificationChannel;
+import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
+import android.os.UserHandle;
+import android.platform.test.annotations.EnableFlags;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
@@ -57,6 +58,7 @@
import com.android.internal.R;
import com.android.internal.widget.CachingIconView;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.SysuiTestableContext;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.flags.Flags;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
@@ -806,6 +808,27 @@
assertThat(row.isDrawingAppearAnimation()).isFalse();
}
+ @Test
+ public void imageResolver_sameNotificationUser_usesContext() throws Exception {
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow(PKG,
+ USER_HANDLE.getUid(1234), USER_HANDLE);
+
+ assertThat(row.getImageResolver().getContext()).isSameInstanceAs(mContext);
+ }
+
+ @Test
+ @EnableFlags(com.android.systemui.Flags.FLAG_NOTIFICATION_ROW_USER_CONTEXT)
+ public void imageResolver_differentNotificationUser_createsUserContext() throws Exception {
+ UserHandle user = new UserHandle(33);
+ Context userContext = new SysuiTestableContext(mContext);
+ mContext.prepareCreateContextAsUser(user, userContext);
+
+ ExpandableNotificationRow row = mNotificationTestHelper.createRow(PKG,
+ user.getUid(1234), user);
+
+ assertThat(row.getImageResolver().getContext()).isSameInstanceAs(userContext);
+ }
+
private void setDrawableIconsInImageView(CachingIconView icon, Drawable iconDrawable,
Drawable rightIconDrawable) {
ImageView iconView = mock(ImageView.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index a6bfaa4..c717991 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -569,7 +569,10 @@
throws Exception {
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
- mContext.LAYOUT_INFLATER_SERVICE);
+ Context.LAYOUT_INFLATER_SERVICE);
+ if (com.android.systemui.Flags.notificationRowUserContext()) {
+ inflater.setFactory2(new RowInflaterTask.RowAsyncLayoutInflater(entry));
+ }
mRow = (ExpandableNotificationRow) inflater.inflate(
R.layout.status_bar_notification_row,
null /* root */,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
index 2d76027..0358474 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestableContext.java
@@ -14,6 +14,7 @@
package com.android.systemui;
+import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -30,12 +31,15 @@
import com.android.internal.annotations.GuardedBy;
import com.android.systemui.res.R;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
public class SysuiTestableContext extends TestableContext {
@GuardedBy("mRegisteredReceivers")
private final Set<BroadcastReceiver> mRegisteredReceivers = new ArraySet<>();
+ private final Map<UserHandle, Context> mContextForUser = new HashMap<>();
public SysuiTestableContext(Context base) {
super(base);
@@ -153,4 +157,22 @@
}
super.unregisterReceiver(receiver);
}
+
+ /**
+ * Sets a Context object that will be returned as the result of {@link #createContextAsUser}
+ * for a specific {@code user}.
+ */
+ public void prepareCreateContextAsUser(UserHandle user, Context context) {
+ mContextForUser.put(user, context);
+ }
+
+ @Override
+ @NonNull
+ public Context createContextAsUser(UserHandle user, int flags) {
+ Context userContext = mContextForUser.get(user);
+ if (userContext != null) {
+ return userContext;
+ }
+ return super.createContextAsUser(user, flags);
+ }
}