在Android自动化测试中,通过自动化测试脚本填充联系人、通话记录、短信等数据,可以模拟出更接近真实用户的使用场景。这种模拟有助于发现那些在日常使用中才会出现的问题,从而提高测试的全面性和准确性。
联系人
权限
读写联系人需要以下权限,直接动态申请即可
1 2
   | <uses-permission android:name="android.permission.READ_CONTACTS"/> <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
   | 
 
填充方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
   | private boolean insertContacts(String names, String num) {          ArrayList<ContentProviderOperation> ops = new ArrayList<>();     ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)              .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)              .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)              .build());
      ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)               .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)              .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, names)              .build());
      ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)               .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, num)               .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE)               .build());
      try {         getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);            return true;     } catch (Exception e) {         Log.e(TAG, "insertContacts error: " + e);         return false;     } }
  | 
 
删除方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
   | private void deleteAllContacts() {     Uri uri = ContactsContract.Contacts.CONTENT_URI;     String[] projection = new String[]{ContactsContract.Contacts._ID};       String selection = null;       String[] selectionArgs = null;     String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";  
           Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);     if (cursor != null) {         try {             while (cursor.moveToNext()) {                                  @SuppressLint("Range") long contactId = cursor.getLong(cursor.getColumnIndex(ContactsContract.Contacts._ID));                 if (deleteContact(contactId)) {                     Log.d(TAG, String.format("delete contact %s succ\n", contactId));                 } else {                     Log.e(TAG, String.format("delete contact %s fail\n", contactId));                 }             }         } finally {             cursor.close();         }     } }
  private boolean deleteContact(long contactId) {     try {         Uri deleteUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, contactId);           int rowsDeleted = getContentResolver().delete(deleteUri, null, null);           if (rowsDeleted > 0) {             return true;         }     } catch (Exception e) {         Log.e(TAG, "deleteContactError: " + e);     }     return false; }
  | 
 
通话记录
权限
读写通话记录需要以下权限,直接动态申请即可
1 2
   | <uses-permission android:name="android.permission.READ_CALL_LOG"/> <uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
   | 
 
填充方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | private boolean insertCallLog(String number, String duration, String type, String isNew) {     ContentValues values = new ContentValues();     values.put(CallLog.Calls.NUMBER, number);       values.put(CallLog.Calls.DATE, System.currentTimeMillis());       values.put(CallLog.Calls.DURATION, duration);       values.put(CallLog.Calls.TYPE, type);      values.put(CallLog.Calls.NEW, isNew);       try {         getContentResolver().insert(CallLog.Calls.CONTENT_URI, values);         return true;     } catch (Exception e) {         Log.e(TAG, "insertCallLog error: " + e);         return false;     } }
  | 
 
删除方法
1 2 3 4 5 6 7 8 9 10 11 12 13
   | private boolean deleteAllCallLogs() {     try {                  int rowsDeleted = getContentResolver().delete(CallLog.Calls.CONTENT_URI, null, null);                   if (rowsDeleted > 0) {             return true;         }     } catch (Exception e) {         Log.e(TAG, "deleteAllCallLogs error: " + e);     }     return false; }
  | 
 
短信
权限
短信较为特殊,由于Android4.4之后,除了默认短信应用以外,其他应用将无法插入短信。因此需要将APK伪装成一个短信应用,并设置为默认的短信应用。
仅在默认处理程序中使用的权限  | Android Developers
AndroidManifest.xml中添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
   | <uses-permission android:name="android.permission.SEND_SMS" /> <uses-permission android:name="android.permission.RECEIVE_SMS"/> <uses-permission android:name="android.permission.READ_SMS" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"     tools:ignore="QueryAllPackagesPermission" />
  <application     android:allowBackup="true"     android:dataExtractionRules="@xml/data_extraction_rules"     android:fullBackupContent="@xml/backup_rules"     android:icon="@mipmap/app"     android:label="@string/app_name"     android:roundIcon="@mipmap/app_round"     android:supportsRtl="true"     android:theme="@style/Theme.AutoFill"     >     <receiver         android:name=".SmsReceiver"         android:permission="android.permission.BROADCAST_SMS"         android:exported="true"         tools:ignore="WrongManifestParent">         <intent-filter>             <action android:name="android.provider.Telephony.SMS_DELIVER" />         </intent-filter>     </receiver>     <receiver         android:name=".MmsReceiver"         android:permission="android.permission.BROADCAST_WAP_PUSH"         android:exported="true"         tools:ignore="WrongManifestParent">         <intent-filter>             <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />             <data android:mimeType="application/vnd.wap.mms-message" />         </intent-filter>     </receiver>     <service         android:name=".HeadlessSmsSendService"         android:exported="true"         android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"         tools:ignore="WrongManifestParent">         <intent-filter>             <action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />             <category android:name="android.intent.category.DEFAULT" />
              <data android:scheme="sms" />             <data android:scheme="smsto" />             <data android:scheme="mms" />             <data android:scheme="mmsto" />         </intent-filter>     </service>     <activity         android:name=".MainActivity"         android:exported="true">         <intent-filter>             <action android:name="android.intent.action.SEND" />             <action android:name="android.intent.action.SENDTO" />
              <category android:name="android.intent.category.DEFAULT" />             <category android:name="android.intent.category.BROWSABLE" />
              <data android:scheme="sms" />             <data android:scheme="smsto" />             <data android:scheme="mms" />             <data android:scheme="mmsto" />         </intent-filter>         <intent-filter>             <action android:name="android.intent.action.MAIN" />             <category android:name="android.intent.category.LAUNCHER" />         </intent-filter>     </activity> </application>
   | 
 
分别创建空的HeadlessSmsSendService,MmsReceiver,SmsActivity,SmsReceiver,SmsService
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
   | public class HeadlessSmsSendService extends Service {     @Nullable     @Override     public IBinder onBind(Intent intent) {         return null;     } }   public class MmsReceiver extends BroadcastReceiver {     @Override     public void onReceive(Context context, Intent intent) {       } }   public class SmsActivity extends Activity { }   public class SmsReceiver extends BroadcastReceiver {     @Override     public void onReceive(Context context, Intent intent) {       } }   public class SmsReceiver extends BroadcastReceiver {     @Override     public void onReceive(Context context, Intent intent) {       } }
  | 
 

最后,需要将APK设置为默认短信应用(需要手动授予)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
   |  private String getDefaultSms() {     String packageName = "null";     Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("smsto:"));     PackageManager packageManager = getApplicationContext().getPackageManager();     ResolveInfo resolveInfo = packageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);     if (resolveInfo != null) {         packageName = resolveInfo.activityInfo.packageName;     }     return packageName; }
 
  private void setDefaultSms(int requestCode) {     String defaultSmsPkg = Telephony.Sms.getDefaultSmsPackage(getApplicationContext());     Log.d(TAG, "default SMS: " + defaultSmsPkg);     if (!defaultSmsPkg.equals(getPackageName())) {         RoleManager roleManager = (RoleManager) getSystemService(Context.ROLE_SERVICE);         if (roleManager != null && roleManager.isRoleAvailable(RoleManager.ROLE_SMS)) {             Intent roleRequestIntent = roleManager.createRequestRoleIntent(RoleManager.ROLE_SMS);             if (roleRequestIntent != null) {                 startActivityForResult(roleRequestIntent, requestCode);               }         }     } }
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {     super.onActivityResult(requestCode, resultCode, data);           }
 
  | 
 
填充方法
1 2 3 4 5 6 7 8 9 10 11
   | private void insertMessages(String num, String body, long date) {     ContentResolver contentResolver = getContentResolver();     ContentValues values = new ContentValues();     Uri uri = Uri.parse("content://sms/");     values.put(Telephony.Sms.ADDRESS, num);     values.put(Telephony.Sms.DATE, date);     values.put(Telephony.Sms.READ, false);     values.put(Telephony.Sms.STATUS, Telephony.Sms.STATUS_NONE);     values.put(Telephony.Sms.BODY, body);     contentResolver.insert(uri, values); }
  | 
 
删除方法
1 2 3 4 5 6 7 8 9 10
   | private void deleteAllSMS() {     Uri uriSms = Uri.parse("content://sms/");     Cursor c = getContentResolver().query(uriSms, null, null, null, null);
      while (c.moveToNext()) {         long id = c.getLong(c.getColumnIndexOrThrow("_id"));         getContentResolver().delete(Uri.parse("content://sms/" + id), null, null);     }     c.close(); }
  |