diff options
| author | 2025-02-11 16:41:24 -0800 | |
|---|---|---|
| committer | 2025-02-18 11:07:52 -0800 | |
| commit | 699df130f80d3f851c5d798c68a620a0577ea278 (patch) | |
| tree | 2348538697680e6e1c16ef340e4fd7599ca16f48 | |
| parent | 3e9f981c1f669460af027a50d51e5a425ebda073 (diff) | |
Implement an empty constructor for DialogFragments
Without an empty constructor, Pia crashes when a configuration change
takes palce. Data required by these dialogFragments are now set to
fragment arguments. This means that AppSnippet is now required to be
parcellable.
Bug: 394724957
Test: atest CtsPackageInstallTestCases CtsPackageUninstallTestCases CtsPackageInstallerCUJInstallationTestCases
Flag: android.content.pm.use_pia_v2
Change-Id: If1ff2de6f4ad286619fc40bb10c0b24ec6be5a31
15 files changed, 529 insertions, 69 deletions
diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp index a30c0c3c6d4c..8b1828c5f41f 100644 --- a/packages/PackageInstaller/Android.bp +++ b/packages/PackageInstaller/Android.bp @@ -47,19 +47,21 @@ android_app { sdk_version: "system_current", rename_resources_package: false, static_libs: [ - "androidx.leanback_leanback", + "android.content.pm.flags-aconfig-java", + "android.multiuser.flags-aconfig-java", + "android.os.flags-aconfig-java", "androidx.annotation_annotation", "androidx.fragment_fragment", - "androidx.lifecycle_lifecycle-livedata", + "androidx.leanback_leanback", "androidx.lifecycle_lifecycle-extensions", - "android.content.pm.flags-aconfig-java", - "android.os.flags-aconfig-java", - "android.multiuser.flags-aconfig-java", + "androidx.lifecycle_lifecycle-livedata", + "kotlin-parcelize-runtime", ], lint: { error_checks: ["Recycle"], }, + kotlin_plugins: ["kotlin-parcelize-compiler-plugin"], } android_app { @@ -79,19 +81,22 @@ android_app { overrides: ["PackageInstaller"], static_libs: [ - "androidx.leanback_leanback", - "androidx.fragment_fragment", - "androidx.lifecycle_lifecycle-livedata", - "androidx.lifecycle_lifecycle-extensions", "android.content.pm.flags-aconfig-java", - "android.os.flags-aconfig-java", "android.multiuser.flags-aconfig-java", + "android.os.flags-aconfig-java", + "androidx.annotation_annotation", + "androidx.fragment_fragment", + "androidx.leanback_leanback", + "androidx.lifecycle_lifecycle-extensions", + "androidx.lifecycle_lifecycle-livedata", + "kotlin-parcelize-runtime", ], aaptflags: ["--product tablet"], lint: { error_checks: ["Recycle"], }, + kotlin_plugins: ["kotlin-parcelize-compiler-plugin"], } android_app { @@ -111,18 +116,20 @@ android_app { overrides: ["PackageInstaller"], static_libs: [ - "androidx.leanback_leanback", + "android.content.pm.flags-aconfig-java", + "android.multiuser.flags-aconfig-java", + "android.os.flags-aconfig-java", "androidx.annotation_annotation", "androidx.fragment_fragment", - "androidx.lifecycle_lifecycle-livedata", + "androidx.leanback_leanback", "androidx.lifecycle_lifecycle-extensions", - "android.content.pm.flags-aconfig-java", - "android.os.flags-aconfig-java", - "android.multiuser.flags-aconfig-java", + "androidx.lifecycle_lifecycle-livedata", + "kotlin-parcelize-runtime", ], aaptflags: ["--product tv"], lint: { error_checks: ["Recycle"], }, + kotlin_plugins: ["kotlin-parcelize-compiler-plugin"], } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt index 8de8fbb3e688..a8dad096e4b0 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt @@ -18,8 +18,8 @@ package com.android.packageinstaller.v2.model import android.app.Activity import android.content.Intent -import android.content.pm.PackageManager import android.content.pm.PackageInstaller +import android.content.pm.PackageManager import android.graphics.drawable.Drawable sealed class InstallStage(val stageCode: Int) { @@ -42,7 +42,7 @@ class InstallReady : InstallStage(STAGE_READY) data class InstallUserActionRequired( val actionReason: Int, - private val appSnippet: PackageUtil.AppSnippet? = null, + val appSnippet: PackageUtil.AppSnippet? = null, val isAppUpdating: Boolean = false, /** * This holds either a package name or the app label of the install source. @@ -63,7 +63,7 @@ data class InstallUserActionRequired( } } -data class InstallInstalling(private val appSnippet: PackageUtil.AppSnippet) : +data class InstallInstalling(val appSnippet: PackageUtil.AppSnippet) : InstallStage(STAGE_INSTALLING) { val appIcon: Drawable? @@ -74,7 +74,7 @@ data class InstallInstalling(private val appSnippet: PackageUtil.AppSnippet) : } data class InstallSuccess( - private val appSnippet: PackageUtil.AppSnippet, + val appSnippet: PackageUtil.AppSnippet, val shouldReturnResult: Boolean = false, /** * @@ -95,7 +95,7 @@ data class InstallSuccess( } data class InstallFailed( - private val appSnippet: PackageUtil.AppSnippet? = null, + val appSnippet: PackageUtil.AppSnippet? = null, val legacyCode: Int, val statusCode: Int, val message: String? = null, diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt index 828a95fcbb01..e8477ef261a8 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt @@ -17,21 +17,32 @@ package com.android.packageinstaller.v2.model import android.Manifest +import android.annotation.SuppressLint +import android.app.ActivityManager import android.content.Context import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageInstaller import android.content.pm.PackageManager import android.content.res.Resources +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Canvas import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.Drawable import android.net.Uri import android.os.Build +import android.os.Parcel +import android.os.Parcelable import android.os.Process import android.os.UserHandle import android.os.UserManager import android.util.Log +import com.android.packageinstaller.v2.model.PackageUtil.getAppSnippet +import java.io.ByteArrayOutputStream import java.io.File +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize object PackageUtil { private val LOG_TAG = InstallRepository::class.java.simpleName @@ -39,6 +50,24 @@ object PackageUtil { private const val SPLIT_BASE_APK_SUFFIX = "base.apk" const val localLogv = false + const val ARGS_ABORT_REASON: String = "abort_reason" + const val ARGS_ACTION_REASON: String = "action_reason" + const val ARGS_ACTIVITY_RESULT_CODE: String = "activity_result_code" + const val ARGS_APP_DATA_SIZE: String = "app_data_size" + const val ARGS_APP_LABEL: String = "app_label" + const val ARGS_APP_SNIPPET: String = "app_snippet" + const val ARGS_ERROR_DIALOG_TYPE: String = "error_dialog_type" + const val ARGS_IS_ARCHIVE: String = "is_archive" + const val ARGS_IS_CLONE_USER: String = "clone_user" + const val ARGS_IS_UPDATING: String = "is_updating" + const val ARGS_LEGACY_CODE: String = "legacy_code" + const val ARGS_MESSAGE: String = "message" + const val ARGS_RESULT_INTENT: String = "result_intent" + const val ARGS_SHOULD_RETURN_RESULT: String = "should_return_result" + const val ARGS_SOURCE_APP: String = "source_app" + const val ARGS_STATUS_CODE: String = "status_code" + const val ARGS_TITLE: String = "title" + /** * Determines if the UID belongs to the system downloads provider and returns the * [ApplicationInfo] of the provider @@ -238,7 +267,8 @@ object PackageUtil { context.resources, info.getAppIcon() ) else pm.defaultActivityIcon - return AppSnippet(label, icon) + val largeIconSize = getLargeIconSize(context) + return AppSnippet(label, icon, largeIconSize) } /** @@ -247,8 +277,11 @@ object PackageUtil { */ @JvmStatic fun getAppSnippet(context: Context, pkgInfo: PackageInfo): AppSnippet { + val largeIconSize = getLargeIconSize(context) return pkgInfo.applicationInfo?.let { getAppSnippet(context, it) } ?: run { - AppSnippet(pkgInfo.packageName, context.packageManager.defaultActivityIcon) + AppSnippet( + pkgInfo.packageName, context.packageManager.defaultActivityIcon, largeIconSize + ) } } @@ -261,7 +294,8 @@ object PackageUtil { val pm = context.packageManager val label = pm.getApplicationLabel(appInfo) val icon = pm.getApplicationIcon(appInfo) - return AppSnippet(label, icon) + val largeIconSize = getLargeIconSize(context) + return AppSnippet(label, icon, largeIconSize) } /** @@ -270,16 +304,24 @@ object PackageUtil { */ @JvmStatic fun getAppSnippet(context: Context, pkgInfo: PackageInfo, sourceFile: File): AppSnippet { + val largeIconSize = getLargeIconSize(context) pkgInfo.applicationInfo?.let { val appInfoFromFile = processAppInfoForFile(it, sourceFile) val label = getAppLabelFromFile(context, appInfoFromFile) val icon = getAppIconFromFile(context, appInfoFromFile) - return AppSnippet(label, icon) + return AppSnippet(label, icon, largeIconSize) } ?: run { - return AppSnippet(pkgInfo.packageName, context.packageManager.defaultActivityIcon) + return AppSnippet( + pkgInfo.packageName, context.packageManager.defaultActivityIcon, largeIconSize + ) } } + private fun getLargeIconSize(context: Context): Int { + val am = context.getSystemService<ActivityManager>(ActivityManager::class.java) + return am.launcherLargeIconSize + } + /** * Utility method to load application label * @@ -438,7 +480,69 @@ object PackageUtil { * The class to hold an incoming package's icon and label. * See [getAppSnippet] */ - data class AppSnippet(var label: CharSequence?, var icon: Drawable?) { + @Parcelize + data class AppSnippet( + var label: CharSequence?, + var icon: Drawable?, + var iconSize: Int, + ) : Parcelable { + private companion object : Parceler<AppSnippet> { + override fun AppSnippet.write(dest: Parcel, flags: Int) { + dest.writeString(label.toString()) + + val bmp = getBitmapFromDrawable(icon!!) + dest.writeBlob(getBytesFromBitmap(bmp)) + bmp.recycle() + + dest.writeInt(iconSize) + } + + @SuppressLint("UseKtx") + override fun create(parcel: Parcel): AppSnippet { + val label = parcel.readString() + + val b: ByteArray = parcel.readBlob()!! + val bmp: Bitmap? = BitmapFactory.decodeByteArray(b, 0, b.size) + val icon = BitmapDrawable(Resources.getSystem(), bmp) + + val iconSize = parcel.readInt() + + return AppSnippet(label.toString(), icon, iconSize) + } + } + + @SuppressLint("UseKtx") + private fun getBitmapFromDrawable(drawable: Drawable): Bitmap { + // Create an empty bitmap with the dimensions of our drawable + val bmp = Bitmap.createBitmap( + drawable.intrinsicWidth, + drawable.intrinsicHeight, Bitmap.Config.ARGB_8888 + ) + // Associate it with a canvas. This canvas will draw the icon on the bitmap + val canvas = Canvas(bmp) + // Draw the drawable in the canvas. The canvas will ultimately paint the drawable in the + // bitmap held within + drawable.draw(canvas) + + // Scale it down if the icon is too large + if ((bmp.getWidth() > iconSize * 2) || (bmp.getHeight() > iconSize * 2)) { + val scaledBitmap = Bitmap.createScaledBitmap(bmp, iconSize, iconSize, true) + if (scaledBitmap != bmp) { + bmp.recycle() + } + return scaledBitmap + } + return bmp + } + + private fun getBytesFromBitmap(bmp: Bitmap): ByteArray? { + var baos = ByteArrayOutputStream() + baos.use { + bmp.compress(Bitmap.CompressFormat.PNG, 100, it) + } + return baos.toByteArray() + } + override fun toString(): String { return "AppSnippet[label = $label, hasIcon = ${icon != null}]" } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt index 481023ed5677..4a8be8db9248 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt @@ -133,9 +133,10 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { val aborted = installStage as InstallAborted when (aborted.abortReason) { InstallAborted.ABORT_REASON_DONE, - InstallAborted.ABORT_REASON_INTERNAL_ERROR -> { + InstallAborted.ABORT_REASON_INTERNAL_ERROR, + -> { if (aborted.errorDialogType == InstallAborted.DLG_PACKAGE_ERROR) { - val parseErrorDialog = ParseErrorFragment(aborted) + val parseErrorDialog = ParseErrorFragment.newInstance(aborted) showDialogInner(parseErrorDialog) } else { setResult(aborted.activityResultCode, aborted.resultIntent, true) @@ -151,12 +152,12 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { val uar = installStage as InstallUserActionRequired when (uar.actionReason) { InstallUserActionRequired.USER_ACTION_REASON_INSTALL_CONFIRMATION -> { - val actionDialog = InstallConfirmationFragment(uar) + val actionDialog = InstallConfirmationFragment.newInstance(uar) showDialogInner(actionDialog) } InstallUserActionRequired.USER_ACTION_REASON_UNKNOWN_SOURCE -> { - val externalSourceDialog = ExternalSourcesBlockedFragment(uar) + val externalSourceDialog = ExternalSourcesBlockedFragment.newInstance(uar) showDialogInner(externalSourceDialog) } @@ -169,7 +170,7 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { InstallStage.STAGE_INSTALLING -> { val installing = installStage as InstallInstalling - val installingDialog = InstallInstallingFragment(installing) + val installingDialog = InstallInstallingFragment.newInstance(installing) showDialogInner(installingDialog) } @@ -179,7 +180,7 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { val successIntent = success.resultIntent setResult(RESULT_OK, successIntent, true) } else { - val successDialog = InstallSuccessFragment(success) + val successDialog = InstallSuccessFragment.newInstance(success) showDialogInner(successDialog) } } @@ -190,7 +191,7 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { val failureIntent = failed.resultIntent setResult(RESULT_FIRST_USER, failureIntent, true) } else { - val failureDialog = InstallFailedFragment(failed) + val failureDialog = InstallFailedFragment.newInstance(failed) showDialogInner(failureDialog) } } @@ -242,11 +243,11 @@ class InstallLaunch : FragmentActivity(), InstallActionListener { } return when (restriction) { UserManager.DISALLOW_INSTALL_APPS -> - SimpleErrorFragment(R.string.install_apps_user_restriction_dlg_text) + SimpleErrorFragment.newInstance(R.string.install_apps_user_restriction_dlg_text) UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY -> - SimpleErrorFragment(R.string.unknown_apps_user_restriction_dlg_text) + SimpleErrorFragment.newInstance(R.string.unknown_apps_user_restriction_dlg_text) else -> null } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt index 0a02845e0dd3..08bc7666c3e1 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt @@ -101,7 +101,7 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener { if (aborted.abortReason == UninstallAborted.ABORT_REASON_APP_UNAVAILABLE || aborted.abortReason == UninstallAborted.ABORT_REASON_USER_NOT_ALLOWED ) { - val errorDialog = UninstallErrorFragment(aborted) + val errorDialog = UninstallErrorFragment.newInstance(aborted) showDialogInner(errorDialog) } else { setResult(aborted.activityResultCode, null, true) @@ -110,7 +110,7 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener { UninstallStage.STAGE_USER_ACTION_REQUIRED -> { val uar = uninstallStage as UninstallUserActionRequired - val confirmationDialog = UninstallConfirmationFragment(uar) + val confirmationDialog = UninstallConfirmationFragment.newInstance(uar) showDialogInner(confirmationDialog) } @@ -120,7 +120,7 @@ class UninstallLaunch : FragmentActivity(), UninstallActionListener { // And a fragment if the user requests a result back. Should we consolidate and // show a fragment always? val uninstalling = uninstallStage as UninstallUninstalling - val uninstallingDialog = UninstallUninstallingFragment(uninstalling) + val uninstallingDialog = UninstallUninstallingFragment.newInstance(uninstalling) showDialogInner(uninstallingDialog) } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java index 343a213780b3..4c69b9d20315 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ExternalSourcesBlockedFragment.java @@ -16,17 +16,25 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ACTION_REASON; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_IS_UPDATING; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_SOURCE_APP; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallUserActionRequired; +import com.android.packageinstaller.v2.model.PackageUtil.AppSnippet; import com.android.packageinstaller.v2.ui.InstallActionListener; /** @@ -37,14 +45,34 @@ public class ExternalSourcesBlockedFragment extends DialogFragment { private static final String LOG_TAG = ExternalSourcesBlockedFragment.class.getSimpleName(); @NonNull - private final InstallUserActionRequired mDialogData; + private InstallUserActionRequired mDialogData; @NonNull private InstallActionListener mInstallActionListener; @NonNull private AlertDialog mDialog; - public ExternalSourcesBlockedFragment(InstallUserActionRequired dialogData) { - mDialogData = dialogData; + public ExternalSourcesBlockedFragment() { + // Required for DialogFragment + } + + /** + * Creates a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallUserActionRequired} object containing data to display + * in the dialog + * @return an instance of the fragment + */ + public static ExternalSourcesBlockedFragment newInstance( + @NonNull InstallUserActionRequired dialogData) { + Bundle args = new Bundle(); + args.putInt(ARGS_ACTION_REASON, dialogData.getActionReason()); + args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet()); + args.putBoolean(ARGS_IS_UPDATING, dialogData.isAppUpdating()); + args.putString(ARGS_SOURCE_APP, dialogData.getSourceApp()); + + ExternalSourcesBlockedFragment fragment = new ExternalSourcesBlockedFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -56,6 +84,8 @@ public class ExternalSourcesBlockedFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); mDialog = new AlertDialog.Builder(requireContext()) .setTitle(mDialogData.getAppLabel()) @@ -96,4 +126,14 @@ public class ExternalSourcesBlockedFragment extends DialogFragment { super.onResume(); mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true); } + + private void setDialogData(Bundle args) { + int actionReason = args.getInt(ARGS_ACTION_REASON); + AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET, AppSnippet.class); + boolean isUpdating = args.getBoolean(ARGS_IS_UPDATING); + String sourceApp = args.getString(ARGS_SOURCE_APP); + + mDialogData = new InstallUserActionRequired(actionReason, appSnippet, isUpdating, + sourceApp); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java index e186590fa5e2..03768fb56bb8 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallConfirmationFragment.java @@ -16,6 +16,11 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ACTION_REASON; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_IS_UPDATING; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_SOURCE_APP; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; @@ -26,11 +31,14 @@ import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.view.View; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallUserActionRequired; +import com.android.packageinstaller.v2.model.PackageUtil.AppSnippet; import com.android.packageinstaller.v2.ui.InstallActionListener; /** @@ -39,15 +47,34 @@ import com.android.packageinstaller.v2.ui.InstallActionListener; public class InstallConfirmationFragment extends DialogFragment { public static final String LOG_TAG = InstallConfirmationFragment.class.getSimpleName(); - @NonNull - private final InstallUserActionRequired mDialogData; + private InstallUserActionRequired mDialogData; @NonNull private InstallActionListener mInstallActionListener; @NonNull private AlertDialog mDialog; - public InstallConfirmationFragment(@NonNull InstallUserActionRequired dialogData) { - mDialogData = dialogData; + public InstallConfirmationFragment() { + // Required for DialogFragment + } + + /** + * Creates a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallUserActionRequired} object containing data to display + * in the dialog + * @return an instance of the fragment + */ + public static InstallConfirmationFragment newInstance( + @NonNull InstallUserActionRequired dialogData) { + Bundle args = new Bundle(); + args.putInt(ARGS_ACTION_REASON, dialogData.getActionReason()); + args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet()); + args.putBoolean(ARGS_IS_UPDATING, dialogData.isAppUpdating()); + args.putString(ARGS_SOURCE_APP, dialogData.getSourceApp()); + + InstallConfirmationFragment fragment = new InstallConfirmationFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -59,6 +86,8 @@ public class InstallConfirmationFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); View dialogView = getLayoutInflater().inflate(R.layout.install_content_view, null); @@ -127,4 +156,14 @@ public class InstallConfirmationFragment extends DialogFragment { super.onResume(); mDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(true); } + + private void setDialogData(Bundle args) { + int actionReason = args.getInt(ARGS_ACTION_REASON); + AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET, AppSnippet.class); + boolean isUpdating = args.getBoolean(ARGS_IS_UPDATING); + String sourceApp = args.getString(ARGS_SOURCE_APP); + + mDialogData = new InstallUserActionRequired(actionReason, appSnippet, isUpdating, + sourceApp); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallFailedFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallFailedFragment.java index 7c9d98dd4823..6f65441afd88 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallFailedFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallFailedFragment.java @@ -16,19 +16,30 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_LEGACY_CODE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_MESSAGE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_RESULT_INTENT; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_SHOULD_RETURN_RESULT; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_STATUS_CODE; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.pm.PackageInstaller; import android.os.Bundle; import android.util.Log; import android.view.View; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallFailed; +import com.android.packageinstaller.v2.model.PackageUtil.AppSnippet; import com.android.packageinstaller.v2.ui.InstallActionListener; /** @@ -39,11 +50,32 @@ import com.android.packageinstaller.v2.ui.InstallActionListener; public class InstallFailedFragment extends DialogFragment { private static final String LOG_TAG = InstallFailedFragment.class.getSimpleName(); - private final InstallFailed mDialogData; + private InstallFailed mDialogData; private InstallActionListener mInstallActionListener; - public InstallFailedFragment(InstallFailed dialogData) { - mDialogData = dialogData; + public InstallFailedFragment() { + // Required for DialogFragment + } + + /** + * Creates a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallFailed} object containing data to display in the + * dialog + * @return an instance of the fragment + */ + public static InstallFailedFragment newInstance(@NonNull InstallFailed dialogData) { + Bundle args = new Bundle(); + args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet()); + args.putInt(ARGS_LEGACY_CODE, dialogData.getLegacyCode()); + args.putInt(ARGS_STATUS_CODE, dialogData.getStatusCode()); + args.putString(ARGS_MESSAGE, dialogData.getMessage()); + args.putBoolean(ARGS_SHOULD_RETURN_RESULT, dialogData.getShouldReturnResult()); + args.putParcelable(ARGS_RESULT_INTENT, dialogData.getResultIntent()); + + InstallFailedFragment fragment = new InstallFailedFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -55,6 +87,8 @@ public class InstallFailedFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); View dialogView = getLayoutInflater().inflate(R.layout.install_content_view, null); AlertDialog dialog = new AlertDialog.Builder(requireContext()) @@ -105,4 +139,16 @@ public class InstallFailedFragment extends DialogFragment { super.onCancel(dialog); mInstallActionListener.onNegativeResponse(mDialogData.getStageCode()); } + + private void setDialogData(Bundle args) { + AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET, AppSnippet.class); + int legacyCode = args.getInt(ARGS_LEGACY_CODE); + int statusCode = args.getInt(ARGS_STATUS_CODE); + String message = args.getString(ARGS_MESSAGE); + boolean shouldReturnResult = args.getBoolean(ARGS_SHOULD_RETURN_RESULT); + Intent resultIntent = args.getParcelable(ARGS_RESULT_INTENT, Intent.class); + + mDialogData = new InstallFailed(appSnippet, legacyCode, statusCode, message, + shouldReturnResult, resultIntent); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallInstallingFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallInstallingFragment.java index 27210b757181..17093cf16125 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallInstallingFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallInstallingFragment.java @@ -16,17 +16,22 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET; + import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; import android.view.View; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallInstalling; +import com.android.packageinstaller.v2.model.PackageUtil.AppSnippet; /** * Dialog to show when an install is in progress. @@ -34,16 +39,34 @@ import com.android.packageinstaller.v2.model.InstallInstalling; public class InstallInstallingFragment extends DialogFragment { private static final String LOG_TAG = InstallInstallingFragment.class.getSimpleName(); - private final InstallInstalling mDialogData; + private InstallInstalling mDialogData; private AlertDialog mDialog; - public InstallInstallingFragment(InstallInstalling dialogData) { - mDialogData = dialogData; + public InstallInstallingFragment() { + // Required for DialogFragment + } + + /** + * Creates a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallInstalling} object containing data to display in the + * dialog + * @return an instance of the fragment + */ + public static InstallInstallingFragment newInstance(@NonNull InstallInstalling dialogData) { + Bundle args = new Bundle(); + args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet()); + + InstallInstallingFragment fragment = new InstallInstallingFragment(); + fragment.setArguments(args); + return fragment; } @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); View dialogView = getLayoutInflater().inflate(R.layout.install_content_view, null); mDialog = new AlertDialog.Builder(requireContext()) @@ -64,4 +87,9 @@ public class InstallInstallingFragment extends DialogFragment { super.onStart(); mDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setEnabled(false); } + + private void setDialogData(Bundle args) { + AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET, AppSnippet.class); + mDialogData = new InstallInstalling(appSnippet); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallSuccessFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallSuccessFragment.java index 28b5423b2d83..5696afa52622 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallSuccessFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/InstallSuccessFragment.java @@ -16,22 +16,31 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_SNIPPET; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_RESULT_INTENT; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_SHOULD_RETURN_RESULT; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallSuccess; +import com.android.packageinstaller.v2.model.PackageUtil.AppSnippet; import com.android.packageinstaller.v2.ui.InstallActionListener; + import java.util.List; /** @@ -41,13 +50,31 @@ import java.util.List; public class InstallSuccessFragment extends DialogFragment { private static final String LOG_TAG = InstallSuccessFragment.class.getSimpleName(); - private final InstallSuccess mDialogData; + private InstallSuccess mDialogData; private AlertDialog mDialog; private InstallActionListener mInstallActionListener; private PackageManager mPm; - public InstallSuccessFragment(InstallSuccess dialogData) { - mDialogData = dialogData; + public InstallSuccessFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallSuccess} object containing data to display in the + * dialog + * @return an instance of the fragment + */ + public static InstallSuccessFragment newInstance(@NonNull InstallSuccess dialogData) { + Bundle args = new Bundle(); + args.putParcelable(ARGS_APP_SNIPPET, dialogData.getAppSnippet()); + args.putBoolean(ARGS_SHOULD_RETURN_RESULT, dialogData.getShouldReturnResult()); + args.putParcelable(ARGS_RESULT_INTENT, dialogData.getResultIntent()); + + InstallSuccessFragment fragment = new InstallSuccessFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -60,6 +87,8 @@ public class InstallSuccessFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); View dialogView = getLayoutInflater().inflate(R.layout.install_content_view, null); mDialog = new AlertDialog.Builder(requireContext()) @@ -105,4 +134,12 @@ public class InstallSuccessFragment extends DialogFragment { Log.i(LOG_TAG, "Finished installing " + mDialogData.getAppLabel()); mInstallActionListener.onNegativeResponse(mDialogData.getStageCode()); } + + private void setDialogData(Bundle args) { + AppSnippet appSnippet = args.getParcelable(ARGS_APP_SNIPPET, AppSnippet.class); + boolean shouldReturnResult = args.getBoolean(ARGS_SHOULD_RETURN_RESULT); + Intent resultIntent = args.getParcelable(ARGS_RESULT_INTENT, Intent.class); + + mDialogData = new InstallSuccess(appSnippet, shouldReturnResult, resultIntent); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ParseErrorFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ParseErrorFragment.java index cde3d8d9dd2d..6834f44a37cf 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ParseErrorFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/ParseErrorFragment.java @@ -16,14 +16,23 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ABORT_REASON; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ACTIVITY_RESULT_CODE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ERROR_DIALOG_TYPE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_MESSAGE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_RESULT_INTENT; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; import android.util.Log; + import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallAborted; import com.android.packageinstaller.v2.ui.InstallActionListener; @@ -31,11 +40,31 @@ import com.android.packageinstaller.v2.ui.InstallActionListener; public class ParseErrorFragment extends DialogFragment { private static final String LOG_TAG = ParseErrorFragment.class.getSimpleName(); - private final InstallAborted mDialogData; + private InstallAborted mDialogData; private InstallActionListener mInstallActionListener; - public ParseErrorFragment(InstallAborted dialogData) { - mDialogData = dialogData; + public ParseErrorFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link InstallAborted} object containing data to display in the + * dialog + * @return an instance of the fragment + */ + public static ParseErrorFragment newInstance(@NonNull InstallAborted dialogData) { + Bundle args = new Bundle(); + args.putInt(ARGS_ABORT_REASON, dialogData.getAbortReason()); + args.putString(ARGS_MESSAGE, dialogData.getMessage()); + args.putParcelable(ARGS_RESULT_INTENT, dialogData.getResultIntent()); + args.putInt(ARGS_ACTIVITY_RESULT_CODE, dialogData.getActivityResultCode()); + args.putInt(ARGS_ERROR_DIALOG_TYPE, dialogData.getErrorDialogType()); + + ParseErrorFragment fragment = new ParseErrorFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -47,6 +76,8 @@ public class ParseErrorFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); return new AlertDialog.Builder(requireContext()) .setMessage(R.string.Parse_error_dlg_text) @@ -63,4 +94,15 @@ public class ParseErrorFragment extends DialogFragment { mInstallActionListener.onNegativeResponse( mDialogData.getActivityResultCode(), mDialogData.getResultIntent()); } + + private void setDialogData(Bundle args) { + int abortReason = args.getInt(ARGS_ABORT_REASON); + String message = args.getString(ARGS_MESSAGE); + Intent resultIntent = args.getParcelable(ARGS_RESULT_INTENT, Intent.class); + int activityResultCode = args.getInt(ARGS_ACTIVITY_RESULT_CODE); + int errorDialogType = args.getInt(ARGS_ERROR_DIALOG_TYPE); + + mDialogData = new InstallAborted(abortReason, message, resultIntent, activityResultCode, + errorDialogType); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/SimpleErrorFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/SimpleErrorFragment.java index 66a353a3519e..8b1ccd8ab6e9 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/SimpleErrorFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/SimpleErrorFragment.java @@ -16,14 +16,18 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_MESSAGE; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; + import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.InstallStage; import com.android.packageinstaller.v2.ui.InstallActionListener; @@ -31,11 +35,25 @@ import com.android.packageinstaller.v2.ui.InstallActionListener; public class SimpleErrorFragment extends DialogFragment { private static final String LOG_TAG = SimpleErrorFragment.class.getSimpleName(); - private final int mMessageResId; + private int mMessageResId; private InstallActionListener mInstallActionListener; - public SimpleErrorFragment(int messageResId) { - mMessageResId = messageResId; + public SimpleErrorFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @return an instance of the fragment + */ + public static SimpleErrorFragment newInstance(int messageResId) { + Bundle args = new Bundle(); + args.putInt(ARGS_MESSAGE, messageResId); + + SimpleErrorFragment fragment = new SimpleErrorFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -47,6 +65,8 @@ public class SimpleErrorFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { + mMessageResId = requireArguments().getInt(ARGS_MESSAGE); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + "Dialog message: " + requireContext().getString(mMessageResId)); return new AlertDialog.Builder(requireContext()) diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallConfirmationFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallConfirmationFragment.java index 524b4e6a0e63..860f6a085909 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallConfirmationFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallConfirmationFragment.java @@ -18,6 +18,11 @@ package com.android.packageinstaller.v2.ui.fragments; import static android.text.format.Formatter.formatFileSize; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_DATA_SIZE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_IS_ARCHIVE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_MESSAGE; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_TITLE; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; @@ -27,9 +32,11 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; import android.widget.TextView; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.UninstallUserActionRequired; import com.android.packageinstaller.v2.ui.UninstallActionListener; @@ -38,14 +45,34 @@ import com.android.packageinstaller.v2.ui.UninstallActionListener; * Dialog to show while requesting user confirmation for uninstalling an app. */ public class UninstallConfirmationFragment extends DialogFragment { + private static final String LOG_TAG = UninstallConfirmationFragment.class.getSimpleName(); - private final UninstallUserActionRequired mDialogData; + private UninstallUserActionRequired mDialogData; private UninstallActionListener mUninstallActionListener; - private CheckBox mKeepData; - public UninstallConfirmationFragment(UninstallUserActionRequired dialogData) { - mDialogData = dialogData; + public UninstallConfirmationFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link UninstallUserActionRequired} object containing data to + * display in the dialog + * @return an instance of the fragment + */ + public static UninstallConfirmationFragment newInstance( + @NonNull UninstallUserActionRequired dialogData) { + Bundle args = new Bundle(); + args.putLong(ARGS_APP_DATA_SIZE, dialogData.getAppDataSize()); + args.putBoolean(ARGS_IS_ARCHIVE, dialogData.isArchive()); + args.putString(ARGS_TITLE, dialogData.getTitle()); + args.putString(ARGS_MESSAGE, dialogData.getMessage()); + + UninstallConfirmationFragment fragment = new UninstallConfirmationFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -57,6 +84,8 @@ public class UninstallConfirmationFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()) .setTitle(mDialogData.getTitle()) @@ -88,4 +117,13 @@ public class UninstallConfirmationFragment extends DialogFragment { super.onCancel(dialog); mUninstallActionListener.onNegativeResponse(); } + + private void setDialogData(Bundle args) { + long appDataSize = args.getLong(ARGS_APP_DATA_SIZE); + boolean isArchive = args.getBoolean(ARGS_IS_ARCHIVE); + String title = args.getString(ARGS_TITLE); + String message = args.getString(ARGS_MESSAGE); + + mDialogData = new UninstallUserActionRequired(title, message, appDataSize, isArchive); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallErrorFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallErrorFragment.java index 51e16cbff55d..9ed64128088c 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallErrorFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallErrorFragment.java @@ -16,15 +16,19 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_ABORT_REASON; + import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.UninstallAborted; import com.android.packageinstaller.v2.ui.UninstallActionListener; @@ -35,11 +39,27 @@ import com.android.packageinstaller.v2.ui.UninstallActionListener; public class UninstallErrorFragment extends DialogFragment { private static final String LOG_TAG = UninstallErrorFragment.class.getSimpleName(); - private final UninstallAborted mDialogData; + private UninstallAborted mDialogData; private UninstallActionListener mUninstallActionListener; - public UninstallErrorFragment(UninstallAborted dialogData) { - mDialogData = dialogData; + public UninstallErrorFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link UninstallAborted} object containing data to display in the + * dialog + * @return an instance of the fragment + */ + public static UninstallErrorFragment newInstance(UninstallAborted dialogData) { + Bundle args = new Bundle(); + args.putInt(ARGS_ABORT_REASON, dialogData.getAbortReason()); + + UninstallErrorFragment fragment = new UninstallErrorFragment(); + fragment.setArguments(args); + return fragment; } @Override @@ -51,6 +71,8 @@ public class UninstallErrorFragment extends DialogFragment { @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()) .setMessage(mDialogData.getDialogTextResource()) @@ -68,4 +90,9 @@ public class UninstallErrorFragment extends DialogFragment { super.onCancel(dialog); mUninstallActionListener.onNegativeResponse(); } + + private void setDialogData(Bundle args) { + int abortReason = args.getInt(ARGS_ABORT_REASON); + mDialogData = new UninstallAborted(abortReason); + } } diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallUninstallingFragment.java b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallUninstallingFragment.java index 626ff6b92f13..ae56c4d786b8 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallUninstallingFragment.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/fragments/UninstallUninstallingFragment.java @@ -16,12 +16,17 @@ package com.android.packageinstaller.v2.ui.fragments; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_APP_LABEL; +import static com.android.packageinstaller.v2.model.PackageUtil.ARGS_IS_CLONE_USER; + import android.app.AlertDialog; import android.app.Dialog; import android.os.Bundle; import android.util.Log; + import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; + import com.android.packageinstaller.R; import com.android.packageinstaller.v2.model.UninstallUninstalling; @@ -33,13 +38,32 @@ public class UninstallUninstallingFragment extends DialogFragment { private static final String LOG_TAG = UninstallUninstallingFragment.class.getSimpleName(); UninstallUninstalling mDialogData; - public UninstallUninstallingFragment(UninstallUninstalling dialogData) { - mDialogData = dialogData; + UninstallUninstallingFragment() { + // Required for DialogFragment + } + + /** + * Create a new instance of this fragment with necessary data set as fragment arguments + * + * @param dialogData {@link UninstallUninstalling} object containing data to display in + * the dialog + * @return an instance of the fragment + */ + public static UninstallUninstallingFragment newInstance(UninstallUninstalling dialogData) { + Bundle args = new Bundle(); + args.putCharSequence(ARGS_APP_LABEL, dialogData.getAppLabel()); + args.putBoolean(ARGS_IS_CLONE_USER, dialogData.isCloneUser()); + + UninstallUninstallingFragment fragment = new UninstallUninstallingFragment(); + fragment.setArguments(args); + return fragment; } @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { + setDialogData(requireArguments()); + Log.i(LOG_TAG, "Creating " + LOG_TAG + "\n" + mDialogData); AlertDialog.Builder builder = new AlertDialog.Builder(requireContext()) .setCancelable(false); @@ -55,4 +79,11 @@ public class UninstallUninstallingFragment extends DialogFragment { return dialog; } + + private void setDialogData(Bundle args) { + CharSequence label = args.getCharSequence(ARGS_APP_LABEL); + boolean isCloneUser = args.getBoolean(ARGS_IS_CLONE_USER); + + mDialogData = new UninstallUninstalling(label, isCloneUser); + } } |