1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.phone; 18 19 import static android.provider.SimPhonebookContract.ElementaryFiles.EF_ADN; 20 import static android.provider.SimPhonebookContract.ElementaryFiles.EF_FDN; 21 import static android.provider.SimPhonebookContract.ElementaryFiles.EF_SDN; 22 23 import static com.android.internal.telephony.testing.CursorSubject.assertThat; 24 import static com.android.internal.telephony.testing.TelephonyAssertions.assertThrows; 25 26 import static com.google.common.truth.Truth.assertThat; 27 28 import static org.mockito.ArgumentMatchers.any; 29 import static org.mockito.ArgumentMatchers.anyInt; 30 import static org.mockito.ArgumentMatchers.eq; 31 import static org.mockito.Mockito.mock; 32 import static org.mockito.Mockito.spy; 33 import static org.mockito.Mockito.times; 34 import static org.mockito.Mockito.verify; 35 import static org.mockito.Mockito.when; 36 37 import android.content.ContentResolver; 38 import android.content.ContentValues; 39 import android.database.Cursor; 40 import android.net.Uri; 41 import android.provider.SimPhonebookContract; 42 import android.provider.SimPhonebookContract.ElementaryFiles; 43 import android.provider.SimPhonebookContract.SimRecords; 44 import android.telephony.SubscriptionInfo; 45 import android.telephony.SubscriptionManager; 46 import android.util.Pair; 47 48 import androidx.test.core.app.ApplicationProvider; 49 import androidx.test.ext.junit.runners.AndroidJUnit4; 50 import androidx.test.platform.app.InstrumentationRegistry; 51 import androidx.test.rule.provider.ProviderTestRule; 52 53 import com.android.internal.telephony.IIccPhoneBook; 54 import com.android.internal.telephony.uicc.AdnCapacity; 55 import com.android.internal.telephony.uicc.AdnRecord; 56 import com.android.internal.telephony.uicc.IccConstants; 57 58 import com.google.common.collect.ImmutableList; 59 import com.google.common.truth.Correspondence; 60 61 import org.junit.Before; 62 import org.junit.Rule; 63 import org.junit.Test; 64 import org.junit.runner.RunWith; 65 import org.mockito.AdditionalAnswers; 66 import org.mockito.ArgumentCaptor; 67 import org.mockito.Mockito; 68 69 import java.util.ArrayList; 70 import java.util.Arrays; 71 import java.util.Collections; 72 import java.util.HashMap; 73 import java.util.List; 74 import java.util.Map; 75 import java.util.Objects; 76 import java.util.function.Predicate; 77 import java.util.stream.Collectors; 78 79 @RunWith(AndroidJUnit4.class) 80 public final class SimPhonebookProviderTest { 81 82 private static final String EMOJI = new String(Character.toChars(0x1F642)); 83 private static final Correspondence<AdnRecord, AdnRecord> ADN_RECORD_IS_EQUAL = 84 Correspondence.from(AdnRecord::isEqual, "isEqual"); 85 86 @Rule 87 public final ProviderTestRule mProviderRule = new ProviderTestRule.Builder( 88 TestableSimPhonebookProvider.class, SimPhonebookContract.AUTHORITY).build(); 89 90 private ContentResolver mResolver; 91 private FakeIccPhoneBook mIccPhoneBook; 92 private SubscriptionManager mMockSubscriptionManager; 93 createSubscriptionsWithIds(int... subscriptionIds)94 private static List<SubscriptionInfo> createSubscriptionsWithIds(int... subscriptionIds) { 95 ImmutableList.Builder<SubscriptionInfo> builder = ImmutableList.builderWithExpectedSize( 96 subscriptionIds.length); 97 for (int i = 0; i < subscriptionIds.length; i++) { 98 builder.add(createSubscriptionInfo(i, subscriptionIds[i])); 99 } 100 return builder.build(); 101 } 102 createSubscriptionInfo(int slotIndex, int subscriptiondId)103 private static SubscriptionInfo createSubscriptionInfo(int slotIndex, int subscriptiondId) { 104 return new SubscriptionInfo( 105 subscriptiondId, "", slotIndex, null, null, 0, 0, null, 0, null, null, null, null, 106 false, null, null); 107 } 108 109 @Before setUp()110 public void setUp() { 111 mMockSubscriptionManager = spy( 112 Objects.requireNonNull(ApplicationProvider.getApplicationContext() 113 .getSystemService(SubscriptionManager.class))); 114 mIccPhoneBook = new FakeIccPhoneBook(); 115 mResolver = mProviderRule.getResolver(); 116 117 TestableSimPhonebookProvider.setup(mResolver, mMockSubscriptionManager, mIccPhoneBook); 118 } 119 120 @Test query_entityFiles_returnsCursorWithCorrectProjection()121 public void query_entityFiles_returnsCursorWithCorrectProjection() { 122 // Null projection 123 try (Cursor cursor = mResolver.query(ElementaryFiles.CONTENT_URI, null, null, 124 null)) { 125 assertThat(Objects.requireNonNull(cursor).getColumnNames()).asList() 126 .containsExactlyElementsIn( 127 SimPhonebookProvider.ELEMENTARY_FILES_ALL_COLUMNS); 128 } 129 130 // Empty projection 131 try (Cursor cursor = mResolver.query(ElementaryFiles.CONTENT_URI, new String[0], null, 132 null)) { 133 assertThat(cursor).hasColumnNames(); 134 } 135 136 // Single column 137 try (Cursor cursor = mResolver.query(ElementaryFiles.CONTENT_URI, new String[]{ 138 ElementaryFiles.EF_TYPE 139 }, null, null)) { 140 assertThat(cursor).hasColumnNames(ElementaryFiles.EF_TYPE); 141 } 142 143 // Duplicate column 144 try (Cursor cursor = mResolver.query(ElementaryFiles.CONTENT_URI, new String[]{ 145 ElementaryFiles.SUBSCRIPTION_ID, ElementaryFiles.SUBSCRIPTION_ID 146 }, null, null)) { 147 assertThat(cursor).hasColumnNames(ElementaryFiles.SUBSCRIPTION_ID, 148 ElementaryFiles.SUBSCRIPTION_ID); 149 } 150 151 // Random order of all columns 152 String[] projection = Arrays.copyOf( 153 SimPhonebookProvider.ELEMENTARY_FILES_ALL_COLUMNS, 154 SimPhonebookProvider.ELEMENTARY_FILES_ALL_COLUMNS.length); 155 Collections.shuffle(Arrays.asList(projection)); 156 try (Cursor cursor = mResolver.query(ElementaryFiles.CONTENT_URI, projection, null, null)) { 157 assertThat(cursor).hasColumnNames(projection); 158 } 159 } 160 161 @Test query_entityFiles_unrecognizedColumn_throwsIllegalArgumentException()162 public void query_entityFiles_unrecognizedColumn_throwsIllegalArgumentException() { 163 assertThrows(IllegalArgumentException.class, () -> 164 mResolver.query(ElementaryFiles.CONTENT_URI, new String[]{"invalid_column"}, null, 165 null)); 166 } 167 168 @Test query_entityFiles_noSim_returnsEmptyCursor()169 public void query_entityFiles_noSim_returnsEmptyCursor() { 170 when(mMockSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn( 171 ImmutableList.of()); 172 173 try (Cursor cursor = mResolver.query(ElementaryFiles.CONTENT_URI, null, null, null)) { 174 assertThat(cursor).hasCount(0); 175 } 176 } 177 178 @Test query_entityFiles_multiSim_returnsCursorWithRowForEachSimEf()179 public void query_entityFiles_multiSim_returnsCursorWithRowForEachSimEf() { 180 setupSimsWithSubscriptionIds(2, 3, 7); 181 182 mIccPhoneBook.setRecordsSize(2, IccConstants.EF_ADN, 10, 25); 183 mIccPhoneBook.setRecordsSize(2, IccConstants.EF_FDN, 5, 20); 184 mIccPhoneBook.setRecordsSize(2, IccConstants.EF_SDN, 15, 20); 185 mIccPhoneBook.setRecordsSize(3, IccConstants.EF_ADN, 100, 30); 186 // These Will be omitted from results because zero size indicates the EF is not supported. 187 mIccPhoneBook.setRecordsSize(3, IccConstants.EF_FDN, 0, 0); 188 mIccPhoneBook.setRecordsSize(3, IccConstants.EF_SDN, 0, 0); 189 mIccPhoneBook.setRecordsSize(7, IccConstants.EF_ADN, 0, 0); 190 mIccPhoneBook.setRecordsSize(7, IccConstants.EF_FDN, 0, 0); 191 mIccPhoneBook.setRecordsSize(7, IccConstants.EF_SDN, 0, 0); 192 193 String[] projection = { 194 ElementaryFiles.SLOT_INDEX, ElementaryFiles.SUBSCRIPTION_ID, 195 ElementaryFiles.EF_TYPE, ElementaryFiles.MAX_RECORDS, 196 ElementaryFiles.NAME_MAX_LENGTH, ElementaryFiles.PHONE_NUMBER_MAX_LENGTH 197 }; 198 try (Cursor cursor = mResolver.query(ElementaryFiles.CONTENT_URI, projection, null, null)) { 199 assertThat(cursor).hasColumnNames(projection); 200 201 assertThat(cursor) 202 .atRow(0).hasRowValues(0, 2, ElementaryFiles.EF_ADN, 10, 11, 20) 203 .atRow(1).hasRowValues(0, 2, ElementaryFiles.EF_FDN, 5, 6, 20) 204 .atRow(2).hasRowValues(0, 2, ElementaryFiles.EF_SDN, 15, 6, 20) 205 .atRow(3).hasRowValues(1, 3, ElementaryFiles.EF_ADN, 100, 16, 20); 206 } 207 } 208 209 @Test query_entityFiles_simWithZeroSizes_returnsEmptyCursor()210 public void query_entityFiles_simWithZeroSizes_returnsEmptyCursor() { 211 setupSimsWithSubscriptionIds(1); 212 213 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 0, 0); 214 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_FDN, 0, 0); 215 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_SDN, 0, 0); 216 217 try (Cursor cursor = mResolver.query(ElementaryFiles.CONTENT_URI, null, null, null)) { 218 assertThat(cursor).hasCount(0); 219 } 220 } 221 222 @Test query_entityFilesItem_nullProjection_returnsCursorWithCorrectProjection()223 public void query_entityFilesItem_nullProjection_returnsCursorWithCorrectProjection() { 224 setupSimsWithSubscriptionIds(1); 225 mIccPhoneBook.makeAllEfsSupported(1); 226 227 // Null projection 228 try (Cursor cursor = mResolver.query(ElementaryFiles.getItemUri(1, EF_ADN), null, null, 229 null)) { 230 assertThat(Objects.requireNonNull(cursor).getColumnNames()).asList() 231 .containsExactlyElementsIn( 232 SimPhonebookProvider.ELEMENTARY_FILES_ALL_COLUMNS); 233 } 234 } 235 236 @Test query_adnRecords_returnsCursorWithMatchingProjection()237 public void query_adnRecords_returnsCursorWithMatchingProjection() { 238 setupSimsWithSubscriptionIds(1); 239 mIccPhoneBook.makeAllEfsSupported(1); 240 Uri contentAdn = SimRecords.getContentUri(1, EF_ADN); 241 242 // Null projection 243 try (Cursor cursor = mResolver.query(contentAdn, null, null, null)) { 244 assertThat(Objects.requireNonNull(cursor).getColumnNames()).asList() 245 .containsExactlyElementsIn(SimPhonebookProvider.SIM_RECORDS_ALL_COLUMNS); 246 } 247 248 // Empty projection 249 try (Cursor cursor = mResolver.query(contentAdn, new String[0], null, null)) { 250 assertThat(cursor).hasColumnNames(); 251 } 252 253 // Single column 254 try (Cursor cursor = mResolver.query(contentAdn, new String[]{ 255 SimRecords.PHONE_NUMBER 256 }, null, null)) { 257 assertThat(cursor).hasColumnNames(SimRecords.PHONE_NUMBER); 258 } 259 260 // Duplicate column 261 try (Cursor cursor = mResolver.query(contentAdn, new String[]{ 262 SimRecords.PHONE_NUMBER, SimRecords.PHONE_NUMBER 263 }, null, null)) { 264 assertThat(cursor).hasColumnNames(SimRecords.PHONE_NUMBER, SimRecords.PHONE_NUMBER); 265 } 266 267 // Random order of all columns 268 String[] projection = Arrays.copyOf( 269 SimPhonebookProvider.SIM_RECORDS_ALL_COLUMNS, 270 SimPhonebookProvider.SIM_RECORDS_ALL_COLUMNS.length); 271 Collections.shuffle(Arrays.asList(projection)); 272 try (Cursor cursor = mResolver.query(contentAdn, projection, null, null)) { 273 assertThat(cursor).hasColumnNames(projection); 274 } 275 } 276 277 @Test query_adnRecords_noRecords_returnsEmptyCursor()278 public void query_adnRecords_noRecords_returnsEmptyCursor() { 279 setupSimsWithSubscriptionIds(1); 280 mIccPhoneBook.makeAllEfsSupported(1); 281 282 try (Cursor cursor = mResolver.query(SimRecords.getContentUri(1, EF_ADN), null, null, 283 null)) { 284 assertThat(cursor).hasCount(0); 285 } 286 } 287 288 @Test query_simRecords_nullRecordList_returnsEmptyCursor()289 public void query_simRecords_nullRecordList_returnsEmptyCursor() throws Exception { 290 setupSimsWithSubscriptionIds(1); 291 mIccPhoneBook.makeAllEfsSupported(1); 292 // Use a mock so that a null list can be returned 293 IIccPhoneBook mockIccPhoneBook = mock( 294 IIccPhoneBook.class, AdditionalAnswers.delegatesTo(mIccPhoneBook)); 295 when(mockIccPhoneBook.getAdnRecordsInEfForSubscriber(anyInt(), anyInt())).thenReturn(null); 296 TestableSimPhonebookProvider.setup(mResolver, mMockSubscriptionManager, mockIccPhoneBook); 297 298 try (Cursor adnCursor = mResolver.query(SimRecords.getContentUri(1, EF_ADN), null, null, 299 null); 300 Cursor fdnCursor = mResolver.query(SimRecords.getContentUri(1, EF_FDN), null, null, 301 null); 302 Cursor sdnCursor = mResolver.query(SimRecords.getContentUri(1, EF_SDN), null, null, 303 null) 304 ) { 305 assertThat(adnCursor).hasCount(0); 306 assertThat(fdnCursor).hasCount(0); 307 assertThat(sdnCursor).hasCount(0); 308 } 309 } 310 311 @Test query_simRecords_singleSim_returnsDataForCorrectEf()312 public void query_simRecords_singleSim_returnsDataForCorrectEf() { 313 setupSimsWithSubscriptionIds(1); 314 mIccPhoneBook.addRecord(1, IccConstants.EF_ADN, "Person Adn1", "8005550101"); 315 mIccPhoneBook.addRecord(1, IccConstants.EF_ADN, "Person Adn2", "8005550102"); 316 mIccPhoneBook.addRecord(1, IccConstants.EF_FDN, "Person Fdn", "8005550103"); 317 mIccPhoneBook.addRecord(1, IccConstants.EF_SDN, "Person Sdn", "8005550104"); 318 mIccPhoneBook.setDefaultSubscriptionId(1); 319 320 String[] projection = { 321 SimRecords.SUBSCRIPTION_ID, 322 SimRecords.ELEMENTARY_FILE_TYPE, 323 SimRecords.RECORD_NUMBER, 324 SimRecords.NAME, 325 SimRecords.PHONE_NUMBER 326 }; 327 try (Cursor adnCursor = mResolver.query(SimRecords.getContentUri(1, EF_ADN), 328 projection, null, null); 329 Cursor fdnCursor = mResolver.query(SimRecords.getContentUri(1, EF_FDN), 330 projection, null, null); 331 Cursor sdnCursor = mResolver.query(SimRecords.getContentUri(1, EF_SDN), 332 projection, null, null) 333 ) { 334 335 assertThat(adnCursor) 336 .atRow(0).hasRowValues(1, ElementaryFiles.EF_ADN, 1, "Person Adn1", 337 "8005550101") 338 .atRow(1).hasRowValues(1, ElementaryFiles.EF_ADN, 2, "Person Adn2", 339 "8005550102"); 340 assertThat(fdnCursor) 341 .atRow(0).hasRowValues(1, ElementaryFiles.EF_FDN, 1, "Person Fdn", 342 "8005550103"); 343 assertThat(sdnCursor) 344 .atRow(0).hasRowValues(1, ElementaryFiles.EF_SDN, 1, "Person Sdn", 345 "8005550104"); 346 } 347 } 348 349 @Test query_adnRecords_returnsAdnData()350 public void query_adnRecords_returnsAdnData() { 351 setupSimsWithSubscriptionIds(1, 2, 4); 352 mIccPhoneBook.addRecord(1, IccConstants.EF_ADN, "Person Sim1", "8005550101"); 353 mIccPhoneBook.addRecord(1, IccConstants.EF_FDN, "Omitted Sim1", "8005550199"); 354 mIccPhoneBook.addRecord(2, IccConstants.EF_ADN, "Person Sim2a", "8005550103"); 355 mIccPhoneBook.addRecord(2, IccConstants.EF_ADN, "Person Sim2b", "8005550104"); 356 mIccPhoneBook.addRecord(2, IccConstants.EF_ADN, "Person Sim2c", "8005550105"); 357 mIccPhoneBook.addRecord(2, IccConstants.EF_SDN, "Omitted Sim2", "8005550198"); 358 mIccPhoneBook.addRecord(4, IccConstants.EF_ADN, "Person Sim4", "8005550106"); 359 mIccPhoneBook.setDefaultSubscriptionId(1); 360 361 String[] projection = { 362 SimRecords.SUBSCRIPTION_ID, 363 SimRecords.ELEMENTARY_FILE_TYPE, 364 SimRecords.RECORD_NUMBER, 365 SimRecords.NAME, 366 SimRecords.PHONE_NUMBER 367 }; 368 try (Cursor cursorSim1 = mResolver.query(SimRecords.getContentUri(1, EF_ADN), 369 projection, null, null); 370 Cursor cursorSim2 = mResolver.query(SimRecords.getContentUri(2, EF_ADN), 371 projection, null, null); 372 Cursor cursorSim4 = mResolver.query(SimRecords.getContentUri(4, EF_ADN), 373 projection, null, null) 374 ) { 375 376 assertThat(cursorSim1).hasData(new Object[][]{ 377 {1, ElementaryFiles.EF_ADN, 1, "Person Sim1", "8005550101"}, 378 }); 379 assertThat(cursorSim2).hasData(new Object[][]{ 380 {2, ElementaryFiles.EF_ADN, 1, "Person Sim2a", "8005550103"}, 381 {2, ElementaryFiles.EF_ADN, 2, "Person Sim2b", "8005550104"}, 382 {2, ElementaryFiles.EF_ADN, 3, "Person Sim2c", "8005550105"}, 383 }); 384 assertThat(cursorSim4).hasData(new Object[][]{ 385 {4, ElementaryFiles.EF_ADN, 1, "Person Sim4", "8005550106"}, 386 }); 387 } 388 } 389 390 @Test query_fdnRecords_returnsFdnData()391 public void query_fdnRecords_returnsFdnData() { 392 setupSimsWithSubscriptionIds(1, 2, 4); 393 mIccPhoneBook.makeAllEfsSupported(1, 2, 4); 394 mIccPhoneBook.addRecord(1, IccConstants.EF_ADN, "Person Sim1", "8005550101"); 395 mIccPhoneBook.addRecord(2, IccConstants.EF_ADN, "Person Sim2a", "8005550103"); 396 mIccPhoneBook.addRecord(2, IccConstants.EF_FDN, "Person Sim2b", "8005550104"); 397 mIccPhoneBook.addRecord(2, IccConstants.EF_FDN, "Person Sim2c", "8005550105"); 398 mIccPhoneBook.addRecord(4, IccConstants.EF_SDN, "Person Sim4", "8005550106"); 399 mIccPhoneBook.setDefaultSubscriptionId(1); 400 401 String[] projection = { 402 SimRecords.SUBSCRIPTION_ID, 403 SimRecords.ELEMENTARY_FILE_TYPE, 404 SimRecords.RECORD_NUMBER, 405 SimRecords.NAME, 406 SimRecords.PHONE_NUMBER 407 }; 408 try (Cursor cursorSim1Fdn = mResolver.query(SimRecords.getContentUri(1, EF_FDN), 409 projection, null, null); 410 Cursor cursorSim2Fdn = mResolver.query(SimRecords.getContentUri(2, EF_FDN), 411 projection, null, null); 412 Cursor cursorSim4Fdn = mResolver.query(SimRecords.getContentUri(4, EF_FDN), 413 projection, null, null) 414 ) { 415 416 assertThat(cursorSim1Fdn).hasCount(0); 417 assertThat(cursorSim2Fdn).hasData(new Object[][]{ 418 {2, ElementaryFiles.EF_FDN, 1, "Person Sim2b", "8005550104"}, 419 {2, ElementaryFiles.EF_FDN, 2, "Person Sim2c", "8005550105"}, 420 }); 421 assertThat(cursorSim4Fdn).hasCount(0); 422 } 423 } 424 425 @Test query_sdnRecords_returnsSdnData()426 public void query_sdnRecords_returnsSdnData() { 427 setupSimsWithSubscriptionIds(1, 2, 4); 428 mIccPhoneBook.makeAllEfsSupported(1, 2, 4); 429 mIccPhoneBook.addRecord(1, IccConstants.EF_ADN, "Person Adn1", "8005550101"); 430 mIccPhoneBook.addRecord(1, IccConstants.EF_FDN, "Person Fdn1", "8005550102"); 431 mIccPhoneBook.addRecord(1, IccConstants.EF_SDN, "Person Sdn1", "8005550103"); 432 mIccPhoneBook.addRecord(2, IccConstants.EF_ADN, "Person Adn2a", "8005550104"); 433 mIccPhoneBook.addRecord(2, IccConstants.EF_FDN, "Person Fdn2b", "8005550105"); 434 mIccPhoneBook.addRecord(4, IccConstants.EF_SDN, "Person Sdn4a", "8005550106"); 435 mIccPhoneBook.addRecord(4, IccConstants.EF_SDN, "Person Sdn4b", "8005550107"); 436 mIccPhoneBook.setDefaultSubscriptionId(1); 437 438 String[] projection = { 439 SimRecords.SUBSCRIPTION_ID, 440 SimRecords.ELEMENTARY_FILE_TYPE, 441 SimRecords.RECORD_NUMBER, 442 SimRecords.NAME, 443 SimRecords.PHONE_NUMBER 444 }; 445 try (Cursor cursorSim1Sdn = mResolver.query(SimRecords.getContentUri(1, EF_SDN), 446 projection, null, null); 447 Cursor cursorSim2Sdn = mResolver.query(SimRecords.getContentUri(2, EF_SDN), 448 projection, null, null); 449 Cursor cursorSim4Sdn = mResolver.query(SimRecords.getContentUri(4, EF_SDN), 450 projection, null, null) 451 ) { 452 453 assertThat(cursorSim1Sdn) 454 .atRow(0).hasRowValues(1, ElementaryFiles.EF_SDN, 1, "Person Sdn1", 455 "8005550103"); 456 assertThat(cursorSim2Sdn).hasCount(0); 457 assertThat(cursorSim4Sdn) 458 .atRow(0).hasRowValues(4, ElementaryFiles.EF_SDN, 1, "Person Sdn4a", 459 "8005550106") 460 .atRow(1).hasRowValues(4, ElementaryFiles.EF_SDN, 2, "Person Sdn4b", 461 "8005550107"); 462 } 463 } 464 465 @Test query_adnRecords_nonExistentSim_throwsCorrectException()466 public void query_adnRecords_nonExistentSim_throwsCorrectException() { 467 setupSimsWithSubscriptionIds(1); 468 469 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 470 () -> mResolver.query(SimRecords.getContentUri(123, EF_ADN), null, null, null)); 471 assertThat(e).hasMessageThat().isEqualTo("No active SIM with subscription ID 123"); 472 } 473 474 @Test insert_nonExistentSim_throwsCorrectException()475 public void insert_nonExistentSim_throwsCorrectException() { 476 setupSimsWithSubscriptionIds(1); 477 ContentValues values = new ContentValues(); 478 values.put(SimRecords.NAME, "Name"); 479 values.put(SimRecords.PHONE_NUMBER, "123"); 480 481 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 482 () -> mResolver.insert(SimRecords.getContentUri(123, EF_ADN), values)); 483 assertThat(e).hasMessageThat().isEqualTo("No active SIM with subscription ID 123"); 484 } 485 486 @Test update_nonExistentSim_throwsCorrectException()487 public void update_nonExistentSim_throwsCorrectException() { 488 setupSimsWithSubscriptionIds(1); 489 ContentValues values = new ContentValues(); 490 values.put(SimRecords.NAME, "Name"); 491 values.put(SimRecords.PHONE_NUMBER, "123"); 492 493 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 494 () -> mResolver.update(SimRecords.getItemUri(123, EF_ADN, 1), values, null)); 495 assertThat(e).hasMessageThat().isEqualTo("No active SIM with subscription ID 123"); 496 } 497 498 @Test delete_nonExistentSim_throwsCorrectException()499 public void delete_nonExistentSim_throwsCorrectException() { 500 setupSimsWithSubscriptionIds(1); 501 502 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 503 () -> mResolver.delete(SimRecords.getItemUri(123, EF_ADN, 1), null)); 504 assertThat(e).hasMessageThat().isEqualTo("No active SIM with subscription ID 123"); 505 } 506 507 @Test query_adnRecords_zeroSizeEf_throwsCorrectException()508 public void query_adnRecords_zeroSizeEf_throwsCorrectException() { 509 setupSimsWithSubscriptionIds(1); 510 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 0, 0); 511 512 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 513 () -> mResolver.query(SimRecords.getContentUri(1, EF_ADN), null, null, null)); 514 assertThat(e).hasMessageThat().isEqualTo( 515 "adn is not supported for SIM with subscription ID 1"); 516 } 517 518 @Test query_itemUri_returnsCorrectRow()519 public void query_itemUri_returnsCorrectRow() { 520 setupSimsWithSubscriptionIds(1, 2); 521 mIccPhoneBook.addRecord(1, 522 new AdnRecord(IccConstants.EF_ADN, 1, "Name@Adn1[1]", "8005550101")); 523 mIccPhoneBook.addRecord(1, 524 new AdnRecord(IccConstants.EF_ADN, 2, "Name@Adn1[2]", "8005550102")); 525 mIccPhoneBook.addRecord(1, 526 new AdnRecord(IccConstants.EF_ADN, 3, "Name@Adn1[3]", "8005550103")); 527 mIccPhoneBook.addRecord(2, 528 new AdnRecord(IccConstants.EF_ADN, 3, "Name@Adn2[3]", "8005550104")); 529 mIccPhoneBook.addRecord(1, 530 new AdnRecord(IccConstants.EF_FDN, 1, "Name@Fdn1[1]", "8005550105")); 531 mIccPhoneBook.addRecord(2, 532 new AdnRecord(IccConstants.EF_SDN, 1, "Name@Sdn2[1]", "8005550106")); 533 534 String[] projection = { 535 SimRecords.SUBSCRIPTION_ID, SimRecords.ELEMENTARY_FILE_TYPE, 536 SimRecords.RECORD_NUMBER, SimRecords.NAME, SimRecords.PHONE_NUMBER 537 }; 538 try (Cursor item1 = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1), 539 projection, null, null); 540 Cursor item2 = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 3), 541 projection, null, null); 542 Cursor item3 = mResolver.query(SimRecords.getItemUri(2, ElementaryFiles.EF_ADN, 3), 543 projection, null, null); 544 Cursor item4 = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_FDN, 1), 545 projection, null, null); 546 Cursor item5 = mResolver.query(SimRecords.getItemUri(2, ElementaryFiles.EF_SDN, 1), 547 projection, null, null) 548 ) { 549 assertThat(item1).hasSingleRow(1, ElementaryFiles.EF_ADN, 1, "Name@Adn1[1]", 550 "8005550101"); 551 assertThat(item2).hasSingleRow(1, ElementaryFiles.EF_ADN, 3, "Name@Adn1[3]", 552 "8005550103"); 553 assertThat(item3).hasSingleRow(2, ElementaryFiles.EF_ADN, 3, "Name@Adn2[3]", 554 "8005550104"); 555 assertThat(item4).hasSingleRow(1, ElementaryFiles.EF_FDN, 1, "Name@Fdn1[1]", 556 "8005550105"); 557 assertThat(item5).hasSingleRow(2, ElementaryFiles.EF_SDN, 1, "Name@Sdn2[1]", 558 "8005550106"); 559 } 560 } 561 562 @Test query_itemUriNullProjection_returnsCursorWithAllColumns()563 public void query_itemUriNullProjection_returnsCursorWithAllColumns() { 564 setupSimsWithSubscriptionIds(1); 565 mIccPhoneBook.makeAllEfsSupported(1); 566 567 try (Cursor cursor = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1), 568 null, null, null) 569 ) { 570 assertThat(Objects.requireNonNull( 571 cursor).getColumnNames()).asList().containsExactlyElementsIn( 572 SimPhonebookProvider.SIM_RECORDS_ALL_COLUMNS); 573 } 574 } 575 576 @Test query_itemUriEmptyRecord_returnsEmptyCursor()577 public void query_itemUriEmptyRecord_returnsEmptyCursor() { 578 setupSimsWithSubscriptionIds(1); 579 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 30); 580 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_FDN, 1, 30); 581 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_SDN, 1, 30); 582 583 try (Cursor adnItem = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1), 584 null, null, null); 585 Cursor fdnItem = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_FDN, 1), 586 null, null, null); 587 Cursor sdnItem = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_SDN, 1), 588 null, null, null) 589 ) { 590 assertThat(adnItem).hasCount(0); 591 assertThat(fdnItem).hasCount(0); 592 assertThat(sdnItem).hasCount(0); 593 } 594 } 595 596 @Test query_itemUriIndexExceedsMax_returnsEmptyCursor()597 public void query_itemUriIndexExceedsMax_returnsEmptyCursor() { 598 setupSimsWithSubscriptionIds(1); 599 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 30); 600 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_FDN, 1, 30); 601 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_SDN, 1, 30); 602 603 try (Cursor adnItem = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 2), 604 null, null, null); 605 Cursor fdnItem = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_FDN, 2), 606 null, null, null); 607 Cursor sdnItem = mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_SDN, 2), 608 null, null, null) 609 ) { 610 assertThat(adnItem).hasCount(0); 611 assertThat(fdnItem).hasCount(0); 612 assertThat(sdnItem).hasCount(0); 613 } 614 } 615 616 @Test query_invalidItemIndex_throwsIllegalArgumentException()617 public void query_invalidItemIndex_throwsIllegalArgumentException() { 618 setupSimsWithSubscriptionIds(1); 619 mIccPhoneBook.makeAllEfsSupported(1); 620 621 assertThrows(IllegalArgumentException.class, () -> 622 mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, -1), 623 null, null, null)); 624 assertThrows(IllegalArgumentException.class, () -> 625 mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_FDN, -1), 626 null, null, null)); 627 assertThrows(IllegalArgumentException.class, () -> 628 mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_SDN, -1), 629 null, null, null)); 630 assertThrows(IllegalArgumentException.class, () -> 631 mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 0), 632 null, null, null)); 633 assertThrows(IllegalArgumentException.class, () -> 634 mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_FDN, 0), 635 null, null, null)); 636 assertThrows(IllegalArgumentException.class, () -> 637 mResolver.query(SimRecords.getItemUri(1, ElementaryFiles.EF_SDN, 0), 638 null, null, null)); 639 } 640 641 @Test insert_adnRecord_addsAdnRecordAndReturnsUriForNewRecord()642 public void insert_adnRecord_addsAdnRecordAndReturnsUriForNewRecord() { 643 setupSimsWithSubscriptionIds(1); 644 mIccPhoneBook.makeAllEfsSupported(1); 645 646 ContentValues values = new ContentValues(); 647 values.put(SimRecords.NAME, "First Last"); 648 values.put(SimRecords.PHONE_NUMBER, "8005550101"); 649 650 Uri uri = mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values); 651 652 List<AdnRecord> records = mIccPhoneBook.getAdnRecordsInEfForSubscriber( 653 1, IccConstants.EF_ADN).stream() 654 .filter(((Predicate<AdnRecord>) AdnRecord::isEmpty).negate()) 655 .collect(Collectors.toList()); 656 657 assertThat(records) 658 .comparingElementsUsing(ADN_RECORD_IS_EQUAL) 659 .containsExactly(new AdnRecord(IccConstants.EF_ADN, 1, "First Last", "8005550101")); 660 661 assertThat(uri).isEqualTo(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1)); 662 } 663 664 @Test insert_adnRecordWithExistingRecords_returnsUriWithCorrectIndex()665 public void insert_adnRecordWithExistingRecords_returnsUriWithCorrectIndex() { 666 setupSimsWithSubscriptionIds(1); 667 mIccPhoneBook.setDefaultSubscriptionId(1); 668 mIccPhoneBook.addRecord(new AdnRecord(IccConstants.EF_ADN, 2, "Existing1", "8005550101")); 669 mIccPhoneBook.addRecord(new AdnRecord(IccConstants.EF_ADN, 3, "Existing2", "8005550102")); 670 mIccPhoneBook.addRecord(new AdnRecord(IccConstants.EF_ADN, 5, "Existing3", "8005550103")); 671 672 ContentValues values = new ContentValues(); 673 values.put(SimRecords.NAME, "New1"); 674 values.put(SimRecords.PHONE_NUMBER, "8005550104"); 675 676 Uri insert1 = mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values); 677 values.put(SimRecords.NAME, "New2"); 678 values.put(SimRecords.PHONE_NUMBER, "8005550105"); 679 Uri insert2 = mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values); 680 values.put(SimRecords.NAME, "New3"); 681 values.put(SimRecords.PHONE_NUMBER, "8005550106"); 682 Uri insert3 = mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values); 683 684 assertThat( 685 mIccPhoneBook.getAdnRecordsInEfForSubscriber(1, IccConstants.EF_ADN).subList(0, 6)) 686 .comparingElementsUsing(ADN_RECORD_IS_EQUAL) 687 .containsExactly( 688 new AdnRecord(IccConstants.EF_ADN, 1, "New1", "8005550104"), 689 new AdnRecord(IccConstants.EF_ADN, 2, "Existing1", "8005550101"), 690 new AdnRecord(IccConstants.EF_ADN, 3, "Existing2", "8005550102"), 691 new AdnRecord(IccConstants.EF_ADN, 4, "New2", "8005550105"), 692 new AdnRecord(IccConstants.EF_ADN, 5, "Existing3", "8005550103"), 693 new AdnRecord(IccConstants.EF_ADN, 6, "New3", "8005550106")); 694 assertThat(insert1).isEqualTo(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1)); 695 assertThat(insert2).isEqualTo(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 4)); 696 assertThat(insert3).isEqualTo(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 6)); 697 } 698 699 @Test insert_efFull_throwsCorrectException()700 public void insert_efFull_throwsCorrectException() { 701 setupSimsWithSubscriptionIds(1); 702 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 30); 703 mIccPhoneBook.addRecord(1, IccConstants.EF_ADN, "Existing", "8005550101"); 704 705 ContentValues values = new ContentValues(); 706 values.put(SimRecords.NAME, "New"); 707 values.put(SimRecords.PHONE_NUMBER, "8005550102"); 708 709 Uri uri = SimRecords.getContentUri(1, EF_ADN); 710 IllegalStateException e = assertThrows(IllegalStateException.class, 711 () -> mResolver.insert(uri, values)); 712 assertThat(e).hasMessageThat().isEqualTo( 713 uri + " is full. Please delete records to add new ones."); 714 } 715 716 @Test insert_nameWithNonGsmCharacters_addsAdnRecord()717 public void insert_nameWithNonGsmCharacters_addsAdnRecord() { 718 setupSimsWithSubscriptionIds(1); 719 mIccPhoneBook.makeAllEfsSupported(1); 720 721 ContentValues values = new ContentValues(); 722 String name = "abc日本" + EMOJI; 723 values.put(SimRecords.NAME, name); 724 values.put(SimRecords.PHONE_NUMBER, "8005550101"); 725 726 Uri uri = mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values); 727 728 List<AdnRecord> records = mIccPhoneBook.getAdnRecordsInEfForSubscriber( 729 1, IccConstants.EF_ADN).stream() 730 .filter(((Predicate<AdnRecord>) AdnRecord::isEmpty).negate()) 731 .collect(Collectors.toList()); 732 733 assertThat(records) 734 .comparingElementsUsing(ADN_RECORD_IS_EQUAL) 735 .containsExactly(new AdnRecord(IccConstants.EF_ADN, 1, name, "8005550101")); 736 737 assertThat(uri).isEqualTo(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1)); 738 } 739 740 @Test insert_nullValues_returnsNull()741 public void insert_nullValues_returnsNull() { 742 setupSimsWithSubscriptionIds(1); 743 mIccPhoneBook.makeAllEfsSupported(1); 744 745 Uri result = mResolver.insert(SimRecords.getContentUri(1, EF_ADN), null); 746 747 assertThat(result).isNull(); 748 } 749 750 @Test update_nullValues_returnsZero()751 public void update_nullValues_returnsZero() { 752 setupSimsWithSubscriptionIds(1); 753 mIccPhoneBook.makeAllEfsSupported(1); 754 mIccPhoneBook.addAdnRecord(1, "Name", "5550101"); 755 756 int result = mResolver.update(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1), null, 757 null); 758 759 assertThat(result).isEqualTo(0); 760 } 761 762 @Test insert_emptyValues_returnsNull()763 public void insert_emptyValues_returnsNull() { 764 setupSimsWithSubscriptionIds(1); 765 mIccPhoneBook.makeAllEfsSupported(1); 766 767 Uri result = mResolver.insert(SimRecords.getContentUri(1, EF_ADN), new ContentValues()); 768 769 assertThat(result).isNull(); 770 } 771 772 @Test insert_nameOmitted_createsRecordWithJustPhoneNumber()773 public void insert_nameOmitted_createsRecordWithJustPhoneNumber() { 774 setupSimsWithSubscriptionIds(1); 775 mIccPhoneBook.makeAllEfsSupported(1); 776 777 ContentValues values = new ContentValues(); 778 // No name 779 values.put(SimRecords.PHONE_NUMBER, "18005550101"); 780 781 mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values); 782 783 // Null name 784 values.putNull(SimRecords.NAME); 785 values.put(SimRecords.PHONE_NUMBER, "18005550102"); 786 mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values); 787 788 // Empty name 789 values.put(SimRecords.NAME, ""); 790 values.put(SimRecords.PHONE_NUMBER, "18005550103"); 791 mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values); 792 793 assertThat(mIccPhoneBook.getAllValidRecords()) 794 .comparingElementsUsing(ADN_RECORD_IS_EQUAL) 795 .containsExactly( 796 new AdnRecord(IccConstants.EF_ADN, 1, "", "18005550101"), 797 new AdnRecord(IccConstants.EF_ADN, 2, "", "18005550102"), 798 new AdnRecord(IccConstants.EF_ADN, 3, "", "18005550103")); 799 } 800 801 @Test insert_phoneNumberOmitted_throwsCorrectException()802 public void insert_phoneNumberOmitted_throwsCorrectException() { 803 setupSimsWithSubscriptionIds(1); 804 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 25); 805 806 ContentValues values = new ContentValues(); 807 values.put(SimRecords.NAME, "Name"); 808 809 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 810 () -> mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values)); 811 assertThat(e).hasMessageThat().isEqualTo(SimRecords.PHONE_NUMBER + " is required."); 812 } 813 814 @Test insert_nameTooLong_throwsCorrectException()815 public void insert_nameTooLong_throwsCorrectException() { 816 setupSimsWithSubscriptionIds(1); 817 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 25); 818 819 ContentValues values = new ContentValues(); 820 // Name is limited to 11 characters when the max record size is 25 821 values.put(SimRecords.NAME, "1234567890ab"); 822 values.put(SimRecords.PHONE_NUMBER, "8005550102"); 823 824 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 825 () -> mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values)); 826 827 assertThat(e).hasMessageThat().isEqualTo(SimRecords.NAME + " is too long."); 828 829 // 2 bytes per character and 4 for the emoji. So this is 14 characters long. 830 values.put(SimRecords.NAME, "abc日本" + EMOJI); 831 e = assertThrows(IllegalArgumentException.class, 832 () -> mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values)); 833 834 assertThat(e).hasMessageThat().isEqualTo(SimRecords.NAME + " is too long."); 835 } 836 837 @Test insert_phoneNumberTooLong_throwsCorrectException()838 public void insert_phoneNumberTooLong_throwsCorrectException() { 839 setupSimsWithSubscriptionIds(1); 840 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 25); 841 842 ContentValues values = new ContentValues(); 843 values.put(SimRecords.NAME, "Name"); 844 // 21 digits is longer than max of 20 845 values.put(SimRecords.PHONE_NUMBER, "123456789012345678901"); 846 847 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 848 () -> mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values)); 849 850 assertThat(e).hasMessageThat().isEqualTo(SimRecords.PHONE_NUMBER + " is too long."); 851 } 852 853 @Test insert_numberWithInvalidCharacters_throwsCorrectException()854 public void insert_numberWithInvalidCharacters_throwsCorrectException() { 855 setupSimsWithSubscriptionIds(1); 856 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 32); 857 858 ContentValues values = new ContentValues(); 859 values.put(SimRecords.NAME, "Name"); 860 values.put(SimRecords.PHONE_NUMBER, "(800)555-0190 x7777"); 861 862 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 863 () -> mResolver.insert(SimRecords.getContentUri(1, ElementaryFiles.EF_ADN), 864 values, 865 null)); 866 assertThat(e).hasMessageThat().isEqualTo( 867 SimRecords.PHONE_NUMBER + " contains unsupported characters."); 868 869 // The insert didn't actually change the data. 870 assertThat(mIccPhoneBook.getAllValidRecords()).isEmpty(); 871 } 872 873 @Test insert_unsupportedColumn_throwsCorrectException()874 public void insert_unsupportedColumn_throwsCorrectException() { 875 setupSimsWithSubscriptionIds(1); 876 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 25); 877 878 ContentValues values = new ContentValues(); 879 values.put(SimRecords.NAME, "Name"); 880 values.put(SimRecords.PHONE_NUMBER, "18005550101"); 881 values.put(SimRecords.RECORD_NUMBER, 8); 882 values.put("extra_phone2", "18005550102"); 883 884 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 885 () -> mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values)); 886 assertThat(e).hasMessageThat().isEqualTo("Unsupported columns: " 887 + SimRecords.RECORD_NUMBER + ",extra_phone2"); 888 } 889 890 @Test update_existingRecord_updatesRecord()891 public void update_existingRecord_updatesRecord() { 892 setupSimsWithSubscriptionIds(1, 2); 893 AdnRecord[] unchanged = new AdnRecord[]{ 894 new AdnRecord(IccConstants.EF_ADN, 3, "Other1", "8005550102"), 895 new AdnRecord(IccConstants.EF_ADN, 2, "Other2", "8005550103"), 896 new AdnRecord(IccConstants.EF_FDN, 2, "Other3", "8005550104") 897 }; 898 mIccPhoneBook.addRecord(1, unchanged[0]); 899 mIccPhoneBook.addRecord(2, unchanged[1]); 900 mIccPhoneBook.addRecord(2, unchanged[2]); 901 mIccPhoneBook.addRecord(1, 902 new AdnRecord(IccConstants.EF_ADN, 2, "Initial Name", "8005550101")); 903 904 ContentValues values = new ContentValues(); 905 values.put(SimRecords.NAME, "Updated Name"); 906 values.put(SimRecords.PHONE_NUMBER, "8005550105"); 907 908 int result = mResolver.update(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 2), values, 909 null); 910 911 assertThat(result).isEqualTo(1); 912 913 List<AdnRecord> finalRecords = mIccPhoneBook.getAllValidRecords(); 914 915 assertThat(finalRecords).comparingElementsUsing(ADN_RECORD_IS_EQUAL) 916 .containsAtLeastElementsIn(unchanged); 917 assertThat(finalRecords).comparingElementsUsing(ADN_RECORD_IS_EQUAL) 918 .doesNotContain( 919 new AdnRecord(IccConstants.EF_ADN, 2, "Initial Name", "80005550101")); 920 assertThat(finalRecords).comparingElementsUsing(ADN_RECORD_IS_EQUAL) 921 .contains(new AdnRecord(IccConstants.EF_ADN, 2, "Updated Name", "8005550105")); 922 } 923 924 @Test update_emptyRecord_updatesRecord()925 public void update_emptyRecord_updatesRecord() { 926 setupSimsWithSubscriptionIds(1); 927 mIccPhoneBook.makeAllEfsSupported(1); 928 929 ContentValues values = new ContentValues(); 930 values.put(SimRecords.NAME, "name"); 931 values.put(SimRecords.PHONE_NUMBER, "18005550101"); 932 // No record actually exists with record number 10 but we allow clients to update it 933 // as a way to set the information at a specific record number. 934 int result = mResolver.update(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 10), 935 values, null); 936 937 assertThat(result).isEqualTo(1); 938 List<AdnRecord> finalRecords = mIccPhoneBook.getAllValidRecords(); 939 assertThat(finalRecords).comparingElementsUsing(ADN_RECORD_IS_EQUAL) 940 .containsExactly(new AdnRecord(IccConstants.EF_ADN, 10, "name", "18005550101")); 941 } 942 943 @Test delete_existingRecord_deletesRecord()944 public void delete_existingRecord_deletesRecord() { 945 setupSimsWithSubscriptionIds(1, 2); 946 AdnRecord[] unchanged = new AdnRecord[]{ 947 new AdnRecord(IccConstants.EF_ADN, 3, "Other1", "8005550102"), 948 new AdnRecord(IccConstants.EF_ADN, 2, "Other2", "8005550103"), 949 new AdnRecord(IccConstants.EF_FDN, 2, "Other3", "8005550104") 950 }; 951 mIccPhoneBook.addRecord(1, 952 new AdnRecord(IccConstants.EF_ADN, 2, "Initial Name", "8005550101")); 953 mIccPhoneBook.addRecord(1, unchanged[0]); 954 mIccPhoneBook.addRecord(2, unchanged[1]); 955 mIccPhoneBook.addRecord(2, unchanged[2]); 956 957 int result = mResolver.delete(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 2), null); 958 959 assertThat(result).isEqualTo(1); 960 961 assertThat(mIccPhoneBook.getAllValidRecords()).comparingElementsUsing(ADN_RECORD_IS_EQUAL) 962 .containsExactlyElementsIn(unchanged); 963 } 964 965 @Test update_indexExceedingMax_returnsZero()966 public void update_indexExceedingMax_returnsZero() { 967 setupSimsWithSubscriptionIds(1); 968 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 30); 969 970 ContentValues values = new ContentValues(); 971 values.put(SimRecords.NAME, "name"); 972 values.put(SimRecords.PHONE_NUMBER, "18005551010"); 973 int result = mResolver.update(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 2), 974 values, null); 975 976 assertThat(result).isEqualTo(0); 977 } 978 979 @Test update_indexOverflow_throwsIllegalArgumentException()980 public void update_indexOverflow_throwsIllegalArgumentException() { 981 setupSimsWithSubscriptionIds(1); 982 mIccPhoneBook.makeAllEfsSupported(1); 983 984 ContentValues values = new ContentValues(); 985 values.put(SimRecords.NAME, "name"); 986 values.put(SimRecords.PHONE_NUMBER, "18005551010"); 987 assertThrows(IllegalArgumentException.class, () -> mResolver.update( 988 SimRecords.getContentUri(1, EF_ADN).buildUpon().appendPath( 989 String.valueOf((Long.MAX_VALUE))).build(), 990 values, null)); 991 } 992 993 @Test delete_emptyRecord_returnsZero()994 public void delete_emptyRecord_returnsZero() { 995 setupSimsWithSubscriptionIds(1); 996 mIccPhoneBook.makeAllEfsSupported(1); 997 998 int result = mResolver.delete(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 2), null); 999 1000 assertThat(result).isEqualTo(0); 1001 } 1002 1003 @Test delete_indexExceedingMax_returnsZero()1004 public void delete_indexExceedingMax_returnsZero() { 1005 setupSimsWithSubscriptionIds(1); 1006 mIccPhoneBook.makeAllEfsSupported(1); 1007 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 30); 1008 1009 int result = mResolver.delete(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 2), null); 1010 1011 assertThat(result).isEqualTo(0); 1012 } 1013 1014 @Test delete_indexOverflow_throwsIllegalArgumentException()1015 public void delete_indexOverflow_throwsIllegalArgumentException() { 1016 setupSimsWithSubscriptionIds(1); 1017 mIccPhoneBook.makeAllEfsSupported(1); 1018 1019 assertThrows(IllegalArgumentException.class, () -> mResolver.delete( 1020 SimRecords.getContentUri(1, EF_ADN).buildUpon().appendPath( 1021 String.valueOf((Long.MAX_VALUE))).build(), 1022 null)); 1023 } 1024 1025 @Test update_nameOrNumberTooLong_throwsCorrectException()1026 public void update_nameOrNumberTooLong_throwsCorrectException() { 1027 setupSimsWithSubscriptionIds(1); 1028 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 25); 1029 mIccPhoneBook.addRecord(1, IccConstants.EF_ADN, "Initial", "8005550101"); 1030 1031 ContentValues values = new ContentValues(); 1032 // Name is limited to 11 characters 1033 values.put(SimRecords.NAME, "1234567890ab"); 1034 values.put(SimRecords.PHONE_NUMBER, "8005550102"); 1035 1036 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 1037 () -> mResolver.update(SimRecords.getItemUri( 1038 1, ElementaryFiles.EF_ADN, 1), values, null)); 1039 assertThat(e).hasMessageThat().isEqualTo(SimRecords.NAME + " is too long."); 1040 1041 values.put(SimRecords.NAME, "abc"); 1042 values.put(SimRecords.PHONE_NUMBER, "123456789012345678901"); 1043 1044 e = assertThrows(IllegalArgumentException.class, 1045 () -> mResolver.update(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1), 1046 values, 1047 null)); 1048 assertThat(e).hasMessageThat().isEqualTo(SimRecords.PHONE_NUMBER + " is too long."); 1049 // The updates didn't actually change the data 1050 assertThat(mIccPhoneBook.getAllValidRecords()) 1051 .comparingElementsUsing(Correspondence.from(AdnRecord::isEqual, "isEqual")) 1052 .containsExactly(new AdnRecord(IccConstants.EF_ADN, 1, "Initial", "8005550101")); 1053 } 1054 1055 @Test update_numberWithInvalidCharacters_throwsCorrectException()1056 public void update_numberWithInvalidCharacters_throwsCorrectException() { 1057 setupSimsWithSubscriptionIds(1); 1058 mIccPhoneBook.setRecordsSize(1, IccConstants.EF_ADN, 1, 32); 1059 mIccPhoneBook.addRecord(1, IccConstants.EF_ADN, "Initial", "8005550101"); 1060 1061 ContentValues values = new ContentValues(); 1062 values.put(SimRecords.NAME, "Name"); 1063 values.put(SimRecords.PHONE_NUMBER, "(800)555-0190 x7777"); 1064 1065 IllegalArgumentException e = assertThrows(IllegalArgumentException.class, 1066 () -> mResolver.update(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1), 1067 values, 1068 null)); 1069 assertThat(e).hasMessageThat().isEqualTo( 1070 SimRecords.PHONE_NUMBER + " contains unsupported characters."); 1071 1072 // The update didn't actually change the data. 1073 assertThat(mIccPhoneBook.getAllValidRecords()) 1074 .comparingElementsUsing(Correspondence.from(AdnRecord::isEqual, "isEqual")) 1075 .containsExactly(new AdnRecord(IccConstants.EF_ADN, 1, "Initial", "8005550101")); 1076 } 1077 1078 @Test insert_nonAdnDirUris_throwsUnsupportedOperationException()1079 public void insert_nonAdnDirUris_throwsUnsupportedOperationException() { 1080 setupSimsWithSubscriptionIds(1); 1081 mIccPhoneBook.makeAllEfsSupported(1); 1082 1083 ContentValues values = new ContentValues(); 1084 values.put(SimRecords.NAME, "Name"); 1085 values.put(SimRecords.PHONE_NUMBER, "8005550101"); 1086 1087 assertThrows(UnsupportedOperationException.class, () -> 1088 mResolver.insert(ElementaryFiles.CONTENT_URI, values)); 1089 assertThrows(UnsupportedOperationException.class, 1090 () -> mResolver.insert(SimRecords.getContentUri(1, EF_FDN), values)); 1091 assertThrows(UnsupportedOperationException.class, 1092 () -> mResolver.insert(SimRecords.getContentUri(1, EF_SDN), values)); 1093 assertThrows(UnsupportedOperationException.class, () -> 1094 mResolver.insert(SimRecords.getItemUri(1, ElementaryFiles.EF_FDN, 1), values)); 1095 assertThrows(UnsupportedOperationException.class, () -> 1096 mResolver.insert(SimRecords.getItemUri(1, ElementaryFiles.EF_SDN, 1), values)); 1097 } 1098 1099 @Test update_nonAdnDirUris_throwsUnsupportedOperationException()1100 public void update_nonAdnDirUris_throwsUnsupportedOperationException() { 1101 setupSimsWithSubscriptionIds(1); 1102 mIccPhoneBook.makeAllEfsSupported(1); 1103 1104 ContentValues values = new ContentValues(); 1105 values.put(SimRecords.NAME, "Name"); 1106 values.put(SimRecords.PHONE_NUMBER, "8005550101"); 1107 1108 assertThrows(UnsupportedOperationException.class, () -> 1109 mResolver.update(ElementaryFiles.CONTENT_URI, values, null)); 1110 assertThrows(UnsupportedOperationException.class, 1111 () -> mResolver.update(SimRecords.getContentUri(1, EF_FDN), values, null)); 1112 assertThrows(UnsupportedOperationException.class, 1113 () -> mResolver.update(SimRecords.getContentUri(1, EF_SDN), values, null)); 1114 assertThrows(UnsupportedOperationException.class, 1115 () -> mResolver.update(SimRecords.getContentUri(1, EF_SDN), values, null)); 1116 assertThrows(UnsupportedOperationException.class, () -> 1117 mResolver.update(SimRecords.getItemUri(1, ElementaryFiles.EF_FDN, 1), values, 1118 null)); 1119 assertThrows(UnsupportedOperationException.class, () -> 1120 mResolver.update(SimRecords.getItemUri(1, ElementaryFiles.EF_SDN, 1), values, 1121 null)); 1122 } 1123 1124 @Test delete_nonAdnDirUris_throwsUnsupportedOperationException()1125 public void delete_nonAdnDirUris_throwsUnsupportedOperationException() { 1126 setupSimsWithSubscriptionIds(1); 1127 mIccPhoneBook.makeAllEfsSupported(1); 1128 1129 ContentValues values = new ContentValues(); 1130 values.put(SimRecords.NAME, "Name"); 1131 values.put(SimRecords.PHONE_NUMBER, "8005550101"); 1132 1133 assertThrows(UnsupportedOperationException.class, () -> 1134 mResolver.delete(ElementaryFiles.CONTENT_URI, null)); 1135 assertThrows(UnsupportedOperationException.class, 1136 () -> mResolver.delete(SimRecords.getContentUri(1, EF_FDN), null)); 1137 assertThrows(UnsupportedOperationException.class, 1138 () -> mResolver.delete(SimRecords.getContentUri(1, EF_SDN), null)); 1139 assertThrows(UnsupportedOperationException.class, 1140 () -> mResolver.delete(SimRecords.getContentUri(1, EF_SDN), null)); 1141 assertThrows(UnsupportedOperationException.class, () -> 1142 mResolver.delete(SimRecords.getItemUri(1, ElementaryFiles.EF_FDN, 1), null)); 1143 assertThrows(UnsupportedOperationException.class, () -> 1144 mResolver.delete(SimRecords.getItemUri(1, ElementaryFiles.EF_SDN, 1), null)); 1145 } 1146 1147 @Test subscriptionsChange_callsNotifyChange()1148 public void subscriptionsChange_callsNotifyChange() { 1149 // Clear invocations that happened in setUp 1150 Mockito.reset(mMockSubscriptionManager); 1151 setupSimsWithSubscriptionIds(1); 1152 mIccPhoneBook.makeAllEfsSupported(1); 1153 SimPhonebookProvider.ContentNotifier mockNotifier = mock( 1154 SimPhonebookProvider.ContentNotifier.class); 1155 ArgumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener> listenerCaptor = 1156 ArgumentCaptor.forClass(SubscriptionManager.OnSubscriptionsChangedListener.class); 1157 1158 TestableSimPhonebookProvider.setup( 1159 mResolver, mMockSubscriptionManager, mIccPhoneBook, mockNotifier); 1160 verify(mMockSubscriptionManager).addOnSubscriptionsChangedListener( 1161 any(), listenerCaptor.capture()); 1162 listenerCaptor.getValue().onSubscriptionsChanged(); 1163 setupSimsWithSubscriptionIds(1, 2); 1164 listenerCaptor.getValue().onSubscriptionsChanged(); 1165 listenerCaptor.getValue().onSubscriptionsChanged(); 1166 1167 verify(mockNotifier, times(2)).notifyChange(eq(SimPhonebookContract.AUTHORITY_URI)); 1168 } 1169 1170 @Test insert_callsNotifyChange()1171 public void insert_callsNotifyChange() { 1172 // Clear invocations that happened in setUp 1173 Mockito.reset(mMockSubscriptionManager); 1174 setupSimsWithSubscriptionIds(1); 1175 mIccPhoneBook.makeAllEfsSupported(1); 1176 SimPhonebookProvider.ContentNotifier mockNotifier = mock( 1177 SimPhonebookProvider.ContentNotifier.class); 1178 1179 TestableSimPhonebookProvider.setup( 1180 mResolver, mMockSubscriptionManager, mIccPhoneBook, mockNotifier); 1181 1182 ContentValues values = new ContentValues(); 1183 values.put(SimRecords.NAME, "name"); 1184 values.put(SimRecords.PHONE_NUMBER, "5550101"); 1185 mResolver.insert(SimRecords.getContentUri(1, EF_ADN), values); 1186 1187 verify(mockNotifier).notifyChange(eq(SimPhonebookContract.AUTHORITY_URI)); 1188 } 1189 1190 @Test update_callsNotifyChange()1191 public void update_callsNotifyChange() { 1192 // Clear invocations that happened in setUp 1193 Mockito.reset(mMockSubscriptionManager); 1194 setupSimsWithSubscriptionIds(1); 1195 mIccPhoneBook.addAdnRecord(1, "Initial", "5550101"); 1196 SimPhonebookProvider.ContentNotifier mockNotifier = mock( 1197 SimPhonebookProvider.ContentNotifier.class); 1198 1199 TestableSimPhonebookProvider.setup( 1200 mResolver, mMockSubscriptionManager, mIccPhoneBook, mockNotifier); 1201 1202 ContentValues values = new ContentValues(); 1203 values.put(SimRecords.NAME, "Updated"); 1204 values.put(SimRecords.PHONE_NUMBER, "5550102"); 1205 mResolver.update(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1), values, null); 1206 1207 verify(mockNotifier).notifyChange(eq(SimPhonebookContract.AUTHORITY_URI)); 1208 } 1209 1210 @Test delete_callsNotifyChange()1211 public void delete_callsNotifyChange() { 1212 // Clear invocations that happened in setUp 1213 Mockito.reset(mMockSubscriptionManager); 1214 setupSimsWithSubscriptionIds(1); 1215 mIccPhoneBook.addAdnRecord(1, "Initial", "5550101"); 1216 SimPhonebookProvider.ContentNotifier mockNotifier = mock( 1217 SimPhonebookProvider.ContentNotifier.class); 1218 1219 TestableSimPhonebookProvider.setup( 1220 mResolver, mMockSubscriptionManager, mIccPhoneBook, mockNotifier); 1221 1222 mResolver.delete(SimRecords.getItemUri(1, ElementaryFiles.EF_ADN, 1), null); 1223 1224 verify(mockNotifier).notifyChange(eq(SimPhonebookContract.AUTHORITY_URI)); 1225 } 1226 1227 @Test getEncodedNameLength_returnsValueIsCorrect()1228 public void getEncodedNameLength_returnsValueIsCorrect() { 1229 String name = ""; 1230 int length = SimRecords.getEncodedNameLength(mResolver, name); 1231 assertThat(length).isEqualTo(0); 1232 1233 name = "First Last"; 1234 length = SimRecords.getEncodedNameLength(mResolver, name); 1235 assertThat(length).isEqualTo(name.length()); 1236 1237 name = "日本"; 1238 length = SimRecords.getEncodedNameLength(mResolver, name); 1239 assertThat(length).isEqualTo(name.length() * 2 + 1); 1240 1241 name = EMOJI; 1242 length = SimRecords.getEncodedNameLength(mResolver, name); 1243 assertThat(length).isEqualTo(name.length() * 2 + 1); 1244 1245 name = "abc日本" + EMOJI; 1246 length = SimRecords.getEncodedNameLength(mResolver, name); 1247 assertThat(length).isEqualTo(name.length() * 2 + 1); 1248 } 1249 setupSimsWithSubscriptionIds(int... subscriptionIds)1250 private void setupSimsWithSubscriptionIds(int... subscriptionIds) { 1251 when(mMockSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(subscriptionIds); 1252 when(mMockSubscriptionManager.getActiveSubscriptionInfoCount()) 1253 .thenReturn(subscriptionIds.length); 1254 List<SubscriptionInfo> subscriptions = createSubscriptionsWithIds(subscriptionIds); 1255 when(mMockSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(subscriptions); 1256 for (SubscriptionInfo info : subscriptions) { 1257 when(mMockSubscriptionManager.getActiveSubscriptionInfo(info.getSubscriptionId())) 1258 .thenReturn(info); 1259 } 1260 } 1261 1262 public static class FakeIccPhoneBook extends IIccPhoneBook.Default { 1263 1264 private static final int DEFAULT_RECORD_SIZE = 30; 1265 private static final int DEFAULT_RECORDS_COUNT = 100; 1266 1267 // The key for both maps is the (subscription ID, efid) 1268 private Map<Pair<Integer, Integer>, AdnRecord[]> mRecords = new HashMap<>(); 1269 // The value is the single record size 1270 private Map<Pair<Integer, Integer>, Integer> mRecordSizes = new HashMap<>(); 1271 1272 private int mDefaultSubscriptionId = 101; 1273 addRecord(Pair<Integer, Integer> key, AdnRecord record)1274 private void addRecord(Pair<Integer, Integer> key, AdnRecord record) { 1275 // Assume that if records are being added then the test wants it to be a valid 1276 // elementary file so set sizes as well. 1277 if (!mRecordSizes.containsKey(key)) { 1278 setRecordsSize(key.first, key.second, 1279 Math.max(record.getRecId(), DEFAULT_RECORDS_COUNT), DEFAULT_RECORD_SIZE); 1280 } 1281 mRecords.get(key)[record.getRecId() - 1] = record; 1282 } 1283 addRecord(AdnRecord record)1284 public void addRecord(AdnRecord record) { 1285 addRecord(Pair.create(mDefaultSubscriptionId, record.getEfid()), record); 1286 } 1287 addRecord(int subscriptionId, AdnRecord record)1288 public void addRecord(int subscriptionId, AdnRecord record) { 1289 addRecord(Pair.create(subscriptionId, record.getEfid()), record); 1290 } 1291 addRecord(int subscriptionId, int efId, String name, String phoneNumber)1292 public void addRecord(int subscriptionId, int efId, String name, String phoneNumber) { 1293 Pair<Integer, Integer> key = Pair.create(subscriptionId, efId); 1294 AdnRecord[] records = mRecords.computeIfAbsent(key, unused -> 1295 createEmptyRecords(efId, 100)); 1296 int recordIndex = -1; 1297 for (int i = 0; i < records.length; i++) { 1298 if (records[i].isEmpty()) { 1299 recordIndex = i; 1300 break; 1301 } 1302 } 1303 if (recordIndex == -1) { 1304 throw new IllegalStateException(""); 1305 } 1306 addRecord(key, new AdnRecord(efId, recordIndex + 1, name, phoneNumber)); 1307 } 1308 addAdnRecord(int subscriptionId, String name, String phoneNumber)1309 public void addAdnRecord(int subscriptionId, String name, String phoneNumber) { 1310 addRecord(subscriptionId, IccConstants.EF_ADN, name, phoneNumber); 1311 } 1312 addAdnRecord(String name, String phoneNumber)1313 public void addAdnRecord(String name, String phoneNumber) { 1314 addRecord(mDefaultSubscriptionId, IccConstants.EF_ADN, name, phoneNumber); 1315 } 1316 getAllValidRecords()1317 public List<AdnRecord> getAllValidRecords() { 1318 List<AdnRecord> result = new ArrayList<>(); 1319 for (AdnRecord[] records : mRecords.values()) { 1320 for (AdnRecord record : records) { 1321 if (!record.isEmpty()) { 1322 result.add(record); 1323 } 1324 } 1325 } 1326 return result; 1327 } 1328 makeAllEfsSupported()1329 public void makeAllEfsSupported() { 1330 makeAllEfsSupported(mDefaultSubscriptionId); 1331 } 1332 1333 /** 1334 * Sets up the fake to return valid records size for all elementary files for the provided 1335 * subscription IDs. 1336 */ makeAllEfsSupported(int... subscriptionIds)1337 public void makeAllEfsSupported(int... subscriptionIds) { 1338 for (int subId : subscriptionIds) { 1339 makeAllEfsSupported(subId); 1340 } 1341 } 1342 1343 /** 1344 * Sets up the fake to return valid records size for all elementary files for the provided 1345 * subscription IDs. 1346 */ makeAllEfsSupported(int subscriptionId)1347 public void makeAllEfsSupported(int subscriptionId) { 1348 setRecordsSize(subscriptionId, IccConstants.EF_ADN, DEFAULT_RECORDS_COUNT, 1349 DEFAULT_RECORD_SIZE); 1350 setRecordsSize(subscriptionId, IccConstants.EF_FDN, DEFAULT_RECORDS_COUNT, 1351 DEFAULT_RECORD_SIZE); 1352 setRecordsSize(subscriptionId, IccConstants.EF_SDN, DEFAULT_RECORDS_COUNT, 1353 DEFAULT_RECORD_SIZE); 1354 } 1355 setRecordsSize(int subscriptionId, int efid, int maxRecordCount, int maxRecordSize)1356 public void setRecordsSize(int subscriptionId, int efid, int maxRecordCount, 1357 int maxRecordSize) { 1358 Pair<Integer, Integer> key = Pair.create(subscriptionId, efid); 1359 mRecordSizes.put(key, maxRecordSize); 1360 AdnRecord[] records = mRecords.computeIfAbsent(key, unused -> 1361 createEmptyRecords(efid, maxRecordCount)); 1362 if (records.length < maxRecordCount) { 1363 throw new IllegalStateException("Records already initialized with a smaller size"); 1364 } 1365 } 1366 createEmptyRecords(int efid, int count)1367 private AdnRecord[] createEmptyRecords(int efid, int count) { 1368 AdnRecord[] records = new AdnRecord[count]; 1369 for (int i = 0; i < records.length; i++) { 1370 if (records[i] == null) { 1371 records[i] = new AdnRecord(efid, i + 1, "", ""); 1372 } 1373 } 1374 return records; 1375 } 1376 setDefaultSubscriptionId(int defaultSubscriptionId)1377 public void setDefaultSubscriptionId(int defaultSubscriptionId) { 1378 mDefaultSubscriptionId = defaultSubscriptionId; 1379 } 1380 reset()1381 public void reset() { 1382 mRecords.clear(); 1383 mRecordSizes.clear(); 1384 } 1385 1386 @Override getAdnRecordsInEf(int efid)1387 public List<AdnRecord> getAdnRecordsInEf(int efid) { 1388 return getAdnRecordsInEfForSubscriber(mDefaultSubscriptionId, efid); 1389 } 1390 1391 @Override getAdnRecordsInEfForSubscriber(int subId, int efid)1392 public List<AdnRecord> getAdnRecordsInEfForSubscriber(int subId, int efid) { 1393 return Arrays.asList( 1394 mRecords.getOrDefault(Pair.create(subId, efid), new AdnRecord[0])); 1395 } 1396 1397 @Override updateAdnRecordsInEfBySearchForSubscriber(int subId, int efid, ContentValues values, String pin2)1398 public boolean updateAdnRecordsInEfBySearchForSubscriber(int subId, int efid, 1399 ContentValues values, String pin2) { 1400 final String oldTag = values.getAsString(IccProvider.STR_TAG); 1401 final String oldPhoneNumber = values.getAsString(IccProvider.STR_NUMBER); 1402 final String newTag = values.getAsString(IccProvider.STR_NEW_TAG); 1403 final String newPhoneNumber = values.getAsString(IccProvider.STR_NEW_NUMBER); 1404 return updateAdnRecordsInEfBySearchForSubscriber(subId, efid, oldTag, oldPhoneNumber, 1405 newTag, newPhoneNumber, pin2); 1406 1407 } 1408 updateAdnRecordsInEfBySearchForSubscriber(int subId, int efid, String oldTag, String oldPhoneNumber, String newTag, String newPhoneNumber, String pin2)1409 private boolean updateAdnRecordsInEfBySearchForSubscriber(int subId, int efid, String oldTag, 1410 String oldPhoneNumber, String newTag, String newPhoneNumber, String pin2) { 1411 if (!oldTag.isEmpty() || !oldPhoneNumber.isEmpty()) { 1412 throw new IllegalArgumentException( 1413 "updateAdnRecordsInEfBySearchForSubscriber only supports insert"); 1414 } 1415 addRecord(subId, efid, newTag, newPhoneNumber); 1416 return true; 1417 } 1418 1419 @Override updateAdnRecordsInEfByIndexForSubscriber(int subId, int efid, ContentValues values, int index, String pin2)1420 public boolean updateAdnRecordsInEfByIndexForSubscriber(int subId, int efid, 1421 ContentValues values, int index, String pin2) { 1422 final String newTag = values.getAsString(IccProvider.STR_NEW_TAG); 1423 final String newPhoneNumber = values.getAsString(IccProvider.STR_NEW_NUMBER); 1424 return updateAdnRecordsInEfByIndexForSubscriber(subId, efid, newTag, newPhoneNumber, 1425 index, pin2); 1426 1427 } 1428 updateAdnRecordsInEfByIndexForSubscriber(int subId, int efid, String newTag, String newPhoneNumber, int index, String pin2)1429 private boolean updateAdnRecordsInEfByIndexForSubscriber(int subId, int efid, String newTag, 1430 String newPhoneNumber, int index, String pin2) { 1431 AdnRecord[] records = mRecords.computeIfAbsent(Pair.create(subId, efid), unused -> 1432 createEmptyRecords(efid, 100)); 1433 records[index - 1] = new AdnRecord(efid, index, newTag, newPhoneNumber); 1434 return true; 1435 } 1436 1437 @Override getAdnRecordsSize(int efid)1438 public int[] getAdnRecordsSize(int efid) { 1439 return getAdnRecordsSizeForSubscriber(mDefaultSubscriptionId, efid); 1440 } 1441 1442 @Override getAdnRecordsSizeForSubscriber(int subId, int efid)1443 public int[] getAdnRecordsSizeForSubscriber(int subId, int efid) { 1444 Pair<Integer, Integer> key = Pair.create(subId, efid); 1445 Integer recordSize = mRecordSizes.get(key); 1446 if (recordSize == null) { 1447 return new int[]{0, 0, 0}; 1448 } 1449 int count = mRecords.get(key).length; 1450 return new int[]{recordSize, recordSize * count, count}; 1451 } 1452 1453 @Override getAdnRecordsCapacityForSubscriber(int subId)1454 public AdnCapacity getAdnRecordsCapacityForSubscriber(int subId) { 1455 return new AdnCapacity(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); 1456 } 1457 } 1458 1459 /** 1460 * Implementation of SimPhonebookProvider that allows test-doubles to be injected. 1461 * 1462 * <p>The ProviderTestRule doesn't seem to allow a better way to do this since it just 1463 * invokes the constructor. 1464 */ 1465 public static class TestableSimPhonebookProvider extends SimPhonebookProvider { 1466 setup( ContentResolver resolver, SubscriptionManager subscriptionManager, IIccPhoneBook iccPhoneBook)1467 public static void setup( 1468 ContentResolver resolver, 1469 SubscriptionManager subscriptionManager, 1470 IIccPhoneBook iccPhoneBook) { 1471 setup(resolver, subscriptionManager, iccPhoneBook, uri -> { 1472 }); 1473 } 1474 setup( ContentResolver resolver, SubscriptionManager subscriptionManager, IIccPhoneBook iccPhoneBook, ContentNotifier notifier)1475 public static void setup( 1476 ContentResolver resolver, 1477 SubscriptionManager subscriptionManager, 1478 IIccPhoneBook iccPhoneBook, 1479 ContentNotifier notifier) { 1480 TestableSimPhonebookProvider provider = 1481 (TestableSimPhonebookProvider) Objects.requireNonNull( 1482 resolver.acquireContentProviderClient( 1483 SimPhonebookContract.AUTHORITY)) 1484 .getLocalContentProvider(); 1485 InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> 1486 provider.onCreate(subscriptionManager, () -> iccPhoneBook, notifier)); 1487 } 1488 1489 @Override onCreate()1490 public boolean onCreate() { 1491 // We stub super.onCreate because it initializes services which causes an 1492 // IllegalArgumentException because of the context used for the test. 1493 return true; 1494 } 1495 } 1496 } 1497