Loading packages/PackageInstaller/Android.bp +22 −15 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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 { Loading @@ -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"], } packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt +5 −5 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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. Loading @@ -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? Loading @@ -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, /** * Loading @@ -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, Loading packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt +110 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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) } /** Loading @@ -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 ) } } Loading @@ -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) } /** Loading @@ -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 * Loading Loading @@ -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}]" } Loading packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt +10 −9 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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) } Loading @@ -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) } Loading @@ -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) } } Loading @@ -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) } } Loading Loading @@ -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 } Loading packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt +3 −3 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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) } Loading @@ -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) } Loading Loading
packages/PackageInstaller/Android.bp +22 −15 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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 { Loading @@ -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"], }
packages/PackageInstaller/src/com/android/packageinstaller/v2/model/InstallStages.kt +5 −5 Original line number Diff line number Diff line Loading @@ -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) { Loading @@ -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. Loading @@ -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? Loading @@ -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, /** * Loading @@ -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, Loading
packages/PackageInstaller/src/com/android/packageinstaller/v2/model/PackageUtil.kt +110 −6 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading @@ -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) } /** Loading @@ -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 ) } } Loading @@ -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) } /** Loading @@ -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 * Loading Loading @@ -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}]" } Loading
packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/InstallLaunch.kt +10 −9 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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) } Loading @@ -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) } Loading @@ -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) } } Loading @@ -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) } } Loading Loading @@ -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 } Loading
packages/PackageInstaller/src/com/android/packageinstaller/v2/ui/UninstallLaunch.kt +3 −3 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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) } Loading @@ -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) } Loading