Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2009 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 static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertFalse;
     21 import static org.junit.Assert.assertNotNull;
     22 import static org.junit.Assert.assertTrue;
     23 import static org.junit.Assert.fail;
     24 
     25 import android.app.usage.StorageStatsManager;
     26 import android.content.ContentResolver;
     27 import android.content.ContentUris;
     28 import android.content.Context;
     29 import android.content.res.AssetFileDescriptor;
     30 import android.database.Cursor;
     31 import android.net.Uri;
     32 import android.os.SystemClock;
     33 import android.os.storage.StorageManager;
     34 import android.os.storage.StorageVolume;
     35 import android.platform.test.annotations.Presubmit;
     36 import android.provider.MediaStore;
     37 import android.provider.MediaStore.MediaColumns;
     38 import android.util.Log;
     39 
     40 import androidx.test.InstrumentationRegistry;
     41 
     42 import org.junit.After;
     43 import org.junit.Assume;
     44 import org.junit.Before;
     45 import org.junit.Test;
     46 import org.junit.runner.RunWith;
     47 import org.junit.runners.Parameterized;
     48 import org.junit.runners.Parameterized.Parameter;
     49 import org.junit.runners.Parameterized.Parameters;
     50 
     51 import java.io.File;
     52 import java.util.HashSet;
     53 import java.util.Set;
     54 import java.util.UUID;
     55 
     56 @Presubmit
     57 @RunWith(Parameterized.class)
     58 public class MediaStoreTest {
     59     static final String TAG = "MediaStoreTest";
     60 
     61     private static final long SIZE_DELTA = 32_000;
     62 
     63     private Context mContext;
     64     private ContentResolver mContentResolver;
     65 
     66     private Uri mExternalImages;
     67 
     68     @Parameter(0)
     69     public String mVolumeName;
     70 
     71     @Parameters
     72     public static Iterable<? extends Object> data() {
     73         return ProviderTestUtils.getSharedVolumeNames();
     74     }
     75 
     76     private Context getContext() {
     77         return InstrumentationRegistry.getTargetContext();
     78     }
     79 
     80     @Before
     81     public void setUp() throws Exception {
     82         mContext = InstrumentationRegistry.getTargetContext();
     83         mContentResolver = mContext.getContentResolver();
     84 
     85         Log.d(TAG, "Using volume " + mVolumeName);
     86         mExternalImages = MediaStore.Images.Media.getContentUri(mVolumeName);
     87     }
     88 
     89     @After
     90     public void tearDown() throws Exception {
     91         InstrumentationRegistry.getInstrumentation().getUiAutomation()
     92                 .dropShellPermissionIdentity();
     93     }
     94 
     95     @Test
     96     public void testGetMediaScannerUri() {
     97         // query
     98         Cursor c = mContentResolver.query(MediaStore.getMediaScannerUri(), null,
     99                 null, null, null);
    100         assertEquals(1, c.getCount());
    101         c.close();
    102     }
    103 
    104     @Test
    105     public void testGetVersion() {
    106         // We should have valid versions to help detect data wipes
    107         assertNotNull(MediaStore.getVersion(getContext(), MediaStore.VOLUME_INTERNAL));
    108         assertNotNull(MediaStore.getVersion(getContext(), MediaStore.VOLUME_EXTERNAL));
    109         assertNotNull(MediaStore.getVersion(getContext(), MediaStore.VOLUME_EXTERNAL_PRIMARY));
    110     }
    111 
    112     @Test
    113     public void testGetExternalVolumeNames() {
    114         Set<String> volumeNames = MediaStore.getExternalVolumeNames(getContext());
    115 
    116         assertFalse(volumeNames.contains(MediaStore.VOLUME_INTERNAL));
    117         assertFalse(volumeNames.contains(MediaStore.VOLUME_EXTERNAL));
    118         assertTrue(volumeNames.contains(MediaStore.VOLUME_EXTERNAL_PRIMARY));
    119     }
    120 
    121     @Test
    122     public void testGetStorageVolume() throws Exception {
    123         Assume.assumeFalse(MediaStore.VOLUME_EXTERNAL.equals(mVolumeName));
    124 
    125         final Uri uri = ProviderTestUtils.stageMedia(R.raw.volantis, mExternalImages);
    126 
    127         final StorageManager sm = mContext.getSystemService(StorageManager.class);
    128         final StorageVolume sv = sm.getStorageVolume(uri);
    129 
    130         // We should always have a volume for media we just created
    131         assertNotNull(sv);
    132 
    133         if (MediaStore.VOLUME_EXTERNAL_PRIMARY.equals(mVolumeName)) {
    134             assertEquals(sm.getPrimaryStorageVolume(), sv);
    135         }
    136     }
    137 
    138     @Test
    139     public void testGetStorageVolume_Unrelated() throws Exception {
    140         final StorageManager sm = mContext.getSystemService(StorageManager.class);
    141         try {
    142             sm.getStorageVolume(Uri.parse("content://com.example/path/to/item/"));
    143             fail("getStorageVolume unrelated should throw exception");
    144         } catch (IllegalArgumentException expected) {
    145         }
    146     }
    147 
    148     @Test
    149     public void testContributedMedia() throws Exception {
    150         // STOPSHIP: remove this once isolated storage is always enabled
    151         Assume.assumeTrue(StorageManager.hasIsolatedStorage());
    152         Assume.assumeTrue(MediaStore.VOLUME_EXTERNAL_PRIMARY.equals(mVolumeName));
    153 
    154         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
    155                 android.Manifest.permission.CLEAR_APP_USER_DATA,
    156                 android.Manifest.permission.PACKAGE_USAGE_STATS);
    157 
    158         // Start by cleaning up contributed items
    159         MediaStore.deleteContributedMedia(getContext(), getContext().getPackageName(),
    160                 android.os.Process.myUserHandle());
    161 
    162         // Force sync to try updating other views
    163         ProviderTestUtils.executeShellCommand("sync");
    164         SystemClock.sleep(500);
    165 
    166         // Measure usage before
    167         final long beforePackage = getExternalPackageSize();
    168         final long beforeTotal = getExternalTotalSize();
    169         final long beforeContributed = MediaStore.getContributedMediaSize(getContext(),
    170                 getContext().getPackageName(), android.os.Process.myUserHandle());
    171 
    172         final long stageSize;
    173         try (AssetFileDescriptor fd = getContext().getResources()
    174                 .openRawResourceFd(R.raw.volantis)) {
    175             stageSize = fd.getLength();
    176         }
    177 
    178         // Create media both inside and outside sandbox
    179         final Uri inside;
    180         final Uri outside;
    181         final File file = new File(ProviderTestUtils.stageDir(mVolumeName),
    182                 "cts" + System.nanoTime() + ".jpg");
    183         ProviderTestUtils.stageFile(R.raw.volantis, file);
    184         inside = ProviderTestUtils.scanFileFromShell(file);
    185         outside = ProviderTestUtils.stageMedia(R.raw.volantis, mExternalImages);
    186 
    187         {
    188             final HashSet<Long> visible = getVisibleIds(mExternalImages);
    189             assertTrue(visible.contains(ContentUris.parseId(inside)));
    190             assertTrue(visible.contains(ContentUris.parseId(outside)));
    191 
    192             // Force sync to try updating other views
    193             ProviderTestUtils.executeShellCommand("sync");
    194             SystemClock.sleep(500);
    195 
    196             final long afterPackage = getExternalPackageSize();
    197             final long afterTotal = getExternalTotalSize();
    198             final long afterContributed = MediaStore.getContributedMediaSize(getContext(),
    199                     getContext().getPackageName(), android.os.Process.myUserHandle());
    200 
    201             assertMostlyEquals(beforePackage + stageSize, afterPackage, SIZE_DELTA);
    202             assertMostlyEquals(beforeTotal + stageSize + stageSize, afterTotal, SIZE_DELTA);
    203             assertMostlyEquals(beforeContributed + stageSize, afterContributed, SIZE_DELTA);
    204         }
    205 
    206         // Delete only contributed items
    207         MediaStore.deleteContributedMedia(getContext(), getContext().getPackageName(),
    208                 android.os.Process.myUserHandle());
    209         {
    210             final HashSet<Long> visible = getVisibleIds(mExternalImages);
    211             assertTrue(visible.contains(ContentUris.parseId(inside)));
    212             assertFalse(visible.contains(ContentUris.parseId(outside)));
    213 
    214             // Force sync to try updating other views
    215             ProviderTestUtils.executeShellCommand("sync");
    216             SystemClock.sleep(500);
    217 
    218             final long afterPackage = getExternalPackageSize();
    219             final long afterTotal = getExternalTotalSize();
    220             final long afterContributed = MediaStore.getContributedMediaSize(getContext(),
    221                     getContext().getPackageName(), android.os.Process.myUserHandle());
    222 
    223             assertMostlyEquals(beforePackage + stageSize, afterPackage, SIZE_DELTA);
    224             assertMostlyEquals(beforeTotal + stageSize, afterTotal, SIZE_DELTA);
    225             assertMostlyEquals(0, afterContributed, SIZE_DELTA);
    226         }
    227     }
    228 
    229     private long getExternalPackageSize() throws Exception {
    230         final StorageManager storage = getContext().getSystemService(StorageManager.class);
    231         final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class);
    232 
    233         final UUID externalUuid = storage.getUuidForPath(MediaStore.getVolumePath(mVolumeName));
    234         return stats.queryStatsForPackage(externalUuid, getContext().getPackageName(),
    235                 android.os.Process.myUserHandle()).getDataBytes();
    236     }
    237 
    238     private long getExternalTotalSize() throws Exception {
    239         final StorageManager storage = getContext().getSystemService(StorageManager.class);
    240         final StorageStatsManager stats = getContext().getSystemService(StorageStatsManager.class);
    241 
    242         final UUID externalUuid = storage.getUuidForPath(MediaStore.getVolumePath(mVolumeName));
    243         return stats.queryExternalStatsForUser(externalUuid, android.os.Process.myUserHandle())
    244                 .getTotalBytes();
    245     }
    246 
    247     private HashSet<Long> getVisibleIds(Uri collectionUri) {
    248         final HashSet<Long> res = new HashSet<>();
    249         try (Cursor c = mContentResolver.query(collectionUri,
    250                 new String[] { MediaColumns._ID }, null, null)) {
    251             while (c.moveToNext()) {
    252                 res.add(c.getLong(0));
    253             }
    254         }
    255         return res;
    256     }
    257 
    258     private static void assertMostlyEquals(long expected, long actual, long delta) {
    259         if (Math.abs(expected - actual) > delta) {
    260             fail("Expected roughly " + expected + " but was " + actual);
    261         }
    262     }
    263 }
    264