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.Context; 24 import android.content.Intent; 25 import android.content.res.Resources; 26 import android.database.MatrixCursor; 27 import android.graphics.Bitmap; 28 import android.graphics.drawable.BitmapDrawable; 29 import android.net.Uri; 30 import android.provider.CallLog.Calls; 31 import android.provider.ContactsContract.CommonDataKinds.Phone; 32 import android.provider.VoicemailContract; 33 import android.telephony.PhoneNumberUtils; 34 import android.telephony.TelephonyManager; 35 import android.test.ActivityInstrumentationTestCase2; 36 import android.test.suitebuilder.annotation.LargeTest; 37 import android.test.suitebuilder.annotation.MediumTest; 38 import android.util.Log; 39 import android.view.View; 40 import android.widget.FrameLayout; 41 42 import com.android.contacts.common.test.FragmentTestActivity; 43 import com.android.dialer.CallDetailActivity; 44 import com.android.dialer.R; 45 46 import java.util.Date; 47 import java.util.Formatter; 48 import java.util.HashMap; 49 import 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 62 public 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 CallLogFragmentTest()100 public CallLogFragmentTest() { 101 super(FragmentTestActivity.class); 102 mIndex = 1; 103 mRnd = new Random(); 104 } 105 106 @Override setUp()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 testCallViewIsNotVisibleForPrivateAndUnknownNumbers()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 testCallAndGroupViews_GroupView()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 testCallAndGroupViews_StandAloneView()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 testCallAndGroupViews_ChildView()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 testBindView_NumberOnlyNoCache()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 testBindView_NumberOnlyDbCachedFormattedNumber()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 testBindView_WithCachedName()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 testBindView_UriNumber()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 testBindView_HomeLabel()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 testBindView_WorkLabel()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 testBindView_CustomLabel()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 testBindView_WithQuickContactBadge()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 testBindView_WithoutQuickContactBadge()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 testBindView_CallButton()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 testBindView_PlayButton()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. */ getTypeLabel(int phoneType)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 */ checkCallStatus()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 */ getBitmap(String resName)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 */ buildViewListFromDb()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}. */ getPhoneNumberPresentationForListEntry(int index)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 */ insertRandomEntries(int num)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 */ insertWithCachedValues(String number, long date, int duration, int type, String cachedName, int cachedNumberType, String cachedNumberLabel)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 */ insert(String number, int presentation, long date, int duration, int type)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. */ insertValues(Object[] values)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 */ getValuesToInsert(String number, int presentation, long date, int duration, int type)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