Commit 2eac1442 authored by Finnur Thorarinsson's avatar Finnur Thorarinsson Committed by Commit Bot

Contacts Picker: Make contact details of owner more prominent.

Bring the contact, who is currently signed in, to the top.
If no user is signed in, we can still synthesize a contact
entry with the available information (best-effort).

Note: This CL uses a blue star to mark the record that was
moved/synthesized. This should be considered a placeholder.
Will work with UX to flesh out how it should look like.

BUG: 860467

Change-Id: I9c8a7509feac5bc38e8e60878cef9db8acb420e8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1876348
Commit-Queue: Finnur Thorarinsson <finnur@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Auto-Submit: Finnur Thorarinsson <finnur@chromium.org>
Cr-Commit-Position: refs/heads/master@{#712574}
parent 438aaaa4
...@@ -92,6 +92,7 @@ chrome_test_java_sources = [ ...@@ -92,6 +92,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/directactions/DirectActionsInActivityTest.java", "javatests/src/org/chromium/chrome/browser/directactions/DirectActionsInActivityTest.java",
"javatests/src/org/chromium/chrome/browser/directactions/FakeDirectActionReporter.java", "javatests/src/org/chromium/chrome/browser/directactions/FakeDirectActionReporter.java",
"javatests/src/org/chromium/chrome/browser/directactions/MenuDirectActionHandlerTest.java", "javatests/src/org/chromium/chrome/browser/directactions/MenuDirectActionHandlerTest.java",
"javatests/src/org/chromium/chrome/browser/contacts_picker/ContactDetailsTest.java",
"javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java", "javatests/src/org/chromium/chrome/browser/contacts_picker/ContactsPickerDialogTest.java",
"javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java", "javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java",
"javatests/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderViewTest.java", "javatests/src/org/chromium/chrome/browser/contextmenu/RevampedContextMenuHeaderViewTest.java",
......
...@@ -74,4 +74,11 @@ ...@@ -74,4 +74,11 @@
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
<ImageView
android:id="@+id/star"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginEnd="20dp"
android:src="@drawable/btn_star_filled"
android:visibility="gone" />
</merge> </merge>
...@@ -509,6 +509,9 @@ ...@@ -509,6 +509,9 @@
<dimen name="circular_monogram_size">20dp</dimen> <dimen name="circular_monogram_size">20dp</dimen>
<dimen name="circular_monogram_text_size">14dp</dimen> <dimen name="circular_monogram_text_size">14dp</dimen>
<!-- Contact Picker dimensions -->
<dimen name="contact_picker_icon_size">36dp</dimen>
<!-- Photo Picker dimensions --> <!-- Photo Picker dimensions -->
<dimen name="photo_picker_selected_padding">12dp</dimen> <dimen name="photo_picker_selected_padding">12dp</dimen>
<dimen name="photo_picker_label_gap">10dp</dimen> <dimen name="photo_picker_label_gap">10dp</dimen>
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.contacts_picker; package org.chromium.chrome.browser.contacts_picker;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
...@@ -19,6 +20,10 @@ import java.util.List; ...@@ -19,6 +20,10 @@ import java.util.List;
* A class to keep track of the metadata associated with a contact. * A class to keep track of the metadata associated with a contact.
*/ */
public class ContactDetails implements Comparable<ContactDetails> { public class ContactDetails implements Comparable<ContactDetails> {
// The identifier for the information from the signed in user. Must not be a valid id in the
// context of the Android Contacts list.
public static final String SELF_CONTACT_ID = "-1";
/** /**
* A container class for delivering contact details in abbreviated form * A container class for delivering contact details in abbreviated form
* (where only the first email and phone numbers are returned and the rest * (where only the first email and phone numbers are returned and the rest
...@@ -46,6 +51,14 @@ public class ContactDetails implements Comparable<ContactDetails> { ...@@ -46,6 +51,14 @@ public class ContactDetails implements Comparable<ContactDetails> {
// The list of addresses registered for this contact. // The list of addresses registered for this contact.
private final List<PaymentAddress> mAddresses; private final List<PaymentAddress> mAddresses;
// Keeps track of whether this is the contact detail for the owner of the device.
private boolean mIsSelf;
// The avatar icon for the owner of the device. Non-null only if the ContactDetails representing
// the owner were synthesized (not when a pre-existing contact tile was moved to the top).
@Nullable
private Drawable mSelfIcon;
/** /**
* The ContactDetails constructor. * The ContactDetails constructor.
* @param id The unique identifier of this contact. * @param id The unique identifier of this contact.
...@@ -88,6 +101,37 @@ public class ContactDetails implements Comparable<ContactDetails> { ...@@ -88,6 +101,37 @@ public class ContactDetails implements Comparable<ContactDetails> {
return mId; return mId;
} }
/**
* Marks whether object is representing the owner of the device.
* @param value True if this is the contact details for the owner. False otherwise.
*/
public void setIsSelf(boolean value) {
mIsSelf = value;
}
/**
* Returns true if this contact detail is representing the owner of the device.
*/
public boolean isSelf() {
return mIsSelf;
}
/**
* Sets the icon representing the owner of the device.
*/
public void setSelfIcon(Drawable icon) {
mSelfIcon = icon;
}
/**
* Fetch the cached icon for this contact. Returns null if this is not the 'self' contact, all
* other contact avatars should be retrieved through the {@link FetchIconWorkerTask}.
*/
@Nullable
public Drawable getSelfIcon() {
return mSelfIcon;
}
/** /**
* Accessor for the abbreviated display name (first letter of first name and first letter of * Accessor for the abbreviated display name (first letter of first name and first letter of
* last name). * last name).
......
...@@ -13,6 +13,7 @@ import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory; ...@@ -13,6 +13,7 @@ import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.chromium.chrome.R; import org.chromium.chrome.R;
...@@ -49,6 +50,9 @@ public class ContactView extends SelectableItemView<ContactDetails> { ...@@ -49,6 +50,9 @@ public class ContactView extends SelectableItemView<ContactDetails> {
private TextView mPhoneNumber; private TextView mPhoneNumber;
private TextView mPhoneNumberOverflowCount; private TextView mPhoneNumberOverflowCount;
// The UI that indicates this is the owner of the device.
private ImageView mStar;
// The dialog manager to use to show contact details. // The dialog manager to use to show contact details.
private ModalDialogManager mManager; private ModalDialogManager mManager;
...@@ -74,6 +78,7 @@ public class ContactView extends SelectableItemView<ContactDetails> { ...@@ -74,6 +78,7 @@ public class ContactView extends SelectableItemView<ContactDetails> {
mEmailOverflowCount = findViewById(R.id.email_overflow_count); mEmailOverflowCount = findViewById(R.id.email_overflow_count);
mPhoneNumber = findViewById(R.id.telephone_number); mPhoneNumber = findViewById(R.id.telephone_number);
mPhoneNumberOverflowCount = findViewById(R.id.telephone_number_overflow_count); mPhoneNumberOverflowCount = findViewById(R.id.telephone_number_overflow_count);
mStar = findViewById(R.id.star);
mEmailOverflowCount.setOnClickListener(this); mEmailOverflowCount.setOnClickListener(this);
mPhoneNumberOverflowCount.setOnClickListener(this); mPhoneNumberOverflowCount.setOnClickListener(this);
...@@ -181,6 +186,8 @@ public class ContactView extends SelectableItemView<ContactDetails> { ...@@ -181,6 +186,8 @@ public class ContactView extends SelectableItemView<ContactDetails> {
updateTextViewVisibilityAndContent( updateTextViewVisibilityAndContent(
mPhoneNumberOverflowCount, details.overflowTelephoneNumberCount); mPhoneNumberOverflowCount, details.overflowTelephoneNumberCount);
if (contactDetails.isSelf()) mStar.setVisibility(View.VISIBLE);
if (icon == null) { if (icon == null) {
icon = mCategoryView.getIconGenerator().generateIconForText( icon = mCategoryView.getIconGenerator().generateIconForText(
contactDetails.getDisplayNameAbbreviation()); contactDetails.getDisplayNameAbbreviation());
...@@ -212,5 +219,6 @@ public class ContactView extends SelectableItemView<ContactDetails> { ...@@ -212,5 +219,6 @@ public class ContactView extends SelectableItemView<ContactDetails> {
mEmailOverflowCount.setText(""); mEmailOverflowCount.setText("");
mPhoneNumber.setText(""); mPhoneNumber.setText("");
mPhoneNumberOverflowCount.setText(""); mPhoneNumberOverflowCount.setText("");
mStar.setVisibility(View.GONE);
} }
} }
...@@ -6,6 +6,8 @@ package org.chromium.chrome.browser.contacts_picker; ...@@ -6,6 +6,8 @@ package org.chromium.chrome.browser.contacts_picker;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView.ViewHolder;
import org.chromium.base.VisibleForTesting; import org.chromium.base.VisibleForTesting;
...@@ -61,12 +63,19 @@ public class ContactViewHolder ...@@ -61,12 +63,19 @@ public class ContactViewHolder
return; return;
} }
Bitmap icon = mCategoryView.getIconCache().getBitmap(mContact.getId()); Drawable drawable = contact.getSelfIcon();
if (icon == null) { if (drawable != null) {
mWorkerTask = new FetchIconWorkerTask(mContact.getId(), mContentResolver, this); assert drawable instanceof BitmapDrawable;
mWorkerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
mItemView.initialize(contact, bitmap);
} else {
Bitmap icon = mCategoryView.getIconCache().getBitmap(mContact.getId());
if (icon == null) {
mWorkerTask = new FetchIconWorkerTask(mContact.getId(), mContentResolver, this);
mWorkerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
mItemView.initialize(contact, icon);
} }
mItemView.initialize(contact, icon);
} }
/** /**
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.contacts_picker; package org.chromium.chrome.browser.contacts_picker;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.provider.ContactsContract; import android.provider.ContactsContract;
...@@ -38,6 +39,9 @@ class ContactsFetcherWorkerTask extends AsyncTask<ArrayList<ContactDetails>> { ...@@ -38,6 +39,9 @@ class ContactsFetcherWorkerTask extends AsyncTask<ArrayList<ContactDetails>> {
void contactsRetrieved(ArrayList<ContactDetails> contacts); void contactsRetrieved(ArrayList<ContactDetails> contacts);
} }
// The current context to use.
private Context mContext;
// The content resolver to use for looking up contacts. // The content resolver to use for looking up contacts.
private ContentResolver mContentResolver; private ContentResolver mContentResolver;
...@@ -58,17 +62,18 @@ class ContactsFetcherWorkerTask extends AsyncTask<ArrayList<ContactDetails>> { ...@@ -58,17 +62,18 @@ class ContactsFetcherWorkerTask extends AsyncTask<ArrayList<ContactDetails>> {
/** /**
* A ContactsFetcherWorkerTask constructor. * A ContactsFetcherWorkerTask constructor.
* @param contentResolver The ContentResolver to use to fetch the contacts data. * @param context The Context to use.
* @param callback The callback to use to communicate back the results. * @param callback The callback to use to communicate back the results.
* @param includeNames Whether names were requested by the website. * @param includeNames Whether names were requested by the website.
* @param includeEmails Whether to include emails in the data fetched. * @param includeEmails Whether to include emails in the data fetched.
* @param includeTel Whether to include telephones in the data fetched. * @param includeTel Whether to include telephones in the data fetched.
* @param includeAddresses Whether to include telephones in the data fetched. * @param includeAddresses Whether to include telephones in the data fetched.
*/ */
public ContactsFetcherWorkerTask(ContentResolver contentResolver, public ContactsFetcherWorkerTask(Context context, ContactsRetrievedCallback callback,
ContactsRetrievedCallback callback, boolean includeNames, boolean includeEmails, boolean includeNames, boolean includeEmails, boolean includeTel,
boolean includeTel, boolean includeAddresses) { boolean includeAddresses) {
mContentResolver = contentResolver; mContext = context;
mContentResolver = context.getContentResolver();
mCallback = callback; mCallback = callback;
mIncludeNames = includeNames; mIncludeNames = includeNames;
mIncludeEmails = includeEmails; mIncludeEmails = includeEmails;
......
...@@ -51,6 +51,8 @@ class FetchIconWorkerTask extends AsyncTask<Bitmap> { ...@@ -51,6 +51,8 @@ class FetchIconWorkerTask extends AsyncTask<Bitmap> {
public FetchIconWorkerTask( public FetchIconWorkerTask(
String id, ContentResolver contentResolver, IconRetrievedCallback callback) { String id, ContentResolver contentResolver, IconRetrievedCallback callback) {
mContactId = id; mContactId = id;
// Avatar icon for own info should not be obtained through the contacts list.
assert !id.equals(ContactDetails.SELF_CONTACT_ID);
mContentResolver = contentResolver; mContentResolver = contentResolver;
mCallback = callback; mCallback = callback;
} }
......
...@@ -4,30 +4,42 @@ ...@@ -4,30 +4,42 @@
package org.chromium.chrome.browser.contacts_picker; package org.chromium.chrome.browser.contacts_picker;
import android.accounts.Account;
import android.annotation.SuppressLint;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Adapter; import android.support.v7.widget.RecyclerView.Adapter;
import android.text.TextUtils;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import org.chromium.base.VisibleForTesting; import org.chromium.base.VisibleForTesting;
import org.chromium.base.task.AsyncTask; import org.chromium.base.task.AsyncTask;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.signin.DisplayableProfileData;
import org.chromium.chrome.browser.signin.ProfileDataCache;
import org.chromium.components.signin.AccountManagerFacade;
import org.chromium.components.signin.ChromeSigninController;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale; import java.util.Locale;
/** /**
* A data adapter for the Contacts Picker. * A data adapter for the Contacts Picker.
*/ */
public class PickerAdapter extends Adapter<RecyclerView.ViewHolder> public class PickerAdapter extends Adapter<RecyclerView.ViewHolder>
implements ContactsFetcherWorkerTask.ContactsRetrievedCallback, implements ContactsFetcherWorkerTask.ContactsRetrievedCallback, TopView.ChipToggledCallback,
TopView.ChipToggledCallback { ProfileDataCache.Observer {
/** /**
* A ViewHolder for the top-most view in the RecyclerView. The view it contains has a * A ViewHolder for the top-most view in the RecyclerView. The view it contains has a
* checkbox and some multi-line text that goes with it, so clicks on either text line * checkbox and some multi-line text that goes with it, so clicks on either text line
...@@ -70,6 +82,9 @@ public class PickerAdapter extends Adapter<RecyclerView.ViewHolder> ...@@ -70,6 +82,9 @@ public class PickerAdapter extends Adapter<RecyclerView.ViewHolder>
int CONTACT_DETAILS = 1; int CONTACT_DETAILS = 1;
} }
// The current context to use.
private Context mContext;
// The category view to use to show the contacts. // The category view to use to show the contacts.
private PickerCategoryView mCategoryView; private PickerCategoryView mCategoryView;
...@@ -85,9 +100,22 @@ public class PickerAdapter extends Adapter<RecyclerView.ViewHolder> ...@@ -85,9 +100,22 @@ public class PickerAdapter extends Adapter<RecyclerView.ViewHolder>
// The full list of all registered contacts on the device. // The full list of all registered contacts on the device.
private ArrayList<ContactDetails> mContactDetails; private ArrayList<ContactDetails> mContactDetails;
// The email address of the owner of the device.
@Nullable
private String mOwnerEmail;
// The async worker task to use for fetching the contact details. // The async worker task to use for fetching the contact details.
private ContactsFetcherWorkerTask mWorkerTask; private ContactsFetcherWorkerTask mWorkerTask;
// 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;
// Whether the user has switched to search mode. // Whether the user has switched to search mode.
private boolean mSearchMode; private boolean mSearchMode;
...@@ -106,29 +134,33 @@ public class PickerAdapter extends Adapter<RecyclerView.ViewHolder> ...@@ -106,29 +134,33 @@ public class PickerAdapter extends Adapter<RecyclerView.ViewHolder>
// A list of contacts to use for testing (instead of querying Android). // A list of contacts to use for testing (instead of querying Android).
private static ArrayList<ContactDetails> sTestContacts; private static ArrayList<ContactDetails> sTestContacts;
// An owner email to use when testing.
private static String sTestOwnerEmail;
/** /**
* The PickerAdapter constructor. * The PickerAdapter constructor.
* @param categoryView The category view to use to show the contacts. * @param categoryView The category view to use to show the contacts.
* @param contentResolver The content resolver to use to fetch the data. * @param context The current context.
* @param formattedOrigin The origin the data will be shared with. * @param formattedOrigin The origin the data will be shared with.
*/ */
public PickerAdapter(PickerCategoryView categoryView, ContentResolver contentResolver, public PickerAdapter(PickerCategoryView categoryView, Context context, String formattedOrigin) {
String formattedOrigin) { mContext = context;
mCategoryView = categoryView; mCategoryView = categoryView;
mContentResolver = contentResolver; mContentResolver = context.getContentResolver();
mFormattedOrigin = formattedOrigin; mFormattedOrigin = formattedOrigin;
sIncludeNames = true; sIncludeNames = true;
sIncludeEmails = true; sIncludeEmails = true;
sIncludeTelephones = true; sIncludeTelephones = true;
mProfileDataCache = new ProfileDataCache(context,
mContext.getResources().getDimensionPixelSize(R.dimen.contact_picker_icon_size));
if (getAllContacts() == null && sTestContacts == null) { if (getAllContacts() == null && sTestContacts == null) {
mWorkerTask = new ContactsFetcherWorkerTask(mContentResolver, this, mWorkerTask = new ContactsFetcherWorkerTask(context, this, mCategoryView.includeNames,
mCategoryView.includeNames, mCategoryView.includeEmails, mCategoryView.includeEmails, mCategoryView.includeTel,
mCategoryView.includeTel, mCategoryView.includeAddresses); mCategoryView.includeAddresses);
mWorkerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); mWorkerTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} else { } else {
mContactDetails = sTestContacts; contactsRetrieved(sTestContacts);
notifyDataSetChanged();
} }
} }
...@@ -175,13 +207,55 @@ public class PickerAdapter extends Adapter<RecyclerView.ViewHolder> ...@@ -175,13 +207,55 @@ public class PickerAdapter extends Adapter<RecyclerView.ViewHolder>
return mContactDetails; return mContactDetails;
} }
// Adapter:
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
addProfileDataObserver();
}
@Override
public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
super.onDetachedFromRecyclerView(recyclerView);
removeProfileDataObserver();
}
// ContactsFetcherWorkerTask.ContactsRetrievedCallback: // ContactsFetcherWorkerTask.ContactsRetrievedCallback:
@Override @Override
public void contactsRetrieved(ArrayList<ContactDetails> contacts) { public void contactsRetrieved(ArrayList<ContactDetails> contacts) {
mContactDetails = contacts; mContactDetails = contacts;
if (mTopView != null) mTopView.updateContactCount(mContactDetails.size()); mOwnerEmail = getOwnerEmail();
notifyDataSetChanged(); if (!processOwnerInfo(contacts) && mOwnerEmail != null) {
// Processing was not complete, finish the rest asynchronously. Flow continues in
// onProfileDataUpdated.
mWaitingOnOwnerInfo = true;
addProfileDataObserver();
mProfileDataCache.update(Collections.singletonList(mOwnerEmail));
mContactDetails.add(0, constructOwnerInfo(mOwnerEmail));
}
update();
}
// ProfileDataCache.Observer
@Override
public void onProfileDataUpdated(String accountId) {
if (!mWaitingOnOwnerInfo || !TextUtils.equals(accountId, mOwnerEmail)) {
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(mOwnerEmail);
ContactDetails contact = mContactDetails.get(0);
Drawable icon = profileData.getImage();
contact.setSelfIcon(icon);
update();
} }
// RecyclerView.Adapter: // RecyclerView.Adapter:
...@@ -294,9 +368,120 @@ public class PickerAdapter extends Adapter<RecyclerView.ViewHolder> ...@@ -294,9 +368,120 @@ public class PickerAdapter extends Adapter<RecyclerView.ViewHolder>
return sIncludeTelephones; return sIncludeTelephones;
} }
/** Sets a list of contacts to use as data for the dialog. For testing use only. */ /**
* Sets a list of contacts to use as data for the dialog, and the owner email. For testing use
* only.
*/
@VisibleForTesting @VisibleForTesting
public static void setTestContacts(ArrayList<ContactDetails> contacts) { public static void setTestContactsAndOwner(
ArrayList<ContactDetails> contacts, String ownerEmail) {
sTestContacts = contacts; sTestContacts = contacts;
sTestOwnerEmail = ownerEmail;
}
private void addProfileDataObserver() {
if (!mObserving) {
mObserving = true;
mProfileDataCache.addObserver(this);
}
}
private void removeProfileDataObserver() {
if (mObserving) {
mObserving = false;
mProfileDataCache.removeObserver(this);
}
}
private void update() {
if (mTopView != null) mTopView.updateContactCount(mContactDetails.size());
notifyDataSetChanged();
}
/**
* Returns the email for the currently signed-in user. If that is not available, return the
* first Google account associated with this phone instead.
*/
private String getOwnerEmail() {
if (sTestOwnerEmail != null) return sTestOwnerEmail;
ChromeSigninController controller = ChromeSigninController.get();
Account account = controller.getSignedInUser();
if (account != null) {
return account.name;
}
AccountManagerFacade manager = AccountManagerFacade.get();
List<Account> accounts = manager.tryGetGoogleAccounts();
if (accounts.size() > 0) {
return accounts.get(0).name;
}
return null;
}
/**
* Attempts to figure out if the owner of the device is listed in the available contact details.
* If so move it to the top of the list. If not found, returns false.
* @return Returns true if processing is complete, false if waiting on asynchronous fetching of
* missing data for the owner info.
*/
private boolean processOwnerInfo(ArrayList<ContactDetails> contacts) {
if (mOwnerEmail == null) {
return true;
}
ArrayList<Integer> matches = new ArrayList<Integer>();
for (int i = 0; i < contacts.size(); ++i) {
List<String> emails = contacts.get(i).getEmails();
for (int y = 0; y < emails.size(); ++y) {
if (TextUtils.equals(emails.get(y), mOwnerEmail)) {
matches.add(i);
break;
}
}
}
if (matches.size() == 0) {
// No match was found, return false so that a record can be synthesized.
return false;
}
// Move the contacts that match owner email to the top of the list.
for (int i = 0; i < matches.size(); ++i) {
int match = matches.get(i);
ContactDetails contact = contacts.get(match);
contact.setIsSelf(true);
contacts.remove(match);
contacts.add(i, contact);
}
return true;
}
/**
* 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. Telephone number is obtained via the telephony service, if that permission has
* already been granted, otherwise left blank.
* @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)) {
ChromeSigninController controller = ChromeSigninController.get();
name = controller.getSignedInAccountName();
}
ArrayList<String> telephones = new ArrayList<>();
ContactDetails contact = new ContactDetails(ContactDetails.SELF_CONTACT_ID, name,
Collections.singletonList(ownerEmail), telephones, /*addresses=*/null);
Drawable icon = profileData.getImage();
contact.setIsSelf(true);
contact.setSelfIcon(icon);
return contact;
} }
} }
...@@ -151,7 +151,7 @@ public class PickerCategoryView extends OptimizedFrameLayout ...@@ -151,7 +151,7 @@ public class PickerCategoryView extends OptimizedFrameLayout
R.string.contacts_picker_no_contacts_found, R.string.contacts_picker_no_contacts_found,
R.string.contacts_picker_no_contacts_found); R.string.contacts_picker_no_contacts_found);
mPickerAdapter = new PickerAdapter(this, context.getContentResolver(), formattedOrigin); mPickerAdapter = new PickerAdapter(this, context, formattedOrigin);
mRecyclerView = mSelectableListLayout.initializeRecyclerView(mPickerAdapter); mRecyclerView = mSelectableListLayout.initializeRecyclerView(mPickerAdapter);
int titleId = multiSelectionAllowed ? R.string.contacts_picker_select_contacts int titleId = multiSelectionAllowed ? R.string.contacts_picker_select_contacts
: R.string.contacts_picker_select_contact; : R.string.contacts_picker_select_contact;
......
// Copyright 2019 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.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.payments.mojom.PaymentAddress;
import java.util.Arrays;
import java.util.List;
/**
* Tests for the ContactDetails class.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
public class ContactDetailsTest {
@Rule
public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
new ChromeActivityTestRule<>(ChromeActivity.class);
Context mContext;
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getInstrumentation()
.getTargetContext()
.getApplicationContext();
}
private void compareAbbreviatedContactDetails(ContactDetails.AbbreviatedContactDetails expected,
ContactDetails.AbbreviatedContactDetails actual) {
Assert.assertEquals(expected.primaryEmail, actual.primaryEmail);
Assert.assertEquals(expected.overflowEmailCount, actual.overflowEmailCount);
Assert.assertEquals(expected.primaryTelephoneNumber, actual.primaryTelephoneNumber);
Assert.assertEquals(
expected.overflowTelephoneNumberCount, actual.overflowTelephoneNumberCount);
}
@Test
@SmallTest
public void testBasics() {
PaymentAddress address1 = new PaymentAddress();
address1.city = "city";
address1.country = "country";
address1.addressLine = new String[] {"formattedAddress1"};
address1.postalCode = "postalCode";
address1.region = "region";
address1.dependentLocality = "";
address1.sortingCode = "";
address1.organization = "";
address1.recipient = "";
address1.phone = "";
PaymentAddress address2 = new PaymentAddress();
address2.city = "city";
address2.country = "country";
address2.addressLine = new String[] {"formattedAddress2"};
address2.postalCode = "postalCode";
address2.region = "region";
address2.dependentLocality = "";
address2.sortingCode = "";
address2.organization = "";
address2.recipient = "";
address2.phone = "";
ContactDetails contact = new ContactDetails("id", "Display Name",
Arrays.asList("email@example.com", "email2@example.com"),
Arrays.asList("555 123-4567", "555 765-4321"), Arrays.asList(address1, address2));
Assert.assertEquals("id", contact.getId());
Assert.assertEquals("Display Name", contact.getDisplayName());
Assert.assertEquals("DN", contact.getDisplayNameAbbreviation());
List<String> emails = contact.getEmails();
Assert.assertEquals(2, emails.size());
Assert.assertEquals("email@example.com", emails.get(0));
Assert.assertEquals("email2@example.com", emails.get(1));
List<String> telephones = contact.getPhoneNumbers();
Assert.assertEquals(2, telephones.size());
Assert.assertEquals("555 123-4567", telephones.get(0));
Assert.assertEquals("555 765-4321", telephones.get(1));
List<PaymentAddress> addresses = contact.getAddresses();
Assert.assertEquals(2, addresses.size());
Assert.assertEquals("formattedAddress1", addresses.get(0).addressLine[0]);
Assert.assertEquals("formattedAddress2", addresses.get(1).addressLine[0]);
Assert.assertEquals(false, contact.isSelf());
Assert.assertEquals(null, contact.getSelfIcon());
contact.setIsSelf(true);
Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.BLUE);
BitmapDrawable drawable = new BitmapDrawable(bitmap);
contact.setSelfIcon(drawable);
Assert.assertEquals(true, contact.isSelf());
Assert.assertTrue(null != contact.getSelfIcon());
Assert.assertEquals("", contact.getContactDetailsAsString(false, false));
Assert.assertEquals("email@example.com\nemail2@example.com",
contact.getContactDetailsAsString(true, false));
Assert.assertEquals(
"555 123-4567\n555 765-4321", contact.getContactDetailsAsString(false, true));
Resources resources = mContext.getResources();
ContactDetails.AbbreviatedContactDetails expected =
new ContactDetails.AbbreviatedContactDetails();
expected.primaryEmail = "email@example.com";
expected.overflowEmailCount = "(+ 1 more)";
expected.primaryTelephoneNumber = "555 123-4567";
expected.overflowTelephoneNumberCount = "(+ 1 more)";
// Test with full details.
ContactDetails.AbbreviatedContactDetails actual = contact.getAbbreviatedContactDetails(
/*includeEmails=*/true, /*includeTels=*/true, resources);
compareAbbreviatedContactDetails(expected, actual);
// Test with only email details.
actual = contact.getAbbreviatedContactDetails(
/*includeEmails=*/true, /*includeTels=*/false, resources);
expected.primaryTelephoneNumber = "";
expected.overflowTelephoneNumberCount = "";
compareAbbreviatedContactDetails(expected, actual);
// Test with no details.
actual = contact.getAbbreviatedContactDetails(
/*includeEmails=*/false, /*includeTels=*/false, resources);
expected.primaryEmail = "";
expected.overflowEmailCount = "";
compareAbbreviatedContactDetails(expected, actual);
// Test with only telephone details.
actual = contact.getAbbreviatedContactDetails(
/*includeEmails=*/false, /*includeTels=*/true, resources);
expected.primaryTelephoneNumber = "555 123-4567";
expected.overflowTelephoneNumberCount = "(+ 1 more)";
compareAbbreviatedContactDetails(expected, actual);
}
}
...@@ -94,34 +94,6 @@ public class ContactsPickerDialogTest ...@@ -94,34 +94,6 @@ public class ContactsPickerDialogTest
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
mActivityTestRule.startMainActivityOnBlankPage(); mActivityTestRule.startMainActivityOnBlankPage();
mTestContacts = new ArrayList<ContactDetails>();
PaymentAddress address = new PaymentAddress();
address.city = "city";
address.country = "country";
address.addressLine = new String[] {"formattedAddress"};
address.postalCode = "postalCode";
address.region = "region";
address.dependentLocality = "";
address.sortingCode = "";
address.organization = "";
address.recipient = "";
address.phone = "";
mTestContacts.add(new ContactDetails("0", "Contact 0", Arrays.asList("0@example.com"),
Arrays.asList("555-1234"), Arrays.asList(address)));
mTestContacts.add(new ContactDetails("1", "Contact 1", /*emails=*/null,
/*phoneNumbers=*/null, /*addresses=*/null));
mTestContacts.add(new ContactDetails("2", "Contact 2", /*emails=*/null,
/*phoneNumbers=*/null, /*addresses=*/null));
mTestContacts.add(new ContactDetails("3", "Contact 3", /*emails=*/null,
/*phoneNumbers=*/null, /*addresses=*/null));
mTestContacts.add(new ContactDetails("4", "Contact 4", /*emails=*/null,
/*phoneNumbers=*/null, /*addresses=*/null));
mTestContacts.add(new ContactDetails("5", "Contact 5", /*emails=*/null,
/*phoneNumbers=*/null, /*addresses=*/null));
PickerAdapter.setTestContacts(mTestContacts);
Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888); Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap); Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.BLUE); canvas.drawColor(Color.BLUE);
...@@ -206,6 +178,18 @@ public class ContactsPickerDialogTest ...@@ -206,6 +178,18 @@ public class ContactsPickerDialogTest
} }
} }
/**
* Clicks a single view in the Recyclerview in search mode.
* @param position The position of the item to click (zero-based)..
* @param expectedSelectionCount The expected selection count after the view has been clicked.
* @param expectSelection True if the clicked-on view should become selected.
*/
private void clickViewInSearchMode(final int position, final int expectedSelectionCount,
final boolean expectSelection) throws Exception {
// Search mode does not have the Select All checkbox, so we don't need to skip it.
clickView(position - 1, expectedSelectionCount, expectSelection);
}
private void clickDone() throws Exception { private void clickDone() throws Exception {
Assert.assertEquals(false, mClosing); Assert.assertEquals(false, mClosing);
mClosing = true; mClosing = true;
...@@ -269,6 +253,12 @@ public class ContactsPickerDialogTest ...@@ -269,6 +253,12 @@ public class ContactsPickerDialogTest
TestTouchUtils.performClickOnMainSync(InstrumentationRegistry.getInstrumentation(), search); TestTouchUtils.performClickOnMainSync(InstrumentationRegistry.getInstrumentation(), search);
} }
private void setSearchString(String query, int expectedMatches) {
TestThreadUtils.runOnUiThreadBlocking(
() -> mDialog.getCategoryViewForTesting().onSearchTextChanged(query));
Assert.assertEquals(expectedMatches, getRecyclerView().getAdapter().getItemCount());
}
private void dismissDialog() throws Exception { private void dismissDialog() throws Exception {
Assert.assertEquals(false, mClosing); Assert.assertEquals(false, mClosing);
mClosing = true; mClosing = true;
...@@ -288,9 +278,53 @@ public class ContactsPickerDialogTest ...@@ -288,9 +278,53 @@ public class ContactsPickerDialogTest
return (TopView) view; return (TopView) view;
} }
/**
* Sets the contacts to use during the test.
* @param ownerEmail If not null, includes a few contact entries representing owners.
*/
private void setTestContacts(String ownerEmail) {
mTestContacts = new ArrayList<ContactDetails>();
PaymentAddress address = new PaymentAddress();
address.city = "city";
address.country = "country";
address.addressLine = new String[] {"formattedAddress"};
address.postalCode = "postalCode";
address.region = "region";
address.dependentLocality = "";
address.sortingCode = "";
address.organization = "";
address.recipient = "";
address.phone = "";
mTestContacts.add(new ContactDetails("0", "Contact 0", Arrays.asList("0@example.com"),
Arrays.asList("555-1234"), Arrays.asList(address)));
mTestContacts.add(new ContactDetails("1", "Contact 1", /*emails=*/null,
/*phoneNumbers=*/null, /*addresses=*/null));
mTestContacts.add(new ContactDetails("2", "Contact 2", /*emails=*/null,
/*phoneNumbers=*/null, /*addresses=*/null));
mTestContacts.add(new ContactDetails("3", "Contact 3", /*emails=*/null,
/*phoneNumbers=*/null, /*addresses=*/null));
mTestContacts.add(new ContactDetails("4", "Contact 4", /*emails=*/null,
/*phoneNumbers=*/null, /*addresses=*/null));
mTestContacts.add(new ContactDetails("5", "Contact 5", /*emails=*/null,
/*phoneNumbers=*/null, /*addresses=*/null));
if (ownerEmail != null) {
// Note: The dialog will move Contact 6 (owner) to the top of the list.
ContactDetails owner = new ContactDetails("6", "Contact 6",
Arrays.asList("owner@example.com"), /*phoneNumbers=*/null, /*addresses=*/null);
ContactDetails owner2 = new ContactDetails("7", "Contact 7",
Arrays.asList("owner@example.com"), /*phoneNumbers=*/null, /*addresses=*/null);
mTestContacts.add(owner);
mTestContacts.add(owner2);
}
PickerAdapter.setTestContactsAndOwner(mTestContacts, ownerEmail);
}
@Test @Test
@LargeTest @LargeTest
public void testOriginString() throws Throwable { public void testOriginString() throws Throwable {
setTestContacts(/*ownerEmail=*/null);
createDialog(/* multiselect = */ true, /* includeNames = */ true, createDialog(/* multiselect = */ true, /* includeNames = */ true,
/* includeEmails = */ true, /* includeEmails = */ true,
/* includeTel = */ true, /* includeTel = */ true,
...@@ -311,6 +345,7 @@ public class ContactsPickerDialogTest ...@@ -311,6 +345,7 @@ public class ContactsPickerDialogTest
@Test @Test
@LargeTest @LargeTest
public void testFilterVisibilityForDataInclusion() throws Throwable { public void testFilterVisibilityForDataInclusion() throws Throwable {
setTestContacts(/*ownerEmail=*/null);
createDialog(/* multiselect = */ false, /* includeNames = */ true, createDialog(/* multiselect = */ false, /* includeNames = */ true,
/* includeEmails = */ false, /* includeEmails = */ false,
/* includeTel = */ true, /* includeTel = */ true,
...@@ -338,6 +373,7 @@ public class ContactsPickerDialogTest ...@@ -338,6 +373,7 @@ public class ContactsPickerDialogTest
@Test @Test
@LargeTest @LargeTest
public void testNoSelection() throws Throwable { public void testNoSelection() throws Throwable {
setTestContacts(/*ownerEmail=*/"notanowner@example.com");
createDialog(/* multiselect = */ false, /* includeNames = */ true, createDialog(/* multiselect = */ false, /* includeNames = */ true,
/* includeEmails = */ true, /* includeEmails = */ true,
/* includeTel = */ true, /* includeTel = */ true,
...@@ -354,9 +390,32 @@ public class ContactsPickerDialogTest ...@@ -354,9 +390,32 @@ public class ContactsPickerDialogTest
Assert.assertEquals(ContactsPickerAction.CANCEL, mLastActionRecorded); Assert.assertEquals(ContactsPickerAction.CANCEL, mLastActionRecorded);
} }
@Test
@LargeTest
public void testOwnerContact() throws Throwable {
setTestContacts(/*ownerEmail=*/"owner@example.com");
createDialog(/* multiselect = */ false, /* includeNames = */ true,
/* includeEmails = */ true,
/* includeTel = */ true,
/* includeAddresses = */ true);
Assert.assertTrue(mDialog.isShowing());
int expectedSelectionCount = 1;
clickView(0, expectedSelectionCount, /* expectSelection = */ true);
clickDone();
Assert.assertEquals(ContactsPickerAction.CONTACTS_SELECTED, mLastActionRecorded);
Assert.assertEquals(1, mLastSelectedContacts.size());
Assert.assertEquals(
mTestContacts.get(0).getDisplayName(), mLastSelectedContacts.get(0).names.get(0));
Assert.assertEquals(12, mLastPercentageShared);
Assert.assertEquals(15, mLastPropertiesRequested);
}
@Test @Test
@LargeTest @LargeTest
public void testSingleSelectionContacts() throws Throwable { public void testSingleSelectionContacts() throws Throwable {
setTestContacts(/*ownerEmail=*/null);
createDialog(/* multiselect = */ false, /* includeNames = */ true, createDialog(/* multiselect = */ false, /* includeNames = */ true,
/* includeEmails = */ true, /* includeEmails = */ true,
/* includeTel = */ true, /* includeTel = */ true,
...@@ -380,6 +439,7 @@ public class ContactsPickerDialogTest ...@@ -380,6 +439,7 @@ public class ContactsPickerDialogTest
@Test @Test
@LargeTest @LargeTest
public void testMultiSelectionContacts() throws Throwable { public void testMultiSelectionContacts() throws Throwable {
setTestContacts(/*ownerEmail=*/null);
createDialog(/* multiselect = */ true, /* includeNames = */ true, createDialog(/* multiselect = */ true, /* includeNames = */ true,
/* includeEmails = */ true, /* includeEmails = */ true,
/* includeTel = */ true, /* includeTel = */ true,
...@@ -408,6 +468,7 @@ public class ContactsPickerDialogTest ...@@ -408,6 +468,7 @@ public class ContactsPickerDialogTest
@Test @Test
@LargeTest @LargeTest
public void testNamesRemoved() throws Throwable { public void testNamesRemoved() throws Throwable {
setTestContacts(/*ownerEmail=*/null);
createDialog(/* multiselect = */ false, /* includeNames = */ true, createDialog(/* multiselect = */ false, /* includeNames = */ true,
/* includeEmails = */ true, /* includeEmails = */ true,
/* includeTel = */ true, /* includeTel = */ true,
...@@ -444,6 +505,7 @@ public class ContactsPickerDialogTest ...@@ -444,6 +505,7 @@ public class ContactsPickerDialogTest
@Test @Test
@LargeTest @LargeTest
public void testEmailsRemoved() throws Throwable { public void testEmailsRemoved() throws Throwable {
setTestContacts(/*ownerEmail=*/null);
createDialog(/* multiselect = */ false, /* includeNames = */ true, createDialog(/* multiselect = */ false, /* includeNames = */ true,
/* includeEmails = */ true, /* includeEmails = */ true,
/* includeTel = */ true, /* includeTel = */ true,
...@@ -468,6 +530,7 @@ public class ContactsPickerDialogTest ...@@ -468,6 +530,7 @@ public class ContactsPickerDialogTest
@Test @Test
@LargeTest @LargeTest
public void testTelephonesRemoved() throws Throwable { public void testTelephonesRemoved() throws Throwable {
setTestContacts(/*ownerEmail=*/null);
createDialog(/* multiselect = */ false, /* includeNames = */ true, createDialog(/* multiselect = */ false, /* includeNames = */ true,
/* includeEmails = */ true, /* includeEmails = */ true,
/* includeTel = */ true, /* includeTel = */ true,
...@@ -492,6 +555,7 @@ public class ContactsPickerDialogTest ...@@ -492,6 +555,7 @@ public class ContactsPickerDialogTest
@Test @Test
@LargeTest @LargeTest
public void testPropertiesRequested() throws Throwable { public void testPropertiesRequested() throws Throwable {
setTestContacts(/*ownerEmail=*/null);
// Create a dialog showing names only. // Create a dialog showing names only.
createDialog(/* multiselect = */ false, /* includeNames = */ true, createDialog(/* multiselect = */ false, /* includeNames = */ true,
/* includeEmails = */ false, /* includeEmails = */ false,
...@@ -532,19 +596,20 @@ public class ContactsPickerDialogTest ...@@ -532,19 +596,20 @@ public class ContactsPickerDialogTest
@Test @Test
@LargeTest @LargeTest
public void testSelectAll() throws Throwable { public void testSelectAll() throws Throwable {
setTestContacts(/*ownerEmail=*/"owner@example.com");
createDialog(/* multiselect = */ true, /* includeNames = */ true, createDialog(/* multiselect = */ true, /* includeNames = */ true,
/* includeEmails = */ true, /* includeEmails = */ true,
/* includeTel = */ true, /* includeTel = */ true,
/* includeAddresses = */ true); /* includeAddresses = */ true);
Assert.assertTrue(mDialog.isShowing()); Assert.assertTrue(mDialog.isShowing());
toggleSelectAll(6, ContactsPickerAction.SELECT_ALL); toggleSelectAll(8, ContactsPickerAction.SELECT_ALL);
toggleSelectAll(0, ContactsPickerAction.UNDO_SELECT_ALL); toggleSelectAll(0, ContactsPickerAction.UNDO_SELECT_ALL);
// Manually select one item. // Manually select one item.
clickView(0, /* expectedSelectionCount = */ 1, /* expectSelection = */ true); clickView(0, /* expectedSelectionCount = */ 1, /* expectSelection = */ true);
toggleSelectAll(6, ContactsPickerAction.SELECT_ALL); toggleSelectAll(8, ContactsPickerAction.SELECT_ALL);
toggleSelectAll(0, ContactsPickerAction.UNDO_SELECT_ALL); toggleSelectAll(0, ContactsPickerAction.UNDO_SELECT_ALL);
// Select the rest of the items manually. // Select the rest of the items manually.
...@@ -554,14 +619,44 @@ public class ContactsPickerDialogTest ...@@ -554,14 +619,44 @@ public class ContactsPickerDialogTest
clickView(3, ++expectedSelectionCount, /* expectSelection = */ true); clickView(3, ++expectedSelectionCount, /* expectSelection = */ true);
clickView(4, ++expectedSelectionCount, /* expectSelection = */ true); clickView(4, ++expectedSelectionCount, /* expectSelection = */ true);
clickView(5, ++expectedSelectionCount, /* expectSelection = */ true); clickView(5, ++expectedSelectionCount, /* expectSelection = */ true);
clickView(6, ++expectedSelectionCount, /* expectSelection = */ true);
clickView(7, ++expectedSelectionCount, /* expectSelection = */ true);
toggleSelectAll(6, ContactsPickerAction.SELECT_ALL); toggleSelectAll(8, ContactsPickerAction.SELECT_ALL);
toggleSelectAll(0, ContactsPickerAction.UNDO_SELECT_ALL); toggleSelectAll(0, ContactsPickerAction.UNDO_SELECT_ALL);
} }
@Test
@LargeTest
public void testSearchString() throws Throwable {
setTestContacts(/*ownerEmail=*/null);
createDialog(/* multiselect = */ false, /* includeNames = */ true,
/* includeEmails = */ true,
/* includeTel = */ true,
/* includeAddresses = */ true);
Assert.assertTrue(mDialog.isShowing());
clickSearchButton();
setSearchString("NoMatches", /*expectedMatches=*/0);
setSearchString("Contact", /*expectedMatches=*/6);
setSearchString("Contact 3", /*expectedMatches=*/1);
int expectedSelectionCount = 1;
clickViewInSearchMode(0, expectedSelectionCount, /* expectSelection = */ true);
clickDone();
Assert.assertEquals(ContactsPickerAction.CONTACTS_SELECTED, mLastActionRecorded);
Assert.assertEquals(1, mLastSelectedContacts.size());
Assert.assertEquals(
mTestContacts.get(3).getDisplayName(), mLastSelectedContacts.get(0).names.get(0));
Assert.assertEquals(16, mLastPercentageShared);
Assert.assertEquals(15, mLastPropertiesRequested);
}
@Test @Test
@LargeTest @LargeTest
public void testNoSearchStringNoCrash() throws Throwable { public void testNoSearchStringNoCrash() throws Throwable {
setTestContacts(/*ownerEmail=*/null);
createDialog(/* multiselect = */ true, /* includeNames = */ true, createDialog(/* multiselect = */ true, /* includeNames = */ true,
/* includeEmails = */ true, /* includeEmails = */ true,
/* includeTel = */ true, /* includeTel = */ true,
...@@ -575,7 +670,7 @@ public class ContactsPickerDialogTest ...@@ -575,7 +670,7 @@ public class ContactsPickerDialogTest
@Test @Test
@LargeTest @LargeTest
public void testEmptyContactListCrash() throws Throwable { public void testEmptyContactListCrash() throws Throwable {
PickerAdapter.setTestContacts(new ArrayList<ContactDetails>()); PickerAdapter.setTestContactsAndOwner(new ArrayList<ContactDetails>(), null);
createDialog(/* multiselect = */ true, /* includeNames = */ true, createDialog(/* multiselect = */ true, /* includeNames = */ true,
/* includeEmails = */ true, /* includeEmails = */ true,
......
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