ContactsProvider2Test.java revision ac13ddd04d665442de846b59234bdc936a6699b4
190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)/* 290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * Copyright (C) 2009 The Android Open Source Project 390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * 490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License"); 590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * you may not use this file except in compliance with the License. 690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * You may obtain a copy of the License at 790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * 890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * http://www.apache.org/licenses/LICENSE-2.0 990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * 1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * Unless required by applicable law or agreed to in writing, software 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS, 1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * See the License for the specific language governing permissions and 1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * limitations under the License. 1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) */ 1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)package com.android.providers.contacts; 1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import com.android.internal.util.ArrayUtils; 200529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; 2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns; 2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import com.google.android.collect.Lists; 2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.accounts.Account; 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.content.ContentProviderOperation; 260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.content.ContentProviderResult; 270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.content.ContentUris; 280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.content.ContentValues; 290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.content.Entity; 300529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.content.EntityIterator; 310529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.content.res.AssetFileDescriptor; 320529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.database.Cursor; 330529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.net.Uri; 340529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.provider.ContactsContract; 350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.provider.ContactsContract.AggregationExceptions; 3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.provider.ContactsContract.CommonDataKinds.Email; 3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.provider.ContactsContract.CommonDataKinds.GroupMembership; 38116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport android.provider.ContactsContract.CommonDataKinds.Im; 39116680a4aac90f2aa7413d9095a592090648e557Ben Murdochimport android.provider.ContactsContract.CommonDataKinds.Nickname; 40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.provider.ContactsContract.CommonDataKinds.Organization; 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.provider.ContactsContract.CommonDataKinds.Phone; 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.provider.ContactsContract.CommonDataKinds.Photo; 4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.provider.ContactsContract.CommonDataKinds.StructuredName; 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import android.provider.ContactsContract.CommonDataKinds.StructuredPostal; 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import android.provider.ContactsContract.ContactCounts; 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import android.provider.ContactsContract.Contacts; 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import android.provider.ContactsContract.Data; 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import android.provider.ContactsContract.Directory; 4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.provider.ContactsContract.DisplayNameSources; 5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)import android.provider.ContactsContract.Groups; 51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.provider.ContactsContract.PhoneLookup; 52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)import android.provider.ContactsContract.PhoneticNameStyle; 533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.provider.ContactsContract.ProviderStatus; 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import android.provider.ContactsContract.RawContacts; 550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochimport android.provider.ContactsContract.RawContactsEntity; 563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import android.provider.ContactsContract.SearchSnippetColumns; 57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import android.provider.ContactsContract.Settings; 58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import android.provider.ContactsContract.StatusUpdates; 59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import android.provider.LiveFolders; 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import android.provider.OpenableColumns; 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import android.test.MoreAsserts; 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)import android.test.suitebuilder.annotation.LargeTest; 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.io.FileInputStream; 653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.io.IOException; 663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.io.InputStream; 673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import java.text.Collator; 68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import java.util.Arrays; 69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)import java.util.Locale; 70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) 71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/** 72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * Unit tests for {@link ContactsProvider2}. 73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * 7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * Run the test like this: 7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * <code> 7623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) * adb shell am instrument -e class com.android.providers.contacts.ContactsProvider2Test -w \ 7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * com.android.providers.contacts.tests/android.test.InstrumentationTestRunner 781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) * </code> 79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */ 8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)@LargeTest 8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)public class ContactsProvider2Test extends BaseContactsProvider2Test { 8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public void testContactsProjection() { 840529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch assertProjection(Contacts.CONTENT_URI, new String[]{ 850529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Contacts._ID, 860529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Contacts.DISPLAY_NAME_PRIMARY, 875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Contacts.DISPLAY_NAME_ALTERNATIVE, 885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Contacts.DISPLAY_NAME_SOURCE, 890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Contacts.PHONETIC_NAME, 900529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Contacts.PHONETIC_NAME_STYLE, 910529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Contacts.SORT_KEY_PRIMARY, 920529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Contacts.SORT_KEY_ALTERNATIVE, 930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Contacts.LAST_TIME_CONTACTED, 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Contacts.TIMES_CONTACTED, 9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.STARRED, 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) Contacts.IN_VISIBLE_GROUP, 97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Contacts.PHOTO_ID, 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Contacts.CUSTOM_RINGTONE, 99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Contacts.HAS_PHONE_NUMBER, 100e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch Contacts.SEND_TO_VOICEMAIL, 1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Contacts.LOOKUP_KEY, 102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) Contacts.NAME_RAW_CONTACT_ID, 10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.CONTACT_PRESENCE, 10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.CONTACT_CHAT_CAPABILITY, 10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.CONTACT_STATUS, 10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.CONTACT_STATUS_TIMESTAMP, 10790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.CONTACT_STATUS_RES_PACKAGE, 1080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Contacts.CONTACT_STATUS_LABEL, 1090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch Contacts.CONTACT_STATUS_ICON, 1100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch }); 1110529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch } 11290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 11390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public void testContactsWithSnippetProjection() { 11490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) assertProjection(Contacts.CONTENT_FILTER_URI.buildUpon().appendPath("nothing").build(), 11590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) new String[]{ 116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Contacts._ID, 117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) Contacts.DISPLAY_NAME_PRIMARY, 1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) Contacts.DISPLAY_NAME_ALTERNATIVE, 11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.DISPLAY_NAME_SOURCE, 12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.PHONETIC_NAME, 12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.PHONETIC_NAME_STYLE, 12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.SORT_KEY_PRIMARY, 12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) Contacts.SORT_KEY_ALTERNATIVE, 124 Contacts.LAST_TIME_CONTACTED, 125 Contacts.TIMES_CONTACTED, 126 Contacts.STARRED, 127 Contacts.IN_VISIBLE_GROUP, 128 Contacts.PHOTO_ID, 129 Contacts.CUSTOM_RINGTONE, 130 Contacts.HAS_PHONE_NUMBER, 131 Contacts.SEND_TO_VOICEMAIL, 132 Contacts.LOOKUP_KEY, 133 Contacts.NAME_RAW_CONTACT_ID, 134 Contacts.CONTACT_PRESENCE, 135 Contacts.CONTACT_CHAT_CAPABILITY, 136 Contacts.CONTACT_STATUS, 137 Contacts.CONTACT_STATUS_TIMESTAMP, 138 Contacts.CONTACT_STATUS_RES_PACKAGE, 139 Contacts.CONTACT_STATUS_LABEL, 140 Contacts.CONTACT_STATUS_ICON, 141 142 SearchSnippetColumns.SNIPPET_MIMETYPE, 143 SearchSnippetColumns.SNIPPET_DATA_ID, 144 SearchSnippetColumns.SNIPPET_DATA1, 145 SearchSnippetColumns.SNIPPET_DATA2, 146 SearchSnippetColumns.SNIPPET_DATA3, 147 SearchSnippetColumns.SNIPPET_DATA4, 148 }); 149 } 150 151 public void testRawContactsProjection() { 152 assertProjection(RawContacts.CONTENT_URI, new String[]{ 153 RawContacts._ID, 154 RawContacts.CONTACT_ID, 155 RawContacts.ACCOUNT_NAME, 156 RawContacts.ACCOUNT_TYPE, 157 RawContacts.SOURCE_ID, 158 RawContacts.VERSION, 159 RawContacts.DIRTY, 160 RawContacts.DELETED, 161 RawContacts.DISPLAY_NAME_PRIMARY, 162 RawContacts.DISPLAY_NAME_ALTERNATIVE, 163 RawContacts.DISPLAY_NAME_SOURCE, 164 RawContacts.PHONETIC_NAME, 165 RawContacts.PHONETIC_NAME_STYLE, 166 RawContacts.NAME_VERIFIED, 167 RawContacts.SORT_KEY_PRIMARY, 168 RawContacts.SORT_KEY_ALTERNATIVE, 169 RawContacts.TIMES_CONTACTED, 170 RawContacts.LAST_TIME_CONTACTED, 171 RawContacts.CUSTOM_RINGTONE, 172 RawContacts.SEND_TO_VOICEMAIL, 173 RawContacts.STARRED, 174 RawContacts.AGGREGATION_MODE, 175 RawContacts.SYNC1, 176 RawContacts.SYNC2, 177 RawContacts.SYNC3, 178 RawContacts.SYNC4, 179 }); 180 } 181 182 public void testDataProjection() { 183 assertProjection(Data.CONTENT_URI, new String[]{ 184 Data._ID, 185 Data.RAW_CONTACT_ID, 186 Data.DATA_VERSION, 187 Data.IS_PRIMARY, 188 Data.IS_SUPER_PRIMARY, 189 Data.RES_PACKAGE, 190 Data.MIMETYPE, 191 Data.DATA1, 192 Data.DATA2, 193 Data.DATA3, 194 Data.DATA4, 195 Data.DATA5, 196 Data.DATA6, 197 Data.DATA7, 198 Data.DATA8, 199 Data.DATA9, 200 Data.DATA10, 201 Data.DATA11, 202 Data.DATA12, 203 Data.DATA13, 204 Data.DATA14, 205 Data.DATA15, 206 Data.SYNC1, 207 Data.SYNC2, 208 Data.SYNC3, 209 Data.SYNC4, 210 Data.CONTACT_ID, 211 Data.PRESENCE, 212 Data.CHAT_CAPABILITY, 213 Data.STATUS, 214 Data.STATUS_TIMESTAMP, 215 Data.STATUS_RES_PACKAGE, 216 Data.STATUS_LABEL, 217 Data.STATUS_ICON, 218 RawContacts.ACCOUNT_NAME, 219 RawContacts.ACCOUNT_TYPE, 220 RawContacts.SOURCE_ID, 221 RawContacts.VERSION, 222 RawContacts.DIRTY, 223 RawContacts.NAME_VERIFIED, 224 Contacts._ID, 225 Contacts.DISPLAY_NAME_PRIMARY, 226 Contacts.DISPLAY_NAME_ALTERNATIVE, 227 Contacts.DISPLAY_NAME_SOURCE, 228 Contacts.PHONETIC_NAME, 229 Contacts.PHONETIC_NAME_STYLE, 230 Contacts.SORT_KEY_PRIMARY, 231 Contacts.SORT_KEY_ALTERNATIVE, 232 Contacts.LAST_TIME_CONTACTED, 233 Contacts.TIMES_CONTACTED, 234 Contacts.STARRED, 235 Contacts.IN_VISIBLE_GROUP, 236 Contacts.PHOTO_ID, 237 Contacts.CUSTOM_RINGTONE, 238 Contacts.SEND_TO_VOICEMAIL, 239 Contacts.LOOKUP_KEY, 240 Contacts.NAME_RAW_CONTACT_ID, 241 Contacts.CONTACT_PRESENCE, 242 Contacts.CONTACT_CHAT_CAPABILITY, 243 Contacts.CONTACT_STATUS, 244 Contacts.CONTACT_STATUS_TIMESTAMP, 245 Contacts.CONTACT_STATUS_RES_PACKAGE, 246 Contacts.CONTACT_STATUS_LABEL, 247 Contacts.CONTACT_STATUS_ICON, 248 GroupMembership.GROUP_SOURCE_ID, 249 }); 250 } 251 252 public void testDistinctDataProjection() { 253 assertProjection(Phone.CONTENT_FILTER_URI.buildUpon().appendPath("123").build(), 254 new String[]{ 255 Data._ID, 256 Data.DATA_VERSION, 257 Data.IS_PRIMARY, 258 Data.IS_SUPER_PRIMARY, 259 Data.RES_PACKAGE, 260 Data.MIMETYPE, 261 Data.DATA1, 262 Data.DATA2, 263 Data.DATA3, 264 Data.DATA4, 265 Data.DATA5, 266 Data.DATA6, 267 Data.DATA7, 268 Data.DATA8, 269 Data.DATA9, 270 Data.DATA10, 271 Data.DATA11, 272 Data.DATA12, 273 Data.DATA13, 274 Data.DATA14, 275 Data.DATA15, 276 Data.SYNC1, 277 Data.SYNC2, 278 Data.SYNC3, 279 Data.SYNC4, 280 Data.CONTACT_ID, 281 Data.PRESENCE, 282 Data.CHAT_CAPABILITY, 283 Data.STATUS, 284 Data.STATUS_TIMESTAMP, 285 Data.STATUS_RES_PACKAGE, 286 Data.STATUS_LABEL, 287 Data.STATUS_ICON, 288 Contacts._ID, 289 Contacts.DISPLAY_NAME_PRIMARY, 290 Contacts.DISPLAY_NAME_ALTERNATIVE, 291 Contacts.DISPLAY_NAME_SOURCE, 292 Contacts.PHONETIC_NAME, 293 Contacts.PHONETIC_NAME_STYLE, 294 Contacts.SORT_KEY_PRIMARY, 295 Contacts.SORT_KEY_ALTERNATIVE, 296 Contacts.LAST_TIME_CONTACTED, 297 Contacts.TIMES_CONTACTED, 298 Contacts.STARRED, 299 Contacts.IN_VISIBLE_GROUP, 300 Contacts.PHOTO_ID, 301 Contacts.CUSTOM_RINGTONE, 302 Contacts.SEND_TO_VOICEMAIL, 303 Contacts.LOOKUP_KEY, 304 Contacts.CONTACT_PRESENCE, 305 Contacts.CONTACT_CHAT_CAPABILITY, 306 Contacts.CONTACT_STATUS, 307 Contacts.CONTACT_STATUS_TIMESTAMP, 308 Contacts.CONTACT_STATUS_RES_PACKAGE, 309 Contacts.CONTACT_STATUS_LABEL, 310 Contacts.CONTACT_STATUS_ICON, 311 GroupMembership.GROUP_SOURCE_ID, 312 }); 313 } 314 315 public void testEntityProjection() { 316 assertProjection( 317 Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, 0), 318 Contacts.Entity.CONTENT_DIRECTORY), 319 new String[]{ 320 Contacts.Entity._ID, 321 Contacts.Entity.DATA_ID, 322 Contacts.Entity.RAW_CONTACT_ID, 323 Data.DATA_VERSION, 324 Data.IS_PRIMARY, 325 Data.IS_SUPER_PRIMARY, 326 Data.RES_PACKAGE, 327 Data.MIMETYPE, 328 Data.DATA1, 329 Data.DATA2, 330 Data.DATA3, 331 Data.DATA4, 332 Data.DATA5, 333 Data.DATA6, 334 Data.DATA7, 335 Data.DATA8, 336 Data.DATA9, 337 Data.DATA10, 338 Data.DATA11, 339 Data.DATA12, 340 Data.DATA13, 341 Data.DATA14, 342 Data.DATA15, 343 Data.SYNC1, 344 Data.SYNC2, 345 Data.SYNC3, 346 Data.SYNC4, 347 Data.CONTACT_ID, 348 Data.PRESENCE, 349 Data.CHAT_CAPABILITY, 350 Data.STATUS, 351 Data.STATUS_TIMESTAMP, 352 Data.STATUS_RES_PACKAGE, 353 Data.STATUS_LABEL, 354 Data.STATUS_ICON, 355 RawContacts.ACCOUNT_NAME, 356 RawContacts.ACCOUNT_TYPE, 357 RawContacts.SOURCE_ID, 358 RawContacts.VERSION, 359 RawContacts.DELETED, 360 RawContacts.DIRTY, 361 RawContacts.NAME_VERIFIED, 362 RawContacts.SYNC1, 363 RawContacts.SYNC2, 364 RawContacts.SYNC3, 365 RawContacts.SYNC4, 366 RawContacts.IS_RESTRICTED, 367 Contacts._ID, 368 Contacts.DISPLAY_NAME_PRIMARY, 369 Contacts.DISPLAY_NAME_ALTERNATIVE, 370 Contacts.DISPLAY_NAME_SOURCE, 371 Contacts.PHONETIC_NAME, 372 Contacts.PHONETIC_NAME_STYLE, 373 Contacts.SORT_KEY_PRIMARY, 374 Contacts.SORT_KEY_ALTERNATIVE, 375 Contacts.LAST_TIME_CONTACTED, 376 Contacts.TIMES_CONTACTED, 377 Contacts.STARRED, 378 Contacts.IN_VISIBLE_GROUP, 379 Contacts.PHOTO_ID, 380 Contacts.CUSTOM_RINGTONE, 381 Contacts.SEND_TO_VOICEMAIL, 382 Contacts.LOOKUP_KEY, 383 Contacts.NAME_RAW_CONTACT_ID, 384 Contacts.CONTACT_PRESENCE, 385 Contacts.CONTACT_CHAT_CAPABILITY, 386 Contacts.CONTACT_STATUS, 387 Contacts.CONTACT_STATUS_TIMESTAMP, 388 Contacts.CONTACT_STATUS_RES_PACKAGE, 389 Contacts.CONTACT_STATUS_LABEL, 390 Contacts.CONTACT_STATUS_ICON, 391 GroupMembership.GROUP_SOURCE_ID, 392 }); 393 } 394 395 public void testRawEntityProjection() { 396 assertProjection(RawContactsEntity.CONTENT_URI, new String[]{ 397 RawContacts.Entity.DATA_ID, 398 RawContacts._ID, 399 RawContacts.CONTACT_ID, 400 RawContacts.ACCOUNT_NAME, 401 RawContacts.ACCOUNT_TYPE, 402 RawContacts.SOURCE_ID, 403 RawContacts.VERSION, 404 RawContacts.DIRTY, 405 RawContacts.NAME_VERIFIED, 406 RawContacts.DELETED, 407 RawContacts.IS_RESTRICTED, 408 RawContacts.SYNC1, 409 RawContacts.SYNC2, 410 RawContacts.SYNC3, 411 RawContacts.SYNC4, 412 RawContacts.STARRED, 413 Data.DATA_VERSION, 414 Data.IS_PRIMARY, 415 Data.IS_SUPER_PRIMARY, 416 Data.RES_PACKAGE, 417 Data.MIMETYPE, 418 Data.DATA1, 419 Data.DATA2, 420 Data.DATA3, 421 Data.DATA4, 422 Data.DATA5, 423 Data.DATA6, 424 Data.DATA7, 425 Data.DATA8, 426 Data.DATA9, 427 Data.DATA10, 428 Data.DATA11, 429 Data.DATA12, 430 Data.DATA13, 431 Data.DATA14, 432 Data.DATA15, 433 Data.SYNC1, 434 Data.SYNC2, 435 Data.SYNC3, 436 Data.SYNC4, 437 GroupMembership.GROUP_SOURCE_ID, 438 }); 439 } 440 441 public void testPhoneLookupProjection() { 442 assertProjection(PhoneLookup.CONTENT_FILTER_URI.buildUpon().appendPath("123").build(), 443 new String[]{ 444 PhoneLookup._ID, 445 PhoneLookup.LOOKUP_KEY, 446 PhoneLookup.DISPLAY_NAME, 447 PhoneLookup.LAST_TIME_CONTACTED, 448 PhoneLookup.TIMES_CONTACTED, 449 PhoneLookup.STARRED, 450 PhoneLookup.IN_VISIBLE_GROUP, 451 PhoneLookup.PHOTO_ID, 452 PhoneLookup.CUSTOM_RINGTONE, 453 PhoneLookup.HAS_PHONE_NUMBER, 454 PhoneLookup.SEND_TO_VOICEMAIL, 455 PhoneLookup.NUMBER, 456 PhoneLookup.TYPE, 457 PhoneLookup.LABEL, 458 }); 459 } 460 461 public void testGroupsProjection() { 462 assertProjection(Groups.CONTENT_URI, new String[]{ 463 Groups._ID, 464 Groups.ACCOUNT_NAME, 465 Groups.ACCOUNT_TYPE, 466 Groups.SOURCE_ID, 467 Groups.DIRTY, 468 Groups.VERSION, 469 Groups.RES_PACKAGE, 470 Groups.TITLE, 471 Groups.TITLE_RES, 472 Groups.GROUP_VISIBLE, 473 Groups.SYSTEM_ID, 474 Groups.DELETED, 475 Groups.NOTES, 476 Groups.SHOULD_SYNC, 477 Groups.FAVORITES, 478 Groups.AUTO_ADD, 479 Groups.SYNC1, 480 Groups.SYNC2, 481 Groups.SYNC3, 482 Groups.SYNC4, 483 }); 484 } 485 486 public void testGroupsSummaryProjection() { 487 assertProjection(Groups.CONTENT_SUMMARY_URI, new String[]{ 488 Groups._ID, 489 Groups.ACCOUNT_NAME, 490 Groups.ACCOUNT_TYPE, 491 Groups.SOURCE_ID, 492 Groups.DIRTY, 493 Groups.VERSION, 494 Groups.RES_PACKAGE, 495 Groups.TITLE, 496 Groups.TITLE_RES, 497 Groups.GROUP_VISIBLE, 498 Groups.SYSTEM_ID, 499 Groups.DELETED, 500 Groups.NOTES, 501 Groups.SHOULD_SYNC, 502 Groups.FAVORITES, 503 Groups.AUTO_ADD, 504 Groups.SYNC1, 505 Groups.SYNC2, 506 Groups.SYNC3, 507 Groups.SYNC4, 508 Groups.SUMMARY_COUNT, 509 Groups.SUMMARY_WITH_PHONES, 510 }); 511 } 512 513 public void testAggregateExceptionProjection() { 514 assertProjection(AggregationExceptions.CONTENT_URI, new String[]{ 515 AggregationExceptionColumns._ID, 516 AggregationExceptions.TYPE, 517 AggregationExceptions.RAW_CONTACT_ID1, 518 AggregationExceptions.RAW_CONTACT_ID2, 519 }); 520 } 521 522 public void testSettingsProjection() { 523 assertProjection(Settings.CONTENT_URI, new String[]{ 524 Settings.ACCOUNT_NAME, 525 Settings.ACCOUNT_TYPE, 526 Settings.UNGROUPED_VISIBLE, 527 Settings.SHOULD_SYNC, 528 Settings.ANY_UNSYNCED, 529 Settings.UNGROUPED_COUNT, 530 Settings.UNGROUPED_WITH_PHONES, 531 }); 532 } 533 534 public void testStatusUpdatesProjection() { 535 assertProjection(StatusUpdates.CONTENT_URI, new String[]{ 536 PresenceColumns.RAW_CONTACT_ID, 537 StatusUpdates.DATA_ID, 538 StatusUpdates.IM_ACCOUNT, 539 StatusUpdates.IM_HANDLE, 540 StatusUpdates.PROTOCOL, 541 StatusUpdates.CUSTOM_PROTOCOL, 542 StatusUpdates.PRESENCE, 543 StatusUpdates.CHAT_CAPABILITY, 544 StatusUpdates.STATUS, 545 StatusUpdates.STATUS_TIMESTAMP, 546 StatusUpdates.STATUS_RES_PACKAGE, 547 StatusUpdates.STATUS_ICON, 548 StatusUpdates.STATUS_LABEL, 549 }); 550 } 551 552 public void testLiveFoldersProjection() { 553 assertProjection( 554 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, "live_folders/contacts"), 555 new String[]{ 556 LiveFolders._ID, 557 LiveFolders.NAME, 558 }); 559 } 560 561 public void testDirectoryProjection() { 562 assertProjection(Directory.CONTENT_URI, new String[]{ 563 Directory._ID, 564 Directory.PACKAGE_NAME, 565 Directory.TYPE_RESOURCE_ID, 566 Directory.DISPLAY_NAME, 567 Directory.DIRECTORY_AUTHORITY, 568 Directory.ACCOUNT_TYPE, 569 Directory.ACCOUNT_NAME, 570 Directory.EXPORT_SUPPORT, 571 }); 572 } 573 574 public void testRawContactsInsert() { 575 ContentValues values = new ContentValues(); 576 577 values.put(RawContacts.ACCOUNT_NAME, "a"); 578 values.put(RawContacts.ACCOUNT_TYPE, "b"); 579 values.put(RawContacts.SOURCE_ID, "c"); 580 values.put(RawContacts.VERSION, 42); 581 values.put(RawContacts.DIRTY, 1); 582 values.put(RawContacts.DELETED, 1); 583 values.put(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED); 584 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 585 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 586 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 587 values.put(RawContacts.STARRED, 1); 588 values.put(RawContacts.SYNC1, "e"); 589 values.put(RawContacts.SYNC2, "f"); 590 values.put(RawContacts.SYNC3, "g"); 591 values.put(RawContacts.SYNC4, "h"); 592 593 Uri rowUri = mResolver.insert(RawContacts.CONTENT_URI, values); 594 long rawContactId = ContentUris.parseId(rowUri); 595 596 assertStoredValues(rowUri, values); 597 assertSelection(RawContacts.CONTENT_URI, values, RawContacts._ID, rawContactId); 598 assertNetworkNotified(true); 599 } 600 601 public void testDataDirectoryWithLookupUri() { 602 ContentValues values = new ContentValues(); 603 604 long rawContactId = createRawContactWithName(); 605 insertPhoneNumber(rawContactId, "555-GOOG-411"); 606 insertEmail(rawContactId, "google@android.com"); 607 608 long contactId = queryContactId(rawContactId); 609 String lookupKey = queryLookupKey(contactId); 610 611 // Complete and valid lookup URI 612 Uri lookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey); 613 Uri dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY); 614 615 assertDataRows(dataUri, values); 616 617 // Complete but stale lookup URI 618 lookupUri = ContactsContract.Contacts.getLookupUri(contactId + 1, lookupKey); 619 dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY); 620 assertDataRows(dataUri, values); 621 622 // Incomplete lookup URI (lookup key only, no contact ID) 623 dataUri = Uri.withAppendedPath(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, 624 lookupKey), Contacts.Data.CONTENT_DIRECTORY); 625 assertDataRows(dataUri, values); 626 } 627 628 private void assertDataRows(Uri dataUri, ContentValues values) { 629 Cursor cursor = mResolver.query(dataUri, new String[]{ Data.DATA1 }, null, null, Data._ID); 630 assertEquals(3, cursor.getCount()); 631 cursor.moveToFirst(); 632 values.put(Data.DATA1, "John Doe"); 633 assertCursorValues(cursor, values); 634 635 cursor.moveToNext(); 636 values.put(Data.DATA1, "555-GOOG-411"); 637 assertCursorValues(cursor, values); 638 639 cursor.moveToNext(); 640 values.put(Data.DATA1, "google@android.com"); 641 assertCursorValues(cursor, values); 642 643 cursor.close(); 644 } 645 646 public void testContactEntitiesWithIdBasedUri() { 647 ContentValues values = new ContentValues(); 648 Account account1 = new Account("act1", "actype1"); 649 Account account2 = new Account("act2", "actype2"); 650 651 long rawContactId1 = createRawContactWithName(account1); 652 insertImHandle(rawContactId1, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk"); 653 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", StatusUpdates.IDLE, "Busy", 90, 654 StatusUpdates.CAPABILITY_HAS_CAMERA); 655 656 long rawContactId2 = createRawContact(account2); 657 setAggregationException( 658 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 659 660 long contactId = queryContactId(rawContactId1); 661 662 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 663 Uri entityUri = Uri.withAppendedPath(contactUri, Contacts.Entity.CONTENT_DIRECTORY); 664 665 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 666 } 667 668 public void testContactEntitiesWithLookupUri() { 669 ContentValues values = new ContentValues(); 670 Account account1 = new Account("act1", "actype1"); 671 Account account2 = new Account("act2", "actype2"); 672 673 long rawContactId1 = createRawContactWithName(account1); 674 insertImHandle(rawContactId1, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk"); 675 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", StatusUpdates.IDLE, "Busy", 90, 676 StatusUpdates.CAPABILITY_HAS_CAMERA); 677 678 long rawContactId2 = createRawContact(account2); 679 setAggregationException( 680 AggregationExceptions.TYPE_KEEP_TOGETHER, rawContactId1, rawContactId2); 681 682 long contactId = queryContactId(rawContactId1); 683 String lookupKey = queryLookupKey(contactId); 684 685 // First try with a matching contact ID 686 Uri contactLookupUri = ContactsContract.Contacts.getLookupUri(contactId, lookupKey); 687 Uri entityUri = Uri.withAppendedPath(contactLookupUri, Contacts.Entity.CONTENT_DIRECTORY); 688 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 689 690 // Now try with a contact ID mismatch 691 contactLookupUri = ContactsContract.Contacts.getLookupUri(contactId + 1, lookupKey); 692 entityUri = Uri.withAppendedPath(contactLookupUri, Contacts.Entity.CONTENT_DIRECTORY); 693 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 694 695 // Now try without an ID altogether 696 contactLookupUri = Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey); 697 entityUri = Uri.withAppendedPath(contactLookupUri, Contacts.Entity.CONTENT_DIRECTORY); 698 assertEntityRows(entityUri, contactId, rawContactId1, rawContactId2); 699 } 700 701 private void assertEntityRows(Uri entityUri, long contactId, long rawContactId1, 702 long rawContactId2) { 703 ContentValues values = new ContentValues(); 704 705 Cursor cursor = mResolver.query(entityUri, null, null, null, 706 Contacts.Entity.RAW_CONTACT_ID + "," + Contacts.Entity.DATA_ID); 707 assertEquals(3, cursor.getCount()); 708 709 // First row - name 710 cursor.moveToFirst(); 711 values.put(Contacts.Entity.CONTACT_ID, contactId); 712 values.put(Contacts.Entity.RAW_CONTACT_ID, rawContactId1); 713 values.put(Contacts.Entity.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); 714 values.put(Contacts.Entity.DATA1, "John Doe"); 715 values.put(Contacts.Entity.ACCOUNT_NAME, "act1"); 716 values.put(Contacts.Entity.ACCOUNT_TYPE, "actype1"); 717 values.put(Contacts.Entity.DISPLAY_NAME, "John Doe"); 718 values.put(Contacts.Entity.DISPLAY_NAME_ALTERNATIVE, "Doe, John"); 719 values.put(Contacts.Entity.NAME_RAW_CONTACT_ID, rawContactId1); 720 values.put(Contacts.Entity.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 721 values.put(Contacts.Entity.CONTACT_PRESENCE, StatusUpdates.IDLE); 722 values.put(Contacts.Entity.CONTACT_STATUS, "Busy"); 723 values.putNull(Contacts.Entity.PRESENCE); 724 assertCursorValues(cursor, values); 725 726 // Second row - IM 727 cursor.moveToNext(); 728 values.put(Contacts.Entity.CONTACT_ID, contactId); 729 values.put(Contacts.Entity.RAW_CONTACT_ID, rawContactId1); 730 values.put(Contacts.Entity.MIMETYPE, Im.CONTENT_ITEM_TYPE); 731 values.put(Contacts.Entity.DATA1, "gtalk"); 732 values.put(Contacts.Entity.ACCOUNT_NAME, "act1"); 733 values.put(Contacts.Entity.ACCOUNT_TYPE, "actype1"); 734 values.put(Contacts.Entity.DISPLAY_NAME, "John Doe"); 735 values.put(Contacts.Entity.DISPLAY_NAME_ALTERNATIVE, "Doe, John"); 736 values.put(Contacts.Entity.NAME_RAW_CONTACT_ID, rawContactId1); 737 values.put(Contacts.Entity.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 738 values.put(Contacts.Entity.CONTACT_PRESENCE, StatusUpdates.IDLE); 739 values.put(Contacts.Entity.CONTACT_STATUS, "Busy"); 740 values.put(Contacts.Entity.PRESENCE, StatusUpdates.IDLE); 741 assertCursorValues(cursor, values); 742 743 // Third row - second raw contact, not data 744 cursor.moveToNext(); 745 values.put(Contacts.Entity.CONTACT_ID, contactId); 746 values.put(Contacts.Entity.RAW_CONTACT_ID, rawContactId2); 747 values.putNull(Contacts.Entity.MIMETYPE); 748 values.putNull(Contacts.Entity.DATA_ID); 749 values.putNull(Contacts.Entity.DATA1); 750 values.put(Contacts.Entity.ACCOUNT_NAME, "act2"); 751 values.put(Contacts.Entity.ACCOUNT_TYPE, "actype2"); 752 values.put(Contacts.Entity.DISPLAY_NAME, "John Doe"); 753 values.put(Contacts.Entity.DISPLAY_NAME_ALTERNATIVE, "Doe, John"); 754 values.put(Contacts.Entity.NAME_RAW_CONTACT_ID, rawContactId1); 755 values.put(Contacts.Entity.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 756 values.put(Contacts.Entity.CONTACT_PRESENCE, StatusUpdates.IDLE); 757 values.put(Contacts.Entity.CONTACT_STATUS, "Busy"); 758 values.putNull(Contacts.Entity.PRESENCE); 759 assertCursorValues(cursor, values); 760 761 cursor.close(); 762 } 763 764 public void testDataInsert() { 765 long rawContactId = createRawContactWithName("John", "Doe"); 766 767 ContentValues values = new ContentValues(); 768 putDataValues(values, rawContactId); 769 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 770 long dataId = ContentUris.parseId(dataUri); 771 772 long contactId = queryContactId(rawContactId); 773 values.put(RawContacts.CONTACT_ID, contactId); 774 assertStoredValues(dataUri, values); 775 776 assertSelection(Data.CONTENT_URI, values, Data._ID, dataId); 777 778 // Access the same data through the directory under RawContacts 779 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 780 Uri rawContactDataUri = 781 Uri.withAppendedPath(rawContactUri, RawContacts.Data.CONTENT_DIRECTORY); 782 assertSelection(rawContactDataUri, values, Data._ID, dataId); 783 784 // Access the same data through the directory under Contacts 785 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 786 Uri contactDataUri = Uri.withAppendedPath(contactUri, Contacts.Data.CONTENT_DIRECTORY); 787 assertSelection(contactDataUri, values, Data._ID, dataId); 788 assertNetworkNotified(true); 789 } 790 791 public void testRawContactDataQuery() { 792 Account account1 = new Account("a", "b"); 793 Account account2 = new Account("c", "d"); 794 long rawContactId1 = createRawContact(account1); 795 Uri dataUri1 = insertStructuredName(rawContactId1, "John", "Doe"); 796 long rawContactId2 = createRawContact(account2); 797 Uri dataUri2 = insertStructuredName(rawContactId2, "Jane", "Doe"); 798 799 Uri uri1 = maybeAddAccountQueryParameters(dataUri1, account1); 800 Uri uri2 = maybeAddAccountQueryParameters(dataUri2, account2); 801 assertStoredValue(uri1, Data._ID, ContentUris.parseId(dataUri1)) ; 802 assertStoredValue(uri2, Data._ID, ContentUris.parseId(dataUri2)) ; 803 } 804 805 public void testPhonesQuery() { 806 807 ContentValues values = new ContentValues(); 808 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 809 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 810 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 811 values.put(RawContacts.TIMES_CONTACTED, 54321); 812 values.put(RawContacts.STARRED, 1); 813 814 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 815 long rawContactId = ContentUris.parseId(rawContactUri); 816 817 insertStructuredName(rawContactId, "Meghan", "Knox"); 818 Uri uri = insertPhoneNumber(rawContactId, "18004664411"); 819 long phoneId = ContentUris.parseId(uri); 820 821 822 long contactId = queryContactId(rawContactId); 823 values.clear(); 824 values.put(Data._ID, phoneId); 825 values.put(Data.RAW_CONTACT_ID, rawContactId); 826 values.put(RawContacts.CONTACT_ID, contactId); 827 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 828 values.put(Phone.NUMBER, "18004664411"); 829 values.put(Phone.TYPE, Phone.TYPE_HOME); 830 values.putNull(Phone.LABEL); 831 values.put(Contacts.DISPLAY_NAME, "Meghan Knox"); 832 values.put(Contacts.CUSTOM_RINGTONE, "d"); 833 values.put(Contacts.SEND_TO_VOICEMAIL, 1); 834 values.put(Contacts.LAST_TIME_CONTACTED, 12345); 835 values.put(Contacts.TIMES_CONTACTED, 54321); 836 values.put(Contacts.STARRED, 1); 837 838 assertStoredValues(ContentUris.withAppendedId(Phone.CONTENT_URI, phoneId), values); 839 assertSelection(Phone.CONTENT_URI, values, Data._ID, phoneId); 840 } 841 842 public void testPhonesFilterQuery() { 843 long rawContactId1 = createRawContactWithName("Hot", "Tamale"); 844 insertPhoneNumber(rawContactId1, "18004664411"); 845 insertPhoneNumber(rawContactId1, "1-800-466-4411"); 846 847 long rawContactId2 = createRawContactWithName("Hot", "Tamale"); 848 insertPhoneNumber(rawContactId2, "1-800-466-4411"); 849 850 Uri filterUri1 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "tamale"); 851 ContentValues values = new ContentValues(); 852 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 853 values.put(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); 854 values.put(Phone.NUMBER, "1-800-466-4411"); 855 values.put(Phone.TYPE, Phone.TYPE_HOME); 856 values.putNull(Phone.LABEL); 857 assertStoredValuesWithProjection(filterUri1, values); 858 859 Uri filterUri2 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "1-800-GOOG-411"); 860 assertStoredValues(filterUri2, values); 861 862 Uri filterUri3 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "18004664"); 863 assertStoredValues(filterUri3, values); 864 865 Uri filterUri4 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "encilada"); 866 assertEquals(0, getCount(filterUri4, null, null)); 867 868 Uri filterUri5 = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, "*"); 869 assertEquals(0, getCount(filterUri5, null, null)); 870 } 871 872 public void testPhoneLookup() { 873 ContentValues values = new ContentValues(); 874 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 875 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 876 877 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 878 long rawContactId = ContentUris.parseId(rawContactUri); 879 880 insertStructuredName(rawContactId, "Hot", "Tamale"); 881 insertPhoneNumber(rawContactId, "18004664411"); 882 883 Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411"); 884 885 values.clear(); 886 values.put(PhoneLookup._ID, queryContactId(rawContactId)); 887 values.put(PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 888 values.put(PhoneLookup.NUMBER, "18004664411"); 889 values.put(PhoneLookup.TYPE, Phone.TYPE_HOME); 890 values.putNull(PhoneLookup.LABEL); 891 values.put(PhoneLookup.CUSTOM_RINGTONE, "d"); 892 values.put(PhoneLookup.SEND_TO_VOICEMAIL, 1); 893 assertStoredValues(lookupUri1, values); 894 895 // In the context that 8004664411 is a valid number, "4664411" as a 896 // call id should not match to "8004664411" 897 Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "4664411"); 898 assertEquals(0, getCount(lookupUri2, null, null)); 899 } 900 901 public void testPhoneLookupUseCases() { 902 ContentValues values = new ContentValues(); 903 Uri rawContactUri; 904 long rawContactId; 905 Uri lookupUri2; 906 907 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 908 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 909 910 // International format in contacts 911 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 912 rawContactId = ContentUris.parseId(rawContactUri); 913 914 insertStructuredName(rawContactId, "Hot", "Tamale"); 915 insertPhoneNumber(rawContactId, "+1-650-861-0000"); 916 917 values.clear(); 918 919 // match with international format 920 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0000"); 921 assertEquals(1, getCount(lookupUri2, null, null)); 922 923 // match with national format 924 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0000"); 925 assertEquals(1, getCount(lookupUri2, null, null)); 926 927 // National format in contacts 928 values.clear(); 929 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 930 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 931 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 932 rawContactId = ContentUris.parseId(rawContactUri); 933 934 insertStructuredName(rawContactId, "Hot1", "Tamale"); 935 insertPhoneNumber(rawContactId, "650-861-0001"); 936 937 values.clear(); 938 939 // match with international format 940 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0001"); 941 assertEquals(2, getCount(lookupUri2, null, null)); 942 943 // match with national format 944 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0001"); 945 assertEquals(2, getCount(lookupUri2, null, null)); 946 947 // Local format in contacts 948 values.clear(); 949 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 950 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 951 rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 952 rawContactId = ContentUris.parseId(rawContactUri); 953 954 insertStructuredName(rawContactId, "Hot2", "Tamale"); 955 insertPhoneNumber(rawContactId, "861-0002"); 956 957 values.clear(); 958 959 // match with international format 960 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "+1 650 861 0002"); 961 assertEquals(1, getCount(lookupUri2, null, null)); 962 963 // match with national format 964 lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "650 861 0002"); 965 assertEquals(1, getCount(lookupUri2, null, null)); 966 } 967 968 public void testPhoneUpdate() { 969 ContentValues values = new ContentValues(); 970 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 971 long rawContactId = ContentUris.parseId(rawContactUri); 972 973 insertStructuredName(rawContactId, "Hot", "Tamale"); 974 Uri phoneUri = insertPhoneNumber(rawContactId, "18004664411"); 975 976 Uri lookupUri1 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664411"); 977 assertStoredValue(lookupUri1, PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 978 979 values.clear(); 980 values.put(Phone.NUMBER, "18004664422"); 981 mResolver.update(phoneUri, values, null, null); 982 983 Uri lookupUri2 = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, "8004664422"); 984 assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 985 986 // Setting number to null will remove the phone lookup record 987 values.clear(); 988 values.putNull(Phone.NUMBER); 989 mResolver.update(phoneUri, values, null, null); 990 991 assertEquals(0, getCount(lookupUri2, null, null)); 992 993 // Let's restore that phone lookup record 994 values.clear(); 995 values.put(Phone.NUMBER, "18004664422"); 996 mResolver.update(phoneUri, values, null, null); 997 assertStoredValue(lookupUri2, PhoneLookup.DISPLAY_NAME, "Hot Tamale"); 998 assertNetworkNotified(true); 999 } 1000 1001 public void testEmailsQuery() { 1002 ContentValues values = new ContentValues(); 1003 values.put(RawContacts.CUSTOM_RINGTONE, "d"); 1004 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 1005 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 1006 values.put(RawContacts.TIMES_CONTACTED, 54321); 1007 values.put(RawContacts.STARRED, 1); 1008 1009 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1010 long rawContactId = ContentUris.parseId(rawContactUri); 1011 1012 insertStructuredName(rawContactId, "Meghan", "Knox"); 1013 Uri uri = insertEmail(rawContactId, "meghan@acme.com"); 1014 long emailId = ContentUris.parseId(uri); 1015 1016 long contactId = queryContactId(rawContactId); 1017 values.clear(); 1018 values.put(Data._ID, emailId); 1019 values.put(Data.RAW_CONTACT_ID, rawContactId); 1020 values.put(RawContacts.CONTACT_ID, contactId); 1021 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 1022 values.put(Email.DATA, "meghan@acme.com"); 1023 values.put(Email.TYPE, Email.TYPE_HOME); 1024 values.putNull(Email.LABEL); 1025 values.put(Contacts.DISPLAY_NAME, "Meghan Knox"); 1026 values.put(Contacts.CUSTOM_RINGTONE, "d"); 1027 values.put(Contacts.SEND_TO_VOICEMAIL, 1); 1028 values.put(Contacts.LAST_TIME_CONTACTED, 12345); 1029 values.put(Contacts.TIMES_CONTACTED, 54321); 1030 values.put(Contacts.STARRED, 1); 1031 1032 assertStoredValues(ContentUris.withAppendedId(Email.CONTENT_URI, emailId), values); 1033 assertSelection(Email.CONTENT_URI, values, Data._ID, emailId); 1034 } 1035 1036 public void testEmailsLookupQuery() { 1037 long rawContactId = createRawContactWithName("Hot", "Tamale"); 1038 insertEmail(rawContactId, "tamale@acme.com"); 1039 1040 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "tamale@acme.com"); 1041 ContentValues values = new ContentValues(); 1042 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 1043 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 1044 values.put(Email.DATA, "tamale@acme.com"); 1045 values.put(Email.TYPE, Email.TYPE_HOME); 1046 values.putNull(Email.LABEL); 1047 assertStoredValues(filterUri1, values); 1048 1049 Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "Ta<TaMale@acme.com>"); 1050 assertStoredValues(filterUri2, values); 1051 1052 Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, "encilada@acme.com"); 1053 assertEquals(0, getCount(filterUri3, null, null)); 1054 } 1055 1056 public void testEmailsFilterQuery() { 1057 long rawContactId1 = createRawContactWithName("Hot", "Tamale"); 1058 insertEmail(rawContactId1, "tamale@acme.com"); 1059 insertEmail(rawContactId1, "tamale@acme.com"); 1060 1061 long rawContactId2 = createRawContactWithName("Hot", "Tamale"); 1062 insertEmail(rawContactId2, "tamale@acme.com"); 1063 1064 Uri filterUri1 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tam"); 1065 ContentValues values = new ContentValues(); 1066 values.put(Contacts.DISPLAY_NAME, "Hot Tamale"); 1067 values.put(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); 1068 values.put(Email.DATA, "tamale@acme.com"); 1069 values.put(Email.TYPE, Email.TYPE_HOME); 1070 values.putNull(Email.LABEL); 1071 assertStoredValuesWithProjection(filterUri1, values); 1072 1073 Uri filterUri2 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hot"); 1074 assertStoredValuesWithProjection(filterUri2, values); 1075 1076 Uri filterUri3 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "hottamale"); 1077 assertStoredValuesWithProjection(filterUri3, values); 1078 1079 Uri filterUri4 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "tamale@acme"); 1080 assertStoredValuesWithProjection(filterUri4, values); 1081 1082 Uri filterUri5 = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "encilada"); 1083 assertEquals(0, getCount(filterUri5, null, null)); 1084 } 1085 1086 public void testPostalsQuery() { 1087 long rawContactId = createRawContactWithName("Alice", "Nextore"); 1088 Uri dataUri = insertPostalAddress(rawContactId, "1600 Amphiteatre Ave, Mountain View"); 1089 long dataId = ContentUris.parseId(dataUri); 1090 1091 long contactId = queryContactId(rawContactId); 1092 ContentValues values = new ContentValues(); 1093 values.put(Data._ID, dataId); 1094 values.put(Data.RAW_CONTACT_ID, rawContactId); 1095 values.put(RawContacts.CONTACT_ID, contactId); 1096 values.put(Data.MIMETYPE, StructuredPostal.CONTENT_ITEM_TYPE); 1097 values.put(StructuredPostal.FORMATTED_ADDRESS, "1600 Amphiteatre Ave, Mountain View"); 1098 values.put(Contacts.DISPLAY_NAME, "Alice Nextore"); 1099 1100 assertStoredValues(ContentUris.withAppendedId(StructuredPostal.CONTENT_URI, dataId), 1101 values); 1102 assertSelection(StructuredPostal.CONTENT_URI, values, Data._ID, dataId); 1103 } 1104 1105 public void testQueryContactData() { 1106 ContentValues values = new ContentValues(); 1107 long contactId = createContact(values, "John", "Doe", 1108 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 1109 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO); 1110 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1111 1112 assertStoredValues(contactUri, values); 1113 assertSelection(Contacts.CONTENT_URI, values, Contacts._ID, contactId); 1114 } 1115 1116 public void testQueryContactWithStatusUpdate() { 1117 ContentValues values = new ContentValues(); 1118 long contactId = createContact(values, "John", "Doe", 1119 "18004664411", "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 1120 StatusUpdates.CAPABILITY_HAS_CAMERA); 1121 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 1122 values.put(Contacts.CONTACT_CHAT_CAPABILITY, StatusUpdates.CAPABILITY_HAS_CAMERA); 1123 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1124 assertStoredValuesWithProjection(contactUri, values); 1125 assertSelectionWithProjection(Contacts.CONTENT_URI, values, Contacts._ID, contactId); 1126 } 1127 1128 public void testQueryContactFilter() { 1129 ContentValues values = new ContentValues(); 1130 long rawContactId = createRawContact(values, "18004664411", 1131 "goog411@acme.com", StatusUpdates.INVISIBLE, 4, 1, 0, 1132 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO | 1133 StatusUpdates.CAPABILITY_HAS_VOICE); 1134 1135 ContentValues nameValues = new ContentValues(); 1136 nameValues.put(StructuredName.GIVEN_NAME, "Stu"); 1137 nameValues.put(StructuredName.FAMILY_NAME, "Goulash"); 1138 nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "goo"); 1139 nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "LASH"); 1140 Uri nameUri = insertStructuredName(rawContactId, nameValues); 1141 1142 long contactId = queryContactId(rawContactId); 1143 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 1144 1145 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goulash"); 1146 assertStoredValuesWithProjection(filterUri1, values); 1147 1148 assertContactFilter(contactId, "goolash"); 1149 assertContactFilter(contactId, "lash"); 1150 1151 Uri filterUri2 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goolish"); 1152 assertEquals(0, getCount(filterUri2, null, null)); 1153 1154 // Phonetic name with given/family reversed should not match 1155 Uri filterUri3 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "lashgoo"); 1156 assertEquals(0, getCount(filterUri3, null, null)); 1157 1158 nameValues.clear(); 1159 nameValues.put(StructuredName.PHONETIC_FAMILY_NAME, "ga"); 1160 nameValues.put(StructuredName.PHONETIC_GIVEN_NAME, "losh"); 1161 1162 mResolver.update(nameUri, nameValues, null, null); 1163 1164 assertContactFilter(contactId, "galosh"); 1165 1166 Uri filterUri4 = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, "goolish"); 1167 assertEquals(0, getCount(filterUri4, null, null)); 1168 } 1169 1170 public void testQueryContactStrequent() { 1171 ContentValues values1 = new ContentValues(); 1172 createContact(values1, "Noah", "Tever", "18004664411", 1173 "a@acme.com", StatusUpdates.OFFLINE, 0, 0, 0, 1174 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO); 1175 ContentValues values2 = new ContentValues(); 1176 createContact(values2, "Sam", "Times", "18004664412", 1177 "b@acme.com", StatusUpdates.INVISIBLE, 3, 0, 0, 1178 StatusUpdates.CAPABILITY_HAS_CAMERA); 1179 ContentValues values3 = new ContentValues(); 1180 createContact(values3, "Lotta", "Calling", "18004664413", 1181 "c@acme.com", StatusUpdates.AWAY, 5, 0, 0, 1182 StatusUpdates.CAPABILITY_HAS_VIDEO); 1183 ContentValues values4 = new ContentValues(); 1184 createContact(values4, "Fay", "Veritt", "18004664414", 1185 "d@acme.com", StatusUpdates.AVAILABLE, 0, 1, 0, 1186 StatusUpdates.CAPABILITY_HAS_VIDEO | StatusUpdates.CAPABILITY_HAS_VOICE); 1187 1188 Cursor c = mResolver.query(Contacts.CONTENT_STREQUENT_URI, null, null, null, 1189 Contacts._ID); 1190 assertEquals(3, c.getCount()); 1191 c.moveToFirst(); 1192 assertCursorValues(c, values4); 1193 c.moveToNext(); 1194 assertCursorValues(c, values3); 1195 c.moveToNext(); 1196 assertCursorValues(c, values2); 1197 c.close(); 1198 1199 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_STREQUENT_FILTER_URI, "fay"); 1200 c = mResolver.query(filterUri, null, null, null, Contacts._ID); 1201 assertEquals(1, c.getCount()); 1202 c.moveToFirst(); 1203 assertCursorValues(c, values4); 1204 c.close(); 1205 } 1206 1207 public void testQueryContactGroup() { 1208 long groupId = createGroup(null, "testGroup", "Test Group"); 1209 1210 ContentValues values1 = new ContentValues(); 1211 createContact(values1, "Best", "West", "18004664411", 1212 "west@acme.com", StatusUpdates.OFFLINE, 0, 0, groupId, 1213 StatusUpdates.CAPABILITY_HAS_CAMERA); 1214 1215 ContentValues values2 = new ContentValues(); 1216 createContact(values2, "Rest", "East", "18004664422", 1217 "east@acme.com", StatusUpdates.AVAILABLE, 0, 0, 0, 1218 StatusUpdates.CAPABILITY_HAS_VOICE); 1219 1220 Uri filterUri1 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group"); 1221 Cursor c = mResolver.query(filterUri1, null, null, null, Contacts._ID); 1222 assertEquals(1, c.getCount()); 1223 c.moveToFirst(); 1224 assertCursorValues(c, values1); 1225 c.close(); 1226 1227 Uri filterUri2 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Test Group"); 1228 c = mResolver.query(filterUri2, null, Contacts.DISPLAY_NAME + "=?", 1229 new String[] { "Best West" }, Contacts._ID); 1230 assertEquals(1, c.getCount()); 1231 c.close(); 1232 1233 Uri filterUri3 = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, "Next Group"); 1234 c = mResolver.query(filterUri3, null, null, null, Contacts._ID); 1235 assertEquals(0, c.getCount()); 1236 c.close(); 1237 } 1238 1239 public void testPhonesWithStatusUpdate() { 1240 1241 ContentValues values = new ContentValues(); 1242 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 1243 long rawContactId = ContentUris.parseId(rawContactUri); 1244 insertStructuredName(rawContactId, "John", "Doe"); 1245 Uri photoUri = insertPhoto(rawContactId); 1246 long photoId = ContentUris.parseId(photoUri); 1247 values.put(Contacts.PHOTO_ID, photoId); 1248 insertPhoneNumber(rawContactId, "18004664411"); 1249 insertPhoneNumber(rawContactId, "18004664412"); 1250 insertEmail(rawContactId, "goog411@acme.com"); 1251 insertEmail(rawContactId, "goog412@acme.com"); 1252 1253 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog411@acme.com", 1254 StatusUpdates.INVISIBLE, "Bad", 1255 StatusUpdates.CAPABILITY_HAS_CAMERA); 1256 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "goog412@acme.com", 1257 StatusUpdates.AVAILABLE, "Good", 1258 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VOICE); 1259 long contactId = queryContactId(rawContactId); 1260 1261 Uri uri = Data.CONTENT_URI; 1262 1263 Cursor c = mResolver.query(uri, null, RawContacts.CONTACT_ID + "=" + contactId + " AND " 1264 + Data.MIMETYPE + "='" + Phone.CONTENT_ITEM_TYPE + "'", null, Phone.NUMBER); 1265 assertEquals(2, c.getCount()); 1266 1267 c.moveToFirst(); 1268 1269 values.clear(); 1270 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 1271 values.put(Contacts.CONTACT_STATUS, "Bad"); 1272 values.put(Contacts.DISPLAY_NAME, "John Doe"); 1273 values.put(Phone.NUMBER, "18004664411"); 1274 values.putNull(Phone.LABEL); 1275 values.put(RawContacts.CONTACT_ID, contactId); 1276 assertCursorValues(c, values); 1277 1278 c.moveToNext(); 1279 1280 values.clear(); 1281 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 1282 values.put(Contacts.CONTACT_STATUS, "Bad"); 1283 values.put(Contacts.DISPLAY_NAME, "John Doe"); 1284 values.put(Phone.NUMBER, "18004664412"); 1285 values.putNull(Phone.LABEL); 1286 values.put(RawContacts.CONTACT_ID, contactId); 1287 assertCursorValues(c, values); 1288 1289 c.close(); 1290 } 1291 1292 public void testGroupQuery() { 1293 Account account1 = new Account("a", "b"); 1294 Account account2 = new Account("c", "d"); 1295 long groupId1 = createGroup(account1, "e", "f"); 1296 long groupId2 = createGroup(account2, "g", "h"); 1297 Uri uri1 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account1); 1298 Uri uri2 = maybeAddAccountQueryParameters(Groups.CONTENT_URI, account2); 1299 assertEquals(1, getCount(uri1, null, null)); 1300 assertEquals(1, getCount(uri2, null, null)); 1301 assertStoredValue(uri1, Groups._ID + "=" + groupId1, null, Groups._ID, groupId1) ; 1302 assertStoredValue(uri2, Groups._ID + "=" + groupId2, null, Groups._ID, groupId2) ; 1303 } 1304 1305 public void testGroupInsert() { 1306 ContentValues values = new ContentValues(); 1307 1308 values.put(Groups.ACCOUNT_NAME, "a"); 1309 values.put(Groups.ACCOUNT_TYPE, "b"); 1310 values.put(Groups.SOURCE_ID, "c"); 1311 values.put(Groups.VERSION, 42); 1312 values.put(Groups.GROUP_VISIBLE, 1); 1313 values.put(Groups.TITLE, "d"); 1314 values.put(Groups.TITLE_RES, 1234); 1315 values.put(Groups.NOTES, "e"); 1316 values.put(Groups.RES_PACKAGE, "f"); 1317 values.put(Groups.SYSTEM_ID, "g"); 1318 values.put(Groups.DELETED, 1); 1319 values.put(Groups.SYNC1, "h"); 1320 values.put(Groups.SYNC2, "i"); 1321 values.put(Groups.SYNC3, "j"); 1322 values.put(Groups.SYNC4, "k"); 1323 1324 Uri rowUri = mResolver.insert(Groups.CONTENT_URI, values); 1325 1326 values.put(Groups.DIRTY, 1); 1327 assertStoredValues(rowUri, values); 1328 } 1329 1330 public void testSettingsQuery() { 1331 Account account1 = new Account("a", "b"); 1332 Account account2 = new Account("c", "d"); 1333 createSettings(account1, "0", "0"); 1334 createSettings(account2, "1", "1"); 1335 Uri uri1 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account1); 1336 Uri uri2 = maybeAddAccountQueryParameters(Settings.CONTENT_URI, account2); 1337 assertEquals(1, getCount(uri1, null, null)); 1338 assertEquals(1, getCount(uri2, null, null)); 1339 assertStoredValue(uri1, Settings.SHOULD_SYNC, "0") ; 1340 assertStoredValue(uri1, Settings.UNGROUPED_VISIBLE, "0") ; 1341 assertStoredValue(uri2, Settings.SHOULD_SYNC, "1") ; 1342 assertStoredValue(uri2, Settings.UNGROUPED_VISIBLE, "1") ; 1343 } 1344 1345 public void testDisplayNameParsingWhenPartsUnspecified() { 1346 long rawContactId = createRawContact(); 1347 ContentValues values = new ContentValues(); 1348 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 1349 insertStructuredName(rawContactId, values); 1350 1351 assertStructuredName(rawContactId, "Mr", "John", "Kevin", "von Smith", "Jr."); 1352 } 1353 1354 public void testDisplayNameParsingWhenPartsAreNull() { 1355 long rawContactId = createRawContact(); 1356 ContentValues values = new ContentValues(); 1357 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 1358 values.putNull(StructuredName.GIVEN_NAME); 1359 values.putNull(StructuredName.FAMILY_NAME); 1360 insertStructuredName(rawContactId, values); 1361 assertStructuredName(rawContactId, "Mr", "John", "Kevin", "von Smith", "Jr."); 1362 } 1363 1364 public void testDisplayNameParsingWhenPartsSpecified() { 1365 long rawContactId = createRawContact(); 1366 ContentValues values = new ContentValues(); 1367 values.put(StructuredName.DISPLAY_NAME, "Mr.John Kevin von Smith, Jr."); 1368 values.put(StructuredName.FAMILY_NAME, "Johnson"); 1369 insertStructuredName(rawContactId, values); 1370 1371 assertStructuredName(rawContactId, null, null, null, "Johnson", null); 1372 } 1373 1374 public void testContactWithoutPhoneticName() { 1375 final long rawContactId = createRawContact(null); 1376 1377 ContentValues values = new ContentValues(); 1378 values.put(StructuredName.PREFIX, "Mr"); 1379 values.put(StructuredName.GIVEN_NAME, "John"); 1380 values.put(StructuredName.MIDDLE_NAME, "K."); 1381 values.put(StructuredName.FAMILY_NAME, "Doe"); 1382 values.put(StructuredName.SUFFIX, "Jr."); 1383 Uri dataUri = insertStructuredName(rawContactId, values); 1384 1385 values.clear(); 1386 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 1387 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "John K. Doe, Jr."); 1388 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "Doe, John K., Jr."); 1389 values.putNull(RawContacts.PHONETIC_NAME); 1390 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 1391 values.put(RawContacts.SORT_KEY_PRIMARY, "John K. Doe, Jr."); 1392 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "Doe, John K., Jr."); 1393 1394 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 1395 assertStoredValues(rawContactUri, values); 1396 1397 values.clear(); 1398 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 1399 values.put(Contacts.DISPLAY_NAME_PRIMARY, "John K. Doe, Jr."); 1400 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "Doe, John K., Jr."); 1401 values.putNull(Contacts.PHONETIC_NAME); 1402 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 1403 values.put(Contacts.SORT_KEY_PRIMARY, "John K. Doe, Jr."); 1404 values.put(Contacts.SORT_KEY_ALTERNATIVE, "Doe, John K., Jr."); 1405 1406 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 1407 queryContactId(rawContactId)); 1408 assertStoredValues(contactUri, values); 1409 1410 // The same values should be available through a join with Data 1411 assertStoredValues(dataUri, values); 1412 } 1413 1414 public void testContactWithChineseName() { 1415 1416 // Only run this test when Chinese collation is supported 1417 if (!Arrays.asList(Collator.getAvailableLocales()).contains(Locale.CHINA)) { 1418 return; 1419 } 1420 1421 long rawContactId = createRawContact(null); 1422 1423 ContentValues values = new ContentValues(); 1424 values.put(StructuredName.DISPLAY_NAME, "\u6BB5\u5C0F\u6D9B"); 1425 Uri dataUri = insertStructuredName(rawContactId, values); 1426 1427 values.clear(); 1428 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 1429 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "\u6BB5\u5C0F\u6D9B"); 1430 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B"); 1431 values.putNull(RawContacts.PHONETIC_NAME); 1432 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 1433 values.put(RawContacts.SORT_KEY_PRIMARY, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 1434 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 1435 1436 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 1437 assertStoredValues(rawContactUri, values); 1438 1439 values.clear(); 1440 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 1441 values.put(Contacts.DISPLAY_NAME_PRIMARY, "\u6BB5\u5C0F\u6D9B"); 1442 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "\u6BB5\u5C0F\u6D9B"); 1443 values.putNull(Contacts.PHONETIC_NAME); 1444 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 1445 values.put(Contacts.SORT_KEY_PRIMARY, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 1446 values.put(Contacts.SORT_KEY_ALTERNATIVE, "DUAN \u6BB5 XIAO \u5C0F TAO \u6D9B"); 1447 1448 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 1449 queryContactId(rawContactId)); 1450 assertStoredValues(contactUri, values); 1451 1452 // The same values should be available through a join with Data 1453 assertStoredValues(dataUri, values); 1454 } 1455 1456 public void testContactWithJapaneseName() { 1457 long rawContactId = createRawContact(null); 1458 1459 ContentValues values = new ContentValues(); 1460 values.put(StructuredName.GIVEN_NAME, "\u7A7A\u6D77"); 1461 values.put(StructuredName.PHONETIC_GIVEN_NAME, "\u304B\u3044\u304F\u3046"); 1462 Uri dataUri = insertStructuredName(rawContactId, values); 1463 1464 values.clear(); 1465 values.put(RawContacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 1466 values.put(RawContacts.DISPLAY_NAME_PRIMARY, "\u7A7A\u6D77"); 1467 values.put(RawContacts.DISPLAY_NAME_ALTERNATIVE, "\u7A7A\u6D77"); 1468 values.put(RawContacts.PHONETIC_NAME, "\u304B\u3044\u304F\u3046"); 1469 values.put(RawContacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 1470 values.put(RawContacts.SORT_KEY_PRIMARY, "\u304B\u3044\u304F\u3046"); 1471 values.put(RawContacts.SORT_KEY_ALTERNATIVE, "\u304B\u3044\u304F\u3046"); 1472 1473 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 1474 assertStoredValues(rawContactUri, values); 1475 1476 values.clear(); 1477 values.put(Contacts.DISPLAY_NAME_SOURCE, DisplayNameSources.STRUCTURED_NAME); 1478 values.put(Contacts.DISPLAY_NAME_PRIMARY, "\u7A7A\u6D77"); 1479 values.put(Contacts.DISPLAY_NAME_ALTERNATIVE, "\u7A7A\u6D77"); 1480 values.put(Contacts.PHONETIC_NAME, "\u304B\u3044\u304F\u3046"); 1481 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 1482 values.put(Contacts.SORT_KEY_PRIMARY, "\u304B\u3044\u304F\u3046"); 1483 values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u304B\u3044\u304F\u3046"); 1484 1485 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 1486 queryContactId(rawContactId)); 1487 assertStoredValues(contactUri, values); 1488 1489 // The same values should be available through a join with Data 1490 assertStoredValues(dataUri, values); 1491 } 1492 1493 public void testDisplayNameUpdate() { 1494 long rawContactId1 = createRawContact(); 1495 insertEmail(rawContactId1, "potato@acme.com", true); 1496 1497 long rawContactId2 = createRawContact(); 1498 insertPhoneNumber(rawContactId2, "123456789", true); 1499 1500 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1501 rawContactId1, rawContactId2); 1502 1503 assertAggregated(rawContactId1, rawContactId2, "123456789"); 1504 1505 insertStructuredName(rawContactId2, "Potato", "Head"); 1506 1507 assertAggregated(rawContactId1, rawContactId2, "Potato Head"); 1508 assertNetworkNotified(true); 1509 } 1510 1511 public void testDisplayNameFromData() { 1512 long rawContactId = createRawContact(); 1513 long contactId = queryContactId(rawContactId); 1514 ContentValues values = new ContentValues(); 1515 1516 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1517 1518 assertStoredValue(uri, Contacts.DISPLAY_NAME, null); 1519 insertEmail(rawContactId, "mike@monstersinc.com"); 1520 assertStoredValue(uri, Contacts.DISPLAY_NAME, "mike@monstersinc.com"); 1521 1522 insertEmail(rawContactId, "james@monstersinc.com", true); 1523 assertStoredValue(uri, Contacts.DISPLAY_NAME, "james@monstersinc.com"); 1524 1525 insertPhoneNumber(rawContactId, "1-800-466-4411"); 1526 assertStoredValue(uri, Contacts.DISPLAY_NAME, "1-800-466-4411"); 1527 1528 // If there are title and company, the company is display name. 1529 values.clear(); 1530 values.put(Organization.COMPANY, "Monsters Inc"); 1531 Uri organizationUri = insertOrganization(rawContactId, values); 1532 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Monsters Inc"); 1533 1534 // If there is nickname, that is display name. 1535 insertNickname(rawContactId, "Sully"); 1536 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Sully"); 1537 1538 // If there is structured name, that is display name. 1539 values.clear(); 1540 values.put(StructuredName.GIVEN_NAME, "James"); 1541 values.put(StructuredName.MIDDLE_NAME, "P."); 1542 values.put(StructuredName.FAMILY_NAME, "Sullivan"); 1543 insertStructuredName(rawContactId, values); 1544 assertStoredValue(uri, Contacts.DISPLAY_NAME, "James P. Sullivan"); 1545 } 1546 1547 public void testDisplayNameFromOrganizationWithoutPhoneticName() { 1548 long rawContactId = createRawContact(); 1549 long contactId = queryContactId(rawContactId); 1550 ContentValues values = new ContentValues(); 1551 1552 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1553 1554 // If there is title without company, the title is display name. 1555 values.clear(); 1556 values.put(Organization.TITLE, "Protagonist"); 1557 Uri organizationUri = insertOrganization(rawContactId, values); 1558 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Protagonist"); 1559 1560 // If there are title and company, the company is display name. 1561 values.clear(); 1562 values.put(Organization.COMPANY, "Monsters Inc"); 1563 mResolver.update(organizationUri, values, null, null); 1564 1565 values.clear(); 1566 values.put(Contacts.DISPLAY_NAME, "Monsters Inc"); 1567 values.putNull(Contacts.PHONETIC_NAME); 1568 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 1569 values.put(Contacts.SORT_KEY_PRIMARY, "Monsters Inc"); 1570 values.put(Contacts.SORT_KEY_ALTERNATIVE, "Monsters Inc"); 1571 assertStoredValues(uri, values); 1572 } 1573 1574 public void testDisplayNameFromOrganizationWithJapanesePhoneticName() { 1575 long rawContactId = createRawContact(); 1576 long contactId = queryContactId(rawContactId); 1577 ContentValues values = new ContentValues(); 1578 1579 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1580 1581 // If there is title without company, the title is display name. 1582 values.clear(); 1583 values.put(Organization.COMPANY, "DoCoMo"); 1584 values.put(Organization.PHONETIC_NAME, "\u30C9\u30B3\u30E2"); 1585 Uri organizationUri = insertOrganization(rawContactId, values); 1586 1587 values.clear(); 1588 values.put(Contacts.DISPLAY_NAME, "DoCoMo"); 1589 values.put(Contacts.PHONETIC_NAME, "\u30C9\u30B3\u30E2"); 1590 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.JAPANESE); 1591 values.put(Contacts.SORT_KEY_PRIMARY, "\u30C9\u30B3\u30E2"); 1592 values.put(Contacts.SORT_KEY_ALTERNATIVE, "\u30C9\u30B3\u30E2"); 1593 assertStoredValues(uri, values); 1594 } 1595 1596 public void testDisplayNameFromOrganizationWithChineseName() { 1597 boolean hasChineseCollator = false; 1598 final Locale locale[] = Collator.getAvailableLocales(); 1599 for (int i = 0; i < locale.length; i++) { 1600 if (locale[i].equals(Locale.CHINA)) { 1601 hasChineseCollator = true; 1602 break; 1603 } 1604 } 1605 1606 if (!hasChineseCollator) { 1607 return; 1608 } 1609 1610 long rawContactId = createRawContact(); 1611 long contactId = queryContactId(rawContactId); 1612 ContentValues values = new ContentValues(); 1613 1614 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1615 1616 // If there is title without company, the title is display name. 1617 values.clear(); 1618 values.put(Organization.COMPANY, "\u4E2D\u56FD\u7535\u4FE1"); 1619 Uri organizationUri = insertOrganization(rawContactId, values); 1620 1621 values.clear(); 1622 values.put(Contacts.DISPLAY_NAME, "\u4E2D\u56FD\u7535\u4FE1"); 1623 values.putNull(Contacts.PHONETIC_NAME); 1624 values.put(Contacts.PHONETIC_NAME_STYLE, PhoneticNameStyle.UNDEFINED); 1625 values.put(Contacts.SORT_KEY_PRIMARY, "ZHONG \u4E2D GUO \u56FD DIAN \u7535 XIN \u4FE1"); 1626 values.put(Contacts.SORT_KEY_ALTERNATIVE, "ZHONG \u4E2D GUO \u56FD DIAN \u7535 XIN \u4FE1"); 1627 assertStoredValues(uri, values); 1628 } 1629 1630 public void testLookupByOrganization() { 1631 long rawContactId = createRawContact(); 1632 long contactId = queryContactId(rawContactId); 1633 ContentValues values = new ContentValues(); 1634 1635 values.clear(); 1636 values.put(Organization.COMPANY, "acmecorp"); 1637 values.put(Organization.TITLE, "president"); 1638 Uri organizationUri = insertOrganization(rawContactId, values); 1639 1640 assertContactFilter(contactId, "acmecorp"); 1641 assertContactFilter(contactId, "president"); 1642 1643 values.clear(); 1644 values.put(Organization.DEPARTMENT, "software"); 1645 mResolver.update(organizationUri, values, null, null); 1646 1647 assertContactFilter(contactId, "acmecorp"); 1648 assertContactFilter(contactId, "president"); 1649 1650 values.clear(); 1651 values.put(Organization.COMPANY, "incredibles"); 1652 mResolver.update(organizationUri, values, null, null); 1653 1654 assertContactFilter(contactId, "incredibles"); 1655 assertContactFilter(contactId, "president"); 1656 1657 values.clear(); 1658 values.put(Organization.TITLE, "director"); 1659 mResolver.update(organizationUri, values, null, null); 1660 1661 assertContactFilter(contactId, "incredibles"); 1662 assertContactFilter(contactId, "director"); 1663 1664 values.clear(); 1665 values.put(Organization.COMPANY, "monsters"); 1666 values.put(Organization.TITLE, "scarer"); 1667 mResolver.update(organizationUri, values, null, null); 1668 1669 assertContactFilter(contactId, "monsters"); 1670 assertContactFilter(contactId, "scarer"); 1671 } 1672 1673 private void assertContactFilter(long contactId, String filter) { 1674 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode(filter)); 1675 assertStoredValue(filterUri, Contacts._ID, contactId); 1676 } 1677 1678 public void testSearchSnippetOrganization() throws Exception { 1679 long rawContactId = createRawContactWithName(); 1680 long contactId = queryContactId(rawContactId); 1681 1682 // Some random data element 1683 insertEmail(rawContactId, "inc@corp.com"); 1684 1685 ContentValues values = new ContentValues(); 1686 values.clear(); 1687 values.put(Organization.COMPANY, "acmecorp"); 1688 values.put(Organization.TITLE, "engineer"); 1689 Uri organizationUri = insertOrganization(rawContactId, values); 1690 1691 // Add another matching organization 1692 values.put(Organization.COMPANY, "acmeinc"); 1693 insertOrganization(rawContactId, values); 1694 1695 // Add another non-matching organization 1696 values.put(Organization.COMPANY, "corpacme"); 1697 insertOrganization(rawContactId, values); 1698 1699 // And another data element 1700 insertEmail(rawContactId, "emca@corp.com", true, Email.TYPE_CUSTOM, "Custom"); 1701 1702 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode("acme")); 1703 1704 values.clear(); 1705 values.put(Contacts._ID, contactId); 1706 values.put(SearchSnippetColumns.SNIPPET_DATA_ID, ContentUris.parseId(organizationUri)); 1707 values.put(SearchSnippetColumns.SNIPPET_DATA1, "acmecorp"); 1708 values.put(SearchSnippetColumns.SNIPPET_DATA4, "engineer"); 1709 values.put(SearchSnippetColumns.SNIPPET_MIMETYPE, Organization.CONTENT_ITEM_TYPE); 1710 assertStoredValues(filterUri, values); 1711 } 1712 1713 public void testSearchSnippetEmail() throws Exception { 1714 long rawContactId = createRawContact(); 1715 long contactId = queryContactId(rawContactId); 1716 ContentValues values = new ContentValues(); 1717 1718 Uri dataUri = insertEmail(rawContactId, "acme@corp.com", true, Email.TYPE_CUSTOM, "Custom"); 1719 1720 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode("acme")); 1721 1722 values.clear(); 1723 values.put(Contacts._ID, contactId); 1724 values.put(SearchSnippetColumns.SNIPPET_DATA1, "acme@corp.com"); 1725 values.put(SearchSnippetColumns.SNIPPET_DATA_ID, ContentUris.parseId(dataUri)); 1726 values.put(SearchSnippetColumns.SNIPPET_MIMETYPE, Email.CONTENT_ITEM_TYPE); 1727 values.put(SearchSnippetColumns.SNIPPET_DATA2, Email.TYPE_CUSTOM); 1728 values.put(SearchSnippetColumns.SNIPPET_DATA3, "Custom"); 1729 assertStoredValues(filterUri, values); 1730 } 1731 1732 public void testSearchSnippetNickname() throws Exception { 1733 long rawContactId = createRawContactWithName(); 1734 long contactId = queryContactId(rawContactId); 1735 ContentValues values = new ContentValues(); 1736 1737 Uri dataUri = insertNickname(rawContactId, "Incredible"); 1738 1739 Uri filterUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI, Uri.encode("inc")); 1740 1741 values.clear(); 1742 values.put(Contacts._ID, contactId); 1743 values.put(SearchSnippetColumns.SNIPPET_DATA1, "Incredible"); 1744 values.put(SearchSnippetColumns.SNIPPET_DATA_ID, ContentUris.parseId(dataUri)); 1745 values.put(SearchSnippetColumns.SNIPPET_MIMETYPE, Nickname.CONTENT_ITEM_TYPE); 1746 assertStoredValues(filterUri, values); 1747 } 1748 1749 public void testDisplayNameUpdateFromStructuredNameUpdate() { 1750 long rawContactId = createRawContact(); 1751 Uri nameUri = insertStructuredName(rawContactId, "Slinky", "Dog"); 1752 1753 long contactId = queryContactId(rawContactId); 1754 1755 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1756 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky Dog"); 1757 1758 ContentValues values = new ContentValues(); 1759 values.putNull(StructuredName.FAMILY_NAME); 1760 1761 mResolver.update(nameUri, values, null, null); 1762 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Slinky"); 1763 1764 values.putNull(StructuredName.GIVEN_NAME); 1765 1766 mResolver.update(nameUri, values, null, null); 1767 assertStoredValue(uri, Contacts.DISPLAY_NAME, null); 1768 1769 values.put(StructuredName.FAMILY_NAME, "Dog"); 1770 mResolver.update(nameUri, values, null, null); 1771 1772 assertStoredValue(uri, Contacts.DISPLAY_NAME, "Dog"); 1773 } 1774 1775 public void testInsertDataWithContentProviderOperations() throws Exception { 1776 ContentProviderOperation cpo1 = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI) 1777 .withValues(new ContentValues()) 1778 .build(); 1779 ContentProviderOperation cpo2 = ContentProviderOperation.newInsert(Data.CONTENT_URI) 1780 .withValueBackReference(Data.RAW_CONTACT_ID, 0) 1781 .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE) 1782 .withValue(StructuredName.GIVEN_NAME, "John") 1783 .withValue(StructuredName.FAMILY_NAME, "Doe") 1784 .build(); 1785 ContentProviderResult[] results = 1786 mResolver.applyBatch(ContactsContract.AUTHORITY, Lists.newArrayList(cpo1, cpo2)); 1787 long contactId = queryContactId(ContentUris.parseId(results[0].uri)); 1788 Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1789 assertStoredValue(uri, Contacts.DISPLAY_NAME, "John Doe"); 1790 } 1791 1792 public void testSendToVoicemailDefault() { 1793 long rawContactId = createRawContactWithName(); 1794 long contactId = queryContactId(rawContactId); 1795 1796 Cursor c = queryContact(contactId); 1797 assertTrue(c.moveToNext()); 1798 int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL)); 1799 assertEquals(0, sendToVoicemail); 1800 c.close(); 1801 } 1802 1803 public void testSetSendToVoicemailAndRingtone() { 1804 long rawContactId = createRawContactWithName(); 1805 long contactId = queryContactId(rawContactId); 1806 1807 updateSendToVoicemailAndRingtone(contactId, true, "foo"); 1808 assertSendToVoicemailAndRingtone(contactId, true, "foo"); 1809 assertNetworkNotified(false); 1810 1811 updateSendToVoicemailAndRingtoneWithSelection(contactId, false, "bar"); 1812 assertSendToVoicemailAndRingtone(contactId, false, "bar"); 1813 assertNetworkNotified(false); 1814 } 1815 1816 public void testSendToVoicemailAndRingtoneAfterAggregation() { 1817 long rawContactId1 = createRawContactWithName("a", "b"); 1818 long contactId1 = queryContactId(rawContactId1); 1819 updateSendToVoicemailAndRingtone(contactId1, true, "foo"); 1820 1821 long rawContactId2 = createRawContactWithName("c", "d"); 1822 long contactId2 = queryContactId(rawContactId2); 1823 updateSendToVoicemailAndRingtone(contactId2, true, "bar"); 1824 1825 // Aggregate them 1826 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1827 rawContactId1, rawContactId2); 1828 1829 // Both contacts had "send to VM", the contact now has the same value 1830 assertSendToVoicemailAndRingtone(contactId1, true, "foo,bar"); // Either foo or bar 1831 } 1832 1833 public void testDoNotSendToVoicemailAfterAggregation() { 1834 long rawContactId1 = createRawContactWithName("e", "f"); 1835 long contactId1 = queryContactId(rawContactId1); 1836 updateSendToVoicemailAndRingtone(contactId1, true, null); 1837 1838 long rawContactId2 = createRawContactWithName("g", "h"); 1839 long contactId2 = queryContactId(rawContactId2); 1840 updateSendToVoicemailAndRingtone(contactId2, false, null); 1841 1842 // Aggregate them 1843 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1844 rawContactId1, rawContactId2); 1845 1846 // Since one of the contacts had "don't send to VM" that setting wins for the aggregate 1847 assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), false, null); 1848 } 1849 1850 public void testSetSendToVoicemailAndRingtonePreservedAfterJoinAndSplit() { 1851 long rawContactId1 = createRawContactWithName("i", "j"); 1852 long contactId1 = queryContactId(rawContactId1); 1853 updateSendToVoicemailAndRingtone(contactId1, true, "foo"); 1854 1855 long rawContactId2 = createRawContactWithName("k", "l"); 1856 long contactId2 = queryContactId(rawContactId2); 1857 updateSendToVoicemailAndRingtone(contactId2, false, "bar"); 1858 1859 // Aggregate them 1860 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 1861 rawContactId1, rawContactId2); 1862 1863 // Split them 1864 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 1865 rawContactId1, rawContactId2); 1866 1867 assertSendToVoicemailAndRingtone(queryContactId(rawContactId1), true, "foo"); 1868 assertSendToVoicemailAndRingtone(queryContactId(rawContactId2), false, "bar"); 1869 } 1870 1871 public void testStatusUpdateInsert() { 1872 long rawContactId = createRawContact(); 1873 Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 1874 long dataId = ContentUris.parseId(imUri); 1875 1876 ContentValues values = new ContentValues(); 1877 values.put(StatusUpdates.DATA_ID, dataId); 1878 values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM); 1879 values.putNull(StatusUpdates.CUSTOM_PROTOCOL); 1880 values.put(StatusUpdates.IM_HANDLE, "aim"); 1881 values.put(StatusUpdates.PRESENCE, StatusUpdates.INVISIBLE); 1882 values.put(StatusUpdates.STATUS, "Hiding"); 1883 values.put(StatusUpdates.STATUS_TIMESTAMP, 100); 1884 values.put(StatusUpdates.STATUS_RES_PACKAGE, "a.b.c"); 1885 values.put(StatusUpdates.STATUS_ICON, 1234); 1886 values.put(StatusUpdates.STATUS_LABEL, 2345); 1887 1888 Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values); 1889 1890 assertStoredValues(resultUri, values); 1891 1892 long contactId = queryContactId(rawContactId); 1893 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1894 1895 values.clear(); 1896 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 1897 values.put(Contacts.CONTACT_STATUS, "Hiding"); 1898 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100); 1899 values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "a.b.c"); 1900 values.put(Contacts.CONTACT_STATUS_ICON, 1234); 1901 values.put(Contacts.CONTACT_STATUS_LABEL, 2345); 1902 1903 assertStoredValues(contactUri, values); 1904 1905 values.clear(); 1906 values.put(StatusUpdates.DATA_ID, dataId); 1907 values.put(StatusUpdates.STATUS, "Cloaked"); 1908 values.put(StatusUpdates.STATUS_TIMESTAMP, 200); 1909 values.put(StatusUpdates.STATUS_RES_PACKAGE, "d.e.f"); 1910 values.put(StatusUpdates.STATUS_ICON, 4321); 1911 values.put(StatusUpdates.STATUS_LABEL, 5432); 1912 mResolver.insert(StatusUpdates.CONTENT_URI, values); 1913 1914 values.clear(); 1915 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.INVISIBLE); 1916 values.put(Contacts.CONTACT_STATUS, "Cloaked"); 1917 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 200); 1918 values.put(Contacts.CONTACT_STATUS_RES_PACKAGE, "d.e.f"); 1919 values.put(Contacts.CONTACT_STATUS_ICON, 4321); 1920 values.put(Contacts.CONTACT_STATUS_LABEL, 5432); 1921 assertStoredValues(contactUri, values); 1922 } 1923 1924 public void testStatusUpdateInferAttribution() { 1925 long rawContactId = createRawContact(); 1926 Uri imUri = insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 1927 long dataId = ContentUris.parseId(imUri); 1928 1929 ContentValues values = new ContentValues(); 1930 values.put(StatusUpdates.DATA_ID, dataId); 1931 values.put(StatusUpdates.PROTOCOL, Im.PROTOCOL_AIM); 1932 values.put(StatusUpdates.IM_HANDLE, "aim"); 1933 values.put(StatusUpdates.STATUS, "Hiding"); 1934 1935 Uri resultUri = mResolver.insert(StatusUpdates.CONTENT_URI, values); 1936 1937 values.clear(); 1938 values.put(StatusUpdates.DATA_ID, dataId); 1939 values.put(StatusUpdates.STATUS_LABEL, com.android.internal.R.string.imProtocolAim); 1940 values.put(StatusUpdates.STATUS, "Hiding"); 1941 1942 assertStoredValues(resultUri, values); 1943 } 1944 1945 public void testStatusUpdateMatchingImOrEmail() { 1946 long rawContactId = createRawContact(); 1947 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 1948 insertImHandle(rawContactId, Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im"); 1949 insertEmail(rawContactId, "m@acme.com"); 1950 1951 // Match on IM (standard) 1952 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available", 1953 StatusUpdates.CAPABILITY_HAS_CAMERA); 1954 1955 // Match on IM (custom) 1956 insertStatusUpdate(Im.PROTOCOL_CUSTOM, "my_im_proto", "my_im", StatusUpdates.IDLE, "Idle", 1957 StatusUpdates.CAPABILITY_HAS_CAMERA | StatusUpdates.CAPABILITY_HAS_VIDEO); 1958 1959 // Match on Email 1960 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "m@acme.com", StatusUpdates.AWAY, "Away", 1961 StatusUpdates.CAPABILITY_HAS_VOICE); 1962 1963 // No match 1964 insertStatusUpdate(Im.PROTOCOL_ICQ, null, "12345", StatusUpdates.DO_NOT_DISTURB, "Go away", 1965 StatusUpdates.CAPABILITY_HAS_CAMERA); 1966 1967 Cursor c = mResolver.query(StatusUpdates.CONTENT_URI, new String[] { 1968 StatusUpdates.DATA_ID, StatusUpdates.PROTOCOL, StatusUpdates.CUSTOM_PROTOCOL, 1969 StatusUpdates.PRESENCE, StatusUpdates.STATUS}, 1970 PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null, StatusUpdates.DATA_ID); 1971 assertTrue(c.moveToNext()); 1972 assertStatusUpdate(c, Im.PROTOCOL_AIM, null, StatusUpdates.AVAILABLE, "Available"); 1973 assertTrue(c.moveToNext()); 1974 assertStatusUpdate(c, Im.PROTOCOL_CUSTOM, "my_im_proto", StatusUpdates.IDLE, "Idle"); 1975 assertTrue(c.moveToNext()); 1976 assertStatusUpdate(c, Im.PROTOCOL_GOOGLE_TALK, null, StatusUpdates.AWAY, "Away"); 1977 assertFalse(c.moveToNext()); 1978 c.close(); 1979 1980 long contactId = queryContactId(rawContactId); 1981 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1982 1983 ContentValues values = new ContentValues(); 1984 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 1985 values.put(Contacts.CONTACT_STATUS, "Available"); 1986 assertStoredValuesWithProjection(contactUri, values); 1987 } 1988 1989 public void testStatusUpdateUpdateAndDelete() { 1990 long rawContactId = createRawContact(); 1991 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 1992 1993 long contactId = queryContactId(rawContactId); 1994 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 1995 1996 ContentValues values = new ContentValues(); 1997 values.putNull(Contacts.CONTACT_PRESENCE); 1998 values.putNull(Contacts.CONTACT_STATUS); 1999 assertStoredValuesWithProjection(contactUri, values); 2000 2001 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AWAY, "BUSY", 2002 StatusUpdates.CAPABILITY_HAS_CAMERA); 2003 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.DO_NOT_DISTURB, "GO AWAY", 2004 StatusUpdates.CAPABILITY_HAS_CAMERA); 2005 Uri statusUri = 2006 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", StatusUpdates.AVAILABLE, "Available", 2007 StatusUpdates.CAPABILITY_HAS_CAMERA); 2008 long statusId = ContentUris.parseId(statusUri); 2009 2010 values.put(Contacts.CONTACT_PRESENCE, StatusUpdates.AVAILABLE); 2011 values.put(Contacts.CONTACT_STATUS, "Available"); 2012 assertStoredValuesWithProjection(contactUri, values); 2013 2014 // update status_updates table to set new values for 2015 // status_updates.status 2016 // status_updates.status_ts 2017 // presence 2018 long updatedTs = 200; 2019 String testUpdate = "test_update"; 2020 String selection = StatusUpdates.DATA_ID + "=" + statusId; 2021 values.clear(); 2022 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 2023 values.put(StatusUpdates.STATUS, testUpdate); 2024 values.put(StatusUpdates.PRESENCE, "presence_test"); 2025 mResolver.update(StatusUpdates.CONTENT_URI, values, 2026 StatusUpdates.DATA_ID + "=" + statusId, null); 2027 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 2028 2029 // update status_updates table to set new values for columns in status_updates table ONLY 2030 // i.e., no rows in presence table are to be updated. 2031 updatedTs = 300; 2032 testUpdate = "test_update_new"; 2033 selection = StatusUpdates.DATA_ID + "=" + statusId; 2034 values.clear(); 2035 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 2036 values.put(StatusUpdates.STATUS, testUpdate); 2037 mResolver.update(StatusUpdates.CONTENT_URI, values, 2038 StatusUpdates.DATA_ID + "=" + statusId, null); 2039 // make sure the presence column value is still the old value 2040 values.put(StatusUpdates.PRESENCE, "presence_test"); 2041 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 2042 2043 // update status_updates table to set new values for columns in presence table ONLY 2044 // i.e., no rows in status_updates table are to be updated. 2045 selection = StatusUpdates.DATA_ID + "=" + statusId; 2046 values.clear(); 2047 values.put(StatusUpdates.PRESENCE, "presence_test_new"); 2048 mResolver.update(StatusUpdates.CONTENT_URI, values, 2049 StatusUpdates.DATA_ID + "=" + statusId, null); 2050 // make sure the status_updates table is not updated 2051 values.put(StatusUpdates.STATUS_TIMESTAMP, updatedTs); 2052 values.put(StatusUpdates.STATUS, testUpdate); 2053 assertStoredValuesWithProjection(StatusUpdates.CONTENT_URI, values); 2054 2055 // effect "delete status_updates" operation and expect the following 2056 // data deleted from status_updates table 2057 // presence set to null 2058 mResolver.delete(StatusUpdates.CONTENT_URI, StatusUpdates.DATA_ID + "=" + statusId, null); 2059 values.clear(); 2060 values.putNull(Contacts.CONTACT_PRESENCE); 2061 assertStoredValuesWithProjection(contactUri, values); 2062 } 2063 2064 public void testStatusUpdateWithTimestamp() { 2065 long rawContactId = createRawContact(); 2066 insertImHandle(rawContactId, Im.PROTOCOL_AIM, null, "aim"); 2067 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "gtalk"); 2068 2069 long contactId = queryContactId(rawContactId); 2070 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2071 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Offline", 80, 2072 StatusUpdates.CAPABILITY_HAS_CAMERA); 2073 insertStatusUpdate(Im.PROTOCOL_AIM, null, "aim", 0, "Available", 100, 2074 StatusUpdates.CAPABILITY_HAS_CAMERA); 2075 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "gtalk", 0, "Busy", 90, 2076 StatusUpdates.CAPABILITY_HAS_CAMERA); 2077 2078 // Should return the latest status 2079 ContentValues values = new ContentValues(); 2080 values.put(Contacts.CONTACT_STATUS_TIMESTAMP, 100); 2081 values.put(Contacts.CONTACT_STATUS, "Available"); 2082 assertStoredValuesWithProjection(contactUri, values); 2083 } 2084 2085 private void assertStatusUpdate(Cursor c, int protocol, String customProtocol, int presence, 2086 String status) { 2087 ContentValues values = new ContentValues(); 2088 values.put(StatusUpdates.PROTOCOL, protocol); 2089 values.put(StatusUpdates.CUSTOM_PROTOCOL, customProtocol); 2090 values.put(StatusUpdates.PRESENCE, presence); 2091 values.put(StatusUpdates.STATUS, status); 2092 assertCursorValues(c, values); 2093 } 2094 2095 public void testSingleStatusUpdateRowPerContact() { 2096 int protocol1 = Im.PROTOCOL_GOOGLE_TALK; 2097 String handle1 = "test@gmail.com"; 2098 2099 long rawContactId1 = createRawContact(); 2100 insertImHandle(rawContactId1, protocol1, null, handle1); 2101 2102 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AVAILABLE, "Green", 2103 StatusUpdates.CAPABILITY_HAS_CAMERA); 2104 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.AWAY, "Yellow", 2105 StatusUpdates.CAPABILITY_HAS_CAMERA); 2106 insertStatusUpdate(protocol1, null, handle1, StatusUpdates.INVISIBLE, "Red", 2107 StatusUpdates.CAPABILITY_HAS_CAMERA); 2108 2109 Cursor c = queryContact(queryContactId(rawContactId1), 2110 new String[] {Contacts.CONTACT_PRESENCE, Contacts.CONTACT_STATUS}); 2111 assertEquals(1, c.getCount()); 2112 2113 c.moveToFirst(); 2114 assertEquals(StatusUpdates.INVISIBLE, c.getInt(0)); 2115 assertEquals("Red", c.getString(1)); 2116 c.close(); 2117 } 2118 2119 private void updateSendToVoicemailAndRingtone(long contactId, boolean sendToVoicemail, 2120 String ringtone) { 2121 ContentValues values = new ContentValues(); 2122 values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail); 2123 if (ringtone != null) { 2124 values.put(Contacts.CUSTOM_RINGTONE, ringtone); 2125 } 2126 2127 final Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2128 int count = mResolver.update(uri, values, null, null); 2129 assertEquals(1, count); 2130 } 2131 2132 private void updateSendToVoicemailAndRingtoneWithSelection(long contactId, 2133 boolean sendToVoicemail, String ringtone) { 2134 ContentValues values = new ContentValues(); 2135 values.put(Contacts.SEND_TO_VOICEMAIL, sendToVoicemail); 2136 if (ringtone != null) { 2137 values.put(Contacts.CUSTOM_RINGTONE, ringtone); 2138 } 2139 2140 int count = mResolver.update(Contacts.CONTENT_URI, values, Contacts._ID + "=" + contactId, 2141 null); 2142 assertEquals(1, count); 2143 } 2144 2145 private void assertSendToVoicemailAndRingtone(long contactId, boolean expectedSendToVoicemail, 2146 String expectedRingtone) { 2147 Cursor c = queryContact(contactId); 2148 assertTrue(c.moveToNext()); 2149 int sendToVoicemail = c.getInt(c.getColumnIndex(Contacts.SEND_TO_VOICEMAIL)); 2150 assertEquals(expectedSendToVoicemail ? 1 : 0, sendToVoicemail); 2151 String ringtone = c.getString(c.getColumnIndex(Contacts.CUSTOM_RINGTONE)); 2152 if (expectedRingtone == null) { 2153 assertNull(ringtone); 2154 } else { 2155 assertTrue(ArrayUtils.contains(expectedRingtone.split(","), ringtone)); 2156 } 2157 c.close(); 2158 } 2159 2160 public void testGroupCreationAfterMembershipInsert() { 2161 long rawContactId1 = createRawContact(mAccount); 2162 Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1"); 2163 2164 long groupId = assertSingleGroup(NO_LONG, mAccount, "gsid1", null); 2165 assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri), 2166 rawContactId1, groupId, "gsid1"); 2167 } 2168 2169 public void testGroupReuseAfterMembershipInsert() { 2170 long rawContactId1 = createRawContact(mAccount); 2171 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 2172 Uri groupMembershipUri = insertGroupMembership(rawContactId1, "gsid1"); 2173 2174 assertSingleGroup(groupId1, mAccount, "gsid1", "title1"); 2175 assertSingleGroupMembership(ContentUris.parseId(groupMembershipUri), 2176 rawContactId1, groupId1, "gsid1"); 2177 } 2178 2179 public void testGroupInsertFailureOnGroupIdConflict() { 2180 long rawContactId1 = createRawContact(mAccount); 2181 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 2182 2183 ContentValues values = new ContentValues(); 2184 values.put(GroupMembership.RAW_CONTACT_ID, rawContactId1); 2185 values.put(GroupMembership.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE); 2186 values.put(GroupMembership.GROUP_SOURCE_ID, "gsid1"); 2187 values.put(GroupMembership.GROUP_ROW_ID, groupId1); 2188 try { 2189 mResolver.insert(Data.CONTENT_URI, values); 2190 fail("the insert was expected to fail, but it succeeded"); 2191 } catch (IllegalArgumentException e) { 2192 // this was expected 2193 } 2194 } 2195 2196 public void testContactVisibilityUpdateOnMembershipChange() { 2197 long rawContactId = createRawContact(mAccount); 2198 assertVisibility(rawContactId, "0"); 2199 2200 long visibleGroupId = createGroup(mAccount, "123", "Visible", 1); 2201 long invisibleGroupId = createGroup(mAccount, "567", "Invisible", 0); 2202 2203 Uri membership1 = insertGroupMembership(rawContactId, visibleGroupId); 2204 assertVisibility(rawContactId, "1"); 2205 2206 Uri membership2 = insertGroupMembership(rawContactId, invisibleGroupId); 2207 assertVisibility(rawContactId, "1"); 2208 2209 mResolver.delete(membership1, null, null); 2210 assertVisibility(rawContactId, "0"); 2211 2212 ContentValues values = new ContentValues(); 2213 values.put(GroupMembership.GROUP_ROW_ID, visibleGroupId); 2214 2215 mResolver.update(membership2, values, null, null); 2216 assertVisibility(rawContactId, "1"); 2217 } 2218 2219 private void assertVisibility(long rawContactId, String expectedValue) { 2220 assertStoredValue(Contacts.CONTENT_URI, Contacts._ID + "=" + queryContactId(rawContactId), 2221 null, Contacts.IN_VISIBLE_GROUP, expectedValue); 2222 } 2223 2224 public void testContentEntityIterator() { 2225 // create multiple contacts and check that the selected ones are returned 2226 long id; 2227 2228 long groupId1 = createGroup(mAccount, "gsid1", "title1"); 2229 long groupId2 = createGroup(mAccount, "gsid2", "title2"); 2230 2231 id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c0"); 2232 insertGroupMembership(id, "gsid1"); 2233 insertEmail(id, "c0@email.com"); 2234 insertPhoneNumber(id, "5551212c0"); 2235 2236 long c1 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c1"); 2237 Uri id_1_0 = insertGroupMembership(id, "gsid1"); 2238 Uri id_1_1 = insertGroupMembership(id, "gsid2"); 2239 Uri id_1_2 = insertEmail(id, "c1@email.com"); 2240 Uri id_1_3 = insertPhoneNumber(id, "5551212c1"); 2241 2242 long c2 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c2"); 2243 Uri id_2_0 = insertGroupMembership(id, "gsid1"); 2244 Uri id_2_1 = insertEmail(id, "c2@email.com"); 2245 Uri id_2_2 = insertPhoneNumber(id, "5551212c2"); 2246 2247 long c3 = id = createRawContact(mAccount, RawContacts.SOURCE_ID, "c3"); 2248 Uri id_3_0 = insertGroupMembership(id, groupId2); 2249 Uri id_3_1 = insertEmail(id, "c3@email.com"); 2250 Uri id_3_2 = insertPhoneNumber(id, "5551212c3"); 2251 2252 EntityIterator iterator = RawContacts.newEntityIterator(mResolver.query( 2253 maybeAddAccountQueryParameters(RawContactsEntity.CONTENT_URI, mAccount), null, 2254 RawContacts.SOURCE_ID + " in ('c1', 'c2', 'c3')", null, null)); 2255 Entity entity; 2256 ContentValues[] subValues; 2257 entity = iterator.next(); 2258 assertEquals(c1, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 2259 subValues = asSortedContentValuesArray(entity.getSubValues()); 2260 assertEquals(4, subValues.length); 2261 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 2262 Data._ID, id_1_0, 2263 GroupMembership.GROUP_ROW_ID, groupId1, 2264 GroupMembership.GROUP_SOURCE_ID, "gsid1"); 2265 assertDataRow(subValues[1], GroupMembership.CONTENT_ITEM_TYPE, 2266 Data._ID, id_1_1, 2267 GroupMembership.GROUP_ROW_ID, groupId2, 2268 GroupMembership.GROUP_SOURCE_ID, "gsid2"); 2269 assertDataRow(subValues[2], Email.CONTENT_ITEM_TYPE, 2270 Data._ID, id_1_2, 2271 Email.DATA, "c1@email.com"); 2272 assertDataRow(subValues[3], Phone.CONTENT_ITEM_TYPE, 2273 Data._ID, id_1_3, 2274 Email.DATA, "5551212c1"); 2275 2276 entity = iterator.next(); 2277 assertEquals(c2, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 2278 subValues = asSortedContentValuesArray(entity.getSubValues()); 2279 assertEquals(3, subValues.length); 2280 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 2281 Data._ID, id_2_0, 2282 GroupMembership.GROUP_ROW_ID, groupId1, 2283 GroupMembership.GROUP_SOURCE_ID, "gsid1"); 2284 assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE, 2285 Data._ID, id_2_1, 2286 Email.DATA, "c2@email.com"); 2287 assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE, 2288 Data._ID, id_2_2, 2289 Email.DATA, "5551212c2"); 2290 2291 entity = iterator.next(); 2292 assertEquals(c3, (long) entity.getEntityValues().getAsLong(RawContacts._ID)); 2293 subValues = asSortedContentValuesArray(entity.getSubValues()); 2294 assertEquals(3, subValues.length); 2295 assertDataRow(subValues[0], GroupMembership.CONTENT_ITEM_TYPE, 2296 Data._ID, id_3_0, 2297 GroupMembership.GROUP_ROW_ID, groupId2, 2298 GroupMembership.GROUP_SOURCE_ID, "gsid2"); 2299 assertDataRow(subValues[1], Email.CONTENT_ITEM_TYPE, 2300 Data._ID, id_3_1, 2301 Email.DATA, "c3@email.com"); 2302 assertDataRow(subValues[2], Phone.CONTENT_ITEM_TYPE, 2303 Data._ID, id_3_2, 2304 Email.DATA, "5551212c3"); 2305 2306 assertFalse(iterator.hasNext()); 2307 iterator.close(); 2308 } 2309 2310 public void testDataCreateUpdateDeleteByMimeType() throws Exception { 2311 long rawContactId = createRawContact(); 2312 2313 ContentValues values = new ContentValues(); 2314 values.put(Data.RAW_CONTACT_ID, rawContactId); 2315 values.put(Data.MIMETYPE, "testmimetype"); 2316 values.put(Data.RES_PACKAGE, "oldpackage"); 2317 values.put(Data.IS_PRIMARY, 1); 2318 values.put(Data.IS_SUPER_PRIMARY, 1); 2319 values.put(Data.DATA1, "old1"); 2320 values.put(Data.DATA2, "old2"); 2321 values.put(Data.DATA3, "old3"); 2322 values.put(Data.DATA4, "old4"); 2323 values.put(Data.DATA5, "old5"); 2324 values.put(Data.DATA6, "old6"); 2325 values.put(Data.DATA7, "old7"); 2326 values.put(Data.DATA8, "old8"); 2327 values.put(Data.DATA9, "old9"); 2328 values.put(Data.DATA10, "old10"); 2329 values.put(Data.DATA11, "old11"); 2330 values.put(Data.DATA12, "old12"); 2331 values.put(Data.DATA13, "old13"); 2332 values.put(Data.DATA14, "old14"); 2333 values.put(Data.DATA15, "old15"); 2334 Uri uri = mResolver.insert(Data.CONTENT_URI, values); 2335 assertStoredValues(uri, values); 2336 assertNetworkNotified(true); 2337 2338 values.clear(); 2339 values.put(Data.RES_PACKAGE, "newpackage"); 2340 values.put(Data.IS_PRIMARY, 0); 2341 values.put(Data.IS_SUPER_PRIMARY, 0); 2342 values.put(Data.DATA1, "new1"); 2343 values.put(Data.DATA2, "new2"); 2344 values.put(Data.DATA3, "new3"); 2345 values.put(Data.DATA4, "new4"); 2346 values.put(Data.DATA5, "new5"); 2347 values.put(Data.DATA6, "new6"); 2348 values.put(Data.DATA7, "new7"); 2349 values.put(Data.DATA8, "new8"); 2350 values.put(Data.DATA9, "new9"); 2351 values.put(Data.DATA10, "new10"); 2352 values.put(Data.DATA11, "new11"); 2353 values.put(Data.DATA12, "new12"); 2354 values.put(Data.DATA13, "new13"); 2355 values.put(Data.DATA14, "new14"); 2356 values.put(Data.DATA15, "new15"); 2357 mResolver.update(Data.CONTENT_URI, values, Data.RAW_CONTACT_ID + "=" + rawContactId + 2358 " AND " + Data.MIMETYPE + "='testmimetype'", null); 2359 assertNetworkNotified(true); 2360 2361 // Should not be able to change IS_PRIMARY and IS_SUPER_PRIMARY by the above update 2362 values.put(Data.IS_PRIMARY, 1); 2363 values.put(Data.IS_SUPER_PRIMARY, 1); 2364 assertStoredValues(uri, values); 2365 2366 int count = mResolver.delete(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId 2367 + " AND " + Data.MIMETYPE + "='testmimetype'", null); 2368 assertEquals(1, count); 2369 assertEquals(0, getCount(Data.CONTENT_URI, Data.RAW_CONTACT_ID + "=" + rawContactId 2370 + " AND " + Data.MIMETYPE + "='testmimetype'", null)); 2371 assertNetworkNotified(true); 2372 } 2373 2374 public void testRawContactQuery() { 2375 Account account1 = new Account("a", "b"); 2376 Account account2 = new Account("c", "d"); 2377 long rawContactId1 = createRawContact(account1); 2378 long rawContactId2 = createRawContact(account2); 2379 2380 Uri uri1 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account1); 2381 Uri uri2 = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, account2); 2382 assertEquals(1, getCount(uri1, null, null)); 2383 assertEquals(1, getCount(uri2, null, null)); 2384 assertStoredValue(uri1, RawContacts._ID, rawContactId1) ; 2385 assertStoredValue(uri2, RawContacts._ID, rawContactId2) ; 2386 2387 Uri rowUri1 = ContentUris.withAppendedId(uri1, rawContactId1); 2388 Uri rowUri2 = ContentUris.withAppendedId(uri2, rawContactId2); 2389 assertStoredValue(rowUri1, RawContacts._ID, rawContactId1) ; 2390 assertStoredValue(rowUri2, RawContacts._ID, rawContactId2) ; 2391 } 2392 2393 public void testRawContactDeletion() { 2394 long rawContactId = createRawContact(mAccount); 2395 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 2396 2397 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 2398 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 2399 StatusUpdates.AVAILABLE, null, 2400 StatusUpdates.CAPABILITY_HAS_CAMERA); 2401 long contactId = queryContactId(rawContactId); 2402 2403 assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 2404 null, null)); 2405 assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 2406 + rawContactId, null)); 2407 2408 mResolver.delete(uri, null, null); 2409 2410 assertStoredValue(uri, RawContacts.DELETED, "1"); 2411 assertNetworkNotified(true); 2412 2413 Uri permanentDeletionUri = setCallerIsSyncAdapter(uri, mAccount); 2414 mResolver.delete(permanentDeletionUri, null, null); 2415 assertEquals(0, getCount(uri, null, null)); 2416 assertEquals(0, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 2417 null, null)); 2418 assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 2419 + rawContactId, null)); 2420 assertEquals(0, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null)); 2421 assertNetworkNotified(false); 2422 } 2423 2424 public void testRawContactDeletionKeepingAggregateContact() { 2425 long rawContactId1 = createRawContactWithName(mAccount); 2426 long rawContactId2 = createRawContactWithName(mAccount); 2427 2428 // Same name - should be aggregated 2429 assertAggregated(rawContactId1, rawContactId2); 2430 2431 long contactId = queryContactId(rawContactId1); 2432 2433 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 2434 Uri permanentDeletionUri = setCallerIsSyncAdapter(uri, mAccount); 2435 mResolver.delete(permanentDeletionUri, null, null); 2436 assertEquals(0, getCount(uri, null, null)); 2437 assertEquals(1, getCount(Contacts.CONTENT_URI, Contacts._ID + "=" + contactId, null)); 2438 } 2439 2440 public void testRawContactDeletionWithAccounts() { 2441 long rawContactId = createRawContact(mAccount); 2442 Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 2443 2444 insertImHandle(rawContactId, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 2445 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 2446 StatusUpdates.AVAILABLE, null, 2447 StatusUpdates.CAPABILITY_HAS_CAMERA); 2448 assertEquals(1, getCount(Uri.withAppendedPath(uri, RawContacts.Data.CONTENT_DIRECTORY), 2449 null, null)); 2450 assertEquals(1, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 2451 + rawContactId, null)); 2452 2453 // Do not delete if we are deleting with wrong account. 2454 Uri deleteWithWrongAccountUri = 2455 RawContacts.CONTENT_URI.buildUpon() 2456 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccountTwo.name) 2457 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccountTwo.type) 2458 .build(); 2459 mResolver.delete(deleteWithWrongAccountUri, null, null); 2460 2461 assertStoredValue(uri, RawContacts.DELETED, "0"); 2462 2463 // Delete if we are deleting with correct account. 2464 Uri deleteWithCorrectAccountUri = 2465 RawContacts.CONTENT_URI.buildUpon() 2466 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, mAccount.name) 2467 .appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, mAccount.type) 2468 .build(); 2469 mResolver.delete(deleteWithCorrectAccountUri, null, null); 2470 2471 assertStoredValue(uri, RawContacts.DELETED, "1"); 2472 } 2473 2474 public void testAccountsUpdated() { 2475 // This is to ensure we do not delete contacts with null, null (account name, type) 2476 // accidentally. 2477 long rawContactId3 = createRawContactWithName("James", "Sullivan"); 2478 insertPhoneNumber(rawContactId3, "5234567890"); 2479 Uri rawContact3 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId3); 2480 assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null)); 2481 2482 ContactsProvider2 cp = (ContactsProvider2) getProvider(); 2483 cp.onAccountsUpdated(new Account[]{mAccount, mAccountTwo}); 2484 assertEquals(1, getCount(RawContacts.CONTENT_URI, null, null)); 2485 assertStoredValue(rawContact3, RawContacts.ACCOUNT_NAME, null); 2486 assertStoredValue(rawContact3, RawContacts.ACCOUNT_TYPE, null); 2487 2488 long rawContactId1 = createRawContact(mAccount); 2489 insertEmail(rawContactId1, "account1@email.com"); 2490 long rawContactId2 = createRawContact(mAccountTwo); 2491 insertEmail(rawContactId2, "account2@email.com"); 2492 insertImHandle(rawContactId2, Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com"); 2493 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, "deleteme@android.com", 2494 StatusUpdates.AVAILABLE, null, 2495 StatusUpdates.CAPABILITY_HAS_CAMERA); 2496 2497 cp.onAccountsUpdated(new Account[]{mAccount}); 2498 assertEquals(2, getCount(RawContacts.CONTENT_URI, null, null)); 2499 assertEquals(0, getCount(StatusUpdates.CONTENT_URI, PresenceColumns.RAW_CONTACT_ID + "=" 2500 + rawContactId2, null)); 2501 } 2502 2503 public void testAccountDeletion() { 2504 Account readOnlyAccount = new Account("act", READ_ONLY_ACCOUNT_TYPE); 2505 ContactsProvider2 cp = (ContactsProvider2) getProvider(); 2506 cp.onAccountsUpdated(new Account[]{readOnlyAccount, mAccount}); 2507 2508 long rawContactId1 = createRawContactWithName("John", "Doe", readOnlyAccount); 2509 Uri photoUri1 = insertPhoto(rawContactId1); 2510 long rawContactId2 = createRawContactWithName("john", "doe", mAccount); 2511 Uri photoUri2 = insertPhoto(rawContactId2); 2512 storeValue(photoUri2, Photo.IS_SUPER_PRIMARY, "1"); 2513 2514 assertAggregated(rawContactId1, rawContactId2); 2515 2516 long contactId = queryContactId(rawContactId1); 2517 2518 // The display name should come from the writable account 2519 assertStoredValue(Uri.withAppendedPath( 2520 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 2521 Contacts.Data.CONTENT_DIRECTORY), 2522 Contacts.DISPLAY_NAME, "john doe"); 2523 2524 // The photo should be the one we marked as super-primary 2525 assertStoredValue(Contacts.CONTENT_URI, contactId, 2526 Contacts.PHOTO_ID, ContentUris.parseId(photoUri2)); 2527 2528 // Remove the writable account 2529 cp.onAccountsUpdated(new Account[]{readOnlyAccount}); 2530 2531 // The display name should come from the remaining account 2532 assertStoredValue(Uri.withAppendedPath( 2533 ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), 2534 Contacts.Data.CONTENT_DIRECTORY), 2535 Contacts.DISPLAY_NAME, "John Doe"); 2536 2537 // The photo should be the remaining one 2538 assertStoredValue(Contacts.CONTENT_URI, contactId, 2539 Contacts.PHOTO_ID, ContentUris.parseId(photoUri1)); 2540 2541 } 2542 2543 public void testContactDeletion() { 2544 long rawContactId1 = createRawContactWithName("John", "Doe"); 2545 long rawContactId2 = createRawContactWithName("John", "Doe"); 2546 2547 long contactId = queryContactId(rawContactId1); 2548 2549 mResolver.delete(ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId), null, null); 2550 2551 assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1), 2552 RawContacts.DELETED, "1"); 2553 assertStoredValue(ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2), 2554 RawContacts.DELETED, "1"); 2555 } 2556 2557 public void testMarkAsDirtyParameter() { 2558 long rawContactId = createRawContact(mAccount); 2559 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 2560 2561 Uri uri = insertStructuredName(rawContactId, "John", "Doe"); 2562 clearDirty(rawContactUri); 2563 Uri updateUri = setCallerIsSyncAdapter(uri, mAccount); 2564 2565 ContentValues values = new ContentValues(); 2566 values.put(StructuredName.FAMILY_NAME, "Dough"); 2567 mResolver.update(updateUri, values, null, null); 2568 assertStoredValue(uri, StructuredName.FAMILY_NAME, "Dough"); 2569 assertDirty(rawContactUri, false); 2570 assertNetworkNotified(false); 2571 } 2572 2573 public void testRawContactDirtyAndVersion() { 2574 final long rawContactId = createRawContact(mAccount); 2575 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, rawContactId); 2576 assertDirty(uri, false); 2577 long version = getVersion(uri); 2578 2579 ContentValues values = new ContentValues(); 2580 values.put(ContactsContract.RawContacts.DIRTY, 0); 2581 values.put(ContactsContract.RawContacts.SEND_TO_VOICEMAIL, 1); 2582 values.put(ContactsContract.RawContacts.AGGREGATION_MODE, 2583 RawContacts.AGGREGATION_MODE_IMMEDIATE); 2584 values.put(ContactsContract.RawContacts.STARRED, 1); 2585 assertEquals(1, mResolver.update(uri, values, null, null)); 2586 assertEquals(version, getVersion(uri)); 2587 2588 assertDirty(uri, false); 2589 assertNetworkNotified(false); 2590 2591 Uri emailUri = insertEmail(rawContactId, "goo@woo.com"); 2592 assertDirty(uri, true); 2593 assertNetworkNotified(true); 2594 ++version; 2595 assertEquals(version, getVersion(uri)); 2596 clearDirty(uri); 2597 2598 values = new ContentValues(); 2599 values.put(Email.DATA, "goo@hoo.com"); 2600 mResolver.update(emailUri, values, null, null); 2601 assertDirty(uri, true); 2602 assertNetworkNotified(true); 2603 ++version; 2604 assertEquals(version, getVersion(uri)); 2605 clearDirty(uri); 2606 2607 mResolver.delete(emailUri, null, null); 2608 assertDirty(uri, true); 2609 assertNetworkNotified(true); 2610 ++version; 2611 assertEquals(version, getVersion(uri)); 2612 } 2613 2614 public void testRawContactClearDirty() { 2615 final long rawContactId = createRawContact(mAccount); 2616 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, 2617 rawContactId); 2618 long version = getVersion(uri); 2619 insertEmail(rawContactId, "goo@woo.com"); 2620 assertDirty(uri, true); 2621 version++; 2622 assertEquals(version, getVersion(uri)); 2623 2624 clearDirty(uri); 2625 assertDirty(uri, false); 2626 assertEquals(version, getVersion(uri)); 2627 } 2628 2629 public void testRawContactDeletionSetsDirty() { 2630 final long rawContactId = createRawContact(mAccount); 2631 Uri uri = ContentUris.withAppendedId(ContactsContract.RawContacts.CONTENT_URI, 2632 rawContactId); 2633 long version = getVersion(uri); 2634 clearDirty(uri); 2635 assertDirty(uri, false); 2636 2637 mResolver.delete(uri, null, null); 2638 assertStoredValue(uri, RawContacts.DELETED, "1"); 2639 assertDirty(uri, true); 2640 assertNetworkNotified(true); 2641 version++; 2642 assertEquals(version, getVersion(uri)); 2643 } 2644 2645 public void testDeleteContactWithoutName() { 2646 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues()); 2647 long rawContactId = ContentUris.parseId(rawContactUri); 2648 2649 Uri phoneUri = insertPhoneNumber(rawContactId, "555-123-45678", true); 2650 2651 long contactId = queryContactId(rawContactId); 2652 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2653 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 2654 2655 int numDeleted = mResolver.delete(lookupUri, null, null); 2656 assertEquals(1, numDeleted); 2657 } 2658 2659 public void testDeleteContactWithoutAnyData() { 2660 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, new ContentValues()); 2661 long rawContactId = ContentUris.parseId(rawContactUri); 2662 2663 long contactId = queryContactId(rawContactId); 2664 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2665 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 2666 2667 int numDeleted = mResolver.delete(lookupUri, null, null); 2668 assertEquals(1, numDeleted); 2669 } 2670 2671 public void testDeleteContactWithEscapedUri() { 2672 ContentValues values = new ContentValues(); 2673 values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~"); 2674 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2675 long rawContactId = ContentUris.parseId(rawContactUri); 2676 2677 long contactId = queryContactId(rawContactId); 2678 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2679 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 2680 assertEquals(1, mResolver.delete(lookupUri, null, null)); 2681 } 2682 2683 public void testQueryContactWithEscapedUri() { 2684 ContentValues values = new ContentValues(); 2685 values.put(RawContacts.SOURCE_ID, "!@#$%^&*()_+=-/.,<>?;'\":[]}{\\|`~"); 2686 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2687 long rawContactId = ContentUris.parseId(rawContactUri); 2688 2689 long contactId = queryContactId(rawContactId); 2690 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2691 Uri lookupUri = Contacts.getLookupUri(mResolver, contactUri); 2692 Cursor c = mResolver.query(lookupUri, null, null, null, ""); 2693 assertEquals(1, c.getCount()); 2694 c.close(); 2695 } 2696 2697 public void testGetPhotoUri() { 2698 ContentValues values = new ContentValues(); 2699 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2700 long rawContactId = ContentUris.parseId(rawContactUri); 2701 insertStructuredName(rawContactId, "John", "Doe"); 2702 Uri photoUri = insertPhoto(rawContactId); 2703 2704 Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, 2705 queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY); 2706 2707 long twigId = Long.parseLong(getStoredValue(twigUri, Data._ID)); 2708 assertEquals(ContentUris.parseId(photoUri), twigId); 2709 } 2710 2711 public void testInputStreamForPhoto() throws Exception { 2712 long rawContactId = createRawContact(); 2713 Uri photoUri = insertPhoto(rawContactId); 2714 assertInputStreamContent(loadTestPhoto(), mResolver.openInputStream(photoUri)); 2715 2716 Uri contactPhotoUri = Uri.withAppendedPath( 2717 ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(rawContactId)), 2718 Contacts.Photo.CONTENT_DIRECTORY); 2719 assertInputStreamContent(loadTestPhoto(), mResolver.openInputStream(contactPhotoUri)); 2720 } 2721 2722 private static void assertInputStreamContent(byte[] expected, InputStream is) 2723 throws IOException { 2724 try { 2725 byte[] observed = new byte[expected.length]; 2726 int count = is.read(observed); 2727 assertEquals(expected.length, count); 2728 assertEquals(-1, is.read()); 2729 MoreAsserts.assertEquals(expected, observed); 2730 } finally { 2731 is.close(); 2732 } 2733 } 2734 2735 public void testSuperPrimaryPhoto() { 2736 long rawContactId1 = createRawContact(new Account("a", "a")); 2737 Uri photoUri1 = insertPhoto(rawContactId1); 2738 long photoId1 = ContentUris.parseId(photoUri1); 2739 2740 long rawContactId2 = createRawContact(new Account("b", "b")); 2741 Uri photoUri2 = insertPhoto(rawContactId2); 2742 long photoId2 = ContentUris.parseId(photoUri2); 2743 2744 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 2745 rawContactId1, rawContactId2); 2746 2747 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 2748 queryContactId(rawContactId1)); 2749 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1); 2750 2751 setAggregationException(AggregationExceptions.TYPE_KEEP_SEPARATE, 2752 rawContactId1, rawContactId2); 2753 2754 ContentValues values = new ContentValues(); 2755 values.put(Data.IS_SUPER_PRIMARY, 1); 2756 mResolver.update(photoUri2, values, null, null); 2757 2758 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 2759 rawContactId1, rawContactId2); 2760 contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 2761 queryContactId(rawContactId1)); 2762 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId2); 2763 2764 mResolver.update(photoUri1, values, null, null); 2765 assertStoredValue(contactUri, Contacts.PHOTO_ID, photoId1); 2766 } 2767 2768 public void testUpdatePhoto() { 2769 ContentValues values = new ContentValues(); 2770 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2771 long rawContactId = ContentUris.parseId(rawContactUri); 2772 insertStructuredName(rawContactId, "John", "Doe"); 2773 2774 Uri twigUri = Uri.withAppendedPath(ContentUris.withAppendedId(Contacts.CONTENT_URI, 2775 queryContactId(rawContactId)), Contacts.Photo.CONTENT_DIRECTORY); 2776 2777 values.clear(); 2778 values.put(Data.RAW_CONTACT_ID, rawContactId); 2779 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 2780 values.putNull(Photo.PHOTO); 2781 Uri dataUri = mResolver.insert(Data.CONTENT_URI, values); 2782 long photoId = ContentUris.parseId(dataUri); 2783 2784 assertNull(getStoredValue(twigUri, Data._ID)); 2785 2786 values.clear(); 2787 values.put(Photo.PHOTO, loadTestPhoto()); 2788 mResolver.update(dataUri, values, null, null); 2789 assertNetworkNotified(true); 2790 2791 long twigId = Long.parseLong(getStoredValue(twigUri, Data._ID)); 2792 assertEquals(photoId, twigId); 2793 } 2794 2795 public void testUpdateRawContactDataPhoto() { 2796 // setup a contact with a null photo 2797 ContentValues values = new ContentValues(); 2798 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 2799 long rawContactId = ContentUris.parseId(rawContactUri); 2800 2801 // setup a photo 2802 values.put(Data.RAW_CONTACT_ID, rawContactId); 2803 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 2804 values.putNull(Photo.PHOTO); 2805 2806 // try to do an update before insert should return count == 0 2807 Uri dataUri = Uri.withAppendedPath( 2808 ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId), 2809 RawContacts.Data.CONTENT_DIRECTORY); 2810 assertEquals(0, mResolver.update(dataUri, values, Data.MIMETYPE + "=?", 2811 new String[] {Photo.CONTENT_ITEM_TYPE})); 2812 2813 mResolver.insert(Data.CONTENT_URI, values); 2814 2815 // save a photo to the db 2816 values.clear(); 2817 values.put(Data.MIMETYPE, Photo.CONTENT_ITEM_TYPE); 2818 values.put(Photo.PHOTO, loadTestPhoto()); 2819 assertEquals(1, mResolver.update(dataUri, values, Data.MIMETYPE + "=?", 2820 new String[] {Photo.CONTENT_ITEM_TYPE})); 2821 2822 // verify the photo 2823 Cursor storedPhoto = mResolver.query(dataUri, new String[] {Photo.PHOTO}, 2824 Data.MIMETYPE + "=?", new String[] {Photo.CONTENT_ITEM_TYPE}, null); 2825 storedPhoto.moveToFirst(); 2826 MoreAsserts.assertEquals(loadTestPhoto(), storedPhoto.getBlob(0)); 2827 storedPhoto.close(); 2828 } 2829 2830 public void testUpdateRawContactSetStarred() { 2831 long rawContactId1 = createRawContactWithName(); 2832 Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 2833 long rawContactId2 = createRawContactWithName(); 2834 Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2); 2835 2836 assertAggregated(rawContactId1, rawContactId2); 2837 2838 long contactId = queryContactId(rawContactId1); 2839 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 2840 assertStoredValue(contactUri, Contacts.STARRED, "0"); 2841 2842 ContentValues values = new ContentValues(); 2843 values.put(RawContacts.STARRED, "1"); 2844 2845 mResolver.update(rawContactUri1, values, null, null); 2846 2847 assertStoredValue(rawContactUri1, RawContacts.STARRED, "1"); 2848 assertStoredValue(rawContactUri2, RawContacts.STARRED, "0"); 2849 assertStoredValue(contactUri, Contacts.STARRED, "1"); 2850 2851 values.put(RawContacts.STARRED, "0"); 2852 mResolver.update(rawContactUri1, values, null, null); 2853 2854 assertStoredValue(rawContactUri1, RawContacts.STARRED, "0"); 2855 assertStoredValue(rawContactUri2, RawContacts.STARRED, "0"); 2856 assertStoredValue(contactUri, Contacts.STARRED, "0"); 2857 2858 values.put(Contacts.STARRED, "1"); 2859 mResolver.update(contactUri, values, null, null); 2860 2861 assertStoredValue(rawContactUri1, RawContacts.STARRED, "1"); 2862 assertStoredValue(rawContactUri2, RawContacts.STARRED, "1"); 2863 assertStoredValue(contactUri, Contacts.STARRED, "1"); 2864 } 2865 2866 public void testLiveFolders() { 2867 long rawContactId1 = createRawContactWithName("James", "Sullivan"); 2868 insertPhoneNumber(rawContactId1, "5234567890"); 2869 long contactId1 = queryContactId(rawContactId1); 2870 2871 long rawContactId2 = createRawContactWithName("Mike", "Wazowski"); 2872 long contactId2 = queryContactId(rawContactId2); 2873 storeValue(Contacts.CONTENT_URI, contactId2, Contacts.STARRED, "1"); 2874 2875 long rawContactId3 = createRawContactWithName("Randall", "Boggs"); 2876 long contactId3 = queryContactId(rawContactId3); 2877 long groupId = createGroup(NO_ACCOUNT, "src1", "VIP"); 2878 insertGroupMembership(rawContactId3, groupId); 2879 2880 assertLiveFolderContents( 2881 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 2882 "live_folders/contacts"), 2883 contactId1, "James Sullivan", 2884 contactId2, "Mike Wazowski", 2885 contactId3, "Randall Boggs"); 2886 2887 assertLiveFolderContents( 2888 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 2889 "live_folders/contacts_with_phones"), 2890 contactId1, "James Sullivan"); 2891 2892 assertLiveFolderContents( 2893 Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 2894 "live_folders/favorites"), 2895 contactId2, "Mike Wazowski"); 2896 2897 assertLiveFolderContents( 2898 Uri.withAppendedPath(Uri.withAppendedPath(ContactsContract.AUTHORITY_URI, 2899 "live_folders/contacts"), Uri.encode("VIP")), 2900 contactId3, "Randall Boggs"); 2901 } 2902 2903 private void assertLiveFolderContents(Uri uri, Object... expected) { 2904 Cursor c = mResolver.query(uri, new String[]{LiveFolders._ID, LiveFolders.NAME}, 2905 null, null, LiveFolders._ID); 2906 assertEquals(expected.length/2, c.getCount()); 2907 for (int i = 0; i < expected.length/2; i++) { 2908 assertTrue(c.moveToNext()); 2909 assertEquals(((Long)expected[i * 2]).longValue(), c.getLong(0)); 2910 assertEquals(expected[i * 2 + 1], c.getString(1)); 2911 } 2912 c.close(); 2913 } 2914 2915 public void testContactCounts() { 2916 Uri uri = Contacts.CONTENT_URI.buildUpon() 2917 .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true").build(); 2918 2919 createRawContact(); 2920 createRawContactWithName("James", "Sullivan"); 2921 createRawContactWithName("The Abominable", "Snowman"); 2922 createRawContactWithName("Mike", "Wazowski"); 2923 createRawContactWithName("randall", "boggs"); 2924 createRawContactWithName("Boo", null); 2925 createRawContactWithName("Mary", null); 2926 createRawContactWithName("Roz", null); 2927 2928 Cursor cursor = mResolver.query(uri, 2929 new String[]{Contacts.DISPLAY_NAME}, 2930 null, null, Contacts.SORT_KEY_PRIMARY + " COLLATE LOCALIZED"); 2931 2932 assertFirstLetterValues(cursor, null, "B", "J", "M", "R", "T"); 2933 assertFirstLetterCounts(cursor, 1, 1, 1, 2, 2, 1); 2934 cursor.close(); 2935 2936 cursor = mResolver.query(uri, 2937 new String[]{Contacts.DISPLAY_NAME}, 2938 null, null, Contacts.SORT_KEY_ALTERNATIVE + " COLLATE LOCALIZED DESC"); 2939 2940 assertFirstLetterValues(cursor, "W", "S", "R", "M", "B", null); 2941 assertFirstLetterCounts(cursor, 1, 2, 1, 1, 2, 1); 2942 cursor.close(); 2943 } 2944 2945 private void assertFirstLetterValues(Cursor cursor, String... expected) { 2946 String[] actual = cursor.getExtras() 2947 .getStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES); 2948 MoreAsserts.assertEquals(expected, actual); 2949 } 2950 2951 private void assertFirstLetterCounts(Cursor cursor, int... expected) { 2952 int[] actual = cursor.getExtras() 2953 .getIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS); 2954 MoreAsserts.assertEquals(expected, actual); 2955 } 2956 2957 public void testReadBooleanQueryParameter() { 2958 assertBooleanUriParameter("foo:bar", "bool", true, true); 2959 assertBooleanUriParameter("foo:bar", "bool", false, false); 2960 assertBooleanUriParameter("foo:bar?bool=0", "bool", true, false); 2961 assertBooleanUriParameter("foo:bar?bool=1", "bool", false, true); 2962 assertBooleanUriParameter("foo:bar?bool=false", "bool", true, false); 2963 assertBooleanUriParameter("foo:bar?bool=true", "bool", false, true); 2964 assertBooleanUriParameter("foo:bar?bool=FaLsE", "bool", true, false); 2965 assertBooleanUriParameter("foo:bar?bool=false&some=some", "bool", true, false); 2966 assertBooleanUriParameter("foo:bar?bool=1&some=some", "bool", false, true); 2967 assertBooleanUriParameter("foo:bar?some=bool", "bool", true, true); 2968 assertBooleanUriParameter("foo:bar?bool", "bool", true, true); 2969 } 2970 2971 private void assertBooleanUriParameter(String uriString, String parameter, 2972 boolean defaultValue, boolean expectedValue) { 2973 assertEquals(expectedValue, ContactsProvider2.readBooleanQueryParameter( 2974 Uri.parse(uriString), parameter, defaultValue)); 2975 } 2976 2977 public void testGetQueryParameter() { 2978 assertQueryParameter("foo:bar", "param", null); 2979 assertQueryParameter("foo:bar?param", "param", null); 2980 assertQueryParameter("foo:bar?param=", "param", ""); 2981 assertQueryParameter("foo:bar?param=val", "param", "val"); 2982 assertQueryParameter("foo:bar?param=val&some=some", "param", "val"); 2983 assertQueryParameter("foo:bar?some=some¶m=val", "param", "val"); 2984 assertQueryParameter("foo:bar?some=some¶m=val&else=else", "param", "val"); 2985 assertQueryParameter("foo:bar?param=john%40doe.com", "param", "john@doe.com"); 2986 } 2987 2988 public void testMissingAccountTypeParameter() { 2989 // Try querying for RawContacts only using ACCOUNT_NAME 2990 final Uri queryUri = RawContacts.CONTENT_URI.buildUpon().appendQueryParameter( 2991 RawContacts.ACCOUNT_NAME, "lolwut").build(); 2992 try { 2993 final Cursor cursor = mResolver.query(queryUri, null, null, null, null); 2994 fail("Able to query with incomplete account query parameters"); 2995 } catch (IllegalArgumentException e) { 2996 // Expected behavior. 2997 } 2998 } 2999 3000 public void testInsertInconsistentAccountType() { 3001 // Try inserting RawContact with inconsistent Accounts 3002 final Account red = new Account("red", "red"); 3003 final Account blue = new Account("blue", "blue"); 3004 3005 final ContentValues values = new ContentValues(); 3006 values.put(RawContacts.ACCOUNT_NAME, red.name); 3007 values.put(RawContacts.ACCOUNT_TYPE, red.type); 3008 3009 final Uri insertUri = maybeAddAccountQueryParameters(RawContacts.CONTENT_URI, blue); 3010 try { 3011 mResolver.insert(insertUri, values); 3012 fail("Able to insert RawContact with inconsistent account details"); 3013 } catch (IllegalArgumentException e) { 3014 // Expected behavior. 3015 } 3016 } 3017 3018 public void testProviderStatus() throws Exception { 3019 Cursor cursor = mResolver.query(ProviderStatus.CONTENT_URI, 3020 new String[]{ProviderStatus.DATA1, ProviderStatus.STATUS}, null, null, null); 3021 assertTrue(cursor.moveToFirst()); 3022 assertEquals(0, cursor.getLong(0)); 3023 assertEquals(ProviderStatus.STATUS_NORMAL, cursor.getInt(1)); 3024 cursor.close(); 3025 } 3026 3027 public void testProperties() throws Exception { 3028 ContactsProvider2 provider = (ContactsProvider2)getProvider(); 3029 ContactsDatabaseHelper helper = (ContactsDatabaseHelper)provider.getDatabaseHelper(); 3030 assertNull(helper.getProperty("non-existent", null)); 3031 assertEquals("default", helper.getProperty("non-existent", "default")); 3032 3033 helper.setProperty("existent1", "string1"); 3034 helper.setProperty("existent2", "string2"); 3035 assertEquals("string1", helper.getProperty("existent1", "default")); 3036 assertEquals("string2", helper.getProperty("existent2", "default")); 3037 helper.setProperty("existent1", null); 3038 assertEquals("default", helper.getProperty("existent1", "default")); 3039 } 3040 3041 private class VCardTestUriCreator { 3042 private String mLookup1; 3043 private String mLookup2; 3044 3045 public VCardTestUriCreator(String lookup1, String lookup2) { 3046 super(); 3047 mLookup1 = lookup1; 3048 mLookup2 = lookup2; 3049 } 3050 3051 public Uri getUri1() { 3052 return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup1); 3053 } 3054 3055 public Uri getUri2() { 3056 return Uri.withAppendedPath(Contacts.CONTENT_VCARD_URI, mLookup2); 3057 } 3058 3059 public Uri getCombinedUri() { 3060 return Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, 3061 Uri.encode(mLookup1 + ":" + mLookup2)); 3062 } 3063 } 3064 3065 private VCardTestUriCreator createVCardTestContacts() { 3066 final long rawContactId1 = createRawContact(mAccount, RawContacts.SOURCE_ID, "4:12"); 3067 insertStructuredName(rawContactId1, "John", "Doe"); 3068 3069 final long rawContactId2 = createRawContact(mAccount, RawContacts.SOURCE_ID, "3:4%121"); 3070 insertStructuredName(rawContactId2, "Jane", "Doh"); 3071 3072 final long contactId1 = queryContactId(rawContactId1); 3073 final long contactId2 = queryContactId(rawContactId2); 3074 final Uri contact1Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId1); 3075 final Uri contact2Uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId2); 3076 final String lookup1 = 3077 Uri.encode(Contacts.getLookupUri(mResolver, contact1Uri).getPathSegments().get(2)); 3078 final String lookup2 = 3079 Uri.encode(Contacts.getLookupUri(mResolver, contact2Uri).getPathSegments().get(2)); 3080 return new VCardTestUriCreator(lookup1, lookup2); 3081 } 3082 3083 public void testQueryMultiVCard() { 3084 // No need to create any contacts here, because the query for multiple vcards 3085 // does not go into the database at all 3086 Uri uri = Uri.withAppendedPath(Contacts.CONTENT_MULTI_VCARD_URI, Uri.encode("123:456")); 3087 Cursor cursor = mResolver.query(uri, null, null, null, null); 3088 assertEquals(1, cursor.getCount()); 3089 assertTrue(cursor.moveToFirst()); 3090 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 3091 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 3092 3093 // The resulting name contains date and time. Ensure that before and after are correct 3094 assertTrue(filename.startsWith("vcards_")); 3095 assertTrue(filename.endsWith(".vcf")); 3096 cursor.close(); 3097 } 3098 3099 public void testQueryFileSingleVCard() { 3100 final VCardTestUriCreator contacts = createVCardTestContacts(); 3101 3102 { 3103 Cursor cursor = mResolver.query(contacts.getUri1(), null, null, null, null); 3104 assertEquals(1, cursor.getCount()); 3105 assertTrue(cursor.moveToFirst()); 3106 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 3107 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 3108 assertEquals("John Doe.vcf", filename); 3109 cursor.close(); 3110 } 3111 3112 { 3113 Cursor cursor = mResolver.query(contacts.getUri2(), null, null, null, null); 3114 assertEquals(1, cursor.getCount()); 3115 assertTrue(cursor.moveToFirst()); 3116 assertTrue(cursor.isNull(cursor.getColumnIndex(OpenableColumns.SIZE))); 3117 String filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); 3118 assertEquals("Jane Doh.vcf", filename); 3119 cursor.close(); 3120 } 3121 } 3122 3123 3124 public void testOpenAssetFileMultiVCard() throws IOException { 3125 final VCardTestUriCreator contacts = createVCardTestContacts(); 3126 3127 final AssetFileDescriptor descriptor = 3128 mResolver.openAssetFileDescriptor(contacts.getCombinedUri(), "r"); 3129 final FileInputStream inputStream = descriptor.createInputStream(); 3130 String data = readToEnd(inputStream); 3131 inputStream.close(); 3132 descriptor.close(); 3133 3134 // Ensure that the resulting VCard has both contacts 3135 assertTrue(data.contains("N:Doe;John;;;")); 3136 assertTrue(data.contains("N:Doh;Jane;;;")); 3137 } 3138 3139 public void testOpenAssetFileSingleVCard() throws IOException { 3140 final VCardTestUriCreator contacts = createVCardTestContacts(); 3141 3142 // Ensure that the right VCard is being created in each case 3143 { 3144 final AssetFileDescriptor descriptor = 3145 mResolver.openAssetFileDescriptor(contacts.getUri1(), "r"); 3146 final FileInputStream inputStream = descriptor.createInputStream(); 3147 final String data = readToEnd(inputStream); 3148 assertTrue(data.contains("N:Doe;John;;;")); 3149 assertFalse(data.contains("N:Doh;Jane;;;")); 3150 3151 inputStream.close(); 3152 descriptor.close(); 3153 } 3154 3155 { 3156 final AssetFileDescriptor descriptor = 3157 mResolver.openAssetFileDescriptor(contacts.getUri2(), "r"); 3158 final FileInputStream inputStream = descriptor.createInputStream(); 3159 final String data = readToEnd(inputStream); 3160 inputStream.close(); 3161 descriptor.close(); 3162 3163 assertFalse(data.contains("N:Doe;John;;;")); 3164 assertTrue(data.contains("N:Doh;Jane;;;")); 3165 } 3166 } 3167 3168 public void testAutoGroupMembership() { 3169 long g1 = createGroup(mAccount, "g1", "t1", 0, true /* autoAdd */, false /* favorite */); 3170 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 3171 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, true /* autoAdd */, false /* favorite */); 3172 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, false/* favorite */); 3173 long r1 = createRawContact(mAccount); 3174 long r2 = createRawContact(mAccountTwo); 3175 long r3 = createRawContact(null); 3176 3177 Cursor c = queryGroupMemberships(mAccount); 3178 try { 3179 assertTrue(c.moveToNext()); 3180 assertEquals(g1, c.getLong(0)); 3181 assertEquals(r1, c.getLong(1)); 3182 assertFalse(c.moveToNext()); 3183 } finally { 3184 c.close(); 3185 } 3186 3187 c = queryGroupMemberships(mAccountTwo); 3188 try { 3189 assertTrue(c.moveToNext()); 3190 assertEquals(g3, c.getLong(0)); 3191 assertEquals(r2, c.getLong(1)); 3192 assertFalse(c.moveToNext()); 3193 } finally { 3194 c.close(); 3195 } 3196 } 3197 3198 public void testNoAutoAddMembershipAfterGroupCreation() { 3199 long r1 = createRawContact(mAccount); 3200 long r2 = createRawContact(mAccount); 3201 long r3 = createRawContact(mAccount); 3202 long r4 = createRawContact(mAccountTwo); 3203 long r5 = createRawContact(mAccountTwo); 3204 long r6 = createRawContact(null); 3205 3206 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 3207 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3208 3209 long g1 = createGroup(mAccount, "g1", "t1", 0, true /* autoAdd */, false /* favorite */); 3210 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 3211 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, true /* autoAdd */, false/* favorite */); 3212 3213 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 3214 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3215 } 3216 3217 // create some starred and non-starred contacts, some associated with account, some not 3218 // favorites group created 3219 // the starred contacts should be added to group 3220 // favorites group removed 3221 // no change to starred status 3222 public void testFavoritesMembershipAfterGroupCreation() { 3223 long r1 = createRawContact(mAccount, RawContacts.STARRED, "1"); 3224 long r2 = createRawContact(mAccount); 3225 long r3 = createRawContact(mAccount, RawContacts.STARRED, "1"); 3226 long r4 = createRawContact(mAccountTwo, RawContacts.STARRED, "1"); 3227 long r5 = createRawContact(mAccountTwo); 3228 long r6 = createRawContact(null, RawContacts.STARRED, "1"); 3229 long r7 = createRawContact(null); 3230 3231 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 3232 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3233 3234 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 3235 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false /* favorite */); 3236 long g3 = createGroup(mAccountTwo, "g3", "t3", 0, false /* autoAdd */, false/* favorite */); 3237 3238 assertTrue(queryRawContactIsStarred(r1)); 3239 assertFalse(queryRawContactIsStarred(r2)); 3240 assertTrue(queryRawContactIsStarred(r3)); 3241 assertTrue(queryRawContactIsStarred(r4)); 3242 assertFalse(queryRawContactIsStarred(r5)); 3243 assertTrue(queryRawContactIsStarred(r6)); 3244 assertFalse(queryRawContactIsStarred(r7)); 3245 3246 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3247 Cursor c = queryGroupMemberships(mAccount); 3248 try { 3249 assertTrue(c.moveToNext()); 3250 assertEquals(g1, c.getLong(0)); 3251 assertEquals(r1, c.getLong(1)); 3252 assertTrue(c.moveToNext()); 3253 assertEquals(g1, c.getLong(0)); 3254 assertEquals(r3, c.getLong(1)); 3255 assertFalse(c.moveToNext()); 3256 } finally { 3257 c.close(); 3258 } 3259 3260 updateItem(RawContacts.CONTENT_URI, r6, 3261 RawContacts.ACCOUNT_NAME, mAccount.name, 3262 RawContacts.ACCOUNT_TYPE, mAccount.type); 3263 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3264 c = queryGroupMemberships(mAccount); 3265 try { 3266 assertTrue(c.moveToNext()); 3267 assertEquals(g1, c.getLong(0)); 3268 assertEquals(r1, c.getLong(1)); 3269 assertTrue(c.moveToNext()); 3270 assertEquals(g1, c.getLong(0)); 3271 assertEquals(r3, c.getLong(1)); 3272 assertTrue(c.moveToNext()); 3273 assertEquals(g1, c.getLong(0)); 3274 assertEquals(r6, c.getLong(1)); 3275 assertFalse(c.moveToNext()); 3276 } finally { 3277 c.close(); 3278 } 3279 3280 mResolver.delete(ContentUris.withAppendedId(Groups.CONTENT_URI, g1), null, null); 3281 3282 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 3283 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3284 3285 assertTrue(queryRawContactIsStarred(r1)); 3286 assertFalse(queryRawContactIsStarred(r2)); 3287 assertTrue(queryRawContactIsStarred(r3)); 3288 assertTrue(queryRawContactIsStarred(r4)); 3289 assertFalse(queryRawContactIsStarred(r5)); 3290 assertTrue(queryRawContactIsStarred(r6)); 3291 assertFalse(queryRawContactIsStarred(r7)); 3292 } 3293 3294 public void testFavoritesGroupMembershipChangeAfterStarChange() { 3295 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 3296 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false/* favorite */); 3297 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, true /* favorite */); 3298 long g5 = createGroup(mAccountTwo, "g5", "t5", 0, false /* autoAdd */, false/* favorite */); 3299 long r1 = createRawContact(mAccount, RawContacts.STARRED, "1"); 3300 long r2 = createRawContact(mAccount); 3301 long r3 = createRawContact(mAccountTwo); 3302 3303 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3304 Cursor c = queryGroupMemberships(mAccount); 3305 try { 3306 assertTrue(c.moveToNext()); 3307 assertEquals(g1, c.getLong(0)); 3308 assertEquals(r1, c.getLong(1)); 3309 assertFalse(c.moveToNext()); 3310 } finally { 3311 c.close(); 3312 } 3313 3314 // remove the star from r1 3315 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "0")); 3316 3317 // Since no raw contacts are starred, there should be no group memberships. 3318 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 3319 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3320 3321 // mark r1 as starred 3322 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "1")); 3323 // Now that r1 is starred it should have a membership in the one groups from mAccount 3324 // that is marked as a favorite. 3325 // There should be no memberships in mAccountTwo since it has no starred raw contacts. 3326 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3327 c = queryGroupMemberships(mAccount); 3328 try { 3329 assertTrue(c.moveToNext()); 3330 assertEquals(g1, c.getLong(0)); 3331 assertEquals(r1, c.getLong(1)); 3332 assertFalse(c.moveToNext()); 3333 } finally { 3334 c.close(); 3335 } 3336 3337 // remove the star from r1 3338 assertEquals(1, updateItem(RawContacts.CONTENT_URI, r1, RawContacts.STARRED, "0")); 3339 // Since no raw contacts are starred, there should be no group memberships. 3340 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 3341 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3342 3343 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, queryContactId(r1)); 3344 assertNotNull(contactUri); 3345 3346 // mark r1 as starred via its contact lookup uri 3347 assertEquals(1, updateItem(contactUri, Contacts.STARRED, "1")); 3348 // Now that r1 is starred it should have a membership in the one groups from mAccount 3349 // that is marked as a favorite. 3350 // There should be no memberships in mAccountTwo since it has no starred raw contacts. 3351 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3352 c = queryGroupMemberships(mAccount); 3353 try { 3354 assertTrue(c.moveToNext()); 3355 assertEquals(g1, c.getLong(0)); 3356 assertEquals(r1, c.getLong(1)); 3357 assertFalse(c.moveToNext()); 3358 } finally { 3359 c.close(); 3360 } 3361 3362 // remove the star from r1 3363 updateItem(contactUri, Contacts.STARRED, "0"); 3364 // Since no raw contacts are starred, there should be no group memberships. 3365 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 3366 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3367 } 3368 3369 public void testStarChangedAfterGroupMembershipChange() { 3370 long g1 = createGroup(mAccount, "g1", "t1", 0, false /* autoAdd */, true /* favorite */); 3371 long g2 = createGroup(mAccount, "g2", "t2", 0, false /* autoAdd */, false/* favorite */); 3372 long g4 = createGroup(mAccountTwo, "g4", "t4", 0, false /* autoAdd */, true /* favorite */); 3373 long g5 = createGroup(mAccountTwo, "g5", "t5", 0, false /* autoAdd */, false/* favorite */); 3374 long r1 = createRawContact(mAccount); 3375 long r2 = createRawContact(mAccount); 3376 long r3 = createRawContact(mAccountTwo); 3377 3378 assertFalse(queryRawContactIsStarred(r1)); 3379 assertFalse(queryRawContactIsStarred(r2)); 3380 assertFalse(queryRawContactIsStarred(r3)); 3381 3382 Cursor c; 3383 3384 // add r1 to one favorites group 3385 // r1's star should automatically be set 3386 // r1 should automatically be added to the other favorites group 3387 Uri urir1g1 = insertGroupMembership(r1, g1); 3388 assertTrue(queryRawContactIsStarred(r1)); 3389 assertFalse(queryRawContactIsStarred(r2)); 3390 assertFalse(queryRawContactIsStarred(r3)); 3391 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3392 c = queryGroupMemberships(mAccount); 3393 try { 3394 assertTrue(c.moveToNext()); 3395 assertEquals(g1, c.getLong(0)); 3396 assertEquals(r1, c.getLong(1)); 3397 assertFalse(c.moveToNext()); 3398 } finally { 3399 c.close(); 3400 } 3401 3402 // remove r1 from one favorites group 3403 mResolver.delete(urir1g1, null, null); 3404 // r1's star should no longer be set 3405 assertFalse(queryRawContactIsStarred(r1)); 3406 assertFalse(queryRawContactIsStarred(r2)); 3407 assertFalse(queryRawContactIsStarred(r3)); 3408 // there should be no membership rows 3409 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 3410 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3411 3412 // add r3 to the one favorites group for that account 3413 // r3's star should automatically be set 3414 Uri urir3g4 = insertGroupMembership(r3, g4); 3415 assertFalse(queryRawContactIsStarred(r1)); 3416 assertFalse(queryRawContactIsStarred(r2)); 3417 assertTrue(queryRawContactIsStarred(r3)); 3418 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 3419 c = queryGroupMemberships(mAccountTwo); 3420 try { 3421 assertTrue(c.moveToNext()); 3422 assertEquals(g4, c.getLong(0)); 3423 assertEquals(r3, c.getLong(1)); 3424 assertFalse(c.moveToNext()); 3425 } finally { 3426 c.close(); 3427 } 3428 3429 // remove r3 from the favorites group 3430 mResolver.delete(urir3g4, null, null); 3431 // r3's star should automatically be cleared 3432 assertFalse(queryRawContactIsStarred(r1)); 3433 assertFalse(queryRawContactIsStarred(r2)); 3434 assertFalse(queryRawContactIsStarred(r3)); 3435 assertNoRowsAndClose(queryGroupMemberships(mAccount)); 3436 assertNoRowsAndClose(queryGroupMemberships(mAccountTwo)); 3437 } 3438 3439 public void testReadOnlyRawContact() { 3440 long rawContactId = createRawContact(); 3441 Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId); 3442 storeValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "first"); 3443 storeValue(rawContactUri, RawContacts.RAW_CONTACT_IS_READ_ONLY, 1); 3444 3445 storeValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "second"); 3446 assertStoredValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "first"); 3447 3448 Uri syncAdapterUri = rawContactUri.buildUpon() 3449 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "1") 3450 .build(); 3451 storeValue(syncAdapterUri, RawContacts.CUSTOM_RINGTONE, "third"); 3452 assertStoredValue(rawContactUri, RawContacts.CUSTOM_RINGTONE, "third"); 3453 } 3454 3455 public void testReadOnlyDataRow() { 3456 long rawContactId = createRawContact(); 3457 Uri emailUri = insertEmail(rawContactId, "email"); 3458 Uri phoneUri = insertPhoneNumber(rawContactId, "555-1111"); 3459 3460 storeValue(emailUri, Data.IS_READ_ONLY, "1"); 3461 storeValue(emailUri, Email.ADDRESS, "changed"); 3462 storeValue(phoneUri, Phone.NUMBER, "555-2222"); 3463 assertStoredValue(emailUri, Email.ADDRESS, "email"); 3464 assertStoredValue(phoneUri, Phone.NUMBER, "555-2222"); 3465 3466 Uri syncAdapterUri = emailUri.buildUpon() 3467 .appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "1") 3468 .build(); 3469 storeValue(syncAdapterUri, Email.ADDRESS, "changed"); 3470 assertStoredValue(emailUri, Email.ADDRESS, "changed"); 3471 } 3472 3473 public void testContactWithReadOnlyRawContact() { 3474 long rawContactId1 = createRawContact(); 3475 Uri rawContactUri1 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId1); 3476 storeValue(rawContactUri1, RawContacts.CUSTOM_RINGTONE, "first"); 3477 3478 long rawContactId2 = createRawContact(); 3479 Uri rawContactUri2 = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId2); 3480 storeValue(rawContactUri2, RawContacts.CUSTOM_RINGTONE, "second"); 3481 storeValue(rawContactUri2, RawContacts.RAW_CONTACT_IS_READ_ONLY, 1); 3482 3483 setAggregationException(AggregationExceptions.TYPE_KEEP_TOGETHER, 3484 rawContactId1, rawContactId2); 3485 3486 long contactId = queryContactId(rawContactId1); 3487 3488 Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId); 3489 storeValue(contactUri, Contacts.CUSTOM_RINGTONE, "rt"); 3490 assertStoredValue(contactUri, Contacts.CUSTOM_RINGTONE, "rt"); 3491 assertStoredValue(rawContactUri1, RawContacts.CUSTOM_RINGTONE, "rt"); 3492 assertStoredValue(rawContactUri2, RawContacts.CUSTOM_RINGTONE, "second"); 3493 } 3494 3495 private Cursor queryGroupMemberships(Account account) { 3496 Cursor c = mResolver.query(maybeAddAccountQueryParameters(Data.CONTENT_URI, account), 3497 new String[]{GroupMembership.GROUP_ROW_ID, GroupMembership.RAW_CONTACT_ID}, 3498 Data.MIMETYPE + "=?", new String[]{GroupMembership.CONTENT_ITEM_TYPE}, 3499 GroupMembership.GROUP_SOURCE_ID); 3500 return c; 3501 } 3502 3503 private String readToEnd(FileInputStream inputStream) { 3504 try { 3505 int ch; 3506 StringBuilder stringBuilder = new StringBuilder(); 3507 while ((ch = inputStream.read()) != -1) 3508 stringBuilder.append((char)ch); 3509 return stringBuilder.toString(); 3510 } catch (IOException e) { 3511 return null; 3512 } 3513 } 3514 3515 private void assertQueryParameter(String uriString, String parameter, String expectedValue) { 3516 assertEquals(expectedValue, ContactsProvider2.getQueryParameter( 3517 Uri.parse(uriString), parameter)); 3518 } 3519 3520 private long createContact(ContentValues values, String firstName, String givenName, 3521 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 3522 long groupId, int chatMode) { 3523 return queryContactId(createRawContact(values, firstName, givenName, phoneNumber, email, 3524 presenceStatus, timesContacted, starred, groupId, chatMode)); 3525 } 3526 3527 private long createRawContact(ContentValues values, String firstName, String givenName, 3528 String phoneNumber, String email, int presenceStatus, int timesContacted, int starred, 3529 long groupId, int chatMode) { 3530 long rawContactId = createRawContact(values, phoneNumber, email, presenceStatus, 3531 timesContacted, starred, groupId, chatMode); 3532 insertStructuredName(rawContactId, firstName, givenName); 3533 return rawContactId; 3534 } 3535 3536 private long createRawContact(ContentValues values, String phoneNumber, String email, 3537 int presenceStatus, int timesContacted, int starred, long groupId, int chatMode) { 3538 values.put(RawContacts.STARRED, starred); 3539 values.put(RawContacts.SEND_TO_VOICEMAIL, 1); 3540 values.put(RawContacts.CUSTOM_RINGTONE, "beethoven5"); 3541 values.put(RawContacts.LAST_TIME_CONTACTED, 12345); 3542 values.put(RawContacts.TIMES_CONTACTED, timesContacted); 3543 Uri rawContactUri = mResolver.insert(RawContacts.CONTENT_URI, values); 3544 long rawContactId = ContentUris.parseId(rawContactUri); 3545 Uri photoUri = insertPhoto(rawContactId); 3546 long photoId = ContentUris.parseId(photoUri); 3547 values.put(Contacts.PHOTO_ID, photoId); 3548 insertPhoneNumber(rawContactId, phoneNumber); 3549 insertEmail(rawContactId, email); 3550 3551 insertStatusUpdate(Im.PROTOCOL_GOOGLE_TALK, null, email, presenceStatus, "hacking", 3552 chatMode); 3553 3554 if (groupId != 0) { 3555 insertGroupMembership(rawContactId, groupId); 3556 } 3557 return rawContactId; 3558 } 3559 3560 private void putDataValues(ContentValues values, long rawContactId) { 3561 values.put(Data.RAW_CONTACT_ID, rawContactId); 3562 values.put(Data.MIMETYPE, "testmimetype"); 3563 values.put(Data.RES_PACKAGE, "oldpackage"); 3564 values.put(Data.IS_PRIMARY, 1); 3565 values.put(Data.IS_SUPER_PRIMARY, 1); 3566 values.put(Data.DATA1, "one"); 3567 values.put(Data.DATA2, "two"); 3568 values.put(Data.DATA3, "three"); 3569 values.put(Data.DATA4, "four"); 3570 values.put(Data.DATA5, "five"); 3571 values.put(Data.DATA6, "six"); 3572 values.put(Data.DATA7, "seven"); 3573 values.put(Data.DATA8, "eight"); 3574 values.put(Data.DATA9, "nine"); 3575 values.put(Data.DATA10, "ten"); 3576 values.put(Data.DATA11, "eleven"); 3577 values.put(Data.DATA12, "twelve"); 3578 values.put(Data.DATA13, "thirteen"); 3579 values.put(Data.DATA14, "fourteen"); 3580 values.put(Data.DATA15, "fifteen"); 3581 values.put(Data.SYNC1, "sync1"); 3582 values.put(Data.SYNC2, "sync2"); 3583 values.put(Data.SYNC3, "sync3"); 3584 values.put(Data.SYNC4, "sync4"); 3585 } 3586} 3587 3588