Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e374476 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Adjust policy for "stale" volumes outside module.

We're not ready to commit to VolumeRecord in an API surface, so the
next best choice we have is to place the logic in MediaStore, which
is outside the Mainline module boundary.

This also has the benefit of giving partners control over exactly
what policy they want to use for expiring stale volumes.

Bug: 137890034
Test: atest --test-mapping packages/providers/MediaProvider
Change-Id: I677e4bfa6d08e32775e02c323debbaa90acf632b
parent 30fa0b89
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -6980,6 +6980,11 @@ package android.provider {
    field public static final int FLAG_REMOVABLE_USB = 524288; // 0x80000
  }
  public final class MediaStore {
    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Set<java.lang.String> getRecentExternalVolumeNames(@NonNull android.content.Context);
    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException;
  }
  public abstract class SearchIndexableData {
    ctor public SearchIndexableData();
    ctor public SearchIndexableData(android.content.Context);
+1 −1
Original line number Diff line number Diff line
@@ -2455,7 +2455,7 @@ package android.provider {
    method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static void deleteContributedMedia(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
    method @RequiresPermission(android.Manifest.permission.CLEAR_APP_USER_DATA) public static long getContributedMediaSize(android.content.Context, String, android.os.UserHandle) throws java.io.IOException;
    method @NonNull public static java.io.File getVolumePath(@NonNull String) throws java.io.FileNotFoundException;
    method @NonNull public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException;
    method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public static java.util.Collection<java.io.File> getVolumeScanPaths(@NonNull String) throws java.io.FileNotFoundException;
    method public static android.net.Uri scanFile(android.content.Context, java.io.File);
    method public static android.net.Uri scanFileFromShell(android.content.Context, java.io.File);
    method public static void scanVolume(android.content.Context, java.io.File);
+41 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.Activity;
@@ -62,6 +63,7 @@ import android.os.UserManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
import android.service.media.CameraPrewarmService;
import android.text.TextUtils;
import android.text.format.DateUtils;
@@ -3602,6 +3604,43 @@ public final class MediaStore {
        return volumeNames;
    }

    /**
     * Return list of all specific volume names that have recently been part of
     * {@link #VOLUME_EXTERNAL}.
     * <p>
     * This includes both currently mounted volumes <em>and</em> recently
     * mounted (but currently unmounted) volumes. Any indexed metadata for these
     * volumes is preserved to optimize the speed of remounting at a later time.
     *
     * @hide
     */
    @SystemApi
    @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE)
    public static @NonNull Set<String> getRecentExternalVolumeNames(@NonNull Context context) {
        final StorageManager sm = context.getSystemService(StorageManager.class);

        // We always have primary storage
        final Set<String> volumeNames = new ArraySet<>();
        volumeNames.add(VOLUME_EXTERNAL_PRIMARY);

        final long lastWeek = System.currentTimeMillis() - DateUtils.WEEK_IN_MILLIS;
        for (VolumeRecord rec : sm.getVolumeRecords()) {
            // Skip volumes without valid UUIDs
            if (TextUtils.isEmpty(rec.fsUuid)) continue;

            final VolumeInfo vi = sm.findVolumeByUuid(rec.fsUuid);
            if (vi != null && vi.isVisibleForUser(UserHandle.myUserId())
                    && vi.isMountedReadable()) {
                // We're mounted right now
                volumeNames.add(rec.getNormalizedFsUuid());
            } else if (rec.lastSeenMillis > 0 && rec.lastSeenMillis < lastWeek) {
                // We're not mounted right now, but we've been seen recently
                volumeNames.add(rec.getNormalizedFsUuid());
            }
        }
        return volumeNames;
    }

    /**
     * Return the volume name that the given {@link Uri} references.
     */
@@ -3701,6 +3740,8 @@ public final class MediaStore {
     * @hide
     */
    @TestApi
    @SystemApi
    @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE)
    public static @NonNull Collection<File> getVolumeScanPaths(@NonNull String volumeName)
            throws FileNotFoundException {
        if (TextUtils.isEmpty(volumeName)) {