Loading core/java/android/app/ApplicationPackageManager.java +57 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,8 @@ import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.util.ArrayMap; import android.util.Log; import android.view.Display; Loading Loading @@ -1426,6 +1428,61 @@ final class ApplicationPackageManager extends PackageManager { } } @Override public @NonNull VolumeInfo getApplicationCurrentVolume(ApplicationInfo app) { final StorageManager storage = mContext.getSystemService(StorageManager.class); if (app.isInternal()) { return Preconditions.checkNotNull( storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL)); } else if (app.isExternalAsec()) { final List<VolumeInfo> vols = storage.getVolumes(); for (VolumeInfo vol : vols) { if ((vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isPrimary()) { return vol; } } throw new IllegalStateException("Failed to find primary public volume"); } else { return Preconditions.checkNotNull(storage.findVolumeByUuid(app.volumeUuid)); } } @Override public @NonNull List<VolumeInfo> getApplicationCandidateVolumes(ApplicationInfo app) { final StorageManager storage = mContext.getSystemService(StorageManager.class); final List<VolumeInfo> vols = storage.getVolumes(); final List<VolumeInfo> candidates = new ArrayList<>(); for (VolumeInfo vol : vols) { if (isCandidateVolume(app, vol)) { candidates.add(vol); } } return candidates; } private static boolean isCandidateVolume(ApplicationInfo app, VolumeInfo vol) { // Private internal is always an option if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.getId())) { return true; } // System apps and apps demanding internal storage can't be moved // anywhere else if (app.isSystemApp() || app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { return false; } // Moving into an ASEC on public primary is only an option when app is // internal, or already in ASEC if ((vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isPrimary()) { return app.isInternal() || app.isExternalAsec(); } // Otherwise we can move to any private volume return (vol.getType() == VolumeInfo.TYPE_PRIVATE); } @Override public String getInstallerPackageName(String packageName) { try { Loading core/java/android/content/pm/ApplicationInfo.java +12 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.Printer; import com.android.internal.util.ArrayUtils; Loading Loading @@ -937,6 +938,17 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } /** @hide */ public boolean isInternal() { return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0; } /** @hide */ public boolean isExternalAsec() { return TextUtils.isEmpty(volumeUuid) && (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } /** * @hide */ Loading core/java/android/content/pm/PackageManager.java +7 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.CheckResult; import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.StringRes; Loading Loading @@ -4162,6 +4163,12 @@ public abstract class PackageManager { public abstract void movePackageAndData(String packageName, String volumeUuid, IPackageMoveObserver observer); /** {@hide} */ public abstract @Nullable VolumeInfo getApplicationCurrentVolume(ApplicationInfo app); /** {@hide} */ public abstract @NonNull List<VolumeInfo> getApplicationCandidateVolumes(ApplicationInfo app); /** * Returns the device identity that verifiers can use to associate their scheme to a particular * device. This should not be used by anything other than a package verifier. Loading core/java/android/os/storage/DiskInfo.java +15 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import java.io.CharArrayWriter; import java.util.Objects; /** * Information about a physical disk which may contain one or more Loading Loading @@ -118,6 +119,20 @@ public class DiskInfo implements Parcelable { } } @Override public boolean equals(Object o) { if (o instanceof DiskInfo) { return Objects.equals(id, ((DiskInfo) o).id); } else { return false; } } @Override public int hashCode() { return id.hashCode(); } public static final Creator<DiskInfo> CREATOR = new Creator<DiskInfo>() { @Override public DiskInfo createFromParcel(Parcel in) { Loading core/java/android/os/storage/VolumeInfo.java +36 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ import com.android.internal.util.Preconditions; import java.io.CharArrayWriter; import java.io.File; import java.util.Comparator; import java.util.Objects; /** * Information about a storage volume that may be mounted. A volume may be a Loading Loading @@ -77,6 +79,22 @@ public class VolumeInfo implements Parcelable { private static SparseArray<String> sStateToEnvironment = new SparseArray<>(); private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>(); private static final Comparator<VolumeInfo> sDescriptionComparator = new Comparator<VolumeInfo>() { @Override public int compare(VolumeInfo lhs, VolumeInfo rhs) { if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(lhs.getId())) { return -1; } else if (lhs.getDescription() == null) { return 1; } else if (rhs.getDescription() == null) { return -1; } else { return lhs.getDescription().compareTo(rhs.getDescription()); } } }; static { sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED); sStateToEnvironment.put(VolumeInfo.STATE_MOUNTING, Environment.MEDIA_CHECKING); Loading Loading @@ -150,6 +168,10 @@ public class VolumeInfo implements Parcelable { return getBroadcastForEnvironment(getEnvironmentForState(state)); } public static @NonNull Comparator<VolumeInfo> getDescriptionComparator() { return sDescriptionComparator; } public @NonNull String getId() { return id; } Loading Loading @@ -344,6 +366,20 @@ public class VolumeInfo implements Parcelable { } } @Override public boolean equals(Object o) { if (o instanceof VolumeInfo) { return Objects.equals(id, ((VolumeInfo) o).id); } else { return false; } } @Override public int hashCode() { return id.hashCode(); } public static final Creator<VolumeInfo> CREATOR = new Creator<VolumeInfo>() { @Override public VolumeInfo createFromParcel(Parcel in) { Loading Loading
core/java/android/app/ApplicationPackageManager.java +57 −0 Original line number Diff line number Diff line Loading @@ -67,6 +67,8 @@ import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.util.ArrayMap; import android.util.Log; import android.view.Display; Loading Loading @@ -1426,6 +1428,61 @@ final class ApplicationPackageManager extends PackageManager { } } @Override public @NonNull VolumeInfo getApplicationCurrentVolume(ApplicationInfo app) { final StorageManager storage = mContext.getSystemService(StorageManager.class); if (app.isInternal()) { return Preconditions.checkNotNull( storage.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL)); } else if (app.isExternalAsec()) { final List<VolumeInfo> vols = storage.getVolumes(); for (VolumeInfo vol : vols) { if ((vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isPrimary()) { return vol; } } throw new IllegalStateException("Failed to find primary public volume"); } else { return Preconditions.checkNotNull(storage.findVolumeByUuid(app.volumeUuid)); } } @Override public @NonNull List<VolumeInfo> getApplicationCandidateVolumes(ApplicationInfo app) { final StorageManager storage = mContext.getSystemService(StorageManager.class); final List<VolumeInfo> vols = storage.getVolumes(); final List<VolumeInfo> candidates = new ArrayList<>(); for (VolumeInfo vol : vols) { if (isCandidateVolume(app, vol)) { candidates.add(vol); } } return candidates; } private static boolean isCandidateVolume(ApplicationInfo app, VolumeInfo vol) { // Private internal is always an option if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(vol.getId())) { return true; } // System apps and apps demanding internal storage can't be moved // anywhere else if (app.isSystemApp() || app.installLocation == PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY) { return false; } // Moving into an ASEC on public primary is only an option when app is // internal, or already in ASEC if ((vol.getType() == VolumeInfo.TYPE_PUBLIC) && vol.isPrimary()) { return app.isInternal() || app.isExternalAsec(); } // Otherwise we can move to any private volume return (vol.getType() == VolumeInfo.TYPE_PRIVATE); } @Override public String getInstallerPackageName(String packageName) { try { Loading
core/java/android/content/pm/ApplicationInfo.java +12 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; import android.util.Printer; import com.android.internal.util.ArrayUtils; Loading Loading @@ -937,6 +938,17 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; } /** @hide */ public boolean isInternal() { return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0; } /** @hide */ public boolean isExternalAsec() { return TextUtils.isEmpty(volumeUuid) && (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; } /** * @hide */ Loading
core/java/android/content/pm/PackageManager.java +7 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.annotation.CheckResult; import android.annotation.DrawableRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.StringRes; Loading Loading @@ -4162,6 +4163,12 @@ public abstract class PackageManager { public abstract void movePackageAndData(String packageName, String volumeUuid, IPackageMoveObserver observer); /** {@hide} */ public abstract @Nullable VolumeInfo getApplicationCurrentVolume(ApplicationInfo app); /** {@hide} */ public abstract @NonNull List<VolumeInfo> getApplicationCandidateVolumes(ApplicationInfo app); /** * Returns the device identity that verifiers can use to associate their scheme to a particular * device. This should not be used by anything other than a package verifier. Loading
core/java/android/os/storage/DiskInfo.java +15 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import java.io.CharArrayWriter; import java.util.Objects; /** * Information about a physical disk which may contain one or more Loading Loading @@ -118,6 +119,20 @@ public class DiskInfo implements Parcelable { } } @Override public boolean equals(Object o) { if (o instanceof DiskInfo) { return Objects.equals(id, ((DiskInfo) o).id); } else { return false; } } @Override public int hashCode() { return id.hashCode(); } public static final Creator<DiskInfo> CREATOR = new Creator<DiskInfo>() { @Override public DiskInfo createFromParcel(Parcel in) { Loading
core/java/android/os/storage/VolumeInfo.java +36 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ import com.android.internal.util.Preconditions; import java.io.CharArrayWriter; import java.io.File; import java.util.Comparator; import java.util.Objects; /** * Information about a storage volume that may be mounted. A volume may be a Loading Loading @@ -77,6 +79,22 @@ public class VolumeInfo implements Parcelable { private static SparseArray<String> sStateToEnvironment = new SparseArray<>(); private static ArrayMap<String, String> sEnvironmentToBroadcast = new ArrayMap<>(); private static final Comparator<VolumeInfo> sDescriptionComparator = new Comparator<VolumeInfo>() { @Override public int compare(VolumeInfo lhs, VolumeInfo rhs) { if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(lhs.getId())) { return -1; } else if (lhs.getDescription() == null) { return 1; } else if (rhs.getDescription() == null) { return -1; } else { return lhs.getDescription().compareTo(rhs.getDescription()); } } }; static { sStateToEnvironment.put(VolumeInfo.STATE_UNMOUNTED, Environment.MEDIA_UNMOUNTED); sStateToEnvironment.put(VolumeInfo.STATE_MOUNTING, Environment.MEDIA_CHECKING); Loading Loading @@ -150,6 +168,10 @@ public class VolumeInfo implements Parcelable { return getBroadcastForEnvironment(getEnvironmentForState(state)); } public static @NonNull Comparator<VolumeInfo> getDescriptionComparator() { return sDescriptionComparator; } public @NonNull String getId() { return id; } Loading Loading @@ -344,6 +366,20 @@ public class VolumeInfo implements Parcelable { } } @Override public boolean equals(Object o) { if (o instanceof VolumeInfo) { return Objects.equals(id, ((VolumeInfo) o).id); } else { return false; } } @Override public int hashCode() { return id.hashCode(); } public static final Creator<VolumeInfo> CREATOR = new Creator<VolumeInfo>() { @Override public VolumeInfo createFromParcel(Parcel in) { Loading