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