Fetch user avatars for collaboration messages.
Bug: 374806190 Change-Id: Ib45785ca7208a7b295de0f953d644faabb674ee5 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6020330 Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com> Reviewed-by: Siddhartha S <ssid@chromium.org> Reviewed-by: Calder Kitagawa <ckitagawa@chromium.org> Commit-Queue: Siddhartha S <ssid@chromium.org> Cr-Commit-Position: refs/heads/main@{#1383287}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
4e72956d07
commit
f6b02b90d9
chrome/browser/data_sharing/android/java/src/org/chromium/chrome/browser/data_sharing
components
collaboration
public
data_sharing
public
android
java
src
org
chromium
components
data_sharing
@@ -6,6 +6,8 @@ package org.chromium.chrome.browser.data_sharing;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
@@ -14,6 +16,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
|
||||||
import org.chromium.base.Callback;
|
import org.chromium.base.Callback;
|
||||||
|
import org.chromium.base.CallbackUtils;
|
||||||
import org.chromium.base.Token;
|
import org.chromium.base.Token;
|
||||||
import org.chromium.base.supplier.Supplier;
|
import org.chromium.base.supplier.Supplier;
|
||||||
import org.chromium.chrome.browser.collaboration.messaging.MessagingBackendServiceFactory;
|
import org.chromium.chrome.browser.collaboration.messaging.MessagingBackendServiceFactory;
|
||||||
@@ -27,6 +30,10 @@ import org.chromium.components.collaboration.messaging.InstantNotificationLevel;
|
|||||||
import org.chromium.components.collaboration.messaging.MessageUtils;
|
import org.chromium.components.collaboration.messaging.MessageUtils;
|
||||||
import org.chromium.components.collaboration.messaging.MessagingBackendService;
|
import org.chromium.components.collaboration.messaging.MessagingBackendService;
|
||||||
import org.chromium.components.collaboration.messaging.MessagingBackendService.InstantMessageDelegate;
|
import org.chromium.components.collaboration.messaging.MessagingBackendService.InstantMessageDelegate;
|
||||||
|
import org.chromium.components.data_sharing.DataSharingUIDelegate;
|
||||||
|
import org.chromium.components.data_sharing.GroupMember;
|
||||||
|
import org.chromium.components.data_sharing.configs.DataSharingAvatarBitmapConfig;
|
||||||
|
import org.chromium.components.data_sharing.configs.DataSharingAvatarBitmapConfig.DataSharingAvatarCallback;
|
||||||
import org.chromium.components.messages.MessageBannerProperties;
|
import org.chromium.components.messages.MessageBannerProperties;
|
||||||
import org.chromium.components.messages.MessageDispatcher;
|
import org.chromium.components.messages.MessageDispatcher;
|
||||||
import org.chromium.components.messages.MessageDispatcherProvider;
|
import org.chromium.components.messages.MessageDispatcherProvider;
|
||||||
@@ -34,6 +41,7 @@ import org.chromium.components.messages.MessageIdentifier;
|
|||||||
import org.chromium.components.messages.PrimaryActionClickBehavior;
|
import org.chromium.components.messages.PrimaryActionClickBehavior;
|
||||||
import org.chromium.ui.base.WindowAndroid;
|
import org.chromium.ui.base.WindowAndroid;
|
||||||
import org.chromium.ui.modelutil.PropertyModel;
|
import org.chromium.ui.modelutil.PropertyModel;
|
||||||
|
import org.chromium.ui.util.ColorUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -63,6 +71,7 @@ public class InstantMessageDelegateImpl implements InstantMessageDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final List<AttachedWindowInfo> mAttachList = new ArrayList<>();
|
private final List<AttachedWindowInfo> mAttachList = new ArrayList<>();
|
||||||
|
private final DataSharingUIDelegate mDataSharingUiDelegate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param profile The current profile to get dependencies with.
|
* @param profile The current profile to get dependencies with.
|
||||||
@@ -72,6 +81,7 @@ public class InstantMessageDelegateImpl implements InstantMessageDelegate {
|
|||||||
MessagingBackendService messagingBackendService =
|
MessagingBackendService messagingBackendService =
|
||||||
MessagingBackendServiceFactory.getForProfile(profile);
|
MessagingBackendServiceFactory.getForProfile(profile);
|
||||||
messagingBackendService.setInstantMessageDelegate(this);
|
messagingBackendService.setInstantMessageDelegate(this);
|
||||||
|
mDataSharingUiDelegate = DataSharingServiceFactory.getForProfile(profile).getUiDelegate();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -191,9 +201,21 @@ public class InstantMessageDelegateImpl implements InstantMessageDelegate {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable iconFromMessage(Context context) {
|
private void fetchAvatarIconFromMessage(
|
||||||
// TODO(https://crbug.com/369163940): Fetch this, potentially async.
|
Context context, GroupMember groupMember, Callback<Drawable> onDrawable) {
|
||||||
return ContextCompat.getDrawable(context, R.drawable.ic_features_24dp);
|
DataSharingAvatarCallback onBitmap =
|
||||||
|
(Bitmap bitmap) -> onDrawable.onResult(new BitmapDrawable(bitmap));
|
||||||
|
int sizeInPixels =
|
||||||
|
context.getResources().getDimensionPixelSize(R.dimen.message_description_icon_size);
|
||||||
|
DataSharingAvatarBitmapConfig config =
|
||||||
|
new DataSharingAvatarBitmapConfig.Builder()
|
||||||
|
.setContext(context)
|
||||||
|
.setGroupMember(groupMember)
|
||||||
|
.setIsDarkMode(ColorUtils.inNightMode(context))
|
||||||
|
.setAvatarSizeInPixels(sizeInPixels)
|
||||||
|
.setDataSharingAvatarCallback(onBitmap)
|
||||||
|
.build();
|
||||||
|
mDataSharingUiDelegate.getAvatarBitmap(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showTabRemoved(
|
private void showTabRemoved(
|
||||||
@@ -207,16 +229,23 @@ public class InstantMessageDelegateImpl implements InstantMessageDelegate {
|
|||||||
context.getString(
|
context.getString(
|
||||||
R.string.data_sharing_browser_message_removed_tab, givenName, tabTitle);
|
R.string.data_sharing_browser_message_removed_tab, givenName, tabTitle);
|
||||||
String buttonText = context.getString(R.string.data_sharing_browser_message_reopen);
|
String buttonText = context.getString(R.string.data_sharing_browser_message_reopen);
|
||||||
Drawable icon = iconFromMessage(context);
|
GroupMember groupMember = MessageUtils.extractMember(message);
|
||||||
// TODO(https://crbug.com/369163940): Once the message has the url, we can restore.
|
// TODO(https://crbug.com/369163940): Once the message has the url, we can restore.
|
||||||
showGenericMessage(
|
Runnable action = CallbackUtils.emptyRunnable();
|
||||||
messageDispatcher,
|
|
||||||
MessageIdentifier.TAB_REMOVED_THROUGH_COLLABORATION,
|
fetchAvatarIconFromMessage(
|
||||||
title,
|
context,
|
||||||
buttonText,
|
groupMember,
|
||||||
icon,
|
(icon) -> {
|
||||||
() -> {},
|
showGenericMessage(
|
||||||
onSuccess);
|
messageDispatcher,
|
||||||
|
MessageIdentifier.TAB_REMOVED_THROUGH_COLLABORATION,
|
||||||
|
title,
|
||||||
|
buttonText,
|
||||||
|
icon,
|
||||||
|
action,
|
||||||
|
onSuccess);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showTabChange(
|
private void showTabChange(
|
||||||
@@ -230,16 +259,23 @@ public class InstantMessageDelegateImpl implements InstantMessageDelegate {
|
|||||||
context.getString(
|
context.getString(
|
||||||
R.string.data_sharing_browser_message_changed_tab, givenName, tabTitle);
|
R.string.data_sharing_browser_message_changed_tab, givenName, tabTitle);
|
||||||
String buttonText = context.getString(R.string.data_sharing_browser_message_reopen);
|
String buttonText = context.getString(R.string.data_sharing_browser_message_reopen);
|
||||||
Drawable icon = iconFromMessage(context);
|
GroupMember groupMember = MessageUtils.extractMember(message);
|
||||||
// TODO(https://crbug.com/369163940): Once the message has the url, we can restore.
|
// TODO(https://crbug.com/369163940): Once the message has the url, we can restore.
|
||||||
showGenericMessage(
|
Runnable action = CallbackUtils.emptyRunnable();
|
||||||
messageDispatcher,
|
|
||||||
MessageIdentifier.TAB_NAVIGATED_THROUGH_COLLABORATION,
|
fetchAvatarIconFromMessage(
|
||||||
title,
|
context,
|
||||||
buttonText,
|
groupMember,
|
||||||
icon,
|
(icon) -> {
|
||||||
() -> {},
|
showGenericMessage(
|
||||||
onSuccess);
|
messageDispatcher,
|
||||||
|
MessageIdentifier.TAB_NAVIGATED_THROUGH_COLLABORATION,
|
||||||
|
title,
|
||||||
|
buttonText,
|
||||||
|
icon,
|
||||||
|
action,
|
||||||
|
onSuccess);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showCollaborationMemberAdded(
|
private void showCollaborationMemberAdded(
|
||||||
@@ -258,7 +294,7 @@ public class InstantMessageDelegateImpl implements InstantMessageDelegate {
|
|||||||
givenName,
|
givenName,
|
||||||
tabGroupTitle);
|
tabGroupTitle);
|
||||||
String buttonText = activity.getString(R.string.data_sharing_browser_message_manage);
|
String buttonText = activity.getString(R.string.data_sharing_browser_message_manage);
|
||||||
Drawable icon = iconFromMessage(activity);
|
GroupMember groupMember = MessageUtils.extractMember(message);
|
||||||
Runnable openManageSharingRunnable =
|
Runnable openManageSharingRunnable =
|
||||||
() -> {
|
() -> {
|
||||||
// TODO(crbug.com/379148260): Use shared #isCollaborationIdValid.
|
// TODO(crbug.com/379148260): Use shared #isCollaborationIdValid.
|
||||||
@@ -266,14 +302,20 @@ public class InstantMessageDelegateImpl implements InstantMessageDelegate {
|
|||||||
dataSharingTabManager.showManageSharing(activity, collaborationId);
|
dataSharingTabManager.showManageSharing(activity, collaborationId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
showGenericMessage(
|
|
||||||
messageDispatcher,
|
fetchAvatarIconFromMessage(
|
||||||
MessageIdentifier.COLLABORATION_MEMBER_ADDED,
|
activity,
|
||||||
title,
|
groupMember,
|
||||||
buttonText,
|
(icon) -> {
|
||||||
icon,
|
showGenericMessage(
|
||||||
openManageSharingRunnable,
|
messageDispatcher,
|
||||||
onSuccess);
|
MessageIdentifier.COLLABORATION_MEMBER_ADDED,
|
||||||
|
title,
|
||||||
|
buttonText,
|
||||||
|
icon,
|
||||||
|
openManageSharingRunnable,
|
||||||
|
onSuccess);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showCollaborationRemoved(
|
private void showCollaborationRemoved(
|
||||||
@@ -294,7 +336,7 @@ public class InstantMessageDelegateImpl implements InstantMessageDelegate {
|
|||||||
title,
|
title,
|
||||||
buttonText,
|
buttonText,
|
||||||
icon,
|
icon,
|
||||||
() -> {},
|
CallbackUtils.emptyRunnable(),
|
||||||
onSuccess);
|
onSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -25,6 +25,7 @@ import static org.chromium.components.messages.MessageBannerProperties.TITLE;
|
|||||||
import static org.chromium.components.messages.PrimaryActionClickBehavior.DISMISS_IMMEDIATELY;
|
import static org.chromium.components.messages.PrimaryActionClickBehavior.DISMISS_IMMEDIATELY;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
|
||||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
||||||
|
|
||||||
@@ -54,6 +55,9 @@ import org.chromium.components.collaboration.messaging.MessageAttribution;
|
|||||||
import org.chromium.components.collaboration.messaging.MessagingBackendService;
|
import org.chromium.components.collaboration.messaging.MessagingBackendService;
|
||||||
import org.chromium.components.collaboration.messaging.TabGroupMessageMetadata;
|
import org.chromium.components.collaboration.messaging.TabGroupMessageMetadata;
|
||||||
import org.chromium.components.collaboration.messaging.TabMessageMetadata;
|
import org.chromium.components.collaboration.messaging.TabMessageMetadata;
|
||||||
|
import org.chromium.components.data_sharing.DataSharingService;
|
||||||
|
import org.chromium.components.data_sharing.DataSharingUIDelegate;
|
||||||
|
import org.chromium.components.data_sharing.configs.DataSharingAvatarBitmapConfig;
|
||||||
import org.chromium.components.messages.ManagedMessageDispatcher;
|
import org.chromium.components.messages.ManagedMessageDispatcher;
|
||||||
import org.chromium.components.messages.MessageIdentifier;
|
import org.chromium.components.messages.MessageIdentifier;
|
||||||
import org.chromium.components.messages.MessagesFactory;
|
import org.chromium.components.messages.MessagesFactory;
|
||||||
@@ -81,12 +85,15 @@ public class InstantMessageDelegateImplUnitTest {
|
|||||||
|
|
||||||
@Mock private Profile mProfile;
|
@Mock private Profile mProfile;
|
||||||
@Mock private MessagingBackendService mMessagingBackendService;
|
@Mock private MessagingBackendService mMessagingBackendService;
|
||||||
|
@Mock private DataSharingService mDataSharingService;
|
||||||
|
@Mock private DataSharingUIDelegate mDataSharingUiDelegate;
|
||||||
@Mock private ManagedMessageDispatcher mManagedMessageDispatcher;
|
@Mock private ManagedMessageDispatcher mManagedMessageDispatcher;
|
||||||
@Mock private WindowAndroid mWindowAndroid;
|
@Mock private WindowAndroid mWindowAndroid;
|
||||||
@Mock private TabGroupModelFilter mTabGroupModelFilter;
|
@Mock private TabGroupModelFilter mTabGroupModelFilter;
|
||||||
@Mock private Callback<Boolean> mSuccessCallback;
|
@Mock private Callback<Boolean> mSuccessCallback;
|
||||||
@Mock private DataSharingNotificationManager mDataSharingNotificationManager;
|
@Mock private DataSharingNotificationManager mDataSharingNotificationManager;
|
||||||
@Mock private DataSharingTabManager mDataSharingTabManager;
|
@Mock private DataSharingTabManager mDataSharingTabManager;
|
||||||
|
@Mock private Bitmap mAvatarBitmap;
|
||||||
|
|
||||||
@Captor private ArgumentCaptor<PropertyModel> mPropertyModelCaptor;
|
@Captor private ArgumentCaptor<PropertyModel> mPropertyModelCaptor;
|
||||||
|
|
||||||
@@ -102,6 +109,13 @@ public class InstantMessageDelegateImplUnitTest {
|
|||||||
|
|
||||||
private void onActivity(Activity activity) {
|
private void onActivity(Activity activity) {
|
||||||
MessagingBackendServiceFactory.setForTesting(mMessagingBackendService);
|
MessagingBackendServiceFactory.setForTesting(mMessagingBackendService);
|
||||||
|
DataSharingServiceFactory.setForTesting(mDataSharingService);
|
||||||
|
when(mDataSharingService.getUiDelegate()).thenReturn(mDataSharingUiDelegate);
|
||||||
|
MockitoHelper.doCallback(
|
||||||
|
(DataSharingAvatarBitmapConfig config) ->
|
||||||
|
config.getDataSharingAvatarCallback().onAvatarLoaded(mAvatarBitmap))
|
||||||
|
.when(mDataSharingUiDelegate)
|
||||||
|
.getAvatarBitmap(any());
|
||||||
|
|
||||||
when(mWindowAndroid.getUnownedUserDataHost()).thenReturn(mUnownedUserDataHost);
|
when(mWindowAndroid.getUnownedUserDataHost()).thenReturn(mUnownedUserDataHost);
|
||||||
MessagesFactory.attachMessageDispatcher(mWindowAndroid, mManagedMessageDispatcher);
|
MessagesFactory.attachMessageDispatcher(mWindowAndroid, mManagedMessageDispatcher);
|
||||||
|
@@ -143,6 +143,7 @@ if (is_android) {
|
|||||||
":java",
|
":java",
|
||||||
"//base:base_java",
|
"//base:base_java",
|
||||||
"//base:base_junit_test_support",
|
"//base:base_junit_test_support",
|
||||||
|
"//components/data_sharing:test_support_java",
|
||||||
"//components/data_sharing/public:public_java",
|
"//components/data_sharing/public:public_java",
|
||||||
"//components/saved_tab_groups/public:java",
|
"//components/saved_tab_groups/public:java",
|
||||||
"//third_party/android_deps:robolectric_all_java",
|
"//third_party/android_deps:robolectric_all_java",
|
||||||
|
@@ -7,6 +7,7 @@ package org.chromium.components.collaboration.messaging;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.chromium.base.Token;
|
import org.chromium.base.Token;
|
||||||
|
import org.chromium.components.data_sharing.GroupMember;
|
||||||
|
|
||||||
/** Provides functions to safely read fields out of messages, performing null checks. */
|
/** Provides functions to safely read fields out of messages, performing null checks. */
|
||||||
public class MessageUtils {
|
public class MessageUtils {
|
||||||
@@ -74,4 +75,15 @@ public class MessageUtils {
|
|||||||
? null
|
? null
|
||||||
: message.attribution.collaborationId;
|
: message.attribution.collaborationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns a GroupMember associated with the message, prioritizing affected over triggering. */
|
||||||
|
public static GroupMember extractMember(@Nullable InstantMessage message) {
|
||||||
|
if (message == null || message.attribution == null) {
|
||||||
|
return null;
|
||||||
|
} else if (message.attribution.affectedUser != null) {
|
||||||
|
return message.attribution.affectedUser;
|
||||||
|
} else {
|
||||||
|
return message.attribution.triggeringUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,6 +6,9 @@ package org.chromium.components.collaboration.messaging;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import static org.chromium.components.data_sharing.SharedGroupTestHelper.GROUP_MEMBER1;
|
||||||
|
import static org.chromium.components.data_sharing.SharedGroupTestHelper.GROUP_MEMBER2;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
@@ -125,4 +128,21 @@ public class MessageUtilsUnitTest {
|
|||||||
|
|
||||||
assertEquals("", MessageUtils.extractTabGroupTitle(null));
|
assertEquals("", MessageUtils.extractTabGroupTitle(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExtractMember() {
|
||||||
|
assertEquals(null, MessageUtils.extractMember(null));
|
||||||
|
|
||||||
|
InstantMessage message = new InstantMessage();
|
||||||
|
assertEquals(null, MessageUtils.extractMember(message));
|
||||||
|
|
||||||
|
message.attribution = new MessageAttribution();
|
||||||
|
assertEquals(null, MessageUtils.extractMember(message));
|
||||||
|
|
||||||
|
message.attribution.triggeringUser = GROUP_MEMBER1;
|
||||||
|
assertEquals(GROUP_MEMBER1, MessageUtils.extractMember(message));
|
||||||
|
|
||||||
|
message.attribution.affectedUser = GROUP_MEMBER2;
|
||||||
|
assertEquals(GROUP_MEMBER2, MessageUtils.extractMember(message));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,15 +19,15 @@ public final class DataSharingAvatarBitmapConfig {
|
|||||||
private final DataSharingAvatarCallback mDataSharingAvatarCallback;
|
private final DataSharingAvatarCallback mDataSharingAvatarCallback;
|
||||||
|
|
||||||
/** Interface used to pass the result of avatar loading. */
|
/** Interface used to pass the result of avatar loading. */
|
||||||
|
@FunctionalInterface
|
||||||
public interface DataSharingAvatarCallback {
|
public interface DataSharingAvatarCallback {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the avatar bitmap is ready.
|
* Called when the avatar bitmap is ready.
|
||||||
*
|
*
|
||||||
* @param bitmap The loaded avatar bitmap. If might return null, if group member is
|
* @param bitmap The loaded avatar bitmap. If might return null, if group member is invalid.
|
||||||
* invalid.
|
|
||||||
*/
|
*/
|
||||||
default void onAvatarLoaded(Bitmap bitmap) {}
|
void onAvatarLoaded(Bitmap bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataSharingAvatarBitmapConfig(Builder builder) {
|
private DataSharingAvatarBitmapConfig(Builder builder) {
|
||||||
|
Reference in New Issue
Block a user