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
diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp
index a30c0c3..8b1828c 100644
--- a/packages/PackageInstaller/Android.bp
+++ b/packages/PackageInstaller/Android.bp
@@ -47,19 +47,21 @@
     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 @@
     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 @@
     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 8de8fbb..a8dad09 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 @@
 
 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 @@
 
 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 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 InstallSuccess(
-    private val appSnippet: PackageUtil.AppSnippet,
+    val appSnippet: PackageUtil.AppSnippet,
     val shouldReturnResult: Boolean = false,
     /**
      *
@@ -95,7 +95,7 @@
 }
 
 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 828a95f..e8477ef 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 @@
     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 @@
             context.resources,
             info.getAppIcon()
         ) else pm.defaultActivityIcon
-        return AppSnippet(label, icon)
+        val largeIconSize = getLargeIconSize(context)
+        return AppSnippet(label, icon, largeIconSize)
     }
 
     /**
@@ -247,8 +277,11 @@
      */
     @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 @@
         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 @@
      */
     @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 @@
      * 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 481023e..4a8be8d 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 @@
                 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 @@
                 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 @@
 
             InstallStage.STAGE_INSTALLING -> {
                 val installing = installStage as InstallInstalling
-                val installingDialog = InstallInstallingFragment(installing)
+                val installingDialog = InstallInstallingFragment.newInstance(installing)
                 showDialogInner(installingDialog)
             }
 
@@ -179,7 +180,7 @@
                     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 @@
                     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 @@
         }
         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 0a02845e..08bc766 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 @@
                 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 @@
 
             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 @@
                 //  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 343a213..4c69b9d 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 @@
 
     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 @@
     @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 @@
         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 e186590..03768fb 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.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 @@
 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 @@
     @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 @@
         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 7c9d98d..6f65441 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 @@
 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 @@
     @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 @@
         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 27210b7..17093cf 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 @@
 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 @@
         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 28b5423b..5696afa 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 @@
 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 @@
     @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 @@
         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 cde3d8d..6834f44 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 @@
 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 @@
     @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 @@
         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 66a353a..8b1ccd8 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 @@
 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 @@
     @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 524b4e6..860f6a0 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 @@
 
 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.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 @@
  * 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 UninstallActionListener mUninstallActionListener;
 
+    private static final String LOG_TAG = UninstallConfirmationFragment.class.getSimpleName();
+    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 @@
     @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 @@
         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 51e16cb..9ed6412 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 @@
 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 @@
     @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 @@
         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 626ff6b..ae56c4d 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 @@
     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 @@
 
         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);
+    }
 }