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 17package com.android.dialer.calllog; 18 19import android.app.FragmentManager; 20import android.app.FragmentTransaction; 21import android.content.ComponentName; 22import android.content.ContentUris; 23import android.content.Context; 24import android.content.Intent; 25import android.content.res.Resources; 26import android.database.MatrixCursor; 27import android.graphics.Bitmap; 28import android.graphics.drawable.BitmapDrawable; 29import android.net.Uri; 30import android.provider.CallLog.Calls; 31import android.provider.ContactsContract.CommonDataKinds.Phone; 32import android.provider.VoicemailContract; 33import android.telephony.PhoneNumberUtils; 34import android.telephony.TelephonyManager; 35import android.test.ActivityInstrumentationTestCase2; 36import android.test.suitebuilder.annotation.LargeTest; 37import android.test.suitebuilder.annotation.MediumTest; 38import android.util.Log; 39import android.view.View; 40import android.widget.FrameLayout; 41 42import com.android.contacts.common.test.FragmentTestActivity; 43import com.android.dialer.CallDetailActivity; 44import com.android.dialer.R; 45 46import java.util.Date; 47import java.util.Formatter; 48import java.util.HashMap; 49import java.util.Random; 50 51/** 52 * Tests for the contact call list activity. 53 * 54 * Running all tests: 55 * 56 * runtest contacts 57 * or 58 * adb shell am instrument \ 59 * -w com.android.contacts.tests/android.test.InstrumentationTestRunner 60 */ 61@LargeTest 62public class CallLogFragmentTest extends ActivityInstrumentationTestCase2<FragmentTestActivity> { 63 private static final int RAND_DURATION = -1; 64 private static final long NOW = -1L; 65 66 /** A test value for the URI of a contact. */ 67 private static final Uri TEST_LOOKUP_URI = Uri.parse("content://contacts/2"); 68 /** A test value for the country ISO of the phone number in the call log. */ 69 private static final String TEST_COUNTRY_ISO = "US"; 70 /** A phone number to be used in tests. */ 71 private static final String TEST_NUMBER = "12125551000"; 72 /** The formatted version of {@link #TEST_NUMBER}. */ 73 private static final String TEST_FORMATTED_NUMBER = "1 212-555-1000"; 74 75 private static final String TEST_DEFAULT_CUSTOM_LABEL = "myLabel"; 76 77 /** The activity in which we are hosting the fragment. */ 78 private FragmentTestActivity mActivity; 79 private CallLogFragment mFragment; 80 private FrameLayout mParentView; 81 /** 82 * The adapter used by the fragment to build the rows in the call log. We use it with our own in 83 * memory database. 84 */ 85 private CallLogAdapter mAdapter; 86 private String mVoicemail; 87 88 // In memory array to hold the rows corresponding to the 'calls' table. 89 private MatrixCursor mCursor; 90 private int mIndex; // Of the next row. 91 92 private Random mRnd; 93 94 // An item in the call list. All the methods performing checks use it. 95 private CallLogListItemViews mItem; 96 // The list of views representing the data in the DB. View are in 97 // reverse order compare to the DB. 98 private View[] mList; 99 100 public CallLogFragmentTest() { 101 super(FragmentTestActivity.class); 102 mIndex = 1; 103 mRnd = new Random(); 104 } 105 106 @Override 107 public void setUp() { 108 mActivity = getActivity(); 109 // Needed by the CallLogFragment. 110 mActivity.setTheme(R.style.DialtactsTheme); 111 112 // Create the fragment and load it into the activity. 113 mFragment = new CallLogFragment(); 114 FragmentManager fragmentManager = mActivity.getFragmentManager(); 115 FragmentTransaction transaction = fragmentManager.beginTransaction(); 116 transaction.add(FragmentTestActivity.LAYOUT_ID, mFragment); 117 transaction.commitAllowingStateLoss(); 118 // Wait for the fragment to be loaded. 119 getInstrumentation().waitForIdleSync(); 120 121 final TelephonyManager telephonyManager = 122 (TelephonyManager) mActivity.getSystemService(Context.TELEPHONY_SERVICE); 123 mVoicemail = telephonyManager.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._PROJECTION); 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 } 173 174 @MediumTest 175 public void testCallAndGroupViews_StandAloneView() { 176 mCursor.moveToFirst(); 177 insertPrivate(NOW, 0); 178 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 179 mAdapter.bindViewForTest(view, getActivity(), mCursor); 180 } 181 182 @MediumTest 183 public void testCallAndGroupViews_ChildView() { 184 mCursor.moveToFirst(); 185 insertPrivate(NOW, 0); 186 View view = mAdapter.newChildView(getActivity(), mParentView); 187 mAdapter.bindChildView(view, getActivity(), mCursor); 188 } 189 190 @MediumTest 191 public void testBindView_NumberOnlyNoCache() { 192 mCursor.moveToFirst(); 193 insert(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE); 194 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 195 mAdapter.bindViewForTest(view, getActivity(), mCursor); 196 197 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 198 assertNameIs(views, TEST_NUMBER); 199 } 200 201 @MediumTest 202 public void testBindView_NumberOnlyDbCachedFormattedNumber() { 203 mCursor.moveToFirst(); 204 Object[] values = getValuesToInsert(TEST_NUMBER, 205 Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE); 206 values[CallLogQuery.CACHED_FORMATTED_NUMBER] = TEST_FORMATTED_NUMBER; 207 insertValues(values); 208 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 209 mAdapter.bindViewForTest(view, getActivity(), mCursor); 210 211 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 212 assertNameIs(views, TEST_FORMATTED_NUMBER); 213 } 214 215 @MediumTest 216 public void testBindView_WithCachedName() { 217 mCursor.moveToFirst(); 218 // provide a default custom label instead of an empty string, which corresponds to 219 // {@value com.android.dialer.calllog.ContactInfo#GEOCODE_AS_LABEL} 220 insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE, 221 "John Doe", Phone.TYPE_HOME, TEST_DEFAULT_CUSTOM_LABEL); 222 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 223 mAdapter.bindViewForTest(view, getActivity(), mCursor); 224 225 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 226 assertNameIs(views, "John Doe"); 227 assertLabel(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_HOME)); 228 } 229 230 @MediumTest 231 public void testBindView_UriNumber() { 232 mCursor.moveToFirst(); 233 insertWithCachedValues("sip:johndoe@gmail.com", NOW, 0, Calls.INCOMING_TYPE, 234 "John Doe", Phone.TYPE_HOME, TEST_DEFAULT_CUSTOM_LABEL); 235 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 236 mAdapter.bindViewForTest(view, getActivity(), mCursor); 237 238 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 239 assertNameIs(views, "John Doe"); 240 assertLabel(views, "sip:johndoe@gmail.com", "sip:johndoe@gmail.com"); 241 } 242 243 @MediumTest 244 public void testBindView_HomeLabel() { 245 mCursor.moveToFirst(); 246 // provide a default custom label instead of an empty string, which corresponds to 247 // {@value com.android.dialer.calllog.ContactInfo#GEOCODE_AS_LABEL} 248 insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE, 249 "John Doe", Phone.TYPE_HOME, TEST_DEFAULT_CUSTOM_LABEL); 250 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 251 mAdapter.bindViewForTest(view, getActivity(), mCursor); 252 253 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 254 assertNameIs(views, "John Doe"); 255 assertLabel(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_HOME)); 256 } 257 258 @MediumTest 259 public void testBindView_WorkLabel() { 260 mCursor.moveToFirst(); 261 // provide a default custom label instead of an empty string, which corresponds to 262 // {@link com.android.dialer.calllog.ContactInfo#GEOCODE_AS_LABEL} 263 insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE, 264 "John Doe", Phone.TYPE_WORK, TEST_DEFAULT_CUSTOM_LABEL); 265 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 266 mAdapter.bindViewForTest(view, getActivity(), mCursor); 267 268 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 269 assertNameIs(views, "John Doe"); 270 assertLabel(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_WORK)); 271 } 272 273 @MediumTest 274 public void testBindView_CustomLabel() { 275 mCursor.moveToFirst(); 276 String numberLabel = "My label"; 277 insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE, 278 "John Doe", Phone.TYPE_CUSTOM, numberLabel); 279 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 280 mAdapter.bindViewForTest(view, getActivity(), mCursor); 281 282 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 283 assertNameIs(views, "John Doe"); 284 assertLabel(views, TEST_FORMATTED_NUMBER, numberLabel); 285 } 286 287 @MediumTest 288 public void testBindView_WithQuickContactBadge() { 289 mCursor.moveToFirst(); 290 insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE, 291 "John Doe", Phone.TYPE_HOME, ""); 292 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 293 mAdapter.bindViewForTest(view, getActivity(), mCursor); 294 295 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 296 assertTrue(views.quickContactView.isEnabled()); 297 } 298 299 @MediumTest 300 public void testBindView_WithoutQuickContactBadge() { 301 mCursor.moveToFirst(); 302 insert(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE); 303 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 304 mAdapter.bindViewForTest(view, getActivity(), mCursor); 305 306 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 307 assertFalse(views.quickContactView.isEnabled()); 308 } 309 310 @MediumTest 311 public void testBindView_CallButton() { 312 mCursor.moveToFirst(); 313 insert(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE); 314 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 315 mAdapter.bindViewForTest(view, getActivity(), mCursor); 316 317 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 318 319 // The primaryActionView tag is set in the 320 // {@link com.android.dialer.calllog.CallLogAdapter#bindView} method. If it is possible 321 // to place a call to the phone number, a call intent will have been created for the 322 // primaryActionView. 323 IntentProvider intentProvider = (IntentProvider) views.callBackButtonView.getTag(); 324 Intent intent = intentProvider.getIntent(mActivity); 325 // Starts a call. 326 assertEquals(Intent.ACTION_CALL_PRIVILEGED, intent.getAction()); 327 // To the entry's number. 328 assertEquals(Uri.parse("tel:" + TEST_NUMBER), intent.getData()); 329 } 330 331 @MediumTest 332 public void testBindView_PlayButton() { 333 mCursor.moveToFirst(); 334 insertVoicemail(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0); 335 View view = mAdapter.newStandAloneView(getActivity(), mParentView); 336 mAdapter.bindViewForTest(view, getActivity(), mCursor); 337 338 CallLogListItemViews views = (CallLogListItemViews) view.getTag(); 339 IntentProvider intentProvider = (IntentProvider) views.voicemailButtonView.getTag(); 340 Intent intent = intentProvider.getIntent(mActivity); 341 // Starts the call detail activity. 342 assertEquals(new ComponentName(mActivity, CallDetailActivity.class), 343 intent.getComponent()); 344 // With the given entry. 345 assertEquals(ContentUris.withAppendedId(Calls.CONTENT_URI_WITH_VOICEMAIL, 1), 346 intent.getData()); 347 // With the URI of the voicemail. 348 assertEquals( 349 ContentUris.withAppendedId(VoicemailContract.Voicemails.CONTENT_URI, 1), 350 intent.getParcelableExtra(CallDetailActivity.EXTRA_VOICEMAIL_URI)); 351 // And starts playback. 352 assertTrue( 353 intent.getBooleanExtra(CallDetailActivity.EXTRA_VOICEMAIL_START_PLAYBACK, false)); 354 } 355 356 /** Returns the label associated with a given phone type. */ 357 private CharSequence getTypeLabel(int phoneType) { 358 return Phone.getTypeLabel(getActivity().getResources(), phoneType, ""); 359 } 360 361 // 362 // HELPERS to check conditions on the DB/views 363 // 364 /** 365 * Go over the views in the list and check to ensure that 366 * callable numbers have an associated call intent, where numbers 367 * which are not callable have a null intent. 368 */ 369 private void checkCallStatus() { 370 for (int i = 0; i < mList.length; i++) { 371 if (null == mList[i]) { 372 break; 373 } 374 mItem = (CallLogListItemViews) mList[i].getTag(); 375 int presentation = getPhoneNumberPresentationForListEntry(i); 376 if (presentation == Calls.PRESENTATION_RESTRICTED || 377 presentation == Calls.PRESENTATION_UNKNOWN) { 378 //If number is not callable, the primary action view should have a null tag. 379 assertNull(mItem.callBackButtonView.getTag()); 380 } else { 381 //If the number is callable, the primary action view should have a non-null tag. 382 assertNotNull(mItem.callBackButtonView.getTag()); 383 384 IntentProvider intentProvider = (IntentProvider)mItem.callBackButtonView.getTag(); 385 Intent callIntent = intentProvider.getIntent(mActivity); 386 387 //The intent should be to make the call 388 assertEquals(Intent.ACTION_CALL_PRIVILEGED, callIntent.getAction()); 389 } 390 } 391 } 392 393 394 // 395 // HELPERS to setup the tests. 396 // 397 398 /** 399 * Get the Bitmap from the icons in the contacts package. 400 */ 401 private Bitmap getBitmap(String resName) { 402 Resources r = mActivity.getResources(); 403 int resid = r.getIdentifier(resName, "drawable", 404 getInstrumentation().getTargetContext().getPackageName()); 405 BitmapDrawable d = (BitmapDrawable) r.getDrawable(resid); 406 assertNotNull(d); 407 return d.getBitmap(); 408 } 409 410 // 411 // HELPERS to build/update the call entries (views) from the DB. 412 // 413 414 /** 415 * Read the DB and foreach call either update the existing view if 416 * one exists already otherwise create one. 417 * The list is build from a DESC view of the DB (last inserted entry is first). 418 */ 419 private void buildViewListFromDb() { 420 int i = 0; 421 mCursor.moveToLast(); 422 while(!mCursor.isBeforeFirst()) { 423 if (null == mList[i]) { 424 mList[i] = mAdapter.newStandAloneView(mActivity, mParentView); 425 } 426 mAdapter.bindViewForTest(mList[i], mActivity, mCursor); 427 mCursor.moveToPrevious(); 428 i++; 429 } 430 } 431 432 /** Returns the number presentation associated with the given entry in {{@link #mList}. */ 433 private int getPhoneNumberPresentationForListEntry(int index) { 434 // The entries are added backward, so count from the end of the cursor. 435 mCursor.moveToPosition(mCursor.getCount() - index - 1); 436 return mCursor.getInt(CallLogQuery.NUMBER_PRESENTATION); 437 } 438 439 // 440 // HELPERS to insert numbers in the call log DB. 441 // 442 443 /** 444 * Insert a certain number of random numbers in the DB. Makes sure 445 * there is at least one private and one unknown number in the DB. 446 * @param num Of entries to be inserted. 447 */ 448 private void insertRandomEntries(int num) { 449 if (num < 10) { 450 throw new IllegalArgumentException("num should be >= 10"); 451 } 452 boolean privateOrUnknownOrVm[]; 453 privateOrUnknownOrVm = insertRandomRange(0, num - 2); 454 455 if (privateOrUnknownOrVm[0] && privateOrUnknownOrVm[1]) { 456 insertRandomRange(num - 2, num); 457 } else { 458 insertPrivate(NOW, RAND_DURATION); 459 insertUnknown(NOW, RAND_DURATION); 460 } 461 } 462 463 /** 464 * Insert a new call entry in the test DB. 465 * 466 * It includes the values for the cached contact associated with the number. 467 * 468 * @param number The phone number. 469 * @param date In millisec since epoch. Use NOW to use the current time. 470 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 471 * @param type Either Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE. 472 * @param cachedName the name of the contact with this number 473 * @param cachedNumberType the type of the number, from the contact with this number 474 * @param cachedNumberLabel the label of the number, from the contact with this number 475 */ 476 private void insertWithCachedValues(String number, long date, int duration, int type, 477 String cachedName, int cachedNumberType, String cachedNumberLabel) { 478 insert(number, Calls.PRESENTATION_ALLOWED, date, duration, type); 479 ContactInfo contactInfo = new ContactInfo(); 480 contactInfo.lookupUri = TEST_LOOKUP_URI; 481 contactInfo.name = cachedName; 482 contactInfo.type = cachedNumberType; 483 contactInfo.label = cachedNumberLabel; 484 String formattedNumber = PhoneNumberUtils.formatNumber(number, TEST_COUNTRY_ISO); 485 if (formattedNumber == null) { 486 formattedNumber = number; 487 } 488 contactInfo.formattedNumber = formattedNumber; 489 contactInfo.normalizedNumber = number; 490 contactInfo.photoId = 0; 491 mAdapter.injectContactInfoForTest(number, TEST_COUNTRY_ISO, contactInfo); 492 } 493 494 /** 495 * Insert a new call entry in the test DB. 496 * @param number The phone number. 497 * @param presentation Number representing display rules for "allowed", 498 * "payphone", "restricted", or "unknown". 499 * @param date In millisec since epoch. Use NOW to use the current time. 500 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 501 * @param type Either Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE. 502 */ 503 private void insert(String number, int presentation, long date, int duration, int type) { 504 insertValues(getValuesToInsert(number, presentation, date, duration, type)); 505 } 506 507 /** Inserts the given values in the cursor. */ 508 private void insertValues(Object[] values) { 509 mCursor.addRow(values); 510 ++mIndex; 511 } 512 513 /** 514 * Returns the values for a new call entry. 515 * 516 * @param number The phone number. 517 * @param presentation Number representing display rules for "allowed", 518 * "payphone", "restricted", or "unknown". 519 * @param date In millisec since epoch. Use NOW to use the current time. 520 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 521 * @param type Either Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE. 522 */ 523 private Object[] getValuesToInsert(String number, int presentation, 524 long date, int duration, int type) { 525 Object[] values = CallLogQueryTestUtils.createTestValues(); 526 values[CallLogQuery.ID] = mIndex; 527 values[CallLogQuery.NUMBER] = number; 528 values[CallLogQuery.NUMBER_PRESENTATION] = presentation; 529 values[CallLogQuery.DATE] = date == NOW ? new Date().getTime() : date; 530 values[CallLogQuery.DURATION] = duration < 0 ? mRnd.nextInt(10 * 60) : duration; 531 if (mVoicemail != null && mVoicemail.equals(number)) { 532 assertEquals(Calls.OUTGOING_TYPE, type); 533 } 534 values[CallLogQuery.CALL_TYPE] = type; 535 values[CallLogQuery.COUNTRY_ISO] = TEST_COUNTRY_ISO; 536 return values; 537 } 538 539 /** 540 * Insert a new voicemail entry in the test DB. 541 * @param number The phone number. 542 * @param presentation Number representing display rules for "allowed", 543 * "payphone", "restricted", or "unknown". 544 * @param date In millisec since epoch. Use NOW to use the current time. 545 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 546 */ 547 private void insertVoicemail(String number, int presentation, long date, int duration) { 548 Object[] values = getValuesToInsert(number, presentation, date, duration, Calls.VOICEMAIL_TYPE); 549 // Must have the same index as the row. 550 values[CallLogQuery.VOICEMAIL_URI] = 551 ContentUris.withAppendedId(VoicemailContract.Voicemails.CONTENT_URI, mIndex); 552 insertValues(values); 553 } 554 555 /** 556 * Insert a new private call entry in the test DB. 557 * @param date In millisec since epoch. Use NOW to use the current time. 558 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 559 */ 560 private void insertPrivate(long date, int duration) { 561 insert("", Calls.PRESENTATION_RESTRICTED, date, duration, Calls.INCOMING_TYPE); 562 } 563 564 /** 565 * Insert a new unknown call entry in the test DB. 566 * @param date In millisec since epoch. Use NOW to use the current time. 567 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 568 */ 569 private void insertUnknown(long date, int duration) { 570 insert("", Calls.PRESENTATION_UNKNOWN, date, duration, Calls.INCOMING_TYPE); 571 } 572 573 /** 574 * Insert a new call to voicemail entry in the test DB. 575 * @param date In millisec since epoch. Use NOW to use the current time. 576 * @param duration In seconds of the call. Use RAND_DURATION to pick a random one. 577 */ 578 private void insertCalltoVoicemail(long date, int duration) { 579 // mVoicemail may be null 580 if (mVoicemail != null) { 581 insert(mVoicemail, Calls.PRESENTATION_ALLOWED, date, duration, Calls.OUTGOING_TYPE); 582 } 583 } 584 585 /** 586 * Insert a range [start, end) of random numbers in the DB. For 587 * each row, there is a 1/10 probability that the number will be 588 * marked as PRIVATE or UNKNOWN or VOICEMAIL. For regular numbers, a number is 589 * inserted, its last 4 digits will be the number of the iteration 590 * in the range. 591 * @param start Of the range. 592 * @param end Of the range (excluded). 593 * @return An array with 2 booleans [0 = private number, 1 = 594 * unknown number, 2 = voicemail] to indicate if at least one 595 * private or unknown or voicemail number has been inserted. Since 596 * the numbers are random some tests may want to enforce the 597 * insertion of such numbers. 598 */ 599 // TODO: Should insert numbers with contact entries too. 600 private boolean[] insertRandomRange(int start, int end) { 601 boolean[] privateOrUnknownOrVm = new boolean[] {false, false, false}; 602 603 for (int i = start; i < end; i++ ) { 604 int type = mRnd.nextInt(10); 605 606 if (0 == type) { 607 insertPrivate(NOW, RAND_DURATION); 608 privateOrUnknownOrVm[0] = true; 609 } else if (1 == type) { 610 insertUnknown(NOW, RAND_DURATION); 611 privateOrUnknownOrVm[1] = true; 612 } else if (2 == type) { 613 insertCalltoVoicemail(NOW, RAND_DURATION); 614 privateOrUnknownOrVm[2] = true; 615 } else { 616 int inout = mRnd.nextBoolean() ? Calls.OUTGOING_TYPE : Calls.INCOMING_TYPE; 617 final Formatter formatter = new Formatter(); 618 String number = formatter.format("1800123%04d", i).toString(); 619 formatter.close(); 620 insert(number, Calls.PRESENTATION_ALLOWED, NOW, RAND_DURATION, inout); 621 } 622 } 623 return privateOrUnknownOrVm; 624 } 625 626 /** Asserts that the name text view is shown and contains the given text. */ 627 private void assertNameIs(CallLogListItemViews views, String name) { 628 assertEquals(View.VISIBLE, views.phoneCallDetailsViews.nameView.getVisibility()); 629 assertEquals(name, views.phoneCallDetailsViews.nameView.getText()); 630 } 631 632 /** Asserts that the label text view contains the given text. */ 633 private void assertLabel(CallLogListItemViews views, CharSequence number, 634 CharSequence label) { 635 if (label != null) { 636 assertTrue(views.phoneCallDetailsViews.callLocationAndDate.getText().toString() 637 .contains(label)); 638 } 639 } 640} 641