xref: /aosp_15_r20/cts/tests/tests/provider/src/android/provider/cts/SmsBackupRestoreTest.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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