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.dialer.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.common.test.FragmentTestActivity; 41 import com.android.dialer.CallDetailActivity; 42 import com.android.dialer.R; 43 44 import java.util.Date; 45 import java.util.Formatter; 46 import java.util.HashMap; 47 import java.util.Random; 48 49 /** 50 * Tests for the contact call list activity. 51 * 52 * Running all tests: 53 * 54 * runtest contacts 55 * or 56 * adb shell am instrument \ 57 * -w com.android.contacts.tests/android.test.InstrumentationTestRunner 58 */ 59 @LargeTest 60 public class CallLogFragmentTest extends ActivityInstrumentationTestCase2<FragmentTestActivity> { 61 private static final int RAND_DURATION = -1; 62 private static final long NOW = -1L; 63 64 /** A test value for the URI of a contact. */ 65 private static final Uri TEST_LOOKUP_URI = Uri.parse("content://contacts/2"); 66 /** A test value for the country ISO of the phone number in the call log. */ 67 private static final String TEST_COUNTRY_ISO = "US"; 68 /** A phone number to be used in tests. */ 69 private static final String TEST_NUMBER = "12125551000"; 70 /** The formatted version of {@link #TEST_NUMBER}. */ 71 private static final String TEST_FORMATTED_NUMBER = "1 212-555-1000"; 72 73 /** The activity in which we are hosting the fragment. */ 74 private FragmentTestActivity mActivity; 75 private CallLogFragment mFragment; 76 private FrameLayout mParentView; 77 /** 78 * The adapter used by the fragment to build the rows in the call log. We use it with our own in 79 * memory database. 80 */ 81 private CallLogAdapter mAdapter; 82 private String mVoicemail; 83 84 // In memory array to hold the rows corresponding to the 'calls' table. 85 private MatrixCursor mCursor; 86 private int mIndex; // Of the next row. 87 88 private Random mRnd; 89 90 // References to the icons bitmaps used to build the list are stored in a 91 // map mIcons. The keys to retrieve the icons are: 92 // Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE and Calls.MISSED_TYPE. 93 private HashMap<Integer, Bitmap> mCallTypeIcons; 94 95 // An item in the call list. All the methods performing checks use it. 96 private CallLogListItemViews mItem; 97 // The list of views representing the data in the DB. View are in 98 // reverse order compare to the DB. 99 private View[] mList; 100 101 public CallLogFragmentTest() { 102 super("com.android.dialer", FragmentTestActivity.class); 103 mIndex = 1; 104 mRnd = new Random(); 105 } 106 107 @Override 108 public void setUp() { 109 mActivity = getActivity(); 110 // Needed by the CallLogFragment. 111 mActivity.setTheme(R.style.DialtactsTheme); 112 113 // Create the fragment and load it into the activity. 114 mFragment = new CallLogFragment(); 115 FragmentManager fragmentManager = mActivity.getFragmentManager(); 116 FragmentTransaction transaction = fragmentManager.beginTransaction(); 117 transaction.add(FragmentTestActivity.LAYOUT_ID, mFragment); 118 transaction.commit(); 119 // Wait for the fragment to be loaded. 120 getInstrumentation().waitForIdleSync(); 121 122 mVoicemail = TelephonyManager.getDefault().getVoiceMailNumber(); 123 mAdapter = mFragment.getAdapter(); 124 // Do not process requests for details during tests. This would start a background thread, 125 // which makes the tests flaky. 126 mAdapter.disableRequestProcessingForTest(); 127 mAdapter.stopRequestProcessing(); 128 mParentView = new FrameLayout(mActivity); 129 mCursor = new MatrixCursor(CallLogQuery._PROJECTION); 130 buildIconMap(); 131 } 132 133 /** 134 * Checks that the call icon is not visible for private and 135 * unknown numbers. 136 * Use 2 passes, one where new views are created and one where 137 * half of the total views are updated and the other half created. 138 */ 139 @MediumTest 140 public void testCallViewIsNotVisibleForPrivateAndUnknownNumbers() { 141 final int SIZE = 100; 142 mList = new View[SIZE]; 143 144 // Insert the first batch of entries. 145 mCursor.moveToFirst(); 146 insertRandomEntries(SIZE / 2); 147 int startOfSecondBatch = mCursor.getPosition(); 148 149 buildViewListFromDb(); 150 checkCallStatus(); 151 152 // Append the rest of the entries. We keep the first set of 153 // views around so they get updated and not built from 154 // scratch, this exposes some bugs that are not there when the 155 // call log is launched for the 1st time but show up when the 156 // call log gets updated afterwards. 157 mCursor.move(startOfSecondBatch); 158 insertRandomEntries(SIZE / 2); 159 160 buildViewListFromDb(); 161 checkCallStatus(); 162 } 163 164 @MediumTest 165 public void testCallAndGroupViews_GroupView() { 166 mCursor.moveToFirst(); 167 insertPrivate(NOW, 0); 168 insertPrivate(NOW, 0); 169 insertPrivate(NOW, 0); 170 View view = mAdapter.newGroupView(getActivity(), mParentView); 171 mAdapter.bindGroupView(view, getActivity(), mCursor, 3, false); 172 assertNotNull(view.findViewById(R.id.secondary_action_icon)); 173 } 174 175 @MediumTest 176 public void testCallAndGroupViews_StandAloneView() { 177 mCursor.moveToFirst(); 178 insertPrivate(NOW, 0); 179 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 180 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 181 assertNotNull(view.findViewById(R.id.secondary_action_icon)); 182 } 183 184 @MediumTest 185 public void testCallAndGroupViews_ChildView() { 186 mCursor.moveToFirst(); 187 insertPrivate(NOW, 0); 188 View view = mAdapter.newChildView(getActivity(), mParentView); 189 mAdapter.bindChildView(view, getActivity(), mCursor); 190 assertNotNull(view.findViewById(R.id.secondary_action_icon)); 191 } 192 193 @MediumTest 194 public void testBindView_NumberOnlyNoCache() { 195 mCursor.moveToFirst(); 196 insert(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE); 197 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 198 mAdapter.bindStandAloneView(view, getActivity(), mCursor); 199 200 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 201 assertNameIs(views, TEST_NUMBER); 202 } 203 204 @MediumTest 205 public void testBindView_NumberOnlyDbCachedFormattedNumber() { 206 mCursor.moveToFirst(); 207 Object[] values = getValuesToInsert(TEST_NUMBER, 208 Calls.PRESENTATION_ALLOWED, 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 assertLabel(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 assertLabel(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 assertLabel(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 assertLabel(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 assertLabel(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, Calls.PRESENTATION_ALLOWED, 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, Calls.PRESENTATION_ALLOWED, 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, Calls.PRESENTATION_ALLOWED, 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 int presentation = getPhoneNumberPresentationForListEntry(i); 367 if (presentation == Calls.PRESENTATION_RESTRICTED || 368 presentation == Calls.PRESENTATION_UNKNOWN) { 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.dialer"); 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 presentation associated with the given entry in {{@link #mList}. */ 426 private int getPhoneNumberPresentationForListEntry(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.getInt(CallLogQuery.NUMBER_PRESENTATION); 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. 462 * @param date In millisec since epoch. Use NOW to use the current time. 463 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 464 * @param type Either Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE. 465 * @param cachedName the name of the contact with this number 466 * @param cachedNumberType the type of the number, from the contact with this number 467 * @param cachedNumberLabel the label of the number, from the contact with this number 468 */ 469 private void insertWithCachedValues(String number, long date, int duration, int type, 470 String cachedName, int cachedNumberType, String cachedNumberLabel) { 471 insert(number, Calls.PRESENTATION_ALLOWED, date, duration, type); 472 ContactInfo contactInfo = new ContactInfo(); 473 contactInfo.lookupUri = TEST_LOOKUP_URI; 474 contactInfo.name = cachedName; 475 contactInfo.type = cachedNumberType; 476 contactInfo.label = cachedNumberLabel; 477 String formattedNumber = PhoneNumberUtils.formatNumber(number, TEST_COUNTRY_ISO); 478 if (formattedNumber == null) { 479 formattedNumber = number; 480 } 481 contactInfo.formattedNumber = formattedNumber; 482 contactInfo.normalizedNumber = number; 483 contactInfo.photoId = 0; 484 mAdapter.injectContactInfoForTest(number, TEST_COUNTRY_ISO, contactInfo); 485 } 486 487 /** 488 * Insert a new call entry in the test DB. 489 * @param number The phone number. 490 * @param presentation Number representing display rules for "allowed", 491 * "payphone", "restricted", or "unknown". 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, int presentation, long date, int duration, int type) { 497 insertValues(getValuesToInsert(number, presentation, 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. 510 * @param presentation Number representing display rules for "allowed", 511 * "payphone", "restricted", or "unknown". 512 * @param date In millisec since epoch. Use NOW to use the current time. 513 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 514 * @param type Either Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE. 515 */ 516 private Object[] getValuesToInsert(String number, int presentation, 517 long date, int duration, int type) { 518 Object[] values = CallLogQueryTestUtils.createTestValues(); 519 values[CallLogQuery.ID] = mIndex; 520 values[CallLogQuery.NUMBER] = number; 521 values[CallLogQuery.NUMBER_PRESENTATION] = presentation; 522 values[CallLogQuery.DATE] = date == NOW ? new Date().getTime() : date; 523 values[CallLogQuery.DURATION] = duration < 0 ? mRnd.nextInt(10 * 60) : duration; 524 if (mVoicemail != null && mVoicemail.equals(number)) { 525 assertEquals(Calls.OUTGOING_TYPE, type); 526 } 527 values[CallLogQuery.CALL_TYPE] = type; 528 values[CallLogQuery.COUNTRY_ISO] = TEST_COUNTRY_ISO; 529 return values; 530 } 531 532 /** 533 * Insert a new voicemail entry in the test DB. 534 * @param number The phone number. 535 * @param presentation Number representing display rules for "allowed", 536 * "payphone", "restricted", or "unknown". 537 * @param date In millisec since epoch. Use NOW to use the current time. 538 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 539 */ 540 private void insertVoicemail(String number, int presentation, long date, int duration) { 541 Object[] values = getValuesToInsert(number, presentation, date, duration, Calls.VOICEMAIL_TYPE); 542 // Must have the same index as the row. 543 values[CallLogQuery.VOICEMAIL_URI] = 544 ContentUris.withAppendedId(VoicemailContract.Voicemails.CONTENT_URI, mIndex); 545 insertValues(values); 546 } 547 548 /** 549 * Insert a new private call entry in the test DB. 550 * @param date In millisec since epoch. Use NOW to use the current time. 551 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 552 */ 553 private void insertPrivate(long date, int duration) { 554 insert("", Calls.PRESENTATION_RESTRICTED, date, duration, Calls.INCOMING_TYPE); 555 } 556 557 /** 558 * Insert a new unknown call entry in the test DB. 559 * @param date In millisec since epoch. Use NOW to use the current time. 560 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 561 */ 562 private void insertUnknown(long date, int duration) { 563 insert("", Calls.PRESENTATION_UNKNOWN, date, duration, Calls.INCOMING_TYPE); 564 } 565 566 /** 567 * Insert a new call to voicemail entry in the test DB. 568 * @param date In millisec since epoch. Use NOW to use the current time. 569 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 570 */ 571 private void insertCalltoVoicemail(long date, int duration) { 572 // mVoicemail may be null 573 if (mVoicemail != null) { 574 insert(mVoicemail, Calls.PRESENTATION_ALLOWED, date, duration, Calls.OUTGOING_TYPE); 575 } 576 } 577 578 /** 579 * Insert a range [start, end) of random numbers in the DB. For 580 * each row, there is a 1/10 probability that the number will be 581 * marked as PRIVATE or UNKNOWN or VOICEMAIL. For regular numbers, a number is 582 * inserted, its last 4 digits will be the number of the iteration 583 * in the range. 584 * @param start Of the range. 585 * @param end Of the range (excluded). 586 * @return An array with 2 booleans [0 = private number, 1 = 587 * unknown number, 2 = voicemail] to indicate if at least one 588 * private or unknown or voicemail number has been inserted. Since 589 * the numbers are random some tests may want to enforce the 590 * insertion of such numbers. 591 */ 592 // TODO: Should insert numbers with contact entries too. 593 private boolean[] insertRandomRange(int start, int end) { 594 boolean[] privateOrUnknownOrVm = new boolean[] {false, false, false}; 595 596 for (int i = start; i < end; i++ ) { 597 int type = mRnd.nextInt(10); 598 599 if (0 == type) { 600 insertPrivate(NOW, RAND_DURATION); 601 privateOrUnknownOrVm[0] = true; 602 } else if (1 == type) { 603 insertUnknown(NOW, RAND_DURATION); 604 privateOrUnknownOrVm[1] = true; 605 } else if (2 == type) { 606 insertCalltoVoicemail(NOW, RAND_DURATION); 607 privateOrUnknownOrVm[2] = true; 608 } else { 609 int inout = mRnd.nextBoolean() ? Calls.OUTGOING_TYPE : Calls.INCOMING_TYPE; 610 String number = new Formatter().format("1800123%04d", i).toString(); 611 insert(number, Calls.PRESENTATION_ALLOWED, NOW, RAND_DURATION, inout); 612 } 613 } 614 return privateOrUnknownOrVm; 615 } 616 617 /** Asserts that the name text view is shown and contains the given text. */ 618 private void assertNameIs(CallLogListItemViews views, String name) { 619 assertEquals(View.VISIBLE, views.phoneCallDetailsViews.nameView.getVisibility()); 620 assertEquals(name, views.phoneCallDetailsViews.nameView.getText()); 621 } 622 623 /** Asserts that the label text view contains the given text. */ 624 private void assertLabel(CallLogListItemViews views, CharSequence number, 625 CharSequence label) { 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