| // 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); |
| } |
| } |