• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.providers.contacts;
18 
19 import android.content.ContentUris;
20 import android.content.ContentValues;
21 import android.database.Cursor;
22 import android.net.Uri;
23 import android.os.BatteryStats.Uid.Proc;
24 import android.os.ParcelFileDescriptor;
25 import android.os.Process;
26 import android.provider.CallLog;
27 import android.provider.CallLog.Calls;
28 import android.provider.VoicemailContract;
29 import android.provider.VoicemailContract.Status;
30 import android.provider.VoicemailContract.Voicemails;
31 import android.test.MoreAsserts;
32 import android.test.suitebuilder.annotation.SmallTest;
33 
34 import com.android.common.io.MoreCloseables;
35 
36 import java.io.FileNotFoundException;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.io.OutputStream;
40 import java.util.Arrays;
41 import java.util.List;
42 
43 /**
44  * Unit tests for {@link VoicemailContentProvider}.
45  *
46  * Run the test like this:
47  * <code>
48  * runtest -c com.android.providers.contacts.VoicemailProviderTest contactsprov
49  * </code>
50  */
51 // TODO: Test that calltype and voicemail_uri are auto populated by the provider.
52 @SmallTest
53 public class VoicemailProviderTest extends BaseVoicemailProviderTest {
54     /** Fields specific to call_log provider that should not be exposed by voicemail provider. */
55     private static final String[] CALLLOG_PROVIDER_SPECIFIC_COLUMNS = {
56             Calls.CACHED_NAME,
57             Calls.CACHED_NUMBER_LABEL,
58             Calls.CACHED_NUMBER_TYPE,
59             Calls.TYPE,
60             Calls.VOICEMAIL_URI,
61             Calls.COUNTRY_ISO
62     };
63     /** Total number of columns exposed by voicemail provider. */
64     private static final int NUM_VOICEMAIL_FIELDS = 24;
65 
66     @Override
setUp()67     protected void setUp() throws Exception {
68         super.setUp();
69         setUpForOwnPermission();
70         addProvider(CallLogProviderTestable.class, CallLog.AUTHORITY);
71     }
72 
73     /** Returns the appropriate /voicemail URI. */
voicemailUri()74     private Uri voicemailUri() {
75         return mUseSourceUri ?
76                 Voicemails.buildSourceUri(mActor.packageName) : Voicemails.CONTENT_URI;
77     }
78 
79     /** Returns the appropriate /status URI. */
statusUri()80     private Uri statusUri() {
81         return mUseSourceUri ?
82                 Status.buildSourceUri(mActor.packageName) : Status.CONTENT_URI;
83     }
84 
testInsert()85     public void testInsert() throws Exception {
86         setTimeForTest(1000L);
87         Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues());
88         // We create on purpose a new set of ContentValues here, because the code above modifies
89         // the copy it gets.
90         assertStoredValues(uri, getTestVoicemailValues());
91         assertSelection(uri, getTestVoicemailValues(), Voicemails._ID, ContentUris.parseId(uri));
92         assertEquals(1, countFilesInTestDirectory());
93 
94         assertLastModified(uri, 1000);
95     }
96 
testInsertReadMessageIsNotNew()97     public void testInsertReadMessageIsNotNew() throws Exception {
98         ContentValues values = getTestReadVoicemailValues();
99         Uri uri = mResolver.insert(voicemailUri(), values);
100         String[] projection = {Voicemails.NUMBER, Voicemails.DATE, Voicemails.DURATION,
101                 Voicemails.TRANSCRIPTION, Voicemails.IS_READ, Voicemails.HAS_CONTENT,
102                 Voicemails.SOURCE_DATA, Voicemails.STATE,
103                 Voicemails.BACKED_UP, Voicemails.RESTORED, Voicemails.ARCHIVED,
104                 Voicemails.IS_OMTP_VOICEMAIL
105         };
106         Cursor c = mResolver.query(uri, projection, Calls.NEW + "=0", null,
107                 null);
108         try {
109             assertEquals("Record count", 1, c.getCount());
110             c.moveToFirst();
111             assertEquals(1, countFilesInTestDirectory());
112             assertCursorValues(c, values);
113         } catch (Error e) {
114             TestUtils.dumpCursor(c);
115             throw e;
116         } finally {
117             c.close();
118         }
119     }
120 
121     // Test to ensure that media content can be written and read back.
testFileContent()122     public void testFileContent() throws Exception {
123         Uri uri = insertVoicemail();
124         OutputStream out = mResolver.openOutputStream(uri);
125         byte[] outBuffer = {0x1, 0x2, 0x3, 0x4};
126         out.write(outBuffer);
127         out.flush();
128         out.close();
129         InputStream in = mResolver.openInputStream(uri);
130         byte[] inBuffer = new byte[4];
131         int numBytesRead = in.read(inBuffer);
132         assertEquals(numBytesRead, outBuffer.length);
133         MoreAsserts.assertEquals(outBuffer, inBuffer);
134         // No more data should be left.
135         assertEquals(-1, in.read(inBuffer));
136         in.close();
137     }
138 
testUpdate()139     public void testUpdate() {
140         setTimeForTest(1000L);
141         Uri uri = insertVoicemail();
142         ContentValues values = new ContentValues();
143         values.put(Voicemails.NUMBER, "1-800-263-7643");
144         values.put(Voicemails.DATE, 2000);
145         values.put(Voicemails.DURATION, 40);
146         values.put(Voicemails.TRANSCRIPTION, "Testing 123");
147         values.put(Voicemails.STATE, 2);
148         values.put(Voicemails.HAS_CONTENT, 1);
149         values.put(Voicemails.SOURCE_DATA, "foo");
150         values.put(Voicemails.PHONE_ACCOUNT_COMPONENT_NAME, "dummy_name");
151         values.put(Voicemails.PHONE_ACCOUNT_ID, "dummy_account");
152         values.put(Voicemails.BACKED_UP, 1);
153         values.put(Voicemails.RESTORED, 1);
154         values.put(Voicemails.ARCHIVED, 1);
155         values.put(Voicemails.IS_OMTP_VOICEMAIL, 1);
156         int count = mResolver.update(uri, values, null, null);
157         assertEquals(1, count);
158         assertStoredValues(uri, values);
159         assertLastModified(uri, 1000);
160     }
161 
testUpdateOwnPackageVoicemail_NotDirty()162     public void testUpdateOwnPackageVoicemail_NotDirty() {
163         final Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues());
164         mResolver.update(uri, new ContentValues(), null, null);
165 
166         // Updating a package's own voicemail should not make the voicemail dirty.
167         ContentValues values = getTestVoicemailValues();
168         values.put(Voicemails.DIRTY, "0");
169         assertStoredValues(uri, values);
170     }
171 
testUpdateOwnPackageVoicemail_RemovesDirtyStatus()172     public void testUpdateOwnPackageVoicemail_RemovesDirtyStatus() {
173         ContentValues values = getTestVoicemailValues();
174         values.put(Voicemails.DIRTY, "1");
175         final Uri uri = mResolver.insert(voicemailUri(), getTestVoicemailValues());
176 
177         mResolver.update(uri, new ContentValues(), null, null);
178         // At this point, the voicemail should be set back to not dirty.
179         ContentValues newValues = getTestVoicemailValues();
180         newValues.put(Voicemails.DIRTY, "0");
181         assertStoredValues(uri, newValues);
182     }
183 
testDeleteOwnPackageVoicemail_DeletesRow()184     public void testDeleteOwnPackageVoicemail_DeletesRow() {
185         setUpForFullPermission();
186         final Uri ownVoicemail = insertVoicemail();
187         assertEquals(1, getCount(voicemailUri(), null, null));
188 
189         mResolver.delete(ownVoicemail, null, null);
190 
191         assertEquals(0, getCount(ownVoicemail, null, null));
192     }
193 
testDeleteOtherPackageVoicemail_SetsDirtyStatus()194     public void testDeleteOtherPackageVoicemail_SetsDirtyStatus() {
195         setUpForFullPermission();
196         setTimeForTest(1000L);
197         final Uri anotherVoicemail = insertVoicemailForSourcePackage("another-package");
198         assertEquals(1, getCount(voicemailUri(), null, null));
199 
200         // Clear the mapping for our own UID so that this doesn't look like an internal transaction.
201         mPackageManager.removePackage(Process.myUid());
202         mResolver.delete(anotherVoicemail, null, null);
203 
204         ContentValues values = getTestVoicemailValues();
205         values.put(Voicemails.DIRTY, "1");
206         values.put(Voicemails.DELETED, "1");
207 
208         assertEquals(1, getCount(anotherVoicemail, null, null));
209         assertStoredValues(anotherVoicemail, values);
210         assertLastModified(anotherVoicemail, 1000);
211     }
212 
testDelete()213     public void testDelete() {
214         Uri uri = insertVoicemail();
215         int count = mResolver.delete(voicemailUri(), Voicemails._ID + "="
216                 + ContentUris.parseId(uri), null);
217         assertEquals(1, count);
218         assertEquals(0, getCount(uri, null, null));
219     }
220 
testUpdateAfterDelete_lastModifiedNotChanged()221     public void testUpdateAfterDelete_lastModifiedNotChanged() {
222         setUpForFullPermission();
223         setTimeForTest(1000L);
224         final Uri anotherVoicemail = insertVoicemailForSourcePackage("another-package");
225         assertEquals(1, getCount(voicemailUri(), null, null));
226 
227         // Clear the mapping for our own UID so that this doesn't look like an internal transaction.
228         mPackageManager.removePackage(Process.myUid());
229         mResolver.delete(anotherVoicemail, null, null);
230         assertLastModified(anotherVoicemail, 1000);
231 
232         mPackageManager.addPackage(Process.myUid(), mActor.packageName);
233         setTimeForTest(2000L);
234         mResolver.update(anotherVoicemail, new ContentValues(), null, null);
235         assertLastModified(anotherVoicemail, 1000);
236 
237         setTimeForTest(3000L);
238         ContentValues values = new ContentValues();
239         values.put(Voicemails.DELETED, "0");
240         mResolver.update(anotherVoicemail, values, null, null);
241         assertLastModified(anotherVoicemail, 3000);
242     }
243 
testGetType_ItemUri()244     public void testGetType_ItemUri() throws Exception {
245         // Random item uri.
246         assertEquals(Voicemails.ITEM_TYPE,
247                 mResolver.getType(ContentUris.withAppendedId(Voicemails.CONTENT_URI, 100)));
248         // Item uri of an inserted voicemail.
249         ContentValues values = getTestVoicemailValues();
250         values.put(Voicemails.MIME_TYPE, "foo/bar");
251         Uri uri = mResolver.insert(voicemailUri(), values);
252         assertEquals(Voicemails.ITEM_TYPE, mResolver.getType(uri));
253     }
254 
testGetType_DirUri()255     public void testGetType_DirUri() throws Exception {
256         assertEquals(Voicemails.DIR_TYPE, mResolver.getType(Voicemails.CONTENT_URI));
257         assertEquals(Voicemails.DIR_TYPE, mResolver.getType(Voicemails.buildSourceUri("foo")));
258     }
259 
260     // Test to ensure that without full permission it is not possible to use the base uri (i.e. with
261     // no package URI specified).
testMustUsePackageUriWithoutFullPermission()262     public void testMustUsePackageUriWithoutFullPermission() {
263         setUpForOwnPermission();
264         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
265             @Override
266             public void run() {
267                 mResolver.insert(Voicemails.CONTENT_URI, getTestVoicemailValues());
268             }
269         });
270 
271         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
272             @Override
273             public void run() {
274                 mResolver.update(Voicemails.CONTENT_URI, getTestVoicemailValues(), null, null);
275             }
276         });
277 
278         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
279             @Override
280             public void run() {
281                 mResolver.query(Voicemails.CONTENT_URI, null, null, null, null);
282             }
283         });
284 
285         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
286             @Override
287             public void run() {
288                 mResolver.delete(Voicemails.CONTENT_URI, null, null);
289             }
290         });
291     }
292 
testPermissions_InsertAndQuery()293     public void testPermissions_InsertAndQuery() {
294         setUpForFullPermission();
295         // Insert two records - one each with own and another package.
296         insertVoicemail();
297         insertVoicemailForSourcePackage("another-package");
298         assertEquals(2, getCount(voicemailUri(), null, null));
299 
300         // Now give away full permission and check that only 1 message is accessible.
301         setUpForOwnPermission();
302         assertEquals(1, getCount(voicemailUri(), null, null));
303 
304         // Once again try to insert message for another package. This time
305         // it should fail.
306         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
307             @Override
308             public void run() {
309                 insertVoicemailForSourcePackage("another-package");
310             }
311         });
312 
313         setUpForNoPermission();
314         mUseSourceUri = false;
315         // With the READ_ALL_VOICEMAIL permission, we should now be able to read all voicemails
316         mActor.addPermissions(READ_VOICEMAIL_PERMISSION);
317         assertEquals(2, getCount(voicemailUri(), null, null));
318 
319         // An insert for another package should still fail
320         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
321             @Override
322             public void run() {
323                 insertVoicemailForSourcePackage("another-package");
324             }
325         });
326     }
327 
testPermissions_UpdateAndDelete()328     public void testPermissions_UpdateAndDelete() {
329         setUpForFullPermission();
330         // Insert two records - one each with own and another package.
331         final Uri ownVoicemail = insertVoicemail();
332         final Uri anotherVoicemail = insertVoicemailForSourcePackage("another-package");
333         assertEquals(2, getCount(voicemailUri(), null, null));
334 
335         // Now give away full permission and check that we can update and delete only
336         // the own voicemail.
337         setUpForOwnPermission();
338         mResolver.update(withSourcePackageParam(ownVoicemail),
339                 getTestVoicemailValues(), null, null);
340         mResolver.delete(withSourcePackageParam(ownVoicemail), null, null);
341 
342         // However, attempting to update or delete another-package's voicemail should fail.
343         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
344             @Override
345             public void run() {
346                 mResolver.update(anotherVoicemail, null, null, null);
347             }
348         });
349         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
350             @Override
351             public void run() {
352                 mResolver.delete(anotherVoicemail, null, null);
353             }
354         });
355 
356         // If we have the manage voicemail permission, we should be able to both update voicemails
357         // from all packages.
358         setUpForNoPermission();
359         mActor.addPermissions(WRITE_VOICEMAIL_PERMISSION);
360         mResolver.update(anotherVoicemail, getTestVoicemailValues(), null, null);
361 
362         // Now add the read voicemail permission temporarily to verify that the update actually
363         // worked
364         mActor.addPermissions(READ_VOICEMAIL_PERMISSION);
365         assertStoredValues(anotherVoicemail, getTestVoicemailValues());
366         mActor.removePermissions(READ_VOICEMAIL_PERMISSION);
367 
368         mResolver.delete(anotherVoicemail, null, null);
369 
370         // Now add the read voicemail permission temporarily to verify that the voicemail is
371         // deleted.
372         mActor.addPermissions(READ_VOICEMAIL_PERMISSION);
373 
374         assertEquals(0, getCount(anotherVoicemail, null, null));
375     }
376 
withSourcePackageParam(Uri uri)377     private Uri withSourcePackageParam(Uri uri) {
378         return uri.buildUpon()
379             .appendQueryParameter(VoicemailContract.PARAM_KEY_SOURCE_PACKAGE, mActor.packageName)
380             .build();
381     }
382 
testUriPermissions()383     public void testUriPermissions() {
384         setUpForFullPermission();
385         final Uri uri1 = insertVoicemail();
386         final Uri uri2 = insertVoicemail();
387         // Give away all permissions before querying. Access to both uris should be denied.
388         setUpForNoPermission();
389         checkHasNoAccessToUri(uri1);
390         checkHasNoAccessToUri(uri2);
391 
392         // Just grant permission to uri1. uri1 should pass but uri2 should still fail.
393         mActor.addUriPermissions(uri1);
394         checkHasReadOnlyAccessToUri(uri1);
395         checkHasNoAccessToUri(uri2);
396 
397         // Cleanup.
398         mActor.removeUriPermissions(uri1);
399     }
400 
401     /*
402      * Checks that the READ_ALL_VOICEMAIL permission provides read access to a uri.
403      */
testUriPermissions_ReadAccess()404     public void testUriPermissions_ReadAccess() {
405         setUpForFullPermission();
406         final Uri uri1 = insertVoicemail();
407         // Give away all permissions before querying. Access should be denied.
408         setUpForNoPermission();
409         mUseSourceUri = false;
410         checkHasNoAccessToUri(uri1);
411 
412         mActor.addPermissions(READ_VOICEMAIL_PERMISSION);
413         checkHasReadAccessToUri(uri1);
414     }
415 
416     /*
417      * Checks that the MANAGE_VOICEMAIL permission provides write access to a uri.
418      */
testUriPermissions_WriteAccess()419     public void testUriPermissions_WriteAccess() {
420         setUpForFullPermission();
421         final Uri uri1 = insertVoicemail();
422         // Give away all permissions before querying. Access should be denied.
423         setUpForNoPermission();
424         checkHasNoAccessToUri(uri1);
425 
426         mActor.addPermissions(WRITE_VOICEMAIL_PERMISSION);
427         checkHasUpdateAndDeleteAccessToUri(uri1);
428     }
429 
checkHasNoAccessToUri(final Uri uri)430     private void checkHasNoAccessToUri(final Uri uri) {
431         checkHasNoReadAccessToUri(uri);
432         checkHasNoWriteAccessToUri(uri);
433     }
434 
checkHasReadOnlyAccessToUri(final Uri uri)435     private void checkHasReadOnlyAccessToUri(final Uri uri) {
436         checkHasReadAccessToUri(uri);
437         checkHasNoWriteAccessToUri(uri);
438     }
439 
checkHasReadAccessToUri(final Uri uri)440     private void checkHasReadAccessToUri(final Uri uri) {
441         Cursor cursor = null;
442         try {
443             cursor = mResolver.query(uri, null, null ,null, null);
444             assertEquals(1, cursor.getCount());
445             try {
446                 ParcelFileDescriptor fd = mResolver.openFileDescriptor(uri, "r");
447                 assertNotNull(fd);
448                 fd.close();
449             } catch (FileNotFoundException e) {
450                 fail(e.getMessage());
451             } catch (IOException e) {
452                 fail(e.getMessage());
453             }
454         } finally {
455             MoreCloseables.closeQuietly(cursor);
456         }
457     }
458 
checkHasNoReadAccessToUri(final Uri uri)459     private void checkHasNoReadAccessToUri(final Uri uri) {
460         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
461             @Override
462             public void run() {
463                 mResolver.query(uri, null, null, null, null);
464             }
465         });
466         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
467             @Override
468             public void run() {
469                 try {
470                     mResolver.openFileDescriptor(uri, "r");
471                 } catch (FileNotFoundException e) {
472                     fail(e.getMessage());
473                 }
474             }
475         });
476     }
477 
checkHasUpdateAndDeleteAccessToUri(final Uri uri)478     private void checkHasUpdateAndDeleteAccessToUri(final Uri uri) {
479         mResolver.update(uri, getTestVoicemailValues(), null, null);
480         mResolver.delete(uri, null, null);
481     }
482 
checkHasNoWriteAccessToUri(final Uri uri)483     private void checkHasNoWriteAccessToUri(final Uri uri) {
484         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
485             @Override
486             public void run() {
487                 mResolver.update(uri, getTestVoicemailValues(), null, null);
488             }
489         });
490         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
491             @Override
492             public void run() {
493                 mResolver.delete(uri, null, null);
494             }
495         });
496         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
497             @Override
498             public void run() {
499                 try {
500                     mResolver.openFileDescriptor(uri, "w");
501                 } catch (FileNotFoundException e) {
502                     fail(e.getMessage());
503                 }
504             }
505         });
506         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
507             @Override
508             public void run() {
509                 try {
510                     mResolver.openFileDescriptor(uri, "rw");
511                 } catch (FileNotFoundException e) {
512                     fail(e.getMessage());
513                 }
514             }
515         });
516     }
517 
518     // Test to ensure that all operations fail when no voicemail permission is granted.
testNoPermissions()519     public void testNoPermissions() {
520         setUpForNoPermission();
521         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
522             @Override
523             public void run() {
524                 mResolver.insert(voicemailUri(), getTestVoicemailValues());
525             }
526         });
527         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
528             @Override
529             public void run() {
530                 mResolver.update(voicemailUri(), getTestVoicemailValues(), null, null);
531             }
532         });
533         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
534             @Override
535             public void run() {
536                 mResolver.query(voicemailUri(), null, null, null, null);
537             }
538         });
539         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
540             @Override
541             public void run() {
542                 mResolver.delete(voicemailUri(), null, null);
543             }
544         });
545     }
546 
547     // Test to check that none of the call_log provider specific fields are
548     // insertable through voicemail provider.
testCannotAccessCallLogSpecificFields_Insert()549     public void testCannotAccessCallLogSpecificFields_Insert() {
550         for (String callLogColumn : CALLLOG_PROVIDER_SPECIFIC_COLUMNS) {
551             final ContentValues values = getTestVoicemailValues();
552             values.put(callLogColumn, "foo");
553             EvenMoreAsserts.assertThrows("Column: " + callLogColumn,
554                     IllegalArgumentException.class, new Runnable() {
555                     @Override
556                     public void run() {
557                         mResolver.insert(voicemailUri(), values);
558                     }
559                 });
560         }
561     }
562 
563     // Test to check that none of the call_log provider specific fields are
564     // exposed through voicemail provider query.
testCannotAccessCallLogSpecificFields_Query()565     public void testCannotAccessCallLogSpecificFields_Query() {
566         // Query.
567         Cursor cursor = mResolver.query(voicemailUri(), null, null, null, null);
568         List<String> columnNames = Arrays.asList(cursor.getColumnNames());
569         assertEquals(NUM_VOICEMAIL_FIELDS, columnNames.size());
570         // None of the call_log provider specific columns should be present.
571         for (String callLogColumn : CALLLOG_PROVIDER_SPECIFIC_COLUMNS) {
572             assertFalse("Unexpected column: '" + callLogColumn + "' returned.",
573                     columnNames.contains(callLogColumn));
574         }
575     }
576 
577     // Test to check that none of the call_log provider specific fields are
578     // updatable through voicemail provider.
testCannotAccessCallLogSpecificFields_Update()579     public void testCannotAccessCallLogSpecificFields_Update() {
580         for (String callLogColumn : CALLLOG_PROVIDER_SPECIFIC_COLUMNS) {
581             final Uri insertedUri = insertVoicemail();
582             final ContentValues values = getTestVoicemailValues();
583             values.put(callLogColumn, "foo");
584             EvenMoreAsserts.assertThrows("Column: " + callLogColumn,
585                     IllegalArgumentException.class, new Runnable() {
586                     @Override
587                     public void run() {
588                         mResolver.update(insertedUri, values, null, null);
589                     }
590                 });
591         }
592     }
593 
594     // Tests for voicemail status table.
595 
testStatusInsert()596     public void testStatusInsert() throws Exception {
597         ContentValues values = getTestStatusValues();
598         Uri uri = mResolver.insert(statusUri(), values);
599         assertStoredValues(uri, values);
600         assertSelection(uri, values, Status._ID, ContentUris.parseId(uri));
601     }
602 
testStatusUpdate()603     public void testStatusUpdate() throws Exception {
604         Uri uri = insertTestStatusEntry();
605         ContentValues values = getTestStatusValues();
606         values.put(Status.DATA_CHANNEL_STATE, Status.DATA_CHANNEL_STATE_NO_CONNECTION);
607         values.put(Status.NOTIFICATION_CHANNEL_STATE,
608                 Status.NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING);
609         values.put(Status.SOURCE_TYPE,
610                 "vvm_type_test2");
611         int count = mResolver.update(uri, values, null, null);
612         assertEquals(1, count);
613         assertStoredValues(uri, values);
614     }
615 
testStatusUpsert()616     public void testStatusUpsert() throws Exception {
617         ContentValues values = getTestStatusValues();
618         mResolver.insert(statusUri(), values);
619         ContentValues values2 = new ContentValues();
620         values2.put(Status.CONFIGURATION_STATE, Status.CONFIGURATION_STATE_NOT_CONFIGURED);
621         values.put(Status.CONFIGURATION_STATE, Status.CONFIGURATION_STATE_NOT_CONFIGURED);
622         Uri uri = mResolver.insert(statusUri(), values2);
623         assertStoredValues(uri, values);
624         assertSelection(uri, values, Status._ID, ContentUris.parseId(uri));
625     }
626 
testStatusDelete()627     public void testStatusDelete() {
628         Uri uri = insertTestStatusEntry();
629         int count = mResolver.delete(statusUri(), Status._ID + "="
630                 + ContentUris.parseId(uri), null);
631         assertEquals(1, count);
632         assertEquals(0, getCount(uri, null, null));
633     }
634 
testStatusQuotaInsert()635     public void testStatusQuotaInsert() {
636         ContentValues values = new ContentValues();
637         values.put(Status.SOURCE_PACKAGE, mActor.packageName);
638         values.put(Status.QUOTA_OCCUPIED, 2);
639         values.put(Status.QUOTA_TOTAL, 13);
640         Uri uri = mResolver.insert(statusUri(), values);
641         assertStoredValues(uri, values);
642         assertSelection(uri, values, Status._ID, ContentUris.parseId(uri));
643     }
644 
testStatusQuotaUpdate()645     public void testStatusQuotaUpdate() {
646         Uri uri = insertTestStatusEntry();
647         ContentValues values = new ContentValues();
648         values.put(Status.SOURCE_PACKAGE, mActor.packageName);
649         values.put(Status.QUOTA_OCCUPIED, 2);
650         values.put(Status.QUOTA_TOTAL, 13);
651         int count = mResolver.update(uri, values, null, null);
652         assertEquals(1, count);
653 
654         ContentValues refValues = getTestStatusValues();
655         refValues.put(Status.QUOTA_OCCUPIED, 2);
656         refValues.put(Status.QUOTA_TOTAL, 13);
657         assertStoredValues(uri, refValues);
658     }
659 
testStatusQuotaUpsert()660     public void testStatusQuotaUpsert() {
661         Uri uri = insertTestStatusEntry();
662         ContentValues values = new ContentValues();
663         values.put(Status.SOURCE_PACKAGE, mActor.packageName);
664         values.put(Status.QUOTA_OCCUPIED, 2);
665         int count = mResolver.update(uri, values, null, null);
666 
667         ContentValues values2 = new ContentValues();
668         values2.put(Status.QUOTA_TOTAL, 13);
669         mResolver.insert(uri, values2);
670 
671         ContentValues refValues = getTestStatusValues();
672         refValues.put(Status.QUOTA_OCCUPIED, 2);
673         refValues.put(Status.QUOTA_TOTAL, 13);
674         assertStoredValues(uri, refValues);
675     }
676 
testStatusGetType()677     public void testStatusGetType() throws Exception {
678         // Item URI.
679         Uri uri = insertTestStatusEntry();
680         assertEquals(Status.ITEM_TYPE, mResolver.getType(uri));
681 
682         // base URIs.
683         assertEquals(Status.DIR_TYPE, mResolver.getType(Status.CONTENT_URI));
684         assertEquals(Status.DIR_TYPE, mResolver.getType(Status.buildSourceUri("foo")));
685     }
686 
687     // Basic permission checks for the status table.
testStatusPermissions()688     public void testStatusPermissions() throws Exception {
689         final ContentValues values = getTestStatusValues();
690         // Inserting for another package should fail with any of the URIs.
691         values.put(Status.SOURCE_PACKAGE, "another.package");
692         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
693             @Override
694             public void run() {
695                 mResolver.insert(Status.CONTENT_URI, values);
696             }
697         });
698         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
699             @Override
700             public void run() {
701                 mResolver.insert(Status.buildSourceUri(mActor.packageName), values);
702             }
703         });
704 
705         // But insertion with own package should succeed with the right uri.
706         values.put(Status.SOURCE_PACKAGE, mActor.packageName);
707         final Uri uri = mResolver.insert(Status.buildSourceUri(mActor.packageName), values);
708         assertNotNull(uri);
709 
710         // Updating source_package should not work as well.
711         values.put(Status.SOURCE_PACKAGE, "another.package");
712         EvenMoreAsserts.assertThrows(SecurityException.class, new Runnable() {
713             @Override
714             public void run() {
715                 mResolver.update(uri, values, null, null);
716             }
717         });
718     }
719 
720     // File operation is not supported by /status URI.
testStatusFileOperation()721     public void testStatusFileOperation() throws Exception {
722         final Uri uri = insertTestStatusEntry();
723         EvenMoreAsserts.assertThrows(UnsupportedOperationException.class, new Runnable() {
724             @Override
725             public void run() {
726                 try {
727                     mResolver.openOutputStream(uri);
728                 } catch (FileNotFoundException e) {
729                     fail("Unexpected exception " + e);
730                 }
731             }
732         });
733 
734         EvenMoreAsserts.assertThrows(UnsupportedOperationException.class, new Runnable() {
735             @Override
736             public void run() {
737                 try {
738                     mResolver.openInputStream(uri);
739                 } catch (FileNotFoundException e) {
740                     fail("Unexpected exception " + e);
741                 }
742             }
743         });
744     }
745 
746     /**
747      * Inserts a voicemail record with no source package set. The content provider
748      * will detect source package.
749      */
insertVoicemail()750     private Uri insertVoicemail() {
751         return mResolver.insert(voicemailUri(), getTestVoicemailValues());
752     }
753 
754     /** Inserts a voicemail record for the specified source package. */
insertVoicemailForSourcePackage(String sourcePackage)755     private Uri insertVoicemailForSourcePackage(String sourcePackage) {
756         ContentValues values = getTestVoicemailValues();
757         values.put(Voicemails.SOURCE_PACKAGE, sourcePackage);
758         return mResolver.insert(voicemailUri(), values);
759     }
760 
getTestVoicemailValues()761     private ContentValues getTestVoicemailValues() {
762         ContentValues values = new ContentValues();
763         values.put(Voicemails.NUMBER, "1-800-4664-411");
764         values.put(Voicemails.DATE, 1000);
765         values.put(Voicemails.DURATION, 30);
766         values.put(Voicemails.TRANSCRIPTION, "Testing 123");
767         values.put(Voicemails.IS_READ, 0);
768         values.put(Voicemails.HAS_CONTENT, 0);
769         values.put(Voicemails.SOURCE_DATA, "1234");
770         values.put(Voicemails.STATE, Voicemails.STATE_INBOX);
771         values.put(Voicemails.BACKED_UP, 0);
772         values.put(Voicemails.RESTORED, 0);
773         values.put(Voicemails.ARCHIVED, 0);
774         values.put(Voicemails.IS_OMTP_VOICEMAIL, 0);
775         return values;
776     }
777 
getTestReadVoicemailValues()778     private ContentValues getTestReadVoicemailValues() {
779         ContentValues values = getTestVoicemailValues();
780         values.put(Voicemails.IS_READ, 1);
781         return values;
782     }
783 
insertTestStatusEntry()784     private Uri insertTestStatusEntry() {
785         return mResolver.insert(statusUri(), getTestStatusValues());
786     }
787 
getTestStatusValues()788     private ContentValues getTestStatusValues() {
789         ContentValues values = new ContentValues();
790         values.put(Status.SOURCE_PACKAGE, mActor.packageName);
791         values.put(Status.VOICEMAIL_ACCESS_URI, "tel:901");
792         values.put(Status.SETTINGS_URI, "com.example.voicemail.source.SettingsActivity");
793         values.put(Status.CONFIGURATION_STATE, Status.CONFIGURATION_STATE_OK);
794         values.put(Status.DATA_CHANNEL_STATE, Status.DATA_CHANNEL_STATE_OK);
795         values.put(Status.NOTIFICATION_CHANNEL_STATE, Status.NOTIFICATION_CHANNEL_STATE_OK);
796         values.put(Status.SOURCE_TYPE, "vvm_type_test");
797         return values;
798     }
799 
800 }
801