From eecfcdb28519e82703ce6734f1d2f8f82eb8ab4e Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 23 May 2024 18:06:57 -0300 Subject: [PATCH] Improve icon display when selecting apps for restore --- .../seedvault/restore/AppSelectionAdapter.kt | 14 ++++++++------ .../seedvault/restore/AppSelectionFragment.kt | 4 ++-- .../seedvault/restore/RestoreViewModel.kt | 19 +++++++++---------- .../seedvault/worker/IconManager.kt | 14 ++++++++------ 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/AppSelectionAdapter.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/AppSelectionAdapter.kt index 72b79d13..499184e8 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/restore/AppSelectionAdapter.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/restore/AppSelectionAdapter.kt @@ -1,6 +1,6 @@ package com.stevesoltys.seedvault.restore -import android.graphics.Bitmap +import android.graphics.drawable.Drawable import android.text.format.DateUtils import android.text.format.Formatter import android.view.LayoutInflater @@ -39,7 +39,7 @@ internal data class SelectableAppItem( internal class AppSelectionAdapter( val scope: CoroutineScope, - val iconLoader: suspend (SelectableAppItem, (Bitmap) -> Unit) -> Unit, + val iconLoader: suspend (SelectableAppItem, (Drawable) -> Unit) -> Unit, val listener: (SelectableAppItem) -> Unit, ) : Adapter() { @@ -156,16 +156,18 @@ internal class AppSelectionAdapter( checkBox.visibility = if (item.hasIcon == null) INVISIBLE else VISIBLE progressBar.visibility = if (item.hasIcon == null) VISIBLE else INVISIBLE + val isSpecial = item.metadata.isInternalSystem + appIcon.scaleType = FIT_CENTER appIcon.setImageResource(R.drawable.ic_launcher_default) - if (item.hasIcon == null) { + appIcon.scaleType = if (isSpecial) CENTER else FIT_CENTER + if (item.hasIcon == null && !isSpecial) { appIcon.alpha = 0.5f - } else if (item.hasIcon) { + } else if (item.hasIcon == true || isSpecial) { appIcon.alpha = 0.5f iconJob = scope.launch { iconLoader(item) { bitmap -> - val isSpecial = item.metadata.system && !item.metadata.isLaunchableSystemApp appIcon.scaleType = if (isSpecial) CENTER else FIT_CENTER - appIcon.setImageBitmap(bitmap) + appIcon.setImageDrawable(bitmap) appIcon.alpha = 1f } } diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/AppSelectionFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/AppSelectionFragment.kt index 1cb6bf83..d19cbacd 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/restore/AppSelectionFragment.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/restore/AppSelectionFragment.kt @@ -1,6 +1,6 @@ package com.stevesoltys.seedvault.restore -import android.graphics.Bitmap +import android.graphics.drawable.Drawable import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -73,7 +73,7 @@ class AppSelectionFragment : Fragment() { } } - private suspend fun loadIcon(item: SelectableAppItem, callback: (Bitmap) -> Unit) { + private suspend fun loadIcon(item: SelectableAppItem, callback: (Drawable) -> Unit) { viewModel.loadIcon(item, callback) } diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreViewModel.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreViewModel.kt index 2895a040..25a17a7c 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreViewModel.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/restore/RestoreViewModel.kt @@ -13,14 +13,13 @@ import android.app.backup.IRestoreObserver import android.app.backup.IRestoreSession import android.app.backup.RestoreSet import android.content.Intent -import android.graphics.Bitmap +import android.graphics.drawable.Drawable import android.os.RemoteException import android.os.UserHandle import android.util.Log import androidx.annotation.UiThread import androidx.annotation.WorkerThread import androidx.appcompat.content.res.AppCompatResources.getDrawable -import androidx.core.graphics.drawable.toBitmap import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.asLiveData @@ -199,7 +198,7 @@ internal class RestoreViewModel( ?: return@mapNotNull null if (metadata.time == 0L && !metadata.hasApk()) return@mapNotNull null val name = app.getString(data.nameRes) - SelectableAppItem(packageName, metadata.copy(name = name), true, hasIcon = true) + SelectableAppItem(packageName, metadata.copy(name = name), true) } val systemItem = SelectableAppItem( packageName = PACKAGE_NAME_SYSTEM, @@ -227,10 +226,10 @@ internal class RestoreViewModel( } catch (e: Exception) { Log.e(TAG, "Error loading icons:", e) emptySet() - } + } + systemData.keys + setOf(PACKAGE_NAME_SYSTEM) // update state, so it knows that icons have loaded val updatedItems = items.map { item -> - item.copy(hasIcon = item.hasIcon ?: false || item.packageName in packagesWithIcons) + item.copy(hasIcon = item.packageName in packagesWithIcons) } val newState = SelectedAppsState(updatedItems, allSelected = true, iconsLoaded = true) @@ -239,13 +238,13 @@ internal class RestoreViewModel( mDisplayFragment.setEvent(SELECT_APPS) } - suspend fun loadIcon(item: SelectableAppItem, callback: (Bitmap) -> Unit) { + suspend fun loadIcon(item: SelectableAppItem, callback: (Drawable) -> Unit) { if (item.packageName == PACKAGE_NAME_SYSTEM) { - val bitmap = getDrawable(app, R.drawable.ic_app_settings)!!.toBitmap() - callback(bitmap) + val drawable = getDrawable(app, R.drawable.ic_app_settings)!! + callback(drawable) } else if (item.metadata.isInternalSystem && item.packageName in systemData.keys) { - val bitmap = getDrawable(app, systemData[item.packageName]!!.iconRes)!!.toBitmap() - callback(bitmap) + val drawable = getDrawable(app, systemData[item.packageName]!!.iconRes)!! + callback(drawable) } else { iconManager.loadIcon(item.packageName, callback) } diff --git a/app/src/main/java/com/stevesoltys/seedvault/worker/IconManager.kt b/app/src/main/java/com/stevesoltys/seedvault/worker/IconManager.kt index a061b461..341083ae 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/worker/IconManager.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/worker/IconManager.kt @@ -6,12 +6,13 @@ package com.stevesoltys.seedvault.worker import android.content.Context -import android.graphics.Bitmap import android.graphics.Bitmap.CompressFormat.WEBP_LOSSY import android.graphics.BitmapFactory +import android.graphics.drawable.Drawable import android.util.Log import androidx.appcompat.content.res.AppCompatResources.getDrawable import androidx.core.graphics.drawable.toBitmap +import androidx.core.graphics.drawable.toDrawable import com.stevesoltys.seedvault.R import com.stevesoltys.seedvault.transport.backup.PackageService import kotlinx.coroutines.Dispatchers @@ -92,23 +93,24 @@ internal class IconManager( } private val defaultIcon by lazy { - getDrawable(context, R.drawable.ic_launcher_default)!!.toBitmap() + getDrawable(context, R.drawable.ic_launcher_default)!! } /** * Tries to load the icons for the given [packageName] * that was downloaded before with [downloadIcons]. - * Calls [callback] on the UiThread with the loaded [Bitmap] or the default icon. + * Calls [callback] on the UiThread with the loaded [Drawable] or the default icon. */ - suspend fun loadIcon(packageName: String, callback: (Bitmap) -> Unit) { + suspend fun loadIcon(packageName: String, callback: (Drawable) -> Unit) { try { withContext(Dispatchers.IO) { val folder = File(context.cacheDir, CACHE_FOLDER) val file = File(folder, packageName) file.inputStream().use { inputStream -> - val bitmap = BitmapFactory.decodeStream(inputStream) + val drawable = + BitmapFactory.decodeStream(inputStream).toDrawable(context.resources) withContext(Dispatchers.Main) { - callback(bitmap) + callback(drawable) } } }