Merge "Do not translate FAB downward when transitioning between tabs." into ub-contactsdialer-b-dev
diff --git a/src/com/android/contacts/common/ContactsUtils.java b/src/com/android/contacts/common/ContactsUtils.java
index 2ef68d4..c37e8f8 100644
--- a/src/com/android/contacts/common/ContactsUtils.java
+++ b/src/com/android/contacts/common/ContactsUtils.java
@@ -22,6 +22,7 @@
import android.net.Uri;
import android.os.Build;
import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.support.annotation.IntDef;
import android.provider.ContactsContract.DisplayPhoto;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
@@ -30,8 +31,13 @@
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.model.dataitem.ImDataItem;
import com.android.contacts.common.testing.NeededForTesting;
+import com.android.contacts.common.compat.ContactsCompat;
+import com.android.contacts.common.compat.DirectoryCompat;
+import com.android.contacts.common.compat.SdkSelectionUtils;
import com.android.contacts.common.model.AccountTypeManager;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
public class ContactsUtils {
@@ -46,10 +52,9 @@
private static int sThumbnailSize = -1;
- public static final boolean FLAG_N_FEATURE =
- false // Enforce Pre-N behavior in release build
- && (Build.VERSION.SDK_INT > Build.VERSION_CODES.M
- || Build.VERSION.CODENAME.startsWith("N"));
+ public static final boolean FLAG_N_FEATURE = SdkSelectionUtils.TARGET_N_SDK // build-time flag
+ && (Build.VERSION.SDK_INT > Build.VERSION_CODES.M // runtime flag
+ || Build.VERSION.CODENAME.startsWith("N")); // TODO: remove startsWith("N")
// TODO find a proper place for the canonical version of these
public interface ProviderNames {
@@ -96,6 +101,20 @@
return null;
}
+
+ public static final long USER_TYPE_CURRENT = 0;
+ public static final long USER_TYPE_WORK = 1;
+
+ /**
+ * UserType indicates the user type of the contact. If the contact is from Work User (Work
+ * Profile in Android Multi-User System), it's {@link #USER_TYPE_WORK}, otherwise,
+ * {@link #USER_TYPE_CURRENT}. Please note that current user can be in work profile, where the
+ * dialer is running inside Work Profile.
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({USER_TYPE_CURRENT, USER_TYPE_WORK})
+ public @interface UserType {}
+
/**
* Test if the given {@link CharSequence} contains any graphic characters,
* first checking {@link TextUtils#isEmpty(CharSequence)} to handle null.
@@ -223,4 +242,49 @@
}
return new Pair<>(intent, secondaryIntent);
}
+
+ /**
+ * Determine UserType from directory id and contact id.
+ *
+ * 3 types of query
+ *
+ * 1. 2 profile query: content://com.android.contacts/phone_lookup_enterprise/1234567890
+ * personal and work contact are mixed into one cursor. no directory id. contact_id indicates if
+ * it's work contact
+ *
+ * 2. work local query:
+ * content://com.android.contacts/phone_lookup_enterprise/1234567890?directory=1000000000
+ * either directory_id or contact_id is enough to identify work contact
+ *
+ * 3. work remote query:
+ * content://com.android.contacts/phone_lookup_enterprise/1234567890?directory=1000000003
+ * contact_id is random. only directory_id is available
+ *
+ * Summary: If directory_id is not null, always use directory_id to identify work contact.
+ * (which is the case here) Otherwise, use contact_id.
+ *
+ * @param directoryId directory id of ContactsProvider query
+ * @param contactId contact id
+ * @return UserType indicates the user type of the contact. A directory id or contact id larger
+ * than a thredshold indicates that the contact is stored in Work Profile, but not in
+ * current user. It's a contract by ContactsProvider and check by
+ * Contacts.isEnterpriseDirectoryId and Contacts.isEnterpriseContactId. Currently, only
+ * 2 kinds of users can be detected from the directoryId and contactId as
+ * ContactsProvider can only access current and work user's contacts
+ */
+ public static @UserType long determineUserType(Long directoryId, Long contactId) {
+ // First check directory id
+ if (directoryId != null) {
+ return DirectoryCompat.isEnterpriseDirectoryId(directoryId) ? USER_TYPE_WORK
+ : USER_TYPE_CURRENT;
+ }
+ // Only check contact id if directory id is null
+ if (contactId != null && contactId != 0L
+ && ContactsCompat.isEnterpriseContactId(contactId)) {
+ return USER_TYPE_WORK;
+ } else {
+ return USER_TYPE_CURRENT;
+ }
+
+ }
}
diff --git a/src/com/android/contacts/common/compat/CallableCompat.java b/src/com/android/contacts/common/compat/CallableCompat.java
index 2979f63..d25d4be 100644
--- a/src/com/android/contacts/common/compat/CallableCompat.java
+++ b/src/com/android/contacts/common/compat/CallableCompat.java
@@ -28,8 +28,7 @@
Uri.withAppendedPath(Callable.CONTENT_URI, "filter_enterprise");
public static Uri getContentFilterUri() {
- // TODO: Use N APIs
- if (ContactsUtils.FLAG_N_FEATURE && android.os.Build.VERSION.CODENAME.startsWith("N")) {
+ if (ContactsUtils.FLAG_N_FEATURE) {
return ENTERPRISE_CONTENT_FILTER_URI;
}
return Callable.CONTENT_FILTER_URI;
diff --git a/src/com/android/contacts/common/compat/ContactsCompat.java b/src/com/android/contacts/common/compat/ContactsCompat.java
index 5b50385..5a5e46a 100644
--- a/src/com/android/contacts/common/compat/ContactsCompat.java
+++ b/src/com/android/contacts/common/compat/ContactsCompat.java
@@ -40,8 +40,7 @@
private static final long ENTERPRISE_CONTACT_ID_BASE = 1000000000;
public static Uri getContentUri() {
- // TODO: Use N APIs
- if (ContactsUtils.FLAG_N_FEATURE && android.os.Build.VERSION.CODENAME.startsWith("N")) {
+ if (ContactsUtils.FLAG_N_FEATURE) {
return ENTERPRISE_CONTENT_FILTER_URI;
}
return Contacts.CONTENT_FILTER_URI;
diff --git a/src/com/android/contacts/common/compat/DirectoryCompat.java b/src/com/android/contacts/common/compat/DirectoryCompat.java
index 5f6d8bf..f100938 100644
--- a/src/com/android/contacts/common/compat/DirectoryCompat.java
+++ b/src/com/android/contacts/common/compat/DirectoryCompat.java
@@ -24,30 +24,31 @@
public class DirectoryCompat {
- // TODO: Use N APIs
- private static final Uri ENTERPRISE_CONTENT_URI =
- Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "directories_enterprise");
- // TODO: Use N APIs
- private static final long ENTERPRISE_LOCAL_INVISIBLE = 1000000000L + Directory.LOCAL_INVISIBLE;
-
public static Uri getContentUri() {
- // TODO: Use N APIs
- if (ContactsUtils.FLAG_N_FEATURE && android.os.Build.VERSION.CODENAME.startsWith("N")) {
- return ENTERPRISE_CONTENT_URI;
+ if (ContactsUtils.FLAG_N_FEATURE) {
+ return DirectorySdkCompat.ENTERPRISE_CONTENT_URI;
}
return Directory.CONTENT_URI;
}
public static boolean isInvisibleDirectory(long directoryId) {
- return (directoryId == Directory.LOCAL_INVISIBLE
- || directoryId == ENTERPRISE_LOCAL_INVISIBLE);
+ if (ContactsUtils.FLAG_N_FEATURE) {
+ return (directoryId == Directory.LOCAL_INVISIBLE
+ || directoryId == DirectorySdkCompat.ENTERPRISE_LOCAL_INVISIBLE);
+ }
+ return directoryId == Directory.LOCAL_INVISIBLE;
}
public static boolean isRemoteDirectory(long directoryId) {
- // TODO: Use N APIs
- if (ContactsUtils.FLAG_N_FEATURE && android.os.Build.VERSION.CODENAME.startsWith("N")) {
+ if (ContactsUtils.FLAG_N_FEATURE) {
return DirectorySdkCompat.isRemoteDirectory(directoryId);
}
return !(directoryId == Directory.DEFAULT || directoryId == Directory.LOCAL_INVISIBLE);
}
+
+ public static boolean isEnterpriseDirectoryId(long directoryId) {
+ return ContactsUtils.FLAG_N_FEATURE
+ ? DirectorySdkCompat.isEnterpriseDirectoryId(directoryId)
+ : false;
+ }
}
diff --git a/src/com/android/contacts/common/compat/PhoneCompat.java b/src/com/android/contacts/common/compat/PhoneCompat.java
index 24600f5..5277761 100644
--- a/src/com/android/contacts/common/compat/PhoneCompat.java
+++ b/src/com/android/contacts/common/compat/PhoneCompat.java
@@ -28,8 +28,7 @@
Uri.withAppendedPath(Phone.CONTENT_URI, "filter_enterprise");
public static Uri getContentFilterUri() {
- // TODO: Use N APIs
- if (ContactsUtils.FLAG_N_FEATURE && android.os.Build.VERSION.CODENAME.startsWith("N")) {
+ if (ContactsUtils.FLAG_N_FEATURE) {
return ENTERPRISE_CONTENT_FILTER_URI;
}
return Phone.CONTENT_FILTER_URI;
diff --git a/src/com/android/contacts/common/list/ContactEntryListAdapter.java b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
index 089288b..a7c3504 100644
--- a/src/com/android/contacts/common/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
@@ -418,9 +418,17 @@
DirectoryPartition partition = new DirectoryPartition(false, true);
partition.setDirectoryId(id);
if (DirectoryCompat.isRemoteDirectory(id)) {
- partition.setLabel(mContext.getString(R.string.directory_search_label));
+ if (DirectoryCompat.isEnterpriseDirectoryId(id)) {
+ partition.setLabel(mContext.getString(R.string.directory_search_label_work));
+ } else {
+ partition.setLabel(mContext.getString(R.string.directory_search_label));
+ }
} else {
- partition.setLabel(mDefaultFilterHeaderText.toString());
+ if (DirectoryCompat.isEnterpriseDirectoryId(id)) {
+ partition.setLabel(mContext.getString(R.string.list_filter_phones_work));
+ } else {
+ partition.setLabel(mDefaultFilterHeaderText.toString());
+ }
}
partition.setDirectoryType(cursor.getString(directoryTypeColumnIndex));
partition.setDisplayName(cursor.getString(displayNameColumnIndex));
diff --git a/src/com/android/contacts/common/list/ContactListItemView.java b/src/com/android/contacts/common/list/ContactListItemView.java
index bb3fbc9..90b3d60 100644
--- a/src/com/android/contacts/common/list/ContactListItemView.java
+++ b/src/com/android/contacts/common/list/ContactListItemView.java
@@ -187,6 +187,7 @@
private ImageView mPresenceIcon;
private AppCompatCheckBox mCheckBox;
private ImageView mVideoCallIcon;
+ private ImageView mWorkProfileIcon;
private ColorStateList mSecondaryTextColor;
@@ -537,6 +538,14 @@
MeasureSpec.makeMeasureSpec(mVideoCallIconSize, MeasureSpec.EXACTLY));
}
+ if (isVisible(mWorkProfileIcon)) {
+ mWorkProfileIcon.measure(
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mNameTextViewHeight =
+ Math.max(mNameTextViewHeight, mWorkProfileIcon.getMeasuredHeight());
+ }
+
if (isVisible(mStatusView)) {
// Presence and status are in a same row, so status will be affected by icon size.
final int statusWidth;
@@ -706,11 +715,32 @@
mLabelAndDataViewMaxHeight + mSnippetTextViewHeight + mStatusTextViewHeight;
int textTopBound = (bottomBound + topBound - totalTextHeight) / 2 + mTextOffsetTop;
+ // Work Profile icon align top
+ int workProfileIconWidth = 0;
+ if (isVisible(mWorkProfileIcon)) {
+ workProfileIconWidth = mWorkProfileIcon.getMeasuredWidth();
+ final int distanceFromEnd = mCheckBoxWidth > 0
+ ? mCheckBoxWidth + mGapBetweenImageAndText : 0;
+ if (mPhotoPosition == PhotoPosition.LEFT) {
+ // When photo is on left, label is placed on the right edge of the list item.
+ mWorkProfileIcon.layout(rightBound - workProfileIconWidth - distanceFromEnd,
+ textTopBound,
+ rightBound - distanceFromEnd,
+ textTopBound + mNameTextViewHeight);
+ } else {
+ // When photo is on right, label is placed on the left of data view.
+ mWorkProfileIcon.layout(leftBound + distanceFromEnd,
+ textTopBound,
+ leftBound + workProfileIconWidth + distanceFromEnd,
+ textTopBound + mNameTextViewHeight);
+ }
+ }
+
// Layout all text view and presence icon
// Put name TextView first
if (isVisible(mNameTextView)) {
- final int distanceFromEnd = mCheckBoxWidth > 0
- ? mCheckBoxWidth + mGapBetweenImageAndText : 0;
+ final int distanceFromEnd = workProfileIconWidth
+ + (mCheckBoxWidth > 0 ? mCheckBoxWidth + mGapBetweenImageAndText : 0);
if (mPhotoPosition == PhotoPosition.LEFT) {
mNameTextView.layout(leftBound,
textTopBound,
@@ -722,6 +752,9 @@
rightBound,
textTopBound + mNameTextViewHeight);
}
+ }
+
+ if (isVisible(mNameTextView) || isVisible(mWorkProfileIcon)) {
textTopBound += mNameTextViewHeight;
}
@@ -1318,6 +1351,23 @@
}
}
+ /**
+ * Set to display work profile icon or not
+ *
+ * @param enabled set to display work profile icon or not
+ */
+ public void setWorkProfileIconEnabled(boolean enabled) {
+ if (mWorkProfileIcon != null) {
+ mWorkProfileIcon.setVisibility(enabled ? View.VISIBLE : View.GONE);
+ } else if (enabled) {
+ mWorkProfileIcon = new ImageView(getContext());
+ addView(mWorkProfileIcon);
+ mWorkProfileIcon.setImageResource(R.drawable.ic_work_profile);
+ mWorkProfileIcon.setScaleType(ScaleType.CENTER_INSIDE);
+ mWorkProfileIcon.setVisibility(View.VISIBLE);
+ }
+ }
+
private TruncateAt getTextEllipsis() {
return TruncateAt.MARQUEE;
}
diff --git a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
index fc90fbf..9e886d9 100644
--- a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
+++ b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
@@ -35,6 +35,7 @@
import com.android.contacts.common.CallUtil;
import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
+import com.android.contacts.common.ContactsUtils;
import com.android.contacts.common.GeoUtil;
import com.android.contacts.common.R;
import com.android.contacts.common.compat.CallableCompat;
@@ -321,11 +322,20 @@
public Uri getDataUri(int partitionIndex, Cursor cursor) {
final long directoryId =
((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId();
- if (!DirectoryCompat.isRemoteDirectory(directoryId)) {
+ if (DirectoryCompat.isRemoteDirectory(directoryId)) {
+ return null;
+ } else if (DirectoryCompat.isEnterpriseDirectoryId(directoryId)) {
+ /*
+ * ContentUris.withAppendedId(Data.CONTENT_URI, phoneId), is invalid if
+ * isEnterpriseDirectoryId returns true, because the uri itself will fail since the
+ * ContactsProvider in Android Framework currently doesn't support it. return null until
+ * Android framework has enterprise version of Data.CONTENT_URI
+ */
+ return null;
+ } else {
final long phoneId = cursor.getLong(PhoneQuery.PHONE_ID);
return ContentUris.withAppendedId(Data.CONTENT_URI, phoneId);
}
- return null;
}
/**
@@ -427,6 +437,7 @@
view.removePhotoView(true, false);
}
+ bindWorkProfileIcon(view, partition);
final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
bindPhoneNumber(view, cursor, directory.isDisplayNumber(), position);
@@ -485,6 +496,13 @@
view.hideDisplayName();
}
+ private void bindWorkProfileIcon(final ContactListItemView view, int partition) {
+ final DirectoryPartition directory = (DirectoryPartition) getPartition(partition);
+ final long directoryId = directory.getDirectoryId();
+ final long userType = ContactsUtils.determineUserType(directoryId, null);
+ view.setWorkProfileIconEnabled(userType == ContactsUtils.USER_TYPE_WORK);
+ }
+
protected void bindPhoto(final ContactListItemView view, int partitionIndex, Cursor cursor) {
if (!isPhotoSupported(partitionIndex)) {
view.removePhotoView();