1 /*
2  * Copyright (C) 2023 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.scopedstorage.cts.lib;
18 
19 import static android.provider.MediaStore.VOLUME_EXTERNAL;
20 import static android.scopedstorage.cts.lib.TestUtils.getImageContentUri;
21 import static android.scopedstorage.cts.lib.TestUtils.getVideoContentUri;
22 
23 import static com.google.common.truth.Truth.assertThat;
24 
25 import static org.junit.Assert.fail;
26 
27 import android.content.ContentResolver;
28 import android.content.ContentValues;
29 import android.database.Cursor;
30 import android.net.Uri;
31 import android.os.ParcelFileDescriptor;
32 import android.provider.MediaStore;
33 import android.util.Size;
34 
35 import java.io.File;
36 import java.util.HashSet;
37 import java.util.Set;
38 import java.util.stream.Collectors;
39 
40 /**
41  * Utility class to test media access using the Content Resolver API.
42  *
43  * Its twin class {@link FilePathAccessTestUtils } covers testing using the file system.
44  */
45 public class ResolverAccessTestUtils {
46     // Similar logic also found in ResultsAssertionUtils
assertResolver_readWrite(Uri uri, ContentResolver resolver)47     public static void assertResolver_readWrite(Uri uri, ContentResolver resolver)
48             throws Exception {
49         try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "rw")) {
50             assertThat(pfd).isNotNull();
51         }
52     }
53 
assertResolver_noReadNoWrite(Uri uri, ContentResolver resolver)54     public static void assertResolver_noReadNoWrite(Uri uri, ContentResolver resolver)
55             throws Exception {
56         assertResolver_noRead(uri, resolver);
57         assertResolver_noWrite(uri, resolver);
58     }
59 
assertResolver_noRead(Uri uri, ContentResolver resolver)60     public static void assertResolver_noRead(Uri uri, ContentResolver resolver) throws Exception {
61         try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r")) {
62             fail("Should not grant read access to uri " + uri.toString());
63         } catch (SecurityException expected) {
64             // Success
65         }
66     }
67 
assertResolver_noWrite(Uri uri, ContentResolver resolver)68     public static void assertResolver_noWrite(Uri uri, ContentResolver resolver) throws Exception {
69         try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "w")) {
70             fail("Should not grant write access to uri " + uri.toString());
71         } catch (SecurityException expected) {
72             // Success
73         }
74     }
75 
assertResolver_readOnly(Uri uri, ContentResolver resolver)76     public static void assertResolver_readOnly(Uri uri, ContentResolver resolver) throws Exception {
77         try (ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r")) {
78             assertThat(pfd).isNotNull();
79         }
80         assertResolver_noWrite(uri, resolver);
81     }
82 
assertResolver_canReadThumbnail(Uri uri, ContentResolver resolver)83     public static void assertResolver_canReadThumbnail(Uri uri, ContentResolver resolver)
84             throws Exception {
85         assertThat(resolver.loadThumbnail(uri, new Size(32, 32), null)).isNotNull();
86     }
87 
assertResolver_cannotReadThumbnail(Uri uri, ContentResolver resolver)88     public static void assertResolver_cannotReadThumbnail(Uri uri, ContentResolver resolver)
89             throws Exception {
90         assertThat(resolver.loadThumbnail(uri, new Size(32, 32), null)).isNull();
91     }
92 
93     /**
94      * Checks that specific files are visible and others are not in a given folder
95      */
assertResolver_listFiles(String dir, Set<File> expected, Set<File> notExpected, ContentResolver resolver)96     public static void assertResolver_listFiles(String dir, Set<File> expected,
97             Set<File> notExpected, ContentResolver resolver) {
98         final String[] projection = new String[]{
99                 MediaStore.Files.FileColumns.DISPLAY_NAME};
100         try (Cursor cursor = resolver.query(MediaStore.Files.getContentUri(VOLUME_EXTERNAL),
101                 projection,
102                 MediaStore.Files.FileColumns.RELATIVE_PATH + " LIKE ?", new String[]{
103                         dir + "%"}, null)) {
104             assertThat(collectFromCursor(cursor)).containsAtLeastElementsIn(
105                     expected.stream().map(File::getName).collect(
106                             Collectors.toSet()));
107             assertThat(collectFromCursor(cursor)).doesNotContain(
108                     notExpected.stream().map(File::getName).collect(
109                             Collectors.toSet()));
110         }
111     }
112 
collectFromCursor(Cursor cursor)113     private static Set<String> collectFromCursor(Cursor cursor) {
114         Set<String> result = new HashSet<>();
115         boolean hasMore = cursor.moveToFirst();
116         while (hasMore) {
117             result.add(cursor.getString(0));
118             hasMore = cursor.moveToNext();
119         }
120         return result;
121     }
122 
assertResolver_uriIsFavorite(Uri uri, ContentResolver resolver)123     public static void assertResolver_uriIsFavorite(Uri uri, ContentResolver resolver) {
124         assertThat(getFavorite(uri, resolver)).isEqualTo("1");
125     }
126 
assertResolver_uriIsNotFavorite(Uri uri, ContentResolver resolver)127     public static void assertResolver_uriIsNotFavorite(Uri uri, ContentResolver resolver) {
128         assertThat(getFavorite(uri, resolver)).isEqualTo("0");
129     }
130 
getFavorite(Uri uri, ContentResolver resolver)131     private static String getFavorite(Uri uri, ContentResolver resolver) {
132         try (Cursor c = resolver.query(uri, new String[]{MediaStore.MediaColumns.IS_FAVORITE},
133                 null, null)) {
134             assertThat(c.getCount()).isEqualTo(1);
135             assertThat(c.moveToFirst()).isTrue();
136             return c.getString(0);
137         }
138     }
139 
assertResolver_uriDoesNotExist(Uri uri, ContentResolver resolver)140     public static void assertResolver_uriDoesNotExist(Uri uri, ContentResolver resolver) {
141         try (Cursor c = resolver.query(uri, null,
142                 null, null)) {
143             assertThat(c.getCount()).isEqualTo(0);
144         }
145     }
146 
assertResolver_insert(String file, String folder, Uri tableUri, ContentResolver contentResolver)147     public static Uri assertResolver_insert(String file, String folder, Uri tableUri,
148             ContentResolver contentResolver) {
149         ContentValues values = new ContentValues();
150         values.put(MediaStore.MediaColumns.RELATIVE_PATH, folder);
151         values.put(MediaStore.MediaColumns.DISPLAY_NAME, file);
152         Uri uri = contentResolver.insert(tableUri, values, null);
153         assertThat(uri).isNotNull();
154         return uri;
155     }
156 
assertResolver_insertImage(String file, String folder, ContentResolver contentResolver)157     public static Uri assertResolver_insertImage(String file, String folder,
158             ContentResolver contentResolver) {
159         return assertResolver_insert(file, folder, getImageContentUri(), contentResolver);
160     }
161 
assertResolver_insertVideo(String file, String folder, ContentResolver contentResolver)162     public static Uri assertResolver_insertVideo(String file, String folder,
163             ContentResolver contentResolver) {
164         return assertResolver_insert(file, folder, getVideoContentUri(), contentResolver);
165     }
166 }
167