fix: Don't exceed the maximum number of created shortcuts (#771)
Previous code created one shortcut per account, which could exceed the maximum number of shortcuts allowed, causing a crash. Fix this by creating no more than the max number of shortcuts while ensuring that the active account is always included. Fixes #752
This commit is contained in:
parent
33e1b418cf
commit
597833d660
|
@ -2625,8 +2625,8 @@
|
||||||
<issue
|
<issue
|
||||||
id="ReportShortcutUsage"
|
id="ReportShortcutUsage"
|
||||||
message="Calling this method indicates use of dynamic shortcuts, but there are no calls to methods that track shortcut usage, such as `pushDynamicShortcut` or `reportShortcutUsed`. Calling these methods is recommended, as they track shortcut usage and allow launchers to adjust which shortcuts appear based on activation history. Please see https://developer.android.com/develop/ui/views/launch/shortcuts/managing-shortcuts#track-usage"
|
message="Calling this method indicates use of dynamic shortcuts, but there are no calls to methods that track shortcut usage, such as `pushDynamicShortcut` or `reportShortcutUsed`. Calling these methods is recommended, as they track shortcut usage and allow launchers to adjust which shortcuts appear based on activation history. Please see https://developer.android.com/develop/ui/views/launch/shortcuts/managing-shortcuts#track-usage"
|
||||||
errorLine1=" ShortcutManagerCompat.addDynamicShortcuts(context, listOf(shortcutInfo))"
|
errorLine1=" ShortcutManagerCompat.setDynamicShortcuts(context, shortcuts)"
|
||||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||||
<location
|
<location
|
||||||
file="src/main/java/app/pachli/util/ShareShortcutHelper.kt"
|
file="src/main/java/app/pachli/util/ShareShortcutHelper.kt"
|
||||||
line="96"
|
line="96"
|
||||||
|
|
|
@ -120,7 +120,7 @@ import app.pachli.updatecheck.UpdateCheck
|
||||||
import app.pachli.usecase.DeveloperToolsUseCase
|
import app.pachli.usecase.DeveloperToolsUseCase
|
||||||
import app.pachli.usecase.LogoutUsecase
|
import app.pachli.usecase.LogoutUsecase
|
||||||
import app.pachli.util.getDimension
|
import app.pachli.util.getDimension
|
||||||
import app.pachli.util.updateShortcut
|
import app.pachli.util.updateShortcuts
|
||||||
import at.connyduck.calladapter.networkresult.fold
|
import at.connyduck.calladapter.networkresult.fold
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.RequestManager
|
import com.bumptech.glide.RequestManager
|
||||||
|
@ -1085,7 +1085,7 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, MenuProvider {
|
||||||
updateProfiles()
|
updateProfiles()
|
||||||
|
|
||||||
externalScope.launch {
|
externalScope.launch {
|
||||||
updateShortcut(applicationContext, accountManager.activeAccount!!)
|
updateShortcuts(applicationContext, accountManager)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,10 +21,12 @@ import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
import androidx.core.app.Person
|
import androidx.core.app.Person
|
||||||
import androidx.core.content.pm.ShortcutInfoCompat
|
import androidx.core.content.pm.ShortcutInfoCompat
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
|
import app.pachli.core.accounts.AccountManager
|
||||||
import app.pachli.core.database.model.AccountEntity
|
import app.pachli.core.database.model.AccountEntity
|
||||||
import app.pachli.core.designsystem.R as DR
|
import app.pachli.core.designsystem.R as DR
|
||||||
import app.pachli.core.navigation.MainActivityIntent
|
import app.pachli.core.navigation.MainActivityIntent
|
||||||
|
@ -33,20 +35,19 @@ import java.util.concurrent.ExecutionException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
suspend fun updateShortcut(context: Context, account: AccountEntity) = withContext(Dispatchers.IO) {
|
suspend fun updateShortcuts(context: Context, accountManager: AccountManager) = withContext(Dispatchers.IO) {
|
||||||
val innerSize = context.resources.getDimensionPixelSize(DR.dimen.adaptive_bitmap_inner_size)
|
val innerSize = context.resources.getDimensionPixelSize(DR.dimen.adaptive_bitmap_inner_size)
|
||||||
val outerSize = context.resources.getDimensionPixelSize(DR.dimen.adaptive_bitmap_outer_size)
|
val outerSize = context.resources.getDimensionPixelSize(DR.dimen.adaptive_bitmap_outer_size)
|
||||||
|
|
||||||
val bmp = try {
|
val maxShortcuts = ShortcutManagerCompat.getMaxShortcutCountPerActivity(context)
|
||||||
|
|
||||||
|
val shortcuts = accountManager.getAllAccountsOrderedByActive().take(maxShortcuts).mapNotNull { account ->
|
||||||
|
val drawable = try {
|
||||||
if (TextUtils.isEmpty(account.profilePictureUrl)) {
|
if (TextUtils.isEmpty(account.profilePictureUrl)) {
|
||||||
Glide.with(context)
|
AppCompatResources.getDrawable(context, DR.drawable.avatar_default)
|
||||||
.asBitmap()
|
|
||||||
.load(DR.drawable.avatar_default)
|
|
||||||
.submit(innerSize, innerSize)
|
|
||||||
.get()
|
|
||||||
} else {
|
} else {
|
||||||
Glide.with(context)
|
Glide.with(context)
|
||||||
.asBitmap()
|
.asDrawable()
|
||||||
.load(account.profilePictureUrl)
|
.load(account.profilePictureUrl)
|
||||||
.error(DR.drawable.avatar_default)
|
.error(DR.drawable.avatar_default)
|
||||||
.submit(innerSize, innerSize)
|
.submit(innerSize, innerSize)
|
||||||
|
@ -56,18 +57,16 @@ suspend fun updateShortcut(context: Context, account: AccountEntity) = withConte
|
||||||
// The `.error` handler isn't always used. For example, Glide throws
|
// The `.error` handler isn't always used. For example, Glide throws
|
||||||
// ExecutionException if the URL does not point at an image. Fallback to
|
// ExecutionException if the URL does not point at an image. Fallback to
|
||||||
// the default avatar (https://github.com/bumptech/glide/issues/4672).
|
// the default avatar (https://github.com/bumptech/glide/issues/4672).
|
||||||
Glide.with(context)
|
AppCompatResources.getDrawable(context, DR.drawable.avatar_default)
|
||||||
.asBitmap()
|
} ?: return@mapNotNull null
|
||||||
.load(DR.drawable.avatar_default)
|
|
||||||
.submit(innerSize, innerSize)
|
|
||||||
.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
// inset the loaded bitmap inside a 108dp transparent canvas so it looks good as adaptive icon
|
// inset the loaded bitmap inside a 108dp transparent canvas so it looks good as adaptive icon
|
||||||
val outBmp = Bitmap.createBitmap(outerSize, outerSize, Bitmap.Config.ARGB_8888)
|
val outBmp = Bitmap.createBitmap(outerSize, outerSize, Bitmap.Config.ARGB_8888)
|
||||||
|
|
||||||
val canvas = Canvas(outBmp)
|
val canvas = Canvas(outBmp)
|
||||||
canvas.drawBitmap(bmp, (outerSize - innerSize).toFloat() / 2f, (outerSize - innerSize).toFloat() / 2f, null)
|
val border = (outerSize - innerSize) / 2
|
||||||
|
drawable.setBounds(border, border, border + innerSize, border + innerSize)
|
||||||
|
drawable.draw(canvas)
|
||||||
|
|
||||||
val icon = IconCompat.createWithAdaptiveBitmap(outBmp)
|
val icon = IconCompat.createWithAdaptiveBitmap(outBmp)
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ suspend fun updateShortcut(context: Context, account: AccountEntity) = withConte
|
||||||
putExtra(ShortcutManagerCompat.EXTRA_SHORTCUT_ID, account.id.toString())
|
putExtra(ShortcutManagerCompat.EXTRA_SHORTCUT_ID, account.id.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
val shortcutInfo = ShortcutInfoCompat.Builder(context, account.id.toString())
|
ShortcutInfoCompat.Builder(context, account.id.toString())
|
||||||
.setIntent(intent)
|
.setIntent(intent)
|
||||||
.setCategories(setOf("app.pachli.Share"))
|
.setCategories(setOf("app.pachli.Share"))
|
||||||
.setShortLabel(account.displayName)
|
.setShortLabel(account.displayName)
|
||||||
|
@ -92,8 +91,9 @@ suspend fun updateShortcut(context: Context, account: AccountEntity) = withConte
|
||||||
.setLongLived(true)
|
.setLongLived(true)
|
||||||
.setIcon(icon)
|
.setIcon(icon)
|
||||||
.build()
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
ShortcutManagerCompat.addDynamicShortcuts(context, listOf(shortcutInfo))
|
ShortcutManagerCompat.setDynamicShortcuts(context, shortcuts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeShortcut(context: Context, account: AccountEntity) {
|
fun removeShortcut(context: Context, account: AccountEntity) {
|
||||||
|
|
Loading…
Reference in New Issue