Merge "Don't upsize non-square pictures, even when cropping"
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index 32928ba..f451b2c 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -18,6 +18,7 @@
 
 import com.android.common.content.SyncStateContentProviderHelper;
 import com.android.providers.contacts.ContactsDatabaseHelper.DbProperties;
+import com.android.providers.contacts.aggregation.util.CommonNicknameCache;
 import com.android.providers.contacts.util.NeededForTesting;
 import com.google.android.collect.Sets;
 
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 6de16df..7473718 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -48,6 +48,7 @@
 import com.android.providers.contacts.SearchIndexManager.FtsQueryBuilder;
 import com.android.providers.contacts.aggregation.ContactAggregator;
 import com.android.providers.contacts.aggregation.ContactAggregator.AggregationSuggestionParameter;
+import com.android.providers.contacts.aggregation.util.CommonNicknameCache;
 import com.android.providers.contacts.aggregation.ProfileAggregator;
 import com.android.providers.contacts.util.DbQueryUtils;
 import com.android.providers.contacts.util.NeededForTesting;
@@ -57,6 +58,7 @@
 import com.google.android.collect.Maps;
 import com.google.android.collect.Sets;
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
@@ -5253,9 +5255,8 @@
             }
 
             case STREAM_ITEMS_LIMIT: {
-                MatrixCursor cursor = new MatrixCursor(new String[]{StreamItems.MAX_ITEMS}, 1);
-                cursor.addRow(new Object[]{MAX_STREAM_ITEMS_PER_RAW_CONTACT});
-                return cursor;
+                return buildSingleRowResult(projection, new String[] {StreamItems.MAX_ITEMS},
+                        new Object[] {MAX_STREAM_ITEMS_PER_RAW_CONTACT});
             }
 
             case STREAM_ITEMS_PHOTOS: {
@@ -5283,11 +5284,9 @@
             }
 
             case PHOTO_DIMENSIONS: {
-                MatrixCursor cursor = new MatrixCursor(
-                        new String[]{DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM},
-                        1);
-                cursor.addRow(new Object[]{mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim});
-                return cursor;
+                return buildSingleRowResult(projection,
+                        new String[] {DisplayPhoto.DISPLAY_MAX_DIM, DisplayPhoto.THUMBNAIL_MAX_DIM},
+                        new Object[] {mMaxDisplayPhotoDim, mMaxThumbnailPhotoDim});
             }
 
             case PHONES:
@@ -5848,7 +5847,9 @@
             }
 
             case PROVIDER_STATUS: {
-                return queryProviderStatus(uri, projection);
+                return buildSingleRowResult(projection,
+                        new String[] {ProviderStatus.STATUS, ProviderStatus.DATA1},
+                        new Object[] {mProviderStatus, mEstimatedStorageRequirement});
             }
 
             case DIRECTORIES : {
@@ -5908,21 +5909,6 @@
         return c;
     }
 
-    /**
-     * Creates a single-row cursor containing the current status of the provider.
-     */
-    private Cursor queryProviderStatus(Uri uri, String[] projection) {
-        MatrixCursor cursor = new MatrixCursor(projection);
-        RowBuilder row = cursor.newRow();
-        for (int i = 0; i < projection.length; i++) {
-            if (ProviderStatus.STATUS.equals(projection[i])) {
-                row.add(mProviderStatus);
-            } else if (ProviderStatus.DATA1.equals(projection[i])) {
-                row.add(mEstimatedStorageRequirement);
-            }
-        }
-        return cursor;
-    }
 
     /**
      * Runs the query with the supplied contact ID and lookup ID.  If the query succeeds,
@@ -8131,6 +8117,39 @@
     }
 
     /**
+     * Create a single row cursor for a simple, informational queries, such as
+     * {@link ProviderStatus#CONTENT_URI}.
+     */
+    @VisibleForTesting
+    static Cursor buildSingleRowResult(String[] projection, String[] availableColumns,
+            Object[] data) {
+        Preconditions.checkArgument(availableColumns.length == data.length);
+        if (projection == null) {
+            projection = availableColumns;
+        }
+        final MatrixCursor c = new MatrixCursor(projection, 1);
+        final RowBuilder row = c.newRow();
+
+        // It's O(n^2), but it's okay because we only have a few columns.
+        for (int i = 0; i < c.getColumnCount(); i++) {
+            final String column = c.getColumnName(i);
+
+            boolean found = false;
+            for (int j = 0; j < availableColumns.length; j++) {
+                if (availableColumns[j].equals(column)) {
+                    row.add(data[j]);
+                    found = true;
+                    break;
+                }
+            }
+            if (!found) {
+                throw new IllegalArgumentException("Invalid column " + projection[i]);
+            }
+        }
+        return c;
+    }
+
+    /**
      * @return the currently active {@link ContactsDatabaseHelper} for the current thread.
      */
     @NeededForTesting
diff --git a/src/com/android/providers/contacts/NameNormalizer.java b/src/com/android/providers/contacts/NameNormalizer.java
index 2ac3865..d91bd7c 100644
--- a/src/com/android/providers/contacts/NameNormalizer.java
+++ b/src/com/android/providers/contacts/NameNormalizer.java
@@ -15,6 +15,8 @@
  */
 package com.android.providers.contacts;
 
+import com.android.providers.contacts.util.Hex;
+
 import java.util.Locale;
 import java.text.Collator;
 import java.text.CollationKey;
diff --git a/src/com/android/providers/contacts/aggregation/ContactAggregator.java b/src/com/android/providers/contacts/aggregation/ContactAggregator.java
index a235ce2..60eba95 100644
--- a/src/com/android/providers/contacts/aggregation/ContactAggregator.java
+++ b/src/com/android/providers/contacts/aggregation/ContactAggregator.java
@@ -16,10 +16,7 @@
 
 package com.android.providers.contacts.aggregation;
 
-import com.android.providers.contacts.CommonNicknameCache;
 import com.android.providers.contacts.ContactLookupKey;
-import com.android.providers.contacts.ContactMatcher;
-import com.android.providers.contacts.ContactMatcher.MatchScore;
 import com.android.providers.contacts.ContactsDatabaseHelper;
 import com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns;
 import com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns;
@@ -33,6 +30,9 @@
 import com.android.providers.contacts.ContactsDatabaseHelper.StatusUpdatesColumns;
 import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
 import com.android.providers.contacts.ContactsDatabaseHelper.Views;
+import com.android.providers.contacts.aggregation.util.CommonNicknameCache;
+import com.android.providers.contacts.aggregation.util.ContactMatcher;
+import com.android.providers.contacts.aggregation.util.ContactMatcher.MatchScore;
 import com.android.providers.contacts.ContactsProvider2;
 import com.android.providers.contacts.NameLookupBuilder;
 import com.android.providers.contacts.NameNormalizer;
diff --git a/src/com/android/providers/contacts/aggregation/ProfileAggregator.java b/src/com/android/providers/contacts/aggregation/ProfileAggregator.java
index 6126184..fedf5fe 100644
--- a/src/com/android/providers/contacts/aggregation/ProfileAggregator.java
+++ b/src/com/android/providers/contacts/aggregation/ProfileAggregator.java
@@ -20,10 +20,10 @@
 import android.database.sqlite.SQLiteStatement;
 import android.provider.ContactsContract.Contacts;
 
-import com.android.providers.contacts.CommonNicknameCache;
 import com.android.providers.contacts.ContactLookupKey;
 import com.android.providers.contacts.ContactsDatabaseHelper;
 import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
+import com.android.providers.contacts.aggregation.util.CommonNicknameCache;
 import com.android.providers.contacts.ContactsProvider2;
 import com.android.providers.contacts.NameSplitter;
 import com.android.providers.contacts.PhotoPriorityResolver;
diff --git a/src/com/android/providers/contacts/CommonNicknameCache.java b/src/com/android/providers/contacts/aggregation/util/CommonNicknameCache.java
similarity index 98%
rename from src/com/android/providers/contacts/CommonNicknameCache.java
rename to src/com/android/providers/contacts/aggregation/util/CommonNicknameCache.java
index e1dfae3..d6b799f 100644
--- a/src/com/android/providers/contacts/CommonNicknameCache.java
+++ b/src/com/android/providers/contacts/aggregation/util/CommonNicknameCache.java
@@ -14,7 +14,7 @@
  * limitations under the License
  */
 
-package com.android.providers.contacts;
+package com.android.providers.contacts.aggregation.util;
 
 import com.android.providers.contacts.ContactsDatabaseHelper.NicknameLookupColumns;
 import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
diff --git a/src/com/android/providers/contacts/ContactMatcher.java b/src/com/android/providers/contacts/aggregation/util/ContactMatcher.java
similarity index 99%
rename from src/com/android/providers/contacts/ContactMatcher.java
rename to src/com/android/providers/contacts/aggregation/util/ContactMatcher.java
index e8f4aa5..60e41ab 100644
--- a/src/com/android/providers/contacts/ContactMatcher.java
+++ b/src/com/android/providers/contacts/aggregation/util/ContactMatcher.java
@@ -13,9 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
-package com.android.providers.contacts;
+package com.android.providers.contacts.aggregation.util;
 
 import com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType;
+import com.android.providers.contacts.util.Hex;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/src/com/android/providers/contacts/NameDistance.java b/src/com/android/providers/contacts/aggregation/util/NameDistance.java
similarity index 98%
rename from src/com/android/providers/contacts/NameDistance.java
rename to src/com/android/providers/contacts/aggregation/util/NameDistance.java
index d685ba8..e357ec1 100644
--- a/src/com/android/providers/contacts/NameDistance.java
+++ b/src/com/android/providers/contacts/aggregation/util/NameDistance.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
-package com.android.providers.contacts;
+package com.android.providers.contacts.aggregation.util;
 
 import java.util.Arrays;
 
diff --git a/src/com/android/providers/contacts/Hex.java b/src/com/android/providers/contacts/util/Hex.java
similarity index 98%
rename from src/com/android/providers/contacts/Hex.java
rename to src/com/android/providers/contacts/util/Hex.java
index 090764a..ad26f4b 100644
--- a/src/com/android/providers/contacts/Hex.java
+++ b/src/com/android/providers/contacts/util/Hex.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License
  */
-package com.android.providers.contacts;
+package com.android.providers.contacts.util;
 
 /**
  * Basic hex operations: from byte array to string and vice versa.
diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
index b3b3c28..45c360e 100644
--- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java
@@ -18,6 +18,7 @@
 
 import static com.android.providers.contacts.ContactsActor.PACKAGE_GREY;
 
+import com.android.providers.contacts.util.Hex;
 import com.google.android.collect.Sets;
 
 import android.accounts.Account;
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index bef077c..c7f7dcb 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -6393,6 +6393,53 @@
         cursor.close();
     }
 
+    public void testBuildSingleRowResult() {
+        checkBuildSingleRowResult(
+                new String[] {"b"},
+                new String[] {"a", "b"},
+                new Integer[] {1, 2},
+                new Integer[] {2}
+                );
+
+        checkBuildSingleRowResult(
+                new String[] {"b", "a", "b"},
+                new String[] {"a", "b"},
+                new Integer[] {1, 2},
+                new Integer[] {2, 1, 2}
+                );
+
+        checkBuildSingleRowResult(
+                null, // all columns
+                new String[] {"a", "b"},
+                new Integer[] {1, 2},
+                new Integer[] {1, 2}
+                );
+
+        try {
+            // Access non-existent column
+            ContactsProvider2.buildSingleRowResult(new String[] {"a"}, new String[] {"b"},
+                    new Object[] {1});
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    private void checkBuildSingleRowResult(String[] projection, String[] availableColumns,
+            Object[] data, Integer[] expectedValues) {
+        final Cursor c = ContactsProvider2.buildSingleRowResult(projection, availableColumns, data);
+        try {
+            assertTrue(c.moveToFirst());
+            assertEquals(1, c.getCount());
+            assertEquals(expectedValues.length, c.getColumnCount());
+
+            for (int i = 0; i < expectedValues.length; i++) {
+                assertEquals("column " + i, expectedValues[i], (Integer) c.getInt(i));
+            }
+        } finally {
+            c.close();
+        }
+    }
+
     private Cursor queryGroupMemberships(Account account) {
         Cursor c = mResolver.query(maybeAddAccountQueryParameters(Data.CONTENT_URI, account),
                 new String[]{GroupMembership.GROUP_ROW_ID, GroupMembership.RAW_CONTACT_ID},
diff --git a/tests/src/com/android/providers/contacts/PhotoStoreTest.java b/tests/src/com/android/providers/contacts/PhotoStoreTest.java
index 3a1e713..02b3568 100644
--- a/tests/src/com/android/providers/contacts/PhotoStoreTest.java
+++ b/tests/src/com/android/providers/contacts/PhotoStoreTest.java
@@ -18,6 +18,7 @@
 
 import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
 import com.android.providers.contacts.tests.R;
+import com.android.providers.contacts.util.Hex;
 
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
diff --git a/tests/src/com/android/providers/contacts/NameDistanceTest.java b/tests/src/com/android/providers/contacts/aggregation/util/NameDistanceTest.java
similarity index 90%
rename from tests/src/com/android/providers/contacts/NameDistanceTest.java
rename to tests/src/com/android/providers/contacts/aggregation/util/NameDistanceTest.java
index 45d5eda..7f9f053 100644
--- a/tests/src/com/android/providers/contacts/NameDistanceTest.java
+++ b/tests/src/com/android/providers/contacts/aggregation/util/NameDistanceTest.java
@@ -14,7 +14,11 @@
  * limitations under the License
  */
 
-package com.android.providers.contacts;
+package com.android.providers.contacts.aggregation.util;
+
+import com.android.providers.contacts.NameNormalizer;
+import com.android.providers.contacts.aggregation.util.NameDistance;
+import com.android.providers.contacts.util.Hex;
 
 import android.test.suitebuilder.annotation.SmallTest;