1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.providers.contacts;
18 
19 import android.content.ContentUris;
20 import android.net.Uri;
21 import android.provider.ContactsContract.AggregationExceptions;
22 import android.provider.ContactsContract.Contacts;
23 import android.provider.ContactsContract.RawContacts;
24 import android.test.suitebuilder.annotation.MediumTest;
25 
26 import com.android.providers.contacts.ContactLookupKey.LookupKeySegment;
27 import com.android.providers.contacts.testutil.RawContactUtil;
28 
29 import java.util.ArrayList;
30 
31 /**
32  * Unit tests for {@link ContactLookupKey}.
33  *
34  * Run the test like this:
35  * <code>
36  * adb shell am instrument -e class com.android.providers.contacts.ContactLookupKeyTest -w \
37  *         com.android.providers.contacts.tests/android.test.InstrumentationTestRunner
38  * </code>
39  */
40 @MediumTest
41 public class ContactLookupKeyTest extends BaseContactsProvider2Test {
42 
testLookupKeyUsingDisplayNameAndNoAccount()43     public void testLookupKeyUsingDisplayNameAndNoAccount() {
44         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
45         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "johndoe", null);
46         setAggregationException(
47                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
48 
49         // Normalized display name
50         String normalizedName = NameNormalizer.normalize("johndoe");
51         String expectedLookupKey = "0r" + rawContactId1 + "-" + normalizedName + ".0r"
52                 + rawContactId2 + "-" + normalizedName;
53 
54         long contactId = queryContactId(rawContactId1);
55         assertStoredValue(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
56                 Contacts.LOOKUP_KEY, expectedLookupKey);
57 
58         // Find the contact using lookup key by itself
59         Uri lookupUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, expectedLookupKey);
60         assertStoredValue(lookupUri, Contacts._ID, contactId);
61 
62         // Find the contact using both the lookup key and the correct contact ID
63         assertStoredValue(ContentUris.withAppendedId(lookupUri, contactId),
64                 Contacts._ID, contactId);
65 
66         // Find the contact using both the lookup key and an incorrect contact ID
67         assertStoredValue(ContentUris.withAppendedId(lookupUri, contactId + 1),
68                 Contacts._ID, contactId);
69     }
70 
testLookupKeyUsingSourceIdAndNoAccount()71     public void testLookupKeyUsingSourceIdAndNoAccount() {
72         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
73         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.SOURCE_ID, "123");
74 
75         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "johndoe", null);
76         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.SOURCE_ID, "4.5.6");
77 
78         long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "john", "dough");
79         storeValue(RawContacts.CONTENT_URI, rawContactId3, RawContacts.SOURCE_ID, "http://foo?bar");
80 
81         setAggregationException(
82                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
83         setAggregationException(
84                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId3);
85 
86         // Two source ids, of them escaped
87         String expectedLookupKey = "0i123.0e4..5..6.0ihttp%3A%2F%2Ffoo%3Fbar";
88 
89         long contactId = queryContactId(rawContactId1);
90         assertStoredValue(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
91                 Contacts.LOOKUP_KEY, expectedLookupKey);
92 
93         Uri lookupUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, expectedLookupKey);
94         assertStoredValue(lookupUri, Contacts._ID, contactId);
95     }
96 
testLookupKeySameSourceIdDifferentAccounts()97     public void testLookupKeySameSourceIdDifferentAccounts() {
98         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "Dear", "Doe");
99         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.ACCOUNT_TYPE, "foo");
100         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.ACCOUNT_NAME, "FOO");
101         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.SOURCE_ID, "1");
102 
103         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "Deer", "Dough");
104         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.ACCOUNT_TYPE, "bar");
105         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.ACCOUNT_NAME, "BAR");
106         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.SOURCE_ID, "1");
107 
108         assertNotAggregated(rawContactId1, rawContactId2);
109 
110         int accountHashCode1 = ContactLookupKey.getAccountHashCode("foo", "FOO");
111         int accountHashCode2 = ContactLookupKey.getAccountHashCode("bar", "BAR");
112 
113         long contactId1 = queryContactId(rawContactId1);
114         assertStoredValue(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId1),
115                 Contacts.LOOKUP_KEY, accountHashCode1 + "i1");
116 
117         long contactId2 = queryContactId(rawContactId2);
118         assertStoredValue(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId2),
119                 Contacts.LOOKUP_KEY, accountHashCode2 + "i1");
120 
121         Uri lookupUri1 = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, accountHashCode1 + "i1");
122         assertStoredValue(lookupUri1, Contacts._ID, contactId1);
123 
124         Uri lookupUri2 = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, accountHashCode2 + "i1");
125         assertStoredValue(lookupUri2, Contacts._ID, contactId2);
126     }
127 
testLookupKeyChoosingLargestContact()128     public void testLookupKeyChoosingLargestContact() {
129         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
130         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.SOURCE_ID, "1");
131 
132         long rawContactId2 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
133         storeValue(RawContacts.CONTENT_URI, rawContactId2, RawContacts.SOURCE_ID, "2");
134 
135         long rawContactId3 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
136         storeValue(RawContacts.CONTENT_URI, rawContactId3, RawContacts.SOURCE_ID, "3");
137         setAggregationException(
138                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2);
139         setAggregationException(
140                 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId3);
141 
142         String lookupKey = "0i1.0i2.0i3";
143 
144         long contactId = queryContactId(rawContactId1);
145         assertStoredValue(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
146                 Contacts.LOOKUP_KEY, lookupKey);
147 
148         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, rawContactId1,
149                 rawContactId3);
150         setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, rawContactId2,
151                 rawContactId3);
152         assertAggregated(rawContactId1, rawContactId2);
153         assertNotAggregated(rawContactId1, rawContactId3);
154         assertNotAggregated(rawContactId2, rawContactId3);
155 
156         long largerContactId = queryContactId(rawContactId1);
157         assertStoredValue(
158                 ContentUris.withAppendedId(Contacts.CONTENT_URI, largerContactId),
159                 Contacts.LOOKUP_KEY, "0i1.0i2");
160         assertStoredValue(
161                 ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(rawContactId3)),
162                 Contacts.LOOKUP_KEY, "0i3");
163 
164         Uri lookupUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey);
165         assertStoredValue(lookupUri, Contacts._ID, largerContactId);
166     }
167 
testGetLookupUri()168     public void testGetLookupUri() {
169         long rawContactId1 = RawContactUtil.createRawContactWithName(mResolver, "John", "Doe");
170         storeValue(RawContacts.CONTENT_URI, rawContactId1, RawContacts.SOURCE_ID, "1");
171 
172         long contactId = queryContactId(rawContactId1);
173         String lookupUri = "content://com.android.contacts/contacts/lookup/0i1/" + contactId;
174 
175         Uri contentUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
176         assertEquals(lookupUri,
177                 Contacts.getLookupUri(mResolver, contentUri).toString());
178 
179         Uri staleLookupUri = ContentUris.withAppendedId(
180                 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, "0i1"),
181                 contactId+2);
182         assertEquals(lookupUri,
183                 Contacts.getLookupUri(mResolver, staleLookupUri).toString());
184     }
185 
testParseLookupKey()186     public void testParseLookupKey() {
187         // Display name
188         assertLookupKey("123n1248AC",
189                 new int[]{123},
190                 new int[]{ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME},
191                 new String[]{"1248AC"});
192 
193         // Raw contact ID + display name
194         assertLookupKey("123r20-1248AC",
195                 new int[]{123},
196                 new int[]{ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID},
197                 new String[]{"1248AC"});
198 
199         // Unescaped source ID
200         assertLookupKey("0i1248AC-X",
201                 new int[]{0},
202                 new int[]{ContactLookupKey.LOOKUP_TYPE_SOURCE_ID},
203                 new String[]{"1248AC-X"});
204 
205         // Escaped source ID
206         assertLookupKey("432e12..48AC",
207                 new int[]{432},
208                 new int[]{ContactLookupKey.LOOKUP_TYPE_SOURCE_ID},
209                 new String[]{"12.48AC"});
210 
211         // Compound lookup key
212         assertLookupKey("123n1248AC.0i1248AC.432e12..48AC.123n1248AC.123r30-2184CA",
213                 new int[]{123, 0, 432, 123},
214                 new int[] {
215                         ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME,
216                         ContactLookupKey.LOOKUP_TYPE_SOURCE_ID,
217                         ContactLookupKey.LOOKUP_TYPE_SOURCE_ID,
218                         ContactLookupKey.LOOKUP_TYPE_DISPLAY_NAME,
219                         ContactLookupKey.LOOKUP_TYPE_RAW_CONTACT_ID,
220                 },
221                 new String[]{"1248AC", "1248AC", "12.48AC", "1248AC", "2184CA"});
222     }
223 
assertLookupKey(String lookupKey, int[] accountHashCodes, int[] types, String[] keys)224     private void assertLookupKey(String lookupKey, int[] accountHashCodes, int[] types,
225             String[] keys) {
226         ContactLookupKey key = new ContactLookupKey();
227         ArrayList<LookupKeySegment> list = key.parse(lookupKey);
228         assertEquals(types.length, list.size());
229 
230         for (int i = 0; i < accountHashCodes.length; i++) {
231             LookupKeySegment segment = list.get(i);
232             assertEquals(accountHashCodes[i], segment.accountHashCode);
233             assertEquals(types[i], segment.lookupType);
234             assertEquals(keys[i], segment.key);
235         }
236     }
237 }
238 
239