diff options
11 files changed, 103 insertions, 28 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index bbdb0a19adde..9785da34accf 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12428,7 +12428,7 @@ package android.content.pm { 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 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.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void requestArchive(@NonNull String, @NonNull android.content.IntentSender, int) 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; method @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void uninstall(@NonNull String, @NonNull android.content.IntentSender); method @RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES, android.Manifest.permission.REQUEST_DELETE_PACKAGES}) public void uninstall(@NonNull android.content.pm.VersionedPackage, @NonNull android.content.IntentSender); @@ -12853,6 +12853,8 @@ package android.content.pm { field public static final int COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED = 4; // 0x4 field public static final int COMPONENT_ENABLED_STATE_DISABLED_USER = 3; // 0x3 field public static final int COMPONENT_ENABLED_STATE_ENABLED = 1; // 0x1 + field @FlaggedApi("android.content.pm.archiving") public static final int DELETE_ARCHIVE = 16; // 0x10 + field @FlaggedApi("android.content.pm.archiving") public static final int DELETE_SHOW_DIALOG = 32; // 0x20 field public static final int DONT_KILL_APP = 1; // 0x1 field public static final String EXTRA_VERIFICATION_ID = "android.content.pm.extra.VERIFICATION_ID"; field public static final String EXTRA_VERIFICATION_RESULT = "android.content.pm.extra.VERIFICATION_RESULT"; diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 847edd13bb05..792310e44bfc 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -3872,6 +3872,7 @@ package android.content.pm { field public static final int DATA_LOADER_TYPE_STREAMING = 1; // 0x1 field public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK"; field public static final String EXTRA_DATA_LOADER_TYPE = "android.content.pm.extra.DATA_LOADER_TYPE"; + field @FlaggedApi("android.content.pm.archiving") public static final String EXTRA_DELETE_FLAGS = "android.content.pm.extra.DELETE_FLAGS"; field public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS"; field @Deprecated public static final String EXTRA_RESOLVED_BASE_PATH = "android.content.pm.extra.RESOLVED_BASE_PATH"; field public static final int LOCATION_DATA_APP = 0; // 0x0 diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 1f25fd039dd8..32ecb58ce241 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -80,7 +80,7 @@ interface IPackageInstaller { long timeout); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.DELETE_PACKAGES,android.Manifest.permission.REQUEST_DELETE_PACKAGES})") - void requestArchive(String packageName, String callerPackageName, in IntentSender statusReceiver, in UserHandle userHandle); + void requestArchive(String packageName, String callerPackageName, in IntentSender statusReceiver, in UserHandle userHandle, int flags); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES,android.Manifest.permission.REQUEST_INSTALL_PACKAGES})") void requestUnarchive(String packageName, String callerPackageName, in IntentSender statusReceiver, in UserHandle userHandle); diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index d35c3922e9b7..457fd63fa3d8 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -323,6 +323,14 @@ public class PackageInstaller { */ @SystemApi public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK"; + /** + * Key for passing extra delete flags during archiving. + * + * @hide + */ + @SystemApi + @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING) + public static final String EXTRA_DELETE_FLAGS = "android.content.pm.extra.DELETE_FLAGS"; /** * Type of DataLoader for this session. Will be one of @@ -2330,6 +2338,7 @@ public class PackageInstaller { * communicated. * * @param statusReceiver Callback used to notify when the operation is completed. + * @param flags Flags for archiving. Can be 0 or {@link PackageManager#DELETE_SHOW_DIALOG}. * @throws PackageManager.NameNotFoundException If {@code packageName} isn't found or not * available to the caller or isn't archived. */ @@ -2337,11 +2346,12 @@ public class PackageInstaller { Manifest.permission.DELETE_PACKAGES, Manifest.permission.REQUEST_DELETE_PACKAGES}) @FlaggedApi(Flags.FLAG_ARCHIVING) - public void requestArchive(@NonNull String packageName, @NonNull IntentSender statusReceiver) + public void requestArchive(@NonNull String packageName, @NonNull IntentSender statusReceiver, + @DeleteFlags int flags) throws PackageManager.NameNotFoundException { try { mInstaller.requestArchive(packageName, mInstallerPackageName, statusReceiver, - new UserHandle(mUserId)); + new UserHandle(mUserId), flags); } catch (ParcelableException e) { e.maybeRethrow(PackageManager.NameNotFoundException.class); } catch (RemoteException e) { diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index a22fe3f1452b..7bb673ac998d 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2552,6 +2552,7 @@ public abstract class PackageManager { DELETE_SYSTEM_APP, DELETE_DONT_KILL_APP, DELETE_CHATTY, + DELETE_SHOW_DIALOG, }) @Retention(RetentionPolicy.SOURCE) public @interface DeleteFlags {} @@ -2595,15 +2596,21 @@ public abstract class PackageManager { public static final int DELETE_DONT_KILL_APP = 0x00000008; /** - * Flag parameter for {@link #deletePackage} to indicate that the deletion is an archival. This + * Flag parameter for {@link PackageInstaller#uninstall(VersionedPackage, int, IntentSender)} to + * indicate that the deletion is an archival. This * flag is only for internal usage as part of - * {@link PackageInstaller#requestArchive(String, IntentSender)}. - * - * @hide + * {@link PackageInstaller#requestArchive}. */ + @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING) public static final int DELETE_ARCHIVE = 0x00000010; /** + * Show a confirmation dialog to the user when app is being deleted. + */ + @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING) + public static final int DELETE_SHOW_DIALOG = 0x00000020; + + /** * Flag parameter for {@link #deletePackage} to indicate that package deletion * should be chatty. * @@ -8964,7 +8971,7 @@ public abstract class PackageManager { * Returns true if an app is archivable. * * @throws NameNotFoundException if the given package name is not available to the caller. - * @see PackageInstaller#requestArchive(String, IntentSender) + * @see PackageInstaller#requestArchive */ @FlaggedApi(android.content.pm.Flags.FLAG_ARCHIVING) public boolean isAppArchivable(@NonNull String packageName) throws NameNotFoundException { diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java index 4e28d77aed08..09be76814d92 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallUninstalling.java @@ -116,6 +116,7 @@ public class UninstallUninstalling extends Activity implements int flags = allUsers ? PackageManager.DELETE_ALL_USERS : 0; flags |= keepData ? PackageManager.DELETE_KEEP_DATA : 0; + flags |= getIntent().getIntExtra(PackageInstaller.EXTRA_DELETE_FLAGS, 0); createContextAsUser(user, 0).getPackageManager().getPackageInstaller().uninstall( new VersionedPackage(mAppInfo.packageName, diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java index ba627e9e9202..5c9b728a0f9d 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/UninstallerActivity.java @@ -19,6 +19,7 @@ package com.android.packageinstaller; import static android.app.AppOpsManager.MODE_ALLOWED; import static android.content.pm.Flags.usePiaV2; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; + import static com.android.packageinstaller.PackageUtil.getMaxTargetSdkVersionForUid; import android.Manifest; @@ -55,8 +56,8 @@ import com.android.packageinstaller.handheld.UninstallAlertDialogFragment; import com.android.packageinstaller.television.ErrorFragment; import com.android.packageinstaller.television.UninstallAlertFragment; import com.android.packageinstaller.television.UninstallAppProgress; - import com.android.packageinstaller.v2.ui.UninstallLaunch; + import java.util.List; /* @@ -76,6 +77,7 @@ public class UninstallerActivity extends Activity { public boolean allUsers; public UserHandle user; public PackageManager.UninstallCompleteCallback callback; + public int deleteFlags; } private String mPackageName; @@ -226,10 +228,26 @@ public class UninstallerActivity extends Activity { // Continue as the ActivityInfo isn't critical. } } + parseDeleteFlags(intent); showConfirmationDialog(); } + /** + * Parses specific {@link android.content.pm.PackageManager.DeleteFlags} from {@link Intent} + * to archive an app if requested. + * + * Do not parse any flags because developers might pass here any flags which might cause + * unintended behaviour. + * For more context {@link com.android.server.pm.PackageArchiver#requestArchive}. + */ + private void parseDeleteFlags(Intent intent) { + int deleteFlags = intent.getIntExtra(PackageInstaller.EXTRA_DELETE_FLAGS, 0); + int archive = deleteFlags & PackageManager.DELETE_ARCHIVE; + int keepData = deleteFlags & PackageManager.DELETE_KEEP_DATA; + mDialogInfo.deleteFlags = archive | keepData; + } + public DialogInfo getDialogInfo() { return mDialogInfo; } @@ -347,7 +365,10 @@ public class UninstallerActivity extends Activity { if (returnResult || getCallingActivity() != null) { newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); } - + if (mDialogInfo.deleteFlags != 0) { + newIntent.putExtra(PackageInstaller.EXTRA_DELETE_FLAGS, + mDialogInfo.deleteFlags); + } startActivity(newIntent); } else { int uninstallId; @@ -393,6 +414,7 @@ public class UninstallerActivity extends Activity { int flags = mDialogInfo.allUsers ? PackageManager.DELETE_ALL_USERS : 0; flags |= keepData ? PackageManager.DELETE_KEEP_DATA : 0; + flags |= mDialogInfo.deleteFlags; createContextAsUser(mDialogInfo.user, 0).getPackageManager().getPackageInstaller() .uninstall(new VersionedPackage(mDialogInfo.appInfo.packageName, diff --git a/services/core/java/com/android/server/pm/PackageArchiver.java b/services/core/java/com/android/server/pm/PackageArchiver.java index 9f072f932a95..e3bab3f243c3 100644 --- a/services/core/java/com/android/server/pm/PackageArchiver.java +++ b/services/core/java/com/android/server/pm/PackageArchiver.java @@ -54,6 +54,7 @@ import android.content.pm.LauncherActivityInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.DeleteFlags; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.VersionedPackage; @@ -154,7 +155,8 @@ public class PackageArchiver { @NonNull String packageName, @NonNull String callerPackageName, @NonNull IntentSender intentSender, - @NonNull UserHandle userHandle) { + @NonNull UserHandle userHandle, + @DeleteFlags int flags) { Objects.requireNonNull(packageName); Objects.requireNonNull(callerPackageName); Objects.requireNonNull(intentSender); @@ -195,7 +197,7 @@ public class PackageArchiver { new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), callerPackageName, - DELETE_ARCHIVE | DELETE_KEEP_DATA, + DELETE_ARCHIVE | DELETE_KEEP_DATA | flags, intentSender, userId, binderUid); diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index f731f95b404d..7d6dd62153c1 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -67,6 +67,7 @@ import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageInstaller.UnarchivalStatus; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.DeleteFlags; import android.content.pm.ParceledListSlice; import android.content.pm.VersionedPackage; import android.content.pm.parsing.FrameworkParsingPackageUtils; @@ -1390,11 +1391,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, statusReceiver, versionedPackage.getPackageName(), canSilentlyInstallPackage, userId); - if (mContext.checkCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES) + final boolean shouldShowConfirmationDialog = + (flags & PackageManager.DELETE_SHOW_DIALOG) != 0; + if (!shouldShowConfirmationDialog + && mContext.checkCallingOrSelfPermission(Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) { // Sweet, call straight through! mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); - } else if (canSilentlyInstallPackage) { + } else if (!shouldShowConfirmationDialog && canSilentlyInstallPackage) { // Allow the device owner and affiliated profile owner to silently delete packages // Need to clear the calling identity to get DELETE_PACKAGES permission final long ident = Binder.clearCallingIdentity(); @@ -1419,6 +1423,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements intent.setData(Uri.fromParts("package", versionedPackage.getPackageName(), null)); intent.putExtra(PackageInstaller.EXTRA_CALLBACK, new PackageManager.UninstallCompleteCallback(adapter.getBinder().asBinder())); + if ((flags & PackageManager.DELETE_ARCHIVE) != 0) { + // Delete flags are passed to the uninstaller activity so it can be preserved + // in the follow-up uninstall operation after the user confirmation + intent.putExtra(PackageInstaller.EXTRA_DELETE_FLAGS, flags); + } adapter.onUserActionRequired(intent); } } @@ -1631,9 +1640,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements @NonNull String packageName, @NonNull String callerPackageName, @NonNull IntentSender intentSender, - @NonNull UserHandle userHandle) { + @NonNull UserHandle userHandle, + @DeleteFlags int flags) { mPackageArchiver.requestArchive(packageName, callerPackageName, intentSender, - userHandle); + userHandle, flags); } @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index fc662038d5d5..215e9528a35e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -4639,7 +4639,7 @@ class PackageManagerShellCommand extends ShellCommand { try { mInterface.getPackageInstaller().requestArchive(packageName, /* callerPackageName= */ "", receiver.getIntentSender(), - new UserHandle(translatedUserId)); + new UserHandle(translatedUserId), 0); } catch (Exception e) { pw.println("Failure [" + e.getMessage() + "]"); return 1; diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java index a3ec936273b4..3e73aa30b1cd 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverTest.java @@ -228,7 +228,7 @@ public class PackageArchiverTest { Exception e = assertThrows( SecurityException.class, () -> mArchiveManager.requestArchive(PACKAGE, "different", mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e).hasMessageThat().isEqualTo( String.format( "The UID %s of callerPackageName set by the caller doesn't match the " @@ -245,7 +245,7 @@ public class PackageArchiverTest { Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo( String.format("Package %s not found.", PACKAGE)); @@ -255,7 +255,8 @@ public class PackageArchiverTest { public void archiveApp_packageNotInstalledForUser() throws IntentSender.SendIntentException { mPackageSetting.modifyUserState(UserHandle.CURRENT.getIdentifier()).setInstalled(false); - mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT); + mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT, + 0); rule.mocks().getHandler().flush(); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); @@ -285,7 +286,7 @@ public class PackageArchiverTest { Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo("No installer found"); } @@ -299,7 +300,7 @@ public class PackageArchiverTest { Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo( "Installer does not support unarchival"); @@ -313,7 +314,7 @@ public class PackageArchiverTest { Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo( TextUtils.formatSimple("The app %s does not have a main activity.", PACKAGE)); @@ -325,7 +326,8 @@ public class PackageArchiverTest { doThrow(e).when(mArchiveManager).storeIcon(eq(PACKAGE), any(LauncherActivityInfo.class), eq(mUserId), anyInt(), anyInt()); - mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT); + mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT, + 0); rule.mocks().getHandler().flush(); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); @@ -348,15 +350,16 @@ public class PackageArchiverTest { Exception e = assertThrows( ParcelableException.class, () -> mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, - UserHandle.CURRENT)); + UserHandle.CURRENT, 0)); assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class); assertThat(e.getCause()).hasMessageThat().isEqualTo( TextUtils.formatSimple("The app %s is opted out of archiving.", PACKAGE)); } @Test - public void archiveApp_success() { - mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT); + public void archiveApp_withNoAdditionalFlags_success() { + mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT, + 0); rule.mocks().getHandler().flush(); verify(mInstallerService).uninstall( @@ -369,6 +372,23 @@ public class PackageArchiverTest { } @Test + public void archiveApp_withAdditionalFlags_success() { + mArchiveManager.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender, UserHandle.CURRENT, + PackageManager.DELETE_SHOW_DIALOG); + rule.mocks().getHandler().flush(); + + verify(mInstallerService).uninstall( + eq(new VersionedPackage(PACKAGE, PackageManager.VERSION_CODE_HIGHEST)), + eq(CALLER_PACKAGE), + eq(DELETE_ARCHIVE | DELETE_KEEP_DATA | PackageManager.DELETE_SHOW_DIALOG), + eq(mIntentSender), + eq(UserHandle.CURRENT.getIdentifier()), anyInt()); + assertThat(mPackageSetting.readUserState( + UserHandle.CURRENT.getIdentifier()).getArchiveState()).isEqualTo( + createArchiveState()); + } + + @Test public void isAppArchivable_success() throws PackageManager.NameNotFoundException { assertThat(mArchiveManager.isAppArchivable(PACKAGE, UserHandle.CURRENT)).isTrue(); } |