blob: 5300814a285de216c0a61738c873c459a1320ebc [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.contacts_picker;
import android.accounts.Account;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import androidx.recyclerview.widget.RecyclerView;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.signin.ProfileDataCache;
import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
import org.chromium.components.browser_ui.contacts_picker.ContactDetails;
import org.chromium.components.browser_ui.contacts_picker.PickerAdapter;
import org.chromium.components.signin.AccountManagerFacade;
import org.chromium.components.signin.AccountManagerFacadeProvider;
import org.chromium.components.signin.base.CoreAccountInfo;
import org.chromium.components.signin.identitymanager.ConsentLevel;
import org.chromium.components.signin.identitymanager.IdentityManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* A {@link PickerAdapter} with special behavior tailored for Chrome.
*
* Owner email is looked up in the {@link ProfileDataCache}, or, failing that, via the {@link
* AccountManagerFacade}.
*/
public class ChromePickerAdapter extends PickerAdapter implements ProfileDataCache.Observer {
// The profile data cache to consult when figuring out the signed in user.
private ProfileDataCache mProfileDataCache;
// Whether an observer for ProfileDataCache has been registered.
private boolean mObserving;
// Whether owner info is being fetched asynchronously.
private boolean mWaitingOnOwnerInfo;
public ChromePickerAdapter(Context context) {
mProfileDataCache = new ProfileDataCache(context,
context.getResources().getDimensionPixelSize(R.dimen.contact_picker_icon_size));
}
// Adapter:
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
addProfileDataObserver();
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
removeProfileDataObserver();
}
// ProfileDataCache.Observer:
@Override
public void onProfileDataUpdated(String accountEmail) {
if (!mWaitingOnOwnerInfo || !TextUtils.equals(accountEmail, getOwnerEmail())) {
return;
}
// Now that we've received an update for the right accountId, we can stop listening and
// update our records.
mWaitingOnOwnerInfo = false;
removeProfileDataObserver();
// TODO(finnur): crbug.com/1021477 - Maintain an member instance of this.
DisplayableProfileData profileData =
mProfileDataCache.getProfileDataOrDefault(getOwnerEmail());
ContactDetails contact = getAllContacts().get(0);
Drawable icon = profileData.getImage();
contact.setSelfIcon(icon);
update();
}
private void addProfileDataObserver() {
if (!mObserving) {
mObserving = true;
mProfileDataCache.addObserver(this);
}
}
private void removeProfileDataObserver() {
if (mObserving) {
mObserving = false;
mProfileDataCache.removeObserver(this);
}
}
// PickerAdapter:
/**
* Returns the email for the currently signed-in user. If that is not available, return the
* first Google account associated with this phone instead.
*/
@Override
protected String findOwnerEmail() {
CoreAccountInfo coreAccountInfo = getCoreAccountInfo();
if (coreAccountInfo != null) {
return coreAccountInfo.getEmail();
}
AccountManagerFacade manager = AccountManagerFacadeProvider.getInstance();
List<Account> accounts = manager.tryGetGoogleAccounts();
if (accounts.size() > 0) {
return accounts.get(0).name;
}
return null;
}
@Override
protected void addOwnerInfoToContacts(ArrayList<ContactDetails> contacts) {
// Processing was not complete, finish the rest asynchronously. Flow continues in
// onProfileDataUpdated.
mWaitingOnOwnerInfo = true;
addProfileDataObserver();
mProfileDataCache.update(Collections.singletonList(getOwnerEmail()));
contacts.add(0, constructOwnerInfo(getOwnerEmail()));
}
/**
* Constructs a {@link ContactDetails} record for the currently signed in user. Name is obtained
* via the {@link DisplayableProfileData}, if available, or (alternatively) using the signed in
* information.
* @param ownerEmail The email for the currently signed in user.
* @return The contact info for the currently signed in user.
*/
@SuppressLint("HardwareIds")
private ContactDetails constructOwnerInfo(String ownerEmail) {
DisplayableProfileData profileData = mProfileDataCache.getProfileDataOrDefault(ownerEmail);
String name = profileData.getFullNameOrEmail();
if (TextUtils.isEmpty(name) || TextUtils.equals(name, ownerEmail)) {
name = CoreAccountInfo.getEmailFrom(getCoreAccountInfo());
}
ContactDetails contact = new ContactDetails(ContactDetails.SELF_CONTACT_ID, name,
Collections.singletonList(ownerEmail), /*phoneNumbers=*/null, /*addresses=*/null);
Drawable icon = profileData.getImage();
contact.setIsSelf(true);
contact.setSelfIcon(icon);
return contact;
}
private CoreAccountInfo getCoreAccountInfo() {
// Since this is read-only operation to obtain email address, always using regular profile
// for both regular and off-the-record profile is safe.
IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
Profile.getLastUsedRegularProfile());
return identityManager.getPrimaryAccountInfo(ConsentLevel.SYNC);
}
}