1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.contacts.calllog; 18 19 import android.app.FragmentManager; 20 import android.app.FragmentTransaction; 21 import android.content.ComponentName; 22 import android.content.ContentUris; 23 import android.content.Intent; 24 import android.content.res.Resources; 25 import android.database.MatrixCursor; 26 import android.graphics.Bitmap; 27 import android.graphics.drawable.BitmapDrawable; 28 import android.net.Uri; 29 import android.provider.CallLog.Calls; 30 import android.provider.ContactsContract.CommonDataKinds.Phone; 31 import android.provider.VoicemailContract; 32 import android.telephony.PhoneNumberUtils; 33 import android.telephony.TelephonyManager; 34 import android.test.ActivityInstrumentationTestCase2; 35 import android.test.suitebuilder.annotation.LargeTest; 36 import android.test.suitebuilder.annotation.MediumTest; 37 import android.view.View; 38 import android.widget.FrameLayout; 39 40 import com.android.contacts.CallDetailActivity; 41 import com.android.contacts.R; 42 import com.android.contacts.test.FragmentTestActivity; 43 import com.android.internal.telephony.CallerInfo; 44 45 import java.util.Date; 46 import java.util.Formatter; 47 import java.util.HashMap; 48 import java.util.Random; 49 50 /** 51 * Tests for the contact call list activity. 52 * 53 * Running all tests: 54 * 55 * runtest contacts 56 * or 57 * adb shell am instrument \ 58 * -w com.android.contacts.tests/android.test.InstrumentationTestRunner 59 */ 60 @LargeTest 61 public class CallLogFragmentTest extends ActivityInstrumentationTestCase2<FragmentTestActivity> { 62 private static final int RAND_DURATION = -1; 63 private static final long NOW = -1L; 64 65 /** A test value for the URI of a contact. */ 66 private static final Uri TEST_LOOKUP_URI = Uri.parse("content://contacts/2"); 67 /** A test value for the country ISO of the phone number in the call log. */ 68 private static final String TEST_COUNTRY_ISO = "US"; 69 /** A phone number to be used in tests. */ 70 private static final String TEST_NUMBER = "12125551000"; 71 /** The formatted version of {@link #TEST_NUMBER}. */ 72 private static final String TEST_FORMATTED_NUMBER = "1 212-555-1000"; 73 74 /** The activity in which we are hosting the fragment. */ 75 private FragmentTestActivity mActivity; 76 private CallLogFragment mFragment; 77 private FrameLayout mParentView; 78 /** 79 * The adapter used by the fragment to build the rows in the call log. We use it with our own in 80 * memory database. 81 */ 82 private CallLogAdapter mAdapter; 83 private String mVoicemail; 84 85 // In memory array to hold the rows corresponding to the 'calls' table. 86 private MatrixCursor mCursor; 87 private int mIndex; // Of the next row. 88 89 private Random mRnd; 90 91 // References to the icons bitmaps used to build the list are stored in a 92 // map mIcons. The keys to retrieve the icons are: 93 // Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE and Calls.MISSED_TYPE. 94 private HashMap<Integer, Bitmap> mCallTypeIcons; 95 96 // An item in the call list. All the methods performing checks use it. 97 private CallLogListItemViews mItem; 98 // The list of views representing the data in the DB. View are in 99 // reverse order compare to the DB. 100 private View[] mList; 101 CallLogFragmentTest()102 public CallLogFragmentTest() { 103 super("com.android.contacts", FragmentTestActivity.class); 104 mIndex = 1; 105 mRnd = new Random(); 106 } 107 108 @Override setUp()109 public void setUp() { 110 mActivity = getActivity(); 111 // Needed by the CallLogFragment. 112 mActivity.setTheme(R.style.DialtactsTheme); 113 114 // Create the fragment and load it into the activity. 115 mFragment = new CallLogFragment(); 116 FragmentManager fragmentManager = mActivity.getFragmentManager(); 117 FragmentTransaction transaction = fragmentManager.beginTransaction(); 118 transaction.add(R.id.fragment, mFragment); 119 transaction.commit(); 120 // Wait for the fragment to be loaded. 121 getInstrumentation().waitForIdleSync(); 122 123 mVoicemail = TelephonyManager.getDefault().getVoiceMailNumber(); 124 mAdapter = mFragment.getAdapter(); 125 // Do not process requests for details during tests. This would start a background thread, 126 // which makes the tests flaky. 127 mAdapter.disableRequestProcessingForTest(); 128 mAdapter.stopRequestProcessing(); 129 mParentView = new FrameLayout(mActivity); 130 mCursor = new MatrixCursor(CallLogQuery.EXTENDED_PROJECTION); 131 buildIconMap(); 132 } 133 134 /** 135 * Checks that the call icon is not visible for private and 136 * unknown numbers. 137 * Use 2 passes, one where new views are created and one where 138 * half of the total views are updated and the other half created. 139 */ 140 @MediumTest testCallViewIsNotVisibleForPrivateAndUnknownNumbers()141 public void testCallViewIsNotVisibleForPrivateAndUnknownNumbers() { 142 final int SIZE = 100; 143 mList = new View[SIZE]; 144 145 // Insert the first batch of entries. 146 mCursor.moveToFirst(); 147 insertRandomEntries(SIZE / 2); 148 int startOfSecondBatch = mCursor.getPosition(); 149 150 buildViewListFromDb(); 151 checkCallStatus(); 152 153 // Append the rest of the entries. We keep the first set of 154 // views around so they get updated and not built from 155 // scratch, this exposes some bugs that are not there when the 156 // call log is launched for the 1st time but show up when the 157 // call log gets updated afterwards. 158 mCursor.move(startOfSecondBatch); 159 insertRandomEntries(SIZE / 2); 160 161 buildViewListFromDb(); 162 checkCallStatus(); 163 } 164 165 @MediumTest testCallAndGroupViews_GroupView()166 public void testCallAndGroupViews_GroupView() { 167 mCursor.moveToFirst(); 168 insert(CallerInfo.PRIVATE_NUMBER, NOW, 0, Calls.INCOMING_TYPE); 169 insert(CallerInfo.PRIVATE_NUMBER, NOW, 0, Calls.INCOMING_TYPE); 170 insert(CallerInfo.PRIVATE_NUMBER, NOW, 0, Calls.INCOMING_TYPE); 171 View view = mAdapter.newGroupView(getActivity(), mParentView); 172 mAdapter.bindGroupView(view, getActivity(), mCursor, 3, false); 173 assertNotNull(view.findViewById(R.id.secondary_action_icon)); 174 } 175 176 @MediumTest testCallAndGroupViews_StandAloneView()177 public void testCallAndGroupViews_StandAloneView() { 178 mCursor.moveToFirst(); 179 insert(CallerInfo.PRIVATE_NUMBER, NOW, 0, Calls.INCOMING_TYPE); 180 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 181 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 182 assertNotNull(view.findViewById(R.id.secondary_action_icon)); 183 } 184 185 @MediumTest testCallAndGroupViews_ChildView()186 public void testCallAndGroupViews_ChildView() { 187 mCursor.moveToFirst(); 188 insert(CallerInfo.PRIVATE_NUMBER, NOW, 0, Calls.INCOMING_TYPE); 189 View view = mAdapter.newChildView(getActivity(), mParentView); 190 mAdapter.bindChildView(view, getActivity(), mCursor); 191 assertNotNull(view.findViewById(R.id.secondary_action_icon)); 192 } 193 194 @MediumTest testBindView_NumberOnlyNoCache()195 public void testBindView_NumberOnlyNoCache() { 196 mCursor.moveToFirst(); 197 insert(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE); 198 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 199 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 200 201 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 202 assertNameIs(views, TEST_NUMBER); 203 } 204 205 @MediumTest testBindView_NumberOnlyDbCachedFormattedNumber()206 public void testBindView_NumberOnlyDbCachedFormattedNumber() { 207 mCursor.moveToFirst(); 208 Object[] values = getValuesToInsert(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE); 209 values[CallLogQuery.CACHED_FORMATTED_NUMBER] = TEST_FORMATTED_NUMBER; 210 insertValues(values); 211 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 212 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 213 214 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 215 assertNameIs(views, TEST_FORMATTED_NUMBER); 216 } 217 218 @MediumTest testBindView_WithCachedName()219 public void testBindView_WithCachedName() { 220 mCursor.moveToFirst(); 221 insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE, 222 "John Doe", Phone.TYPE_HOME, ""); 223 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 224 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 225 226 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 227 assertNameIs(views, "John Doe"); 228 assertNumberAndLabelAre(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_HOME)); 229 } 230 231 @MediumTest testBindView_UriNumber()232 public void testBindView_UriNumber() { 233 mCursor.moveToFirst(); 234 insertWithCachedValues("sip:johndoe@gmail.com", NOW, 0, Calls.INCOMING_TYPE, 235 "John Doe", Phone.TYPE_HOME, ""); 236 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 237 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 238 239 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 240 assertNameIs(views, "John Doe"); 241 assertNumberAndLabelAre(views, "sip:johndoe@gmail.com", null); 242 } 243 244 @MediumTest testBindView_HomeLabel()245 public void testBindView_HomeLabel() { 246 mCursor.moveToFirst(); 247 insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE, 248 "John Doe", Phone.TYPE_HOME, ""); 249 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 250 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 251 252 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 253 assertNameIs(views, "John Doe"); 254 assertNumberAndLabelAre(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_HOME)); 255 } 256 257 @MediumTest testBindView_WorkLabel()258 public void testBindView_WorkLabel() { 259 mCursor.moveToFirst(); 260 insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE, 261 "John Doe", Phone.TYPE_WORK, ""); 262 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 263 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 264 265 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 266 assertNameIs(views, "John Doe"); 267 assertNumberAndLabelAre(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_WORK)); 268 } 269 270 @MediumTest testBindView_CustomLabel()271 public void testBindView_CustomLabel() { 272 mCursor.moveToFirst(); 273 String numberLabel = "My label"; 274 insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE, 275 "John Doe", Phone.TYPE_CUSTOM, numberLabel); 276 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 277 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 278 279 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 280 assertNameIs(views, "John Doe"); 281 assertNumberAndLabelAre(views, TEST_FORMATTED_NUMBER, numberLabel); 282 } 283 284 @MediumTest testBindView_WithQuickContactBadge()285 public void testBindView_WithQuickContactBadge() { 286 mCursor.moveToFirst(); 287 insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE, 288 "John Doe", Phone.TYPE_HOME, ""); 289 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 290 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 291 292 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 293 assertTrue(views.quickContactView.isEnabled()); 294 } 295 296 @MediumTest testBindView_WithoutQuickContactBadge()297 public void testBindView_WithoutQuickContactBadge() { 298 mCursor.moveToFirst(); 299 insert(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE); 300 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 301 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 302 303 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 304 assertFalse(views.quickContactView.isEnabled()); 305 } 306 307 @MediumTest testBindView_CallButton()308 public void testBindView_CallButton() { 309 mCursor.moveToFirst(); 310 insert(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE); 311 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 312 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 313 314 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 315 IntentProvider intentProvider = (IntentProvider) views.secondaryActionView.getTag(); 316 Intent intent = intentProvider.getIntent(mActivity); 317 // Starts a call. 318 assertEquals(Intent.ACTION_CALL_PRIVILEGED, intent.getAction()); 319 // To the entry's number. 320 assertEquals(Uri.parse("tel:" + TEST_NUMBER), intent.getData()); 321 } 322 323 @MediumTest testBindView_PlayButton()324 public void testBindView_PlayButton() { 325 mCursor.moveToFirst(); 326 insertVoicemail(TEST_NUMBER, NOW, 0); 327 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 328 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 329 330 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 331 IntentProvider intentProvider = (IntentProvider) views.secondaryActionView.getTag(); 332 Intent intent = intentProvider.getIntent(mActivity); 333 // Starts the call detail activity. 334 assertEquals(new ComponentName(mActivity, CallDetailActivity.class), 335 intent.getComponent()); 336 // With the given entry. 337 assertEquals(ContentUris.withAppendedId(Calls.CONTENT_URI_WITH_VOICEMAIL, 1), 338 intent.getData()); 339 // With the URI of the voicemail. 340 assertEquals( 341 ContentUris.withAppendedId(VoicemailContract.Voicemails.CONTENT_URI, 1), 342 intent.getParcelableExtra(CallDetailActivity.EXTRA_VOICEMAIL_URI)); 343 // And starts playback. 344 assertTrue( 345 intent.getBooleanExtra(CallDetailActivity.EXTRA_VOICEMAIL_START_PLAYBACK, false)); 346 } 347 348 /** Returns the label associated with a given phone type. */ getTypeLabel(int phoneType)349 private CharSequence getTypeLabel(int phoneType) { 350 return Phone.getTypeLabel(getActivity().getResources(), phoneType, ""); 351 } 352 353 // 354 // HELPERS to check conditions on the DB/views 355 // 356 /** 357 * Go over all the views in the list and check that the Call 358 * icon's visibility matches the nature of the number. 359 */ checkCallStatus()360 private void checkCallStatus() { 361 for (int i = 0; i < mList.length; i++) { 362 if (null == mList[i]) { 363 break; 364 } 365 mItem = (CallLogListItemViews) mList[i].getTag(); 366 String number = getPhoneNumberForListEntry(i); 367 if (CallerInfo.PRIVATE_NUMBER.equals(number) || 368 CallerInfo.UNKNOWN_NUMBER.equals(number)) { 369 assertFalse(View.VISIBLE == mItem.secondaryActionView.getVisibility()); 370 } else { 371 assertEquals(View.VISIBLE, mItem.secondaryActionView.getVisibility()); 372 } 373 } 374 } 375 376 377 // 378 // HELPERS to setup the tests. 379 // 380 381 /** 382 * Get the Bitmap from the icons in the contacts package. 383 */ getBitmap(String resName)384 private Bitmap getBitmap(String resName) { 385 Resources r = mActivity.getResources(); 386 int resid = r.getIdentifier(resName, "drawable", "com.android.contacts"); 387 BitmapDrawable d = (BitmapDrawable) r.getDrawable(resid); 388 assertNotNull(d); 389 return d.getBitmap(); 390 } 391 392 /** 393 * Fetch all the icons we need in tests from the contacts app and store them in a map. 394 */ buildIconMap()395 private void buildIconMap() { 396 mCallTypeIcons = new HashMap<Integer, Bitmap>(3); 397 398 mCallTypeIcons.put(Calls.INCOMING_TYPE, getBitmap("ic_call_incoming_holo_dark")); 399 mCallTypeIcons.put(Calls.MISSED_TYPE, getBitmap("ic_call_missed_holo_dark")); 400 mCallTypeIcons.put(Calls.OUTGOING_TYPE, getBitmap("ic_call_outgoing_holo_dark")); 401 } 402 403 // 404 // HELPERS to build/update the call entries (views) from the DB. 405 // 406 407 /** 408 * Read the DB and foreach call either update the existing view if 409 * one exists already otherwise create one. 410 * The list is build from a DESC view of the DB (last inserted entry is first). 411 */ buildViewListFromDb()412 private void buildViewListFromDb() { 413 int i = 0; 414 mCursor.moveToLast(); 415 while(!mCursor.isBeforeFirst()) { 416 if (null == mList[i]) { 417 mList[i] = mAdapter.newStandAloneView(mActivity, mParentView); 418 } 419 mAdapter.bindStandAloneView(mList[i], mActivity, mCursor); 420 mCursor.moveToPrevious(); 421 i++; 422 } 423 } 424 425 /** Returns the number associated with the given entry in {{@link #mList}. */ getPhoneNumberForListEntry(int index)426 private String getPhoneNumberForListEntry(int index) { 427 // The entries are added backward, so count from the end of the cursor. 428 mCursor.moveToPosition(mCursor.getCount() - index - 1); 429 return mCursor.getString(CallLogQuery.NUMBER); 430 } 431 432 // 433 // HELPERS to insert numbers in the call log DB. 434 // 435 436 /** 437 * Insert a certain number of random numbers in the DB. Makes sure 438 * there is at least one private and one unknown number in the DB. 439 * @param num Of entries to be inserted. 440 */ insertRandomEntries(int num)441 private void insertRandomEntries(int num) { 442 if (num < 10) { 443 throw new IllegalArgumentException("num should be >= 10"); 444 } 445 boolean privateOrUnknownOrVm[]; 446 privateOrUnknownOrVm = insertRandomRange(0, num - 2); 447 448 if (privateOrUnknownOrVm[0] && privateOrUnknownOrVm[1]) { 449 insertRandomRange(num - 2, num); 450 } else { 451 insertPrivate(NOW, RAND_DURATION); 452 insertUnknown(NOW, RAND_DURATION); 453 } 454 } 455 456 /** 457 * Insert a new call entry in the test DB. 458 * 459 * It includes the values for the cached contact associated with the number. 460 * 461 * @param number The phone number. For unknown and private numbers, 462 * use CallerInfo.UNKNOWN_NUMBER or CallerInfo.PRIVATE_NUMBER. 463 * @param date In millisec since epoch. Use NOW to use the current time. 464 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 465 * @param type Either Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE. 466 * @param cachedName the name of the contact with this number 467 * @param cachedNumberType the type of the number, from the contact with this number 468 * @param cachedNumberLabel the label of the number, from the contact with this number 469 */ insertWithCachedValues(String number, long date, int duration, int type, String cachedName, int cachedNumberType, String cachedNumberLabel)470 private void insertWithCachedValues(String number, long date, int duration, int type, 471 String cachedName, int cachedNumberType, String cachedNumberLabel) { 472 insert(number, date, duration, type); 473 ContactInfo contactInfo = new ContactInfo(); 474 contactInfo.lookupUri = TEST_LOOKUP_URI; 475 contactInfo.name = cachedName; 476 contactInfo.type = cachedNumberType; 477 contactInfo.label = cachedNumberLabel; 478 String formattedNumber = PhoneNumberUtils.formatNumber(number, TEST_COUNTRY_ISO); 479 if (formattedNumber == null) { 480 formattedNumber = number; 481 } 482 contactInfo.formattedNumber = formattedNumber; 483 contactInfo.normalizedNumber = number; 484 contactInfo.photoId = 0; 485 mAdapter.injectContactInfoForTest(number, TEST_COUNTRY_ISO, contactInfo); 486 } 487 488 /** 489 * Insert a new call entry in the test DB. 490 * @param number The phone number. For unknown and private numbers, 491 * use CallerInfo.UNKNOWN_NUMBER or CallerInfo.PRIVATE_NUMBER. 492 * @param date In millisec since epoch. Use NOW to use the current time. 493 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 494 * @param type Either Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE. 495 */ insert(String number, long date, int duration, int type)496 private void insert(String number, long date, int duration, int type) { 497 insertValues(getValuesToInsert(number, date, duration, type)); 498 } 499 500 /** Inserts the given values in the cursor. */ insertValues(Object[] values)501 private void insertValues(Object[] values) { 502 mCursor.addRow(values); 503 ++mIndex; 504 } 505 506 /** 507 * Returns the values for a new call entry. 508 * 509 * @param number The phone number. For unknown and private numbers, 510 * use CallerInfo.UNKNOWN_NUMBER or CallerInfo.PRIVATE_NUMBER. 511 * @param date In millisec since epoch. Use NOW to use the current time. 512 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 513 * @param type Either Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE. 514 */ getValuesToInsert(String number, long date, int duration, int type)515 private Object[] getValuesToInsert(String number, long date, int duration, int type) { 516 Object[] values = CallLogQueryTestUtils.createTestExtendedValues(); 517 values[CallLogQuery.ID] = mIndex; 518 values[CallLogQuery.NUMBER] = number; 519 values[CallLogQuery.DATE] = date == NOW ? new Date().getTime() : date; 520 values[CallLogQuery.DURATION] = duration < 0 ? mRnd.nextInt(10 * 60) : duration; 521 if (mVoicemail != null && mVoicemail.equals(number)) { 522 assertEquals(Calls.OUTGOING_TYPE, type); 523 } 524 values[CallLogQuery.CALL_TYPE] = type; 525 values[CallLogQuery.COUNTRY_ISO] = TEST_COUNTRY_ISO; 526 values[CallLogQuery.SECTION] = CallLogQuery.SECTION_OLD_ITEM; 527 return values; 528 } 529 530 /** 531 * Insert a new voicemail entry in the test DB. 532 * @param number The phone number. For unknown and private numbers, 533 * use CallerInfo.UNKNOWN_NUMBER or CallerInfo.PRIVATE_NUMBER. 534 * @param date In millisec since epoch. Use NOW to use the current time. 535 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 536 */ 537 private void insertVoicemail(String number, long date, int duration) { 538 Object[] values = getValuesToInsert(number, date, duration, Calls.VOICEMAIL_TYPE); 539 // Must have the same index as the row. 540 values[CallLogQuery.VOICEMAIL_URI] = 541 ContentUris.withAppendedId(VoicemailContract.Voicemails.CONTENT_URI, mIndex); 542 insertValues(values); 543 } 544 545 /** 546 * Insert a new private call entry in the test DB. 547 * @param date In millisec since epoch. Use NOW to use the current time. 548 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 549 */ 550 private void insertPrivate(long date, int duration) { 551 insert(CallerInfo.PRIVATE_NUMBER, date, duration, Calls.INCOMING_TYPE); 552 } 553 554 /** 555 * Insert a new unknown call entry in the test DB. 556 * @param date In millisec since epoch. Use NOW to use the current time. 557 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 558 */ 559 private void insertUnknown(long date, int duration) { 560 insert(CallerInfo.UNKNOWN_NUMBER, date, duration, Calls.INCOMING_TYPE); 561 } 562 563 /** 564 * Insert a new call to voicemail entry in the test DB. 565 * @param date In millisec since epoch. Use NOW to use the current time. 566 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 567 */ 568 private void insertCalltoVoicemail(long date, int duration) { 569 // mVoicemail may be null 570 if (mVoicemail != null) { 571 insert(mVoicemail, date, duration, Calls.OUTGOING_TYPE); 572 } 573 } 574 575 /** 576 * Insert a range [start, end) of random numbers in the DB. For 577 * each row, there is a 1/10 probability that the number will be 578 * marked as PRIVATE or UNKNOWN or VOICEMAIL. For regular numbers, a number is 579 * inserted, its last 4 digits will be the number of the iteration 580 * in the range. 581 * @param start Of the range. 582 * @param end Of the range (excluded). 583 * @return An array with 2 booleans [0 = private number, 1 = 584 * unknown number, 2 = voicemail] to indicate if at least one 585 * private or unknown or voicemail number has been inserted. Since 586 * the numbers are random some tests may want to enforce the 587 * insertion of such numbers. 588 */ 589 // TODO: Should insert numbers with contact entries too. 590 private boolean[] insertRandomRange(int start, int end) { 591 boolean[] privateOrUnknownOrVm = new boolean[] {false, false, false}; 592 593 for (int i = start; i < end; i++ ) { 594 int type = mRnd.nextInt(10); 595 596 if (0 == type) { 597 insertPrivate(NOW, RAND_DURATION); 598 privateOrUnknownOrVm[0] = true; 599 } else if (1 == type) { 600 insertUnknown(NOW, RAND_DURATION); 601 privateOrUnknownOrVm[1] = true; 602 } else if (2 == type) { 603 insertCalltoVoicemail(NOW, RAND_DURATION); 604 privateOrUnknownOrVm[2] = true; 605 } else { 606 int inout = mRnd.nextBoolean() ? Calls.OUTGOING_TYPE : Calls.INCOMING_TYPE; 607 String number = new Formatter().format("1800123%04d", i).toString(); 608 insert(number, NOW, RAND_DURATION, inout); 609 } 610 } 611 return privateOrUnknownOrVm; 612 } 613 614 /** Asserts that the name text view is shown and contains the given text. */ 615 private void assertNameIs(CallLogListItemViews views, String name) { 616 assertEquals(View.VISIBLE, views.phoneCallDetailsViews.nameView.getVisibility()); 617 assertEquals(name, views.phoneCallDetailsViews.nameView.getText()); 618 } 619 620 /** Asserts that the number and label text view contains the given text. */ 621 private void assertNumberAndLabelAre(CallLogListItemViews views, CharSequence number, 622 CharSequence label) { 623 assertEquals(View.VISIBLE, views.phoneCallDetailsViews.numberView.getVisibility()); 624 assertEquals(number, views.phoneCallDetailsViews.numberView.getText().toString()); 625 626 assertEquals(label == null ? View.GONE : View.VISIBLE, 627 views.phoneCallDetailsViews.labelView.getVisibility()); 628 if (label != null) { 629 assertEquals(label, views.phoneCallDetailsViews.labelView.getText().toString()); 630 } 631 } 632 } 633