diff options
author | Milos Stankovic <miloss@google.com> | 2014-09-05 09:57:18 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-09-05 09:57:19 +0000 |
commit | b92e65bd06b95988b553b3f426b4a36e2acab07f (patch) | |
tree | df6abefe42bd577b11e790afebc241603d67d41b | |
parent | e6a52d616cf1138ba68b1d59e44ee2ef06008f68 (diff) | |
parent | 72243803ed432837e6750535d7d0ea2fd14e3d2e (diff) | |
download | android_packages_apps_UnifiedEmail-b92e65bd06b95988b553b3f426b4a36e2acab07f.tar.gz android_packages_apps_UnifiedEmail-b92e65bd06b95988b553b3f426b4a36e2acab07f.tar.bz2 android_packages_apps_UnifiedEmail-b92e65bd06b95988b553b3f426b4a36e2acab07f.zip |
Merge "Creating RankedComparator and using it to sort accounts." into ub-gmail-ur14-dev
-rw-r--r-- | src/com/android/mail/providers/MailAppProvider.java | 34 | ||||
-rw-r--r-- | src/com/android/mail/utils/RankedComparator.java | 75 | ||||
-rw-r--r-- | tests/src/com/android/mail/utils/RankedComparatorTest.java | 100 |
3 files changed, 206 insertions, 3 deletions
diff --git a/src/com/android/mail/providers/MailAppProvider.java b/src/com/android/mail/providers/MailAppProvider.java index 92fe62a35..9aec3290f 100644 --- a/src/com/android/mail/providers/MailAppProvider.java +++ b/src/com/android/mail/providers/MailAppProvider.java @@ -38,7 +38,10 @@ import com.android.mail.providers.UIProvider.AccountCursorExtraKeys; import com.android.mail.utils.LogTag; import com.android.mail.utils.LogUtils; import com.android.mail.utils.MatrixCursorWithExtra; +import com.android.mail.utils.RankedComparator; +import com.google.android.mail.common.base.Function; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -46,6 +49,8 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import java.util.Collections; +import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -89,6 +94,13 @@ public abstract class MailAppProvider extends ContentProvider private final Map<CursorLoader, Boolean> mAccountsLoaded = Maps.newHashMap(); private ContentResolver mResolver; + + /** + * Compares {@link AccountCacheEntry} based on the position of the + * {@link AccountCacheEntry#mAccountsQueryUri} in {@code R.array.account_providers}. + */ + private Comparator<AccountCacheEntry> mAccountComparator; + private static String sAuthority; private static MailAppProvider sInstance; @@ -146,6 +158,19 @@ public abstract class MailAppProvider extends ContentProvider // Load the uris for the account list final String[] accountQueryUris = res.getStringArray(R.array.account_providers); + final Function<AccountCacheEntry, String> accountQueryUriExtractor = + new Function<AccountCacheEntry, String>() { + @Override + public String apply(AccountCacheEntry accountCacheEntry) { + if (accountCacheEntry == null) { + return null; + } + return accountCacheEntry.mAccountsQueryUri.toString(); + } + }; + mAccountComparator = new RankedComparator<AccountCacheEntry, String>( + accountQueryUris, accountQueryUriExtractor); + for (String accountQueryUri : accountQueryUris) { final Uri uri = Uri.parse(accountQueryUri); addAccountsForUriAsync(uri); @@ -176,12 +201,16 @@ public abstract class MailAppProvider extends ContentProvider final Bundle extras = new Bundle(); extras.putInt(AccountCursorExtraKeys.ACCOUNTS_LOADED, allAccountsLoaded() ? 1 : 0); - // Make a copy of the account cache final List<AccountCacheEntry> accountList; synchronized (mAccountCache) { - accountList = ImmutableList.copyOf(mAccountCache.values()); + accountList = Lists.newArrayList(mAccountCache.values()); } + // The order in which providers respond will affect the order of accounts. Because + // mAccountComparator only compares mAccountsQueryUri it will ensure that they are always + // sorted first based on that and later based on order returned by each provider. + Collections.sort(accountList, mAccountComparator); + final MatrixCursor cursor = new MatrixCursorWithExtra(resultProjection, accountList.size(), extras); @@ -536,6 +565,5 @@ public abstract class MailAppProvider extends ContentProvider throw new IllegalArgumentException(e); } } - } } diff --git a/src/com/android/mail/utils/RankedComparator.java b/src/com/android/mail/utils/RankedComparator.java new file mode 100644 index 000000000..2fc15584f --- /dev/null +++ b/src/com/android/mail/utils/RankedComparator.java @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2014 Google Inc. + * Licensed to The Android Open Source Project. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.mail.utils; + +import com.google.android.mail.common.base.Function; +import com.google.common.collect.ImmutableMap; + +import java.util.Comparator; +import java.util.Map; + +/** + * Compares objects of the type {@code T} based on predefined order of the ranks of the type + * {@code K}. The ranks that are not in the predefined order will be considered larger than other + * ranks (if this comparator is used for sorting those elements will be at the end). + * + * @param <T> Type to be compared. + * @param <K> Type of the ranks used for comparison. + */ +public class RankedComparator<T, K> implements Comparator<T> { + + private final Map<K, Integer> mRankOrder; + + private final Function<T, K> mRankExtractorFunction; + + /** + * Creates a comparator that compares objects of type {@code T} by extracting the ranks of the + * objects using {@code rankExtractorFunction} and comparing them by their position in + * {@code rankOrder}. Ranks not present in {@code rankOrder} are considered larger than the + * ranks present in the {@code rankOrder}. + * + * @param rankOrder Order of the ranks. + * @param rankExtractorFunction Function that extracts rank from the object. + */ + public RankedComparator(K[] rankOrder, Function<T, K> rankExtractorFunction) { + final ImmutableMap.Builder<K, Integer> orderBuilder = ImmutableMap.builder(); + for (int i = 0; i < rankOrder.length; i++) { + orderBuilder.put(rankOrder[i], i); + } + mRankOrder = orderBuilder.build(); + + mRankExtractorFunction = rankExtractorFunction; + } + + private int getOrder(T object) { + final K key = mRankExtractorFunction.apply(object); + + if (mRankOrder.containsKey(key)) { + return mRankOrder.get(key); + } + return Integer.MAX_VALUE; + } + + @Override + public int compare(T lhs, T rhs) { + final int orderLhs = getOrder(lhs); + final int orderRhs = getOrder(rhs); + // Order can be Integer.MAX_VALUE so subtraction should not be used. + return orderLhs < orderRhs ? -1 : (orderLhs == orderRhs ? 0 : 1); + } +} diff --git a/tests/src/com/android/mail/utils/RankedComparatorTest.java b/tests/src/com/android/mail/utils/RankedComparatorTest.java new file mode 100644 index 000000000..85e5cd008 --- /dev/null +++ b/tests/src/com/android/mail/utils/RankedComparatorTest.java @@ -0,0 +1,100 @@ +/** + * Copyright (C) 2014 Google Inc. + * Licensed to The Android Open Source Project. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.mail.utils; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.google.android.mail.common.base.Function; + +@SmallTest +public class RankedComparatorTest extends AndroidTestCase { + + private static final String RANK1 = "rank1"; + private static final String RANK2 = "rank2"; + private static final String[] RANKS = new String[]{RANK1, RANK2}; + private static final String UNKNOWN_RANK1 = "unknown_rank_1"; + private static final String UNKNOWN_RANK2 = "unknown_rank_2"; + private static final String NULL_RANK = null; + + private RankedComparator<DummyObject, String> comparator; + + @Override + protected void setUp() throws Exception { + super.setUp(); + comparator = + new RankedComparator<DummyObject, String>(RANKS, DUMMY_OBJECT_TO_RANK_FUNCTION); + } + + public void testSimple() { + DummyObject rank1_1 = new DummyObject(RANK1); + DummyObject rank1_2 = new DummyObject(RANK1); + DummyObject rank2 = new DummyObject(RANK2); + + assertTrue("Same object should be equal to itself.", + comparator.compare(rank1_1, rank1_1) == 0); + assertTrue("Different objects with same rank should be equal.", + comparator.compare(rank1_1, rank1_2) == 0); + + // Testing different ranks and with different order of the parameters + assertTrue(comparator.compare(rank1_1, rank2) < 0); + assertTrue(comparator.compare(rank2, rank1_1) > 0); + } + + public void testUnknownRank() { + DummyObject knownRank = new DummyObject(RANK1); + DummyObject unknownRank1 = new DummyObject(UNKNOWN_RANK1); + DummyObject unknownRank2 = new DummyObject(UNKNOWN_RANK2); + + assertTrue("Known rank should be smaller than unknown rank.", + comparator.compare(knownRank, unknownRank1) < 0); + assertTrue("Unknown rank should be larger than known rank.", + comparator.compare(unknownRank1, knownRank) > 0); + assertTrue("Two different unknown ranks should be equal.", + comparator.compare(unknownRank1, unknownRank2) == 0); + } + + public void testNullRank() { + DummyObject knownRank = new DummyObject(RANK1); + DummyObject unknownRank = new DummyObject(UNKNOWN_RANK1); + DummyObject nullRank = new DummyObject(NULL_RANK); + + assertTrue("Known rank should be smaller than null rank.", + comparator.compare(knownRank, nullRank) < 0); + assertTrue("null rank should be larger than known rank.", + comparator.compare(nullRank, knownRank) > 0); + assertTrue("Unknown and null rank should be equal.", + comparator.compare(unknownRank, nullRank) == 0); + } + + private static final Function<DummyObject, String> DUMMY_OBJECT_TO_RANK_FUNCTION = + new Function<DummyObject, String>() { + @Override + public String apply(DummyObject dummyObject) { + return dummyObject.rank; + } + }; + + private class DummyObject { + private final String rank; + + private DummyObject(String rank) { + this.rank = rank; + } + } +} |