Merge "Parse metadata_sync.data to MetadataEntry Object."
diff --git a/src/com/android/providers/contacts/MetadataEntryParser.java b/src/com/android/providers/contacts/MetadataEntryParser.java
new file mode 100644
index 0000000..a276cae
--- /dev/null
+++ b/src/com/android/providers/contacts/MetadataEntryParser.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2015 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.providers.contacts;
+
+import android.text.TextUtils;
+import com.android.providers.contacts.util.NeededForTesting;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+
+@NeededForTesting
+public class MetadataEntryParser {
+
+    private final static String UNIQUE_CONTACT_ID = "unique_contact_id";
+    private final static String ACCOUNT_TYPE = "account_type";
+    private final static String CUSTOM_ACCOUNT_TYPE = "custom_account_type";
+    private final static String ENUM_VALUE_FOR_CUSTOM_ACCOUNT = "CUSTOM_ACCOUNT";
+    private final static String ACCOUNT_NAME = "account_name";
+    private final static String CONTACT_ID = "contact_id";
+    private final static String CONTACT_PREFS = "contact_prefs";
+    private final static String SEND_TO_VOICEMAIL = "send_to_voicemail";
+    private final static String STARRED = "starred";
+    private final static String PINNED = "pinned";
+    private final static String AGGREGATION_DATA = "aggregation_data";
+    private final static String CONTACT_IDS = "contact_ids";
+    private final static String TYPE = "type";
+    private final static String FIELD_DATA = "field_data";
+    private final static String FIELD_DATA_ID = "field_data_id";
+    private final static String FIELD_DATA_PREFS = "field_data_prefs";
+    private final static String IS_PRIMARY = "is_primary";
+    private final static String IS_SUPER_PRIMARY = "is_super_primary";
+    private final static String USAGE_STATS = "usage_stats";
+    private final static String USAGE_TYPE = "usage_type";
+    private final static String LAST_TIME_USED = "last_time_used";
+    private final static String USAGE_COUNT = "usage_count";
+
+    @NeededForTesting
+    public static class UsageStats {
+        final String mUsageType;
+        final long mLastTimeUsed;
+        final int mTimesUsed;
+
+        @NeededForTesting
+        public UsageStats(String usageType, long lastTimeUsed, int timesUsed) {
+            this.mUsageType = usageType;
+            this.mLastTimeUsed = lastTimeUsed;
+            this.mTimesUsed = timesUsed;
+        }
+    }
+
+    @NeededForTesting
+    public static class FieldData {
+        final long mFieldDataId;
+        final boolean mIsPrimary;
+        final boolean mIsSuperPrimary;
+        final ArrayList<UsageStats> mUsageStatsList;
+
+        @NeededForTesting
+        public FieldData(long fieldDataId, boolean isPrimary, boolean isSuperPrimary,
+                ArrayList<UsageStats> usageStatsList) {
+            this.mFieldDataId = fieldDataId;
+            this.mIsPrimary = isPrimary;
+            this.mIsSuperPrimary = isSuperPrimary;
+            this.mUsageStatsList = usageStatsList;
+        }
+    }
+
+    @NeededForTesting
+    public static class AggregationData {
+        final long mRawContactId1;
+        final long mRawContactId2;
+        final String mType;
+
+        @NeededForTesting
+        public AggregationData(long rawContactId1, long rawContactId2, String type) {
+            this.mRawContactId1 = rawContactId1;
+            this.mRawContactId2 = rawContactId2;
+            this.mType = type;
+        }
+    }
+
+    @NeededForTesting
+    public static class MetadataEntry {
+        final long mRawContactId;
+        final String mAccountType;
+        final String mAccountName;
+        final int mSendToVoicemail;
+        final int mStarred;
+        final int mPinned;
+        final ArrayList<FieldData> mFieldDatas;
+        final ArrayList<AggregationData> mAggregationDatas;
+
+        @NeededForTesting
+        public MetadataEntry(long rawContactId, String accountType, String accountName,
+                int sendToVoicemail, int starred, int pinned,
+            ArrayList<FieldData> fieldDatas,
+            ArrayList<AggregationData> aggregationDatas) {
+            this.mRawContactId = rawContactId;
+            this.mAccountType = accountType;
+            this.mAccountName = accountName;
+            this.mSendToVoicemail = sendToVoicemail;
+            this.mStarred = starred;
+            this.mPinned = pinned;
+            this.mFieldDatas = fieldDatas;
+            this.mAggregationDatas = aggregationDatas;
+        }
+    }
+
+    @NeededForTesting
+    static MetadataEntry parseDataToMetaDataEntry(String inputData) {
+        if (TextUtils.isEmpty(inputData)) {
+            throw new IllegalArgumentException("Input cannot be empty.");
+        }
+
+        try {
+            final JSONObject root = new JSONObject(inputData);
+            // Parse to get rawContactId and account info.
+            final JSONObject uniqueContact = root.getJSONObject(UNIQUE_CONTACT_ID);
+            final String rawContactId = uniqueContact.getString(CONTACT_ID);
+            String accountType = uniqueContact.getString(ACCOUNT_TYPE);
+            if (ENUM_VALUE_FOR_CUSTOM_ACCOUNT.equals(accountType)) {
+                accountType = uniqueContact.getString(CUSTOM_ACCOUNT_TYPE);
+            }
+            final String accountName = uniqueContact.getString(ACCOUNT_NAME);
+            if (TextUtils.isEmpty(rawContactId) || TextUtils.isEmpty(accountType)
+                    || TextUtils.isEmpty(accountName)) {
+                throw new IllegalArgumentException(
+                        "contact_id, account_type, account_name cannot be empty.");
+            }
+
+            // Parse contactPrefs to get sendToVoicemail, starred, pinned.
+            final JSONObject contactPrefs = root.getJSONObject(CONTACT_PREFS);
+            final boolean sendToVoicemail = contactPrefs.getBoolean(SEND_TO_VOICEMAIL);
+            final boolean starred = contactPrefs.getBoolean(STARRED);
+            final int pinned = contactPrefs.getInt(PINNED);
+
+            // Parse aggregationDatas
+            final ArrayList<AggregationData> aggregationsList = new ArrayList<AggregationData>();
+            if (root.has(AGGREGATION_DATA)) {
+                final JSONArray aggregationDatas = root.getJSONArray(AGGREGATION_DATA);
+
+                for (int i = 0; i < aggregationDatas.length(); i++) {
+                    final JSONObject aggregationData = aggregationDatas.getJSONObject(i);
+                    final JSONArray contacts = aggregationData.getJSONArray(CONTACT_IDS);
+
+                    if (contacts.length() != 2) {
+                        throw new IllegalArgumentException(
+                                "There should be two contacts for each aggregation.");
+                    }
+                    final JSONObject rawContact1 = contacts.getJSONObject(0);
+                    final long rawContactId1 = rawContact1.getLong(CONTACT_ID);
+                    final JSONObject rawContact2 = contacts.getJSONObject(1);
+                    final long rawContactId2 = rawContact2.getLong(CONTACT_ID);
+                    final String type = aggregationData.getString(TYPE);
+                    if (TextUtils.isEmpty(type)) {
+                        throw new IllegalArgumentException("Aggregation type cannot be empty.");
+                    }
+
+                    final AggregationData aggregation = new AggregationData(
+                            rawContactId1, rawContactId2, type);
+                    aggregationsList.add(aggregation);
+                }
+            }
+
+            // Parse fieldDatas
+            final ArrayList<FieldData> fieldDatasList = new ArrayList<FieldData>();
+            if (root.has(FIELD_DATA)) {
+                final JSONArray fieldDatas = root.getJSONArray(FIELD_DATA);
+
+                for (int i = 0; i < fieldDatas.length(); i++) {
+                    final JSONObject fieldData = fieldDatas.getJSONObject(i);
+                    final long fieldDataId = fieldData.getLong(FIELD_DATA_ID);
+                    final JSONObject fieldDataPrefs = fieldData.getJSONObject(FIELD_DATA_PREFS);
+                    final boolean isPrimary = fieldDataPrefs.getBoolean(IS_PRIMARY);
+                    final boolean isSuperPrimary = fieldDataPrefs.getBoolean(IS_SUPER_PRIMARY);
+
+                    final ArrayList<UsageStats> usageStatsList = new ArrayList<UsageStats>();
+                    if (fieldData.has(USAGE_STATS)) {
+                        final JSONArray usageStats = fieldData.getJSONArray(USAGE_STATS);
+                        for (int j = 0; j < usageStats.length(); j++) {
+                            final JSONObject usageStat = usageStats.getJSONObject(j);
+                            final String usageType = usageStat.getString(USAGE_TYPE);
+                            if (TextUtils.isEmpty(usageType)) {
+                                throw new IllegalArgumentException("Usage type cannot be empty.");
+                            }
+                            final long lastTimeUsed = usageStat.getLong(LAST_TIME_USED);
+                            final int usageCount = usageStat.getInt(USAGE_COUNT);
+
+                            final UsageStats usageStatsParsed = new UsageStats(
+                                    usageType, lastTimeUsed, usageCount);
+                            usageStatsList.add(usageStatsParsed);
+                        }
+                    }
+
+                    final FieldData fieldDataParse = new FieldData(fieldDataId, isPrimary,
+                            isSuperPrimary, usageStatsList);
+                    fieldDatasList.add(fieldDataParse);
+                }
+            }
+            final MetadataEntry metaDataEntry = new MetadataEntry(Long.parseLong(rawContactId),
+                    accountType, accountName, sendToVoicemail ? 1 : 0, starred ? 1 : 0, pinned,
+                    fieldDatasList, aggregationsList);
+            return metaDataEntry;
+        } catch (JSONException e) {
+            throw new IllegalArgumentException("JSON Exception.", e);
+        }
+    }
+}
diff --git a/tests/assets/test1/testFileDeviceContactMetadataJSON.txt b/tests/assets/test1/testFileDeviceContactMetadataJSON.txt
new file mode 100644
index 0000000..c9494d8
--- /dev/null
+++ b/tests/assets/test1/testFileDeviceContactMetadataJSON.txt
@@ -0,0 +1,61 @@
+{
+  "unique_contact_id": {
+    "account_type": "CUSTOM_ACCOUNT",
+    "custom_account_type": "facebook",
+    "account_name": "android-test",
+    "contact_id": "1111111"
+  },
+  "contact_prefs": {
+    "send_to_voicemail": true,
+    "starred": false,
+    "pinned": 2
+  },
+  "aggregation_data": [
+    {
+      "type": "TOGETHER",
+      "contact_ids": [
+        {
+          "contact_id": "2222222"
+        },
+        {
+          "contact_id": "3333333"
+        }
+      ]
+    }
+  ],
+  "field_data": [
+    {
+      "field_data_id": "1001",
+      "field_data_prefs": {
+        "is_primary": true,
+        "is_super_primary": true
+      },
+      "usage_stats": [
+        {
+          "usage_type": "CALL",
+          "last_time_used": 10000001,
+          "usage_count": 10
+        },
+        {
+          "usage_type": "SHORT_TEXT",
+          "last_time_used": 20000002,
+          "usage_count": 20
+        }
+      ]
+    },
+    {
+      "field_data_id": "1002",
+      "field_data_prefs": {
+        "is_primary": false,
+        "is_super_primary": false
+      },
+      "usage_stats": [
+        {
+          "usage_type": "LONG_TEXT",
+          "last_time_used": 30000003,
+          "usage_count": 30
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/src/com/android/providers/contacts/MetadataEntryParserTest.java b/tests/src/com/android/providers/contacts/MetadataEntryParserTest.java
new file mode 100644
index 0000000..94ca074
--- /dev/null
+++ b/tests/src/com/android/providers/contacts/MetadataEntryParserTest.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2015 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.providers.contacts;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.providers.contacts.MetadataEntryParser.AggregationData;
+import com.android.providers.contacts.MetadataEntryParser.FieldData;
+import com.android.providers.contacts.MetadataEntryParser.MetadataEntry;
+import com.android.providers.contacts.MetadataEntryParser.UsageStats;
+import org.json.JSONException;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+
+/**
+ * Unit tests for {@link MetadataEntryParser}.
+ *
+ * Run the test like this:
+ * <code>
+ adb shell am instrument -e class com.android.providers.contacts.MetadataEntryParserTest -w \
+         com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
+ * </code>
+ */
+@SmallTest
+public class MetadataEntryParserTest extends AndroidTestCase {
+
+    public void testErrorForEmptyInput() {
+        try {
+            MetadataEntryParser.parseDataToMetaDataEntry("");
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+    }
+
+    public void testParseDataToMetadataEntry() throws IOException {
+        long rawContactId = 1111111;
+        String accountType = "facebook";
+        String accountName = "android-test";
+        int sendToVoicemail = 1;
+        int starred = 0;
+        int pinned = 2;
+        long fieldDataId1 = 1001;
+        String usageType1_1 = "CALL";
+        long lastTimeUsed1_1 = 10000001;
+        int timesUsed1_1 = 10;
+        String usageType1_2 = "SHORT_TEXT";
+        long lastTimeUsed1_2 = 20000002;
+        int timesUsed1_2 = 20;
+        long fieldDataId2 = 1002;
+        String usageType2 = "LONG_TEXT";
+        long lastTimeUsed2 = 30000003;
+        int timesUsed2 = 30;
+        long aggregationContact1 = 2222222;
+        long aggregationContact2 = 3333333;
+        String type = "TOGETHER";
+        String inputFile = "test1/testFileDeviceContactMetadataJSON.txt";
+
+        AggregationData aggregationData = new AggregationData(
+                aggregationContact1, aggregationContact2, type);
+        ArrayList<AggregationData> aggregationDataList = new ArrayList<>();
+        aggregationDataList.add(aggregationData);
+
+        UsageStats usageStats1_1 = new UsageStats(usageType1_1, lastTimeUsed1_1, timesUsed1_1);
+        UsageStats usageStats1_2 = new UsageStats(usageType1_2, lastTimeUsed1_2, timesUsed1_2);
+        UsageStats usageStats2 = new UsageStats(usageType2, lastTimeUsed2, timesUsed2);
+
+        ArrayList<UsageStats> usageStats1List = new ArrayList<>();
+        usageStats1List.add(usageStats1_1);
+        usageStats1List.add(usageStats1_2);
+        FieldData fieldData1 = new FieldData(fieldDataId1, true, true, usageStats1List);
+
+        ArrayList<UsageStats> usageStats2List = new ArrayList<>();
+        usageStats2List.add(usageStats2);
+        FieldData fieldData2 = new FieldData(fieldDataId2, false, false, usageStats2List);
+
+        ArrayList<FieldData> fieldDataList = new ArrayList<>();
+        fieldDataList.add(fieldData1);
+        fieldDataList.add(fieldData2);
+
+        MetadataEntry expectedResult = new MetadataEntry(rawContactId, accountType, accountName,
+                sendToVoicemail, starred, pinned, fieldDataList, aggregationDataList);
+
+        String inputJson = readAssetAsString(inputFile);
+        MetadataEntry metadataEntry = MetadataEntryParser.parseDataToMetaDataEntry(
+                inputJson.toString());
+        assertMetaDataEntry(expectedResult, metadataEntry);
+    }
+
+    public void testErrorForMissingContactId() {
+        String input = "{\"unique_contact_id\": {\n" +
+                "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
+                "    \"custom_account_type\": \"facebook\",\n" +
+                "    \"account_name\": \"android-test\"\n" +
+                "  }}";
+        try {
+            MetadataEntryParser.parseDataToMetaDataEntry(input);
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+    }
+
+    public void testErrorForNullContactId() throws JSONException {
+        String input = "{\"unique_contact_id\": {\n" +
+                "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
+                "    \"custom_account_type\": \"facebook\",\n" +
+                "    \"account_name\": \"android-test\",\n" +
+                "    \"contact_id\": \"\"\n" +
+                "  }}";
+        try {
+            MetadataEntryParser.parseDataToMetaDataEntry(input);
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+    }
+
+    public void testErrorForNullAccountType() throws JSONException {
+        String input = "{\"unique_contact_id\": {\n" +
+                "    \"account_type\": \"\",\n" +
+                "    \"custom_account_type\": \"facebook\",\n" +
+                "    \"account_name\": \"android-test\",\n" +
+                "    \"contact_id\": \"\"\n" +
+                "  }}";
+        try {
+            MetadataEntryParser.parseDataToMetaDataEntry(input);
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+    }
+
+    public void testErrorForNullAccountName() throws JSONException {
+        String input = "{\"unique_contact_id\": {\n" +
+                "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
+                "    \"custom_account_type\": \"facebook\",\n" +
+                "    \"account_name\": \"\",\n" +
+                "    \"contact_id\": \"1111111\"\n" +
+                "  }}";
+        try {
+            MetadataEntryParser.parseDataToMetaDataEntry(input);
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+    }
+
+    public void testErrorForNullFieldDataId() throws JSONException {
+        String input = "{\"unique_contact_id\": {\n" +
+                "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
+                "    \"custom_account_type\": \"facebook\",\n" +
+                "    \"account_name\": \"android-test\",\n" +
+                "    \"contact_id\": \"1111111\"\n" +
+                "  },\n" +
+                "    \"contact_prefs\": {\n" +
+                "    \"send_to_voicemail\": true,\n" +
+                "    \"starred\": false,\n" +
+                "    \"pinned\": 2\n" +
+                "  }," +
+                "    \"field_data\": [{\n" +
+                "      \"field_data_id\": \"\"}]" +
+                "}";
+        try {
+            MetadataEntryParser.parseDataToMetaDataEntry(input);
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+    }
+
+    public void testErrorForNullAggregationType() throws JSONException {
+        String input = "{\n" +
+                "  \"unique_contact_id\": {\n" +
+                "    \"account_type\": \"CUSTOM_ACCOUNT\",\n" +
+                "    \"custom_account_type\": \"facebook\",\n" +
+                "    \"account_name\": \"android-test\",\n" +
+                "    \"contact_id\": \"1111111\"\n" +
+                "  },\n" +
+                "  \"contact_prefs\": {\n" +
+                "    \"send_to_voicemail\": true,\n" +
+                "    \"starred\": false,\n" +
+                "    \"pinned\": 2\n" +
+                "  },\n" +
+                "  \"aggregation_data\": [\n" +
+                "    {\n" +
+                "      \"type\": \"\",\n" +
+                "      \"contact_ids\": [\n" +
+                "        {\n" +
+                "          \"contact_id\": \"2222222\"\n" +
+                "        },\n" +
+                "        {\n" +
+                "          \"contact_id\": \"3333333\"\n" +
+                "        }\n" +
+                "      ]\n" +
+                "    }\n" +
+                "  ]}";
+        try {
+            MetadataEntryParser.parseDataToMetaDataEntry(input);
+        } catch (IllegalArgumentException e) {
+            // Expected.
+        }
+    }
+
+    private String readAssetAsString(String fileName) throws IOException {
+        Context context = getTestContext();
+        InputStream input = context.getAssets().open(fileName);
+        ByteArrayOutputStream contents = new ByteArrayOutputStream();
+        int len;
+        byte[] data = new byte[1024];
+        do {
+            len = input.read(data);
+            if (len > 0) contents.write(data, 0, len);
+        } while (len == data.length);
+        return contents.toString();
+    }
+
+    private void assertMetaDataEntry(MetadataEntry entry1, MetadataEntry entry2) {
+        assertEquals(entry1.mRawContactId, entry2.mRawContactId);
+        assertEquals(entry1.mAccountType, entry2.mAccountType);
+        assertEquals(entry1.mAccountName, entry2.mAccountName);
+        assertEquals(entry1.mSendToVoicemail, entry2.mSendToVoicemail);
+        assertEquals(entry1.mStarred, entry2.mStarred);
+        assertEquals(entry1.mPinned, entry2.mPinned);
+        assertAggregationDataListEquals(entry1.mAggregationDatas, entry2.mAggregationDatas);
+        assertFieldDataListEquals(entry1.mFieldDatas, entry2.mFieldDatas);
+    }
+
+    private void assertAggregationDataListEquals(ArrayList<AggregationData> aggregationList1,
+            ArrayList<AggregationData> aggregationList2) {
+        assertEquals(aggregationList1.size(), aggregationList2.size());
+        for (int i = 0; i < aggregationList1.size(); i++) {
+            assertAggregationDataEquals(aggregationList1.get(i), aggregationList2.get(i));
+        }
+    }
+
+    private void assertAggregationDataEquals(AggregationData aggregationData1,
+            AggregationData aggregationData2) {
+        assertEquals(aggregationData1.mRawContactId1, aggregationData2.mRawContactId1);
+        assertEquals(aggregationData1.mRawContactId2, aggregationData2.mRawContactId2);
+        assertEquals(aggregationData1.mType, aggregationData2.mType);
+    }
+
+    private void assertFieldDataListEquals(ArrayList<FieldData> fieldDataList1,
+            ArrayList<FieldData> fieldDataList2) {
+        assertEquals(fieldDataList1.size(), fieldDataList2.size());
+        for (int i = 0; i < fieldDataList1.size(); i++) {
+            assertFieldDataEquals(fieldDataList1.get(i), fieldDataList2.get(i));
+        }
+    }
+
+    private void assertFieldDataEquals(FieldData fieldData1, FieldData fieldData2) {
+        assertEquals(fieldData1.mFieldDataId, fieldData2.mFieldDataId);
+        assertEquals(fieldData1.mIsPrimary, fieldData2.mIsPrimary);
+        assertEquals(fieldData1.mIsSuperPrimary, fieldData2.mIsSuperPrimary);
+        assertUsageStatsListEquals(fieldData1.mUsageStatsList, fieldData2.mUsageStatsList);
+    }
+
+    private void assertUsageStatsListEquals(ArrayList<UsageStats> usageStatsList1,
+            ArrayList<UsageStats> usageStatsList2) {
+        assertEquals(usageStatsList1.size(), usageStatsList2.size());
+        for (int i = 0; i < usageStatsList1.size(); i++) {
+            assertUsageStatsEquals(usageStatsList1.get(i), usageStatsList2.get(i));
+        }
+    }
+
+    private void assertUsageStatsEquals(UsageStats usageStats1, UsageStats usageStats2) {
+        assertEquals(usageStats1.mUsageType, usageStats2.mUsageType);
+        assertEquals(usageStats1.mLastTimeUsed, usageStats2.mLastTimeUsed);
+        assertEquals(usageStats1.mTimesUsed, usageStats2.mTimesUsed);
+    }
+}