1 /* 2 * Copyright (C) 2016 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 android.provider.cts; 18 19 import com.google.android.mms.ContentType; 20 import com.google.android.mms.pdu.CharacterSets; 21 22 import android.app.UiAutomation; 23 import android.content.ContentResolver; 24 import android.content.ContentUris; 25 import android.content.ContentValues; 26 import android.content.Context; 27 import android.content.pm.PackageManager; 28 import android.database.Cursor; 29 import android.net.Uri; 30 import android.provider.BaseColumns; 31 import android.provider.Telephony; 32 import android.util.Log; 33 34 /** 35 * CTS tests for backup and restore of blocked numbers using local transport. 36 */ 37 // To run the tests in this file w/o running all the cts tests: 38 // make cts 39 // cts-tradefed 40 // run cts -m CtsProviderTestCases --test android.provider.cts.SmsBackupRestoreTest 41 public class SmsBackupRestoreTest extends TestCaseThatRunsIfTelephonyIsEnabled { 42 private static final String TAG = "SmsBackupRestoreTest"; 43 private static final String LOCAL_BACKUP_COMPONENT = 44 "com.android.localtransport/.LocalTransport"; 45 private static final String TELEPHONY_PROVIDER_PACKAGE = "com.android.providers.telephony"; 46 47 private static final String[] smsAddressBody1 = new String[] {"+123" , "sms CTS text"}; 48 private static final String[] smsAddressBody2 = new String[] {"+456" , "sms CTS text 2"}; 49 private static final String[] mmsAddresses = new String[] {"+1223", "+43234234"}; 50 private static final String mmsSubject = "MMS Subject CTS"; 51 private static final String mmsBody = "MMS body CTS"; 52 53 private static final String[] ID_PROJECTION = new String[] { BaseColumns._ID }; 54 private static final String[] ID_TEXT_ONLY_PROJECTION = new String[] { BaseColumns._ID, 55 Telephony.Mms.TEXT_ONLY }; 56 private static final String SMS_SELECTION = Telephony.Sms.ADDRESS + " = ? and " 57 + Telephony.Sms.BODY + " = ?"; 58 59 private static final String MMS_SELECTION = Telephony.Mms.SUBJECT + " = ?"; 60 61 private static final String[] MMS_PART_TEXT_PROJECTION = new String[]{Telephony.Mms.Part.TEXT}; 62 private static final String MMS_PART_SELECTION = Telephony.Mms.Part.MSG_ID + " = ?"; 63 private static final String MMS_PART_TEXT_SELECTION = Telephony.Mms.Part.CONTENT_TYPE + " = ?"; 64 private static final String[] MMS_ADDR_PROJECTION = new String[] { Telephony.Mms.Addr.ADDRESS }; 65 private static final String MMS_ADDR_SELECTION = Telephony.Mms.Addr.MSG_ID + " = ?"; 66 67 private Context mContext; 68 private ContentResolver mContentResolver; 69 private UiAutomation mUiAutomation; 70 private String mOldTransport; 71 private boolean mOldBackupEnabled; 72 private boolean mHasFeature; 73 74 @Override 75 protected void setUp() throws Exception { 76 super.setUp(); 77 // Wait for the UI Thread to become idle. 78 getInstrumentation().waitForIdleSync(); 79 mContext = getInstrumentation().getContext(); 80 mContentResolver = mContext.getContentResolver(); 81 mUiAutomation = getInstrumentation().getUiAutomation(); 82 mHasFeature = isFeatureSupported(); 83 if (mHasFeature) { 84 ProviderTestUtils.setDefaultSmsApp(true, mContext.getPackageName(), mUiAutomation); 85 mOldTransport = 86 ProviderTestUtils.setBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation); 87 mOldBackupEnabled = ProviderTestUtils.setBackupEnabled(true, mUiAutomation); 88 clearMessages(); 89 wipeBackup(); 90 } 91 } 92 93 @Override 94 protected void tearDown() throws Exception { 95 if (mHasFeature) { 96 wipeBackup(); 97 clearMessages(); 98 ProviderTestUtils.setBackupEnabled(mOldBackupEnabled, mUiAutomation); 99 ProviderTestUtils.setBackupTransport(mOldTransport, mUiAutomation); 100 ProviderTestUtils.setDefaultSmsApp(false, mContext.getPackageName(), mUiAutomation); 101 } 102 103 super.tearDown(); 104 } 105 106 private boolean isFeatureSupported() throws Exception { 107 return (ProviderTestUtils.hasBackupTransport(LOCAL_BACKUP_COMPONENT, mUiAutomation) 108 && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)); 109 } 110 111 private void clearMessages() { 112 mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody1); 113 mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody2); 114 try (Cursor mmsCursor = 115 mContentResolver.query(Telephony.Mms.CONTENT_URI, ID_PROJECTION, MMS_SELECTION, 116 new String[] {mmsSubject}, null)) { 117 if (mmsCursor != null && mmsCursor.moveToFirst()) { 118 final long mmsId = mmsCursor.getLong(0); 119 final Uri partUri = Telephony.Mms.CONTENT_URI.buildUpon() 120 .appendPath(String.valueOf(mmsId)).appendPath("part").build(); 121 mContentResolver.delete(partUri, MMS_PART_SELECTION, 122 new String[]{String.valueOf(mmsId)}); 123 124 final Uri addrUri = getMmsAddrUri(mmsId); 125 mContentResolver.delete(addrUri, MMS_ADDR_SELECTION, 126 new String[]{String.valueOf(mmsId)}); 127 } 128 } 129 mContentResolver.delete(Telephony.Mms.CONTENT_URI, MMS_SELECTION, new String[]{mmsSubject}); 130 } 131 132 /** 133 * Test adds 2 SMS messages, 1 text-only MMS messages and 1 non-text-only, runs backup, 134 * deletes the messages from the provider, runs restore, check if the messages are in the 135 * provider (with non-text-only one). 136 * @throws Exception 137 */ 138 public void testSmsBackupRestore() throws Exception { 139 if (!mHasFeature) { 140 Log.i(TAG, "skipping testSmsBackupRestore"); 141 return; 142 } 143 144 ContentValues smsContentValues[] = new ContentValues[] { 145 createSmsValues(smsAddressBody1), 146 createSmsValues(smsAddressBody2)}; 147 Log.i(TAG, "Put 2 SMS into the provider"); 148 mContentResolver.bulkInsert(Telephony.Sms.CONTENT_URI, smsContentValues); 149 150 Log.i(TAG, "Put 1 text MMS into the provider"); 151 addMms(true /*isTextOnly*/, mmsBody, mmsSubject, mmsAddresses); 152 Log.i(TAG, "Put 1 non-text MMS into the provider"); 153 addMms(false /*isTextOnly*/, mmsBody, mmsSubject, mmsAddresses); 154 155 Log.i(TAG, "Run backup"); 156 ProviderTestUtils.runBackup(TELEPHONY_PROVIDER_PACKAGE, mUiAutomation); 157 Log.i(TAG, "Delete the messages from the provider"); 158 clearMessages(); 159 Log.i(TAG, "Run restore"); 160 ProviderTestUtils.runRestore(TELEPHONY_PROVIDER_PACKAGE, mUiAutomation); 161 162 Log.i(TAG, "Check the providers for the messages"); 163 assertEquals(1, 164 mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody1)); 165 assertEquals(1, 166 mContentResolver.delete(Telephony.Sms.CONTENT_URI, SMS_SELECTION, smsAddressBody2)); 167 168 try (Cursor mmsCursor = mContentResolver.query(Telephony.Mms.CONTENT_URI, 169 ID_TEXT_ONLY_PROJECTION, MMS_SELECTION, new String[] {mmsSubject}, null)) { 170 assertNotNull(mmsCursor); 171 assertEquals(2, mmsCursor.getCount()); 172 for (mmsCursor.moveToFirst(); !mmsCursor.isAfterLast(); mmsCursor.moveToNext()) { 173 final long mmsId = mmsCursor.getLong(0); 174 final long mmsTextOnly = mmsCursor.getLong(1); 175 assertEquals(mmsTextOnly, 1); 176 final Uri partUri = Telephony.Mms.CONTENT_URI.buildUpon() 177 .appendPath(String.valueOf(mmsId)).appendPath("part").build(); 178 // Check the body. 179 try (Cursor partCursor = mContentResolver.query(partUri, MMS_PART_TEXT_PROJECTION, 180 MMS_PART_TEXT_SELECTION, new String[]{ ContentType.TEXT_PLAIN }, null)) { 181 assertNotNull(partCursor); 182 assertEquals(1, partCursor.getCount()); 183 assertTrue(partCursor.moveToFirst()); 184 assertTrue(partCursor.getString(0).startsWith(mmsBody)); 185 } 186 187 // Check if there are 2 parts (smil and body). 188 assertEquals(2, mContentResolver.delete(partUri, MMS_PART_SELECTION, 189 new String[]{String.valueOf(mmsId)})); 190 191 // Check addresses. 192 final Uri addrUri = getMmsAddrUri(mmsId); 193 try (Cursor addrCursor = mContentResolver.query(addrUri, MMS_ADDR_PROJECTION, 194 MMS_ADDR_SELECTION, new String[]{String.valueOf(mmsId)}, null)) { 195 assertNotNull(addrCursor); 196 for (String addr : mmsAddresses) { 197 addrCursor.moveToNext(); 198 assertEquals(addr, addrCursor.getString(0)); 199 } 200 } 201 assertEquals(mmsAddresses.length, mContentResolver.delete(addrUri, MMS_ADDR_SELECTION, 202 new String[]{String.valueOf(mmsId)})); 203 } 204 } 205 } 206 207 private static Uri getMmsAddrUri(long mmsId) { 208 Uri.Builder builder = Telephony.Mms.CONTENT_URI.buildUpon(); 209 builder.appendPath(String.valueOf(mmsId)).appendPath("addr"); 210 return builder.build(); 211 } 212 213 private void addMms(boolean isTextOnly, String body, String subject, String[] addresses) { 214 // Insert mms. 215 final ContentValues mmsValues = new ContentValues(2); 216 mmsValues.put(Telephony.Mms.TEXT_ONLY, isTextOnly ? 1 : 0); 217 mmsValues.put(Telephony.Mms.MESSAGE_TYPE, 128); 218 mmsValues.put(Telephony.Mms.SUBJECT, subject); 219 final Uri mmsUri = mContentResolver.insert(Telephony.Mms.CONTENT_URI, mmsValues); 220 assertNotNull(mmsUri); 221 final long mmsId = ContentUris.parseId(mmsUri); 222 223 final String srcName = String.format("text.%06d.txt", 0); 224 // Insert body part. 225 final Uri partUri = Telephony.Mms.CONTENT_URI.buildUpon() 226 .appendPath(String.valueOf(mmsId)).appendPath("part").build(); 227 228 final ContentValues values = new ContentValues(8); 229 values.put(Telephony.Mms.Part.MSG_ID, mmsId); 230 values.put(Telephony.Mms.Part.SEQ, 0); 231 values.put(Telephony.Mms.Part.CONTENT_TYPE, ContentType.TEXT_PLAIN); 232 values.put(Telephony.Mms.Part.NAME, srcName); 233 values.put(Telephony.Mms.Part.CONTENT_ID, "<"+srcName+">"); 234 values.put(Telephony.Mms.Part.CONTENT_LOCATION, srcName); 235 values.put(Telephony.Mms.Part.CHARSET, CharacterSets.DEFAULT_CHARSET); 236 if (!isTextOnly) { 237 body = body + " Non text-only"; 238 } 239 values.put(Telephony.Mms.Part.TEXT, body); 240 mContentResolver.insert(partUri, values); 241 242 // Insert addresses. 243 final Uri addrUri = Uri.withAppendedPath(mmsUri, "addr"); 244 for (int i = 0; i < addresses.length; ++i) { 245 ContentValues addrValues = new ContentValues(3); 246 addrValues.put(Telephony.Mms.Addr.TYPE, i); 247 addrValues.put(Telephony.Mms.Addr.CHARSET, CharacterSets.DEFAULT_CHARSET); 248 addrValues.put(Telephony.Mms.Addr.ADDRESS, addresses[i]); 249 addrValues.put(Telephony.Mms.Addr.MSG_ID, mmsId); 250 mContentResolver.insert(addrUri, addrValues); 251 } 252 } 253 254 private static ContentValues createSmsValues(String[] addressBody) { 255 ContentValues smsRow = new ContentValues(); 256 smsRow.put(Telephony.Sms.ADDRESS, addressBody[0]); 257 smsRow.put(Telephony.Sms.BODY, addressBody[1]); 258 return smsRow; 259 } 260 261 private void wipeBackup() throws Exception { 262 ProviderTestUtils.wipeBackup(LOCAL_BACKUP_COMPONENT, TELEPHONY_PROVIDER_PACKAGE, 263 mUiAutomation); 264 } 265 } 266