Commit a5707a7d authored by Alice Wang's avatar Alice Wang Committed by Commit Bot

[Android][Signin] Add observer to listen to monogram update

This CL adds an observer to update ProfileDataCache when user's profile
photo(include monogram) from IdentityManager is updated.

Bug: 1127886
Change-Id: I0c70f72708e50dceb63eb122055315f7818cba06
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2430984Reviewed-by: default avatarBoris Sazonov <bsazonov@chromium.org>
Reviewed-by: default avatarMihai Sardarescu <msarda@chromium.org>
Commit-Queue: Alice Wang <aliceywang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811237}
parent c243c5e7
......@@ -32,6 +32,8 @@ import org.chromium.components.browser_ui.util.AvatarGenerator;
import org.chromium.components.signin.AccountManagerFacadeProvider;
import org.chromium.components.signin.ProfileDataSource;
import org.chromium.components.signin.base.AccountInfo;
import org.chromium.components.signin.base.CoreAccountInfo;
import org.chromium.components.signin.identitymanager.IdentityManager;
import java.util.ArrayList;
import java.util.HashMap;
......@@ -44,7 +46,8 @@ import java.util.Map;
* should be provided by calling {@link #update(List)}
*/
@MainThread
public class ProfileDataCache implements ProfileDownloader.Observer, ProfileDataSource.Observer {
public class ProfileDataCache implements ProfileDownloader.Observer, ProfileDataSource.Observer,
IdentityManager.Observer {
/**
* Observer to get notifications about changes in profile data.
*/
......@@ -112,6 +115,7 @@ public class ProfileDataCache implements ProfileDownloader.Observer, ProfileData
private final ObserverList<Observer> mObservers = new ObserverList<>();
private final Map<String, DisplayableProfileData> mCachedProfileData = new HashMap<>();
private @Nullable final ProfileDataSource mProfileDataSource;
private final IdentityManager mIdentityManager;
public ProfileDataCache(Context context, @Px int imageSize) {
this(context, imageSize, null);
......@@ -130,6 +134,8 @@ public class ProfileDataCache implements ProfileDownloader.Observer, ProfileData
mBadgeConfig = badgeConfig;
mPlaceholderImage = getScaledPlaceholderImage(context, imageSize);
mProfileDataSource = profileDataSource;
mIdentityManager = IdentityServicesProvider.get().getIdentityManager(
Profile.getLastUsedRegularProfile());
}
/**
......@@ -202,6 +208,7 @@ public class ProfileDataCache implements ProfileDownloader.Observer, ProfileData
} else {
ProfileDownloader.addObserver(this);
}
mIdentityManager.addObserver(this);
}
mObservers.addObserver(observer);
}
......@@ -218,13 +225,14 @@ public class ProfileDataCache implements ProfileDownloader.Observer, ProfileData
} else {
ProfileDownloader.removeObserver(this);
}
mIdentityManager.removeObserver(this);
}
}
private void updateCacheFromProfileDataSource() {
for (ProfileDataSource.ProfileData profileData :
mProfileDataSource.getProfileDataMap().values()) {
updateCachedProfileData(createDisplayableProfileData(profileData));
updateCachedProfileDataAndNotifyObservers(createDisplayableProfileData(profileData));
}
}
......@@ -239,7 +247,7 @@ public class ProfileDataCache implements ProfileDownloader.Observer, ProfileData
public void onProfileDownloaded(String accountId, String fullName, String givenName,
Bitmap bitmap) {
ThreadUtils.assertOnUiThread();
updateCachedProfileData(new DisplayableProfileData(
updateCachedProfileDataAndNotifyObservers(new DisplayableProfileData(
accountId, prepareAvatar(bitmap, accountId), fullName, givenName));
}
......@@ -252,10 +260,37 @@ public class ProfileDataCache implements ProfileDownloader.Observer, ProfileData
mCachedProfileData.remove(accountId);
notifyObservers(accountId);
} else {
updateCachedProfileData(createDisplayableProfileData(profileData));
updateCachedProfileDataAndNotifyObservers(createDisplayableProfileData(profileData));
}
}
/**
* Implements {@link IdentityManager.Observer}.
*/
@Override
public void onExtendedAccountInfoUpdated(AccountInfo accountInfo) {
final String accountEmail = accountInfo.getEmail();
DisplayableProfileData profileData = mCachedProfileData.get(accountEmail);
// if profileData is null, we will fetch monogram when generating
// the cache so that different sources will be handled in order.
if (profileData != null && profileData.getImage() == mPlaceholderImage) {
updateCachedProfileDataAndNotifyObservers(new DisplayableProfileData(accountEmail,
prepareAvatar(accountInfo.getAccountImage(), accountEmail),
profileData.getFullName(), profileData.getGivenName()));
}
}
/**
* Implements {@link IdentityManager.Observer}.
*/
@Override
public void onPrimaryAccountSet(CoreAccountInfo account) {}
/**
* Implements {@link IdentityManager.Observer}.
*/
@Override
public void onPrimaryAccountCleared(CoreAccountInfo account) {}
/**
* Returns a profile data cache object without a badge.The badge is put with respect to
......@@ -315,7 +350,7 @@ public class ProfileDataCache implements ProfileDownloader.Observer, ProfileData
return overlayBadgeOnUserPicture(croppedAvatar);
}
private void updateCachedProfileData(DisplayableProfileData profileData) {
private void updateCachedProfileDataAndNotifyObservers(DisplayableProfileData profileData) {
mCachedProfileData.put(profileData.getAccountName(), profileData);
notifyObservers(profileData.getAccountName());
}
......@@ -379,11 +414,9 @@ public class ProfileDataCache implements ProfileDownloader.Observer, ProfileData
* TODO(https://crbug.com/1130545): We should refactor the different sources for getting
* the profile image.
*/
private static @Nullable Bitmap getAccountImageFromIdentityManager(String accountEmail) {
private @Nullable Bitmap getAccountImageFromIdentityManager(String accountEmail) {
AccountInfo accountInfo =
IdentityServicesProvider.get()
.getIdentityManager(Profile.getLastUsedRegularProfile())
.findExtendedAccountInfoForAccountWithRefreshTokenByEmailAddress(
mIdentityManager.findExtendedAccountInfoForAccountWithRefreshTokenByEmailAddress(
accountEmail);
return accountInfo != null ? accountInfo.getAccountImage() : null;
}
......
......@@ -6,6 +6,8 @@ package org.chromium.chrome.browser.signin;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import android.app.Activity;
import android.graphics.Bitmap;
......@@ -20,9 +22,11 @@ import android.widget.ImageView;
import androidx.annotation.Px;
import androidx.test.filters.MediumTest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.chromium.base.test.params.ParameterAnnotations.ClassParameter;
import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
......@@ -30,9 +34,11 @@ import org.chromium.base.test.params.ParameterSet;
import org.chromium.base.test.params.ParameterizedRunner;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
import org.chromium.chrome.test.util.ChromeRenderTestRule;
import org.chromium.components.signin.ProfileDataSource;
import org.chromium.components.signin.identitymanager.IdentityManager;
import org.chromium.components.signin.test.util.FakeProfileDataSource;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.test.util.DummyUiActivityTestCase;
......@@ -67,14 +73,27 @@ public class ProfileDataCacheRenderTest extends DummyUiActivityTestCase {
public ChromeRenderTestRule mRenderTestRule =
ChromeRenderTestRule.Builder.withPublicCorpus().build();
@Mock
private Profile mProfileMock;
@Mock
private IdentityServicesProvider mIdentityServicesProviderMock;
private final IdentityManager mIdentityManager =
new IdentityManager(0 /* nativeIdentityManager */, null /* OAuth2TokenService */);
private FrameLayout mContentView;
private ImageView mImageView;
private FakeProfileDataSource mProfileDataSource;
private ProfileDataCache mProfileDataCache;
@Override
public void setUpTest() throws Exception {
super.setUpTest();
@Before
public void setUp() {
initMocks(this);
Profile.setLastUsedProfileForTesting(mProfileMock);
when(mIdentityServicesProviderMock.getIdentityManager(mProfileMock))
.thenReturn(mIdentityManager);
IdentityServicesProvider.setInstanceForTests(mIdentityServicesProviderMock);
TestThreadUtils.runOnUiThreadBlocking(() -> {
Activity activity = getActivity();
mContentView = new FrameLayout(activity);
......
......@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.signin;
import static org.mockito.Mockito.mockingDetails;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import android.app.Activity;
......@@ -20,6 +21,7 @@ import androidx.annotation.DrawableRes;
import androidx.test.filters.MediumTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
......@@ -28,9 +30,11 @@ import org.mockito.Mock;
import org.chromium.base.test.util.Batch;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.util.ChromeRenderTestRule;
import org.chromium.components.signin.ProfileDataSource;
import org.chromium.components.signin.identitymanager.IdentityManager;
import org.chromium.components.signin.test.util.FakeProfileDataSource;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.test.util.DummyUiActivityTestCase;
......@@ -49,20 +53,32 @@ public class ProfileDataCacheWithBadgeRenderTest extends DummyUiActivityTestCase
public ChromeRenderTestRule mRenderTestRule =
ChromeRenderTestRule.Builder.withPublicCorpus().build();
@Mock
private Profile mProfileMock;
@Mock
private IdentityServicesProvider mIdentityServicesProviderMock;
@Mock
private ProfileDataCache.Observer mObserver;
private static final String TEST_ACCOUNT_NAME = "test@example.com";
private final IdentityManager mIdentityManager =
new IdentityManager(0 /* nativeIdentityManager */, null /* OAuth2TokenService */);
private FrameLayout mContentView;
private ImageView mImageView;
private FakeProfileDataSource mProfileDataSource;
private ProfileDataCache mProfileDataCache;
@Override
public void setUpTest() throws Exception {
super.setUpTest();
@Before
public void setUp() {
initMocks(this);
Profile.setLastUsedProfileForTesting(mProfileMock);
when(mIdentityServicesProviderMock.getIdentityManager(mProfileMock))
.thenReturn(mIdentityManager);
IdentityServicesProvider.setInstanceForTests(mIdentityServicesProviderMock);
TestThreadUtils.runOnUiThreadBlocking(() -> {
Activity activity = getActivity();
mContentView = new FrameLayout(activity);
......
......@@ -46,6 +46,11 @@ public class IdentityManager {
* the settings.
*/
default void onAccountsCookieDeletedByUserAction() {}
/**
* Called after an account is updated.
*/
default void onExtendedAccountInfoUpdated(AccountInfo accountInfo) {}
}
/**
* A simple callback for getAccessToken.
......@@ -126,6 +131,16 @@ public class IdentityManager {
}
}
/**
* Called after an account is updated.
*/
@CalledByNative
private void onExtendedAccountInfoUpdated(AccountInfo accountInfo) {
for (Observer observer : mObservers) {
observer.onExtendedAccountInfoUpdated(accountInfo);
}
}
/**
* Returns whether the user's primary account is available.
*/
......
......@@ -636,6 +636,13 @@ void IdentityManager::OnAccountUpdated(const AccountInfo& info) {
for (auto& observer : observer_list_) {
observer.OnExtendedAccountInfoUpdated(info);
}
#if defined(OS_ANDROID)
if (java_identity_manager_) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_IdentityManager_onExtendedAccountInfoUpdated(
env, java_identity_manager_, ConvertToJavaAccountInfo(env, info));
}
#endif
}
void IdentityManager::OnAccountRemoved(const AccountInfo& info) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment