diff options
| author | 2024-01-08 18:54:00 +0000 | |
|---|---|---|
| committer | 2024-01-22 17:03:42 +0000 | |
| commit | 29c03843205eb5fade3e6ff5dc2f35ae89d9e581 (patch) | |
| tree | 80b3d036e6e1505d9f75e09be347a1e89cb42434 | |
| parent | b431dc66d417d306d6a8d8fae40d54147b921e67 (diff) | |
Adjust reportUnarchivalStatus API based on API council comments.
Test: PackageInstallerArchiveTest
Bug: 314960798
Change-Id: Icc91bc01a759f1df99d93f104b2bc93d7b0d7241
| -rw-r--r-- | core/api/current.txt | 9 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageInstaller.java | 206 |
2 files changed, 212 insertions, 3 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 0e413c41a64a..61219644a224 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12448,6 +12448,7 @@ package android.content.pm { method @NonNull public android.content.pm.PackageInstaller.Session openSession(int) throws java.io.IOException; method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback); method public void registerSessionCallback(@NonNull android.content.pm.PackageInstaller.SessionCallback, @NonNull android.os.Handler); + method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public void reportUnarchivalState(@NonNull android.content.pm.PackageInstaller.UnarchivalState) throws android.content.pm.PackageManager.NameNotFoundException; method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public void reportUnarchivalStatus(int, int, long, @Nullable android.app.PendingIntent) throws android.content.pm.PackageManager.NameNotFoundException; method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void requestArchive(@NonNull String, @NonNull android.content.IntentSender) throws android.content.pm.PackageManager.NameNotFoundException; method @FlaggedApi("android.content.pm.archiving") @RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES, android.Manifest.permission.REQUEST_INSTALL_PACKAGES}) public void requestUnarchive(@NonNull String, @NonNull android.content.IntentSender) throws java.io.IOException, android.content.pm.PackageManager.NameNotFoundException; @@ -12677,6 +12678,14 @@ package android.content.pm { field public static final int USER_ACTION_UNSPECIFIED = 0; // 0x0 } + @FlaggedApi("android.content.pm.archiving") public static final class PackageInstaller.UnarchivalState { + method @NonNull public static android.content.pm.PackageInstaller.UnarchivalState createGenericErrorState(int); + method @NonNull public static android.content.pm.PackageInstaller.UnarchivalState createInsufficientStorageState(int, long, @Nullable android.app.PendingIntent); + method @NonNull public static android.content.pm.PackageInstaller.UnarchivalState createNoConnectivityState(int); + method @NonNull public static android.content.pm.PackageInstaller.UnarchivalState createOkState(int); + method @NonNull public static android.content.pm.PackageInstaller.UnarchivalState createUserActionRequiredState(int, @NonNull android.app.PendingIntent); + } + public class PackageItemInfo { ctor public PackageItemInfo(); ctor public PackageItemInfo(android.content.pm.PackageItemInfo); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index f0efed97d8ed..e7b304622abd 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -738,7 +738,7 @@ public class PackageInstaller { /** * The set of error types that can be set for - * {@link #reportUnarchivalStatus(int, int, PendingIntent)}. + * {@link #reportUnarchivalState}. * * @hide */ @@ -2421,6 +2421,7 @@ public class PackageInstaller { * facilitate the unarchival flow (e.g. user needs to log in). * @throws PackageManager.NameNotFoundException if no unarchival with {@code unarchiveId} exists */ + // TODO(b/314960798) Remove old API once it's unused @RequiresPermission(anyOf = { Manifest.permission.INSTALL_PACKAGES, Manifest.permission.REQUEST_INSTALL_PACKAGES}) @@ -2438,6 +2439,30 @@ public class PackageInstaller { } } + /** + * Reports the state of an unarchival to the system. + * + * @see UnarchivalState for the different state options. + * @throws PackageManager.NameNotFoundException if no unarchival with {@code unarchiveId} exists + */ + @RequiresPermission(anyOf = { + Manifest.permission.INSTALL_PACKAGES, + Manifest.permission.REQUEST_INSTALL_PACKAGES}) + @FlaggedApi(Flags.FLAG_ARCHIVING) + public void reportUnarchivalState(@NonNull UnarchivalState unarchivalState) + throws PackageManager.NameNotFoundException { + Objects.requireNonNull(unarchivalState); + try { + mInstaller.reportUnarchivalStatus(unarchivalState.getUnarchiveId(), + unarchivalState.getStatus(), unarchivalState.getRequiredStorageBytes(), + unarchivalState.getUserActionIntent(), new UserHandle(mUserId)); + } catch (ParcelableException e) { + e.maybeRethrow(PackageManager.NameNotFoundException.class); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + // (b/239722738) This class serves as a bridge between the PackageLite class, which // is a hidden class, and the consumers of this class. (e.g. InstallInstalling.java) // This is a part of an effort to remove dependency on hidden APIs and use SystemAPIs or @@ -4708,10 +4733,10 @@ public class PackageInstaller { codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java", inputSignatures = "private final @android.annotation.Nullable android.graphics.Bitmap mIcon\nprivate final @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate final @android.annotation.NonNull android.icu.util.ULocale mLocale\nprivate final @android.annotation.NonNull java.lang.String mPackageName\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.PackageInstaller.PreapprovalDetails> CREATOR\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\npublic @java.lang.Override int describeContents()\nclass PreapprovalDetails extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.Nullable android.graphics.Bitmap mIcon\nprivate @android.annotation.NonNull java.lang.CharSequence mLabel\nprivate @android.annotation.NonNull android.icu.util.ULocale mLocale\nprivate @android.annotation.NonNull java.lang.String mPackageName\nprivate long mBuilderFieldsSet\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setIcon(android.graphics.Bitmap)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setLabel(java.lang.CharSequence)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setLocale(android.icu.util.ULocale)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails.Builder setPackageName(java.lang.String)\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.PreapprovalDetails build()\nprivate void checkNotUsed()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genToString=true)") + @Deprecated private void __metadata() {} - //@formatter:on // End of generated code @@ -5102,13 +5127,188 @@ public class PackageInstaller { codegenVersion = "1.0.23", sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java", inputSignatures = "public static final @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints GENTLE_UPDATE\nprivate final boolean mDeviceIdleRequired\nprivate final boolean mAppNotForegroundRequired\nprivate final boolean mAppNotInteractingRequired\nprivate final boolean mAppNotTopVisibleRequired\nprivate final boolean mNotInCallRequired\nclass InstallConstraints extends java.lang.Object implements [android.os.Parcelable]\nprivate boolean mDeviceIdleRequired\nprivate boolean mAppNotForegroundRequired\nprivate boolean mAppNotInteractingRequired\nprivate boolean mAppNotTopVisibleRequired\nprivate boolean mNotInCallRequired\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setDeviceIdleRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setAppNotForegroundRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setAppNotInteractingRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setAppNotTopVisibleRequired()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder setNotInCallRequired()\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints build()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genParcelable=true, genHiddenConstructor=true, genEqualsHashCode=true)") + @Deprecated private void __metadata() {} - //@formatter:on // End of generated code } + /** + * Used to communicate the unarchival state in {@link #reportUnarchivalState}. + */ + @FlaggedApi(Flags.FLAG_ARCHIVING) + public static final class UnarchivalState { + + /** + * The caller is able to facilitate the unarchival for the given {@code unarchiveId}. + * + * @param unarchiveId the ID provided by the system as part of the intent.action.UNARCHIVE + * broadcast with EXTRA_UNARCHIVE_ID. + */ + @NonNull + public static UnarchivalState createOkState(int unarchiveId) { + return new UnarchivalState(unarchiveId, UNARCHIVAL_OK, /* requiredStorageBytes= */ -1, + /* userActionIntent= */ null); + } + + /** + * User action is required before commencing with the unarchival for the given + * {@code unarchiveId}. E.g., this could be used if it's necessary for the user to sign-in + * first. + * + * @param unarchiveId the ID provided by the system as part of the + * intent.action.UNARCHIVE + * broadcast with EXTRA_UNARCHIVE_ID. + * @param userActionIntent optional intent to start a follow up action required to + * facilitate the unarchival flow (e.g. user needs to log in). + */ + @NonNull + public static UnarchivalState createUserActionRequiredState(int unarchiveId, + @NonNull PendingIntent userActionIntent) { + Objects.requireNonNull(userActionIntent); + return new UnarchivalState(unarchiveId, UNARCHIVAL_ERROR_USER_ACTION_NEEDED, + /* requiredStorageBytes= */ -1, userActionIntent); + } + + /** + * There is not enough storage to start the unarchival for the given {@code unarchiveId}. + * + * @param unarchiveId the ID provided by the system as part of the + * intent.action.UNARCHIVE + * broadcast with EXTRA_UNARCHIVE_ID. + * @param requiredStorageBytes ff the error is UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE this + * field should be set to specify how many additional bytes of + * storage are required to unarchive the app. + * @param userActionIntent can optionally be set to provide a custom storage-clearing + * action. + */ + @NonNull + public static UnarchivalState createInsufficientStorageState(int unarchiveId, + long requiredStorageBytes, @Nullable PendingIntent userActionIntent) { + return new UnarchivalState(unarchiveId, UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE, + requiredStorageBytes, userActionIntent); + } + + /** + * The device has no data connectivity and unarchival cannot be started for the given + * {@code unarchiveId}. + * + * @param unarchiveId the ID provided by the system as part of the intent.action.UNARCHIVE + * broadcast with EXTRA_UNARCHIVE_ID. + */ + @NonNull + public static UnarchivalState createNoConnectivityState(int unarchiveId) { + return new UnarchivalState(unarchiveId, UNARCHIVAL_ERROR_NO_CONNECTIVITY, + /* requiredStorageBytes= */ -1,/* userActionIntent= */ null); + } + + /** + * Generic error state for all cases that are not covered by other methods in this class. + * + * @param unarchiveId the ID provided by the system as part of the intent.action.UNARCHIVE + * broadcast with EXTRA_UNARCHIVE_ID. + */ + @NonNull + public static UnarchivalState createGenericErrorState(int unarchiveId) { + return new UnarchivalState(unarchiveId, UNARCHIVAL_GENERIC_ERROR, + /* requiredStorageBytes= */ -1,/* userActionIntent= */ null); + } + + + /** + * The ID provided by the system as part of the intent.action.UNARCHIVE broadcast with + * EXTRA_UNARCHIVE_ID. + */ + private final int mUnarchiveId; + + /** Used for the system to provide the user with necessary follow-up steps or errors. */ + @UnarchivalStatus + private final int mStatus; + + /** + * If the error is UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE this field should be set to specify + * how many additional bytes of storage are required to unarchive the app. + */ + private final long mRequiredStorageBytes; + + /** + * Optional intent to start a follow up action required to facilitate the unarchival flow + * (e.g., user needs to log in). + */ + @Nullable + private final PendingIntent mUserActionIntent; + + /** + * Creates a new UnarchivalState. + * + * @param unarchiveId The ID provided by the system as part of the + * intent.action.UNARCHIVE broadcast with + * EXTRA_UNARCHIVE_ID. + * @param status Used for the system to provide the user with necessary + * follow-up steps or errors. + * @param requiredStorageBytes If the error is UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE this + * field should be set to specify + * how many additional bytes of storage are required to + * unarchive the app. + * @param userActionIntent Optional intent to start a follow up action required to + * facilitate the unarchival flow + * (e.g,. user needs to log in). + * @hide + */ + private UnarchivalState( + int unarchiveId, + @UnarchivalStatus int status, + long requiredStorageBytes, + @Nullable PendingIntent userActionIntent) { + this.mUnarchiveId = unarchiveId; + this.mStatus = status; + com.android.internal.util.AnnotationValidations.validate( + UnarchivalStatus.class, null, mStatus); + this.mRequiredStorageBytes = requiredStorageBytes; + this.mUserActionIntent = userActionIntent; + } + + /** + * The ID provided by the system as part of the intent.action.UNARCHIVE broadcast with + * EXTRA_UNARCHIVE_ID. + * + * @hide + */ + int getUnarchiveId() { + return mUnarchiveId; + } + + /** + * Used for the system to provide the user with necessary follow-up steps or errors. + * + * @hide + */ + @UnarchivalStatus int getStatus() { + return mStatus; + } + + /** + * If the error is UNARCHIVAL_ERROR_INSUFFICIENT_STORAGE this field should be set to specify + * how many additional bytes of storage are required to unarchive the app. + * + * @hide + */ + long getRequiredStorageBytes() { + return mRequiredStorageBytes; + } + + /** + * Optional intent to start a follow up action required to facilitate the unarchival flow + * (e.g. user needs to log in). + * + * @hide + */ + @Nullable PendingIntent getUserActionIntent() { + return mUserActionIntent; + } + } + } |