Merge "Bag o' QC UX improvements"
diff --git a/src/com/android/contacts/quickcontact/Action.java b/src/com/android/contacts/quickcontact/Action.java
index fa23286..7d904ab 100644
--- a/src/com/android/contacts/quickcontact/Action.java
+++ b/src/com/android/contacts/quickcontact/Action.java
@@ -45,7 +45,10 @@
public Intent getAlternateIntent();
/** Checks if the contact data for this action is primary. */
- public Boolean isPrimary();
+ public boolean isPrimary();
+
+ /** Checks if the contact data for this action is super primary. */
+ public boolean isSuperPrimary();
/**
* Returns a lookup (@link Uri) for the contact data item or null if there is no data item
@@ -61,4 +64,14 @@
/** Returns the presence of this item or -1 if it was never set */
public int getPresence();
+
+ /**
+ * Returns the number of times this action has been used.
+ */
+ public Integer getTimesUsed();
+
+ /**
+ * Returns the last time this action was used.
+ */
+ public Long getLastTimeUsed();
}
diff --git a/src/com/android/contacts/quickcontact/DataAction.java b/src/com/android/contacts/quickcontact/DataAction.java
index e29b3ef..a0df1e6 100644
--- a/src/com/android/contacts/quickcontact/DataAction.java
+++ b/src/com/android/contacts/quickcontact/DataAction.java
@@ -29,9 +29,9 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.contacts.R;
import com.android.contacts.common.CallUtil;
import com.android.contacts.common.ContactsUtils;
-import com.android.contacts.R;
import com.android.contacts.common.MoreContactUtils;
import com.android.contacts.common.model.account.AccountType.EditType;
import com.android.contacts.common.model.dataitem.DataItem;
@@ -55,6 +55,8 @@
private final Context mContext;
private final DataKind mKind;
private final String mMimeType;
+ private final Integer mTimesUsed;
+ private final Long mLastTimeUsed;
private CharSequence mBody;
private CharSequence mSubtitle;
@@ -67,6 +69,7 @@
private Uri mDataUri;
private long mDataId;
private boolean mIsPrimary;
+ private boolean mIsSuperPrimary;
/**
* Create an action from common {@link Data} elements.
@@ -75,6 +78,8 @@
mContext = context;
mKind = kind;
mMimeType = item.getMimeType();
+ mTimesUsed = item.getTimesUsed();
+ mLastTimeUsed = item.getLastTimeUsed();
// Determine type for subtitle
mSubtitle = "";
@@ -96,7 +101,8 @@
}
}
- mIsPrimary = item.isSuperPrimary();
+ mIsPrimary = item.isPrimary();
+ mIsSuperPrimary = item.isSuperPrimary();
mBody = item.buildDataStringForDisplay(context, kind);
mDataId = item.getId();
@@ -265,11 +271,16 @@
}
@Override
- public Boolean isPrimary() {
+ public boolean isPrimary() {
return mIsPrimary;
}
@Override
+ public boolean isSuperPrimary() {
+ return mIsSuperPrimary;
+ }
+
+ @Override
public Drawable getAlternateIcon() {
if (mAlternateIconRes == 0) return null;
@@ -322,4 +333,14 @@
}
return true;
}
+
+ @Override
+ public Integer getTimesUsed() {
+ return mTimesUsed;
+ }
+
+ @Override
+ public Long getLastTimeUsed() {
+ return mLastTimeUsed;
+ }
}
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 1453ff4..c222aff 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -528,7 +528,6 @@
Trace.endSection();
- final List<String> sortedActionMimeTypes = Lists.newArrayList();
// Maintain a list of phone numbers to pass into SmsInteractionsLoader
final Set<String> phoneNumbers = new HashSet<>();
// Maintain a list of email addresses to pass into CalendarInteractionsLoader
@@ -539,8 +538,7 @@
mEntriesAndActionsTask = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
- computeEntriesAndActions(data, phoneNumbers, emailAddresses,
- sortedActionMimeTypes, entries);
+ computeEntriesAndActions(data, phoneNumbers, emailAddresses, entries);
return null;
}
@@ -551,8 +549,7 @@
// is still running before binding to UI. A new intent could invalidate
// the results, for example.
if (data == mContactData && !isCancelled()) {
- bindEntriesAndActions(entries, phoneNumbers, emailAddresses,
- sortedActionMimeTypes);
+ bindEntriesAndActions(entries, phoneNumbers, emailAddresses);
showActivity();
}
}
@@ -562,8 +559,7 @@
private void bindEntriesAndActions(List<Entry> entries,
Set<String> phoneNumbers,
- Set<String> emailAddresses,
- List<String> sortedActionMimeTypes) {
+ Set<String> emailAddresses) {
Trace.beginSection("start sms loader");
final Bundle phonesExtraBundle = new Bundle();
phonesExtraBundle.putStringArray(KEY_LOADER_EXTRA_PHONES,
@@ -598,7 +594,7 @@
/* isExpanded = */ false);
}
- final boolean hasData = !sortedActionMimeTypes.isEmpty();
+ final boolean hasData = !entries.isEmpty();
mCommunicationCard.setVisibility(hasData ? View.VISIBLE : View.GONE);
Trace.endSection();
@@ -618,7 +614,7 @@
}
private void computeEntriesAndActions(Contact data, Set<String> phoneNumbers,
- Set<String> emailAddresses, List<String> sortedActionMimeTypes, List<Entry> entries) {
+ Set<String> emailAddresses, List<Entry> entries) {
Trace.beginSection("inflate entries and actions");
final ResolveCache cache = ResolveCache.getInstance(this);
@@ -685,35 +681,85 @@
Trace.endSection();
Trace.beginSection("sort mimetypes");
- // All the mime-types to add.
- final Set<String> containedTypes = new HashSet<String>(mActions.keySet());
- // First, add LEADING_MIMETYPES, which are most common.
- for (String mimeType : LEADING_MIMETYPES) {
- if (containedTypes.contains(mimeType)) {
- sortedActionMimeTypes.add(mimeType);
- containedTypes.remove(mimeType);
- entries.addAll(actionsToEntries(mActions.get(mimeType)));
- }
+ /*
+ * Sorting is a multi part step. The end result is to a have a sorted list of the most
+ * used actions, one per mimetype. Then, within each mimetype, the list of actions for that
+ * type is also sorted, based off of {super primary, primary, times used} in that order.
+ */
+ final List<Action> topActions = new ArrayList<>();
+ for (List<Action> mimeTypeActions : mActions.values()) {
+ Collections.sort(mimeTypeActions, new Comparator<Action>() {
+ @Override
+ public int compare(Action lhs, Action rhs) {
+ /*
+ * Actions are compared to the same mimetype based off of three qualities:
+ * 1. Super primary
+ * 2. Primary
+ * 3. Times used
+ */
+ if (lhs.isSuperPrimary()) {
+ return -1;
+ } else if (rhs.isSuperPrimary()) {
+ return 1;
+ } else if (lhs.isPrimary() && !rhs.isPrimary()) {
+ return -1;
+ } else if (!lhs.isPrimary() && rhs.isPrimary()) {
+ return 1;
+ } else {
+ int lhsTimesUsed = lhs.getTimesUsed() == null ? 0 : lhs.getTimesUsed();
+ int rhsTimesUsed = rhs.getTimesUsed() == null ? 0 : rhs.getTimesUsed();
+
+ return rhsTimesUsed - lhsTimesUsed;
+ }
+ }
+ });
+ topActions.add(mimeTypeActions.get(0));
}
- // Add all the remaining ones that are not TRAILING
- for (String mimeType : containedTypes.toArray(new String[containedTypes.size()])) {
- if (!TRAILING_MIMETYPES.contains(mimeType)) {
- sortedActionMimeTypes.add(mimeType);
- containedTypes.remove(mimeType);
- entries.addAll(actionsToEntries(mActions.get(mimeType)));
- }
- }
+ // topActions now contains the top action for each mimetype. This list now needs to be
+ // sorted, based off of {times used, last used, statically defined} in that order.
+ Collections.sort(topActions, new Comparator<Action>() {
+ @Override
+ public int compare(Action lhs, Action rhs) {
+ int lhsTimesUsed = lhs.getTimesUsed() == null ? 0 : lhs.getTimesUsed();
+ int rhsTimesUsed = rhs.getTimesUsed() == null ? 0 : rhs.getTimesUsed();
+ int timesUsedDifference = rhsTimesUsed - lhsTimesUsed;
+ if (timesUsedDifference != 0) {
+ return timesUsedDifference;
+ }
- // Then, add TRAILING_MIMETYPES, which are least common.
- for (String mimeType : TRAILING_MIMETYPES) {
- if (containedTypes.contains(mimeType)) {
- containedTypes.remove(mimeType);
- sortedActionMimeTypes.add(mimeType);
- entries.addAll(actionsToEntries(mActions.get(mimeType)));
- }
- }
+ long lhsLastTimeUsed = lhs.getLastTimeUsed() == null ? 0 : lhs.getLastTimeUsed();
+ long rhsLastTimeUsed = rhs.getLastTimeUsed() == null ? 0 : rhs.getLastTimeUsed();
+ long lastTimeUsedDifference = rhsLastTimeUsed - lhsLastTimeUsed;
+ if (lastTimeUsedDifference > 0) {
+ return 1;
+ } else if (lastTimeUsedDifference < 0) {
+ return -1;
+ }
+ // Times used and last time used are the same. Resort to statically defined.
+ String lhsMimeType = lhs.getMimeType();
+ String rhsMimeType = rhs.getMimeType();
+ for (String mimeType : LEADING_MIMETYPES) {
+ if (lhsMimeType.equals(mimeType)) {
+ return -1;
+ } else if (rhsMimeType.equals(mimeType)) {
+ return 1;
+ }
+ }
+ // Trailing types come last, so flip the returns
+ for (String mimeType : TRAILING_MIMETYPES) {
+ if (lhsMimeType.equals(mimeType)) {
+ return 1;
+ } else if (rhsMimeType.equals(mimeType)) {
+ return -1;
+ }
+ }
+ return 0;
+ }
+ });
+
+ entries.addAll(actionsToEntries(topActions));
Trace.endSection();
}