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 com.android.contacts.CallDetailActivity; 20 import com.android.contacts.R; 21 import com.android.contacts.test.FragmentTestActivity; 22 import com.android.internal.telephony.CallerInfo; 23 24 import android.app.FragmentManager; 25 import android.app.FragmentTransaction; 26 import android.content.ComponentName; 27 import android.content.ContentUris; 28 import android.content.Intent; 29 import android.content.res.Resources; 30 import android.database.MatrixCursor; 31 import android.graphics.Bitmap; 32 import android.graphics.drawable.BitmapDrawable; 33 import android.net.Uri; 34 import android.provider.CallLog.Calls; 35 import android.provider.ContactsContract.CommonDataKinds.Phone; 36 import android.provider.VoicemailContract; 37 import android.telephony.PhoneNumberUtils; 38 import android.telephony.TelephonyManager; 39 import android.test.ActivityInstrumentationTestCase2; 40 import android.test.suitebuilder.annotation.LargeTest; 41 import android.test.suitebuilder.annotation.MediumTest; 42 import android.view.View; 43 import android.widget.FrameLayout; 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 102 public CallLogFragmentTest() { 103 super("com.android.contacts", FragmentTestActivity.class); 104 mIndex = 1; 105 mRnd = new Random(); 106 } 107 108 @Override 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 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 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 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 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 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 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 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 232 public void testBindView_UriNumber() { 233 mCursor.moveToFirst(); 234 insertWithCachedValues("sip:johndoe (at) 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 (at) gmail.com", null); 242 } 243 244 @MediumTest 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 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 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 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 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 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 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. */ 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 */ 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 */ 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 */ 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 */ 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}. */ 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 */ 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 */ 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 */ 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. */ 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 */ 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 numberLabel) { 623 assertEquals(View.VISIBLE, views.phoneCallDetailsViews.numberView.getVisibility()); 624 final CharSequence expectedText; 625 if (numberLabel == null) { 626 expectedText = number; 627 } else { 628 expectedText = numberLabel + " " + number; 629 } 630 assertEquals(expectedText, views.phoneCallDetailsViews.numberView.getText().toString()); 631 } 632 } 633