From bc86a220868a94fee16eb25637308442a4637bf1 Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Fri, 5 Aug 2022 13:30:53 +0200 Subject: [PATCH] Refresh shortcuts after removing one --- .../appshortcuts/AppShortcutRepository.kt | 142 ++++++++++++------ .../search/shortcut/ShortcutItemVM.kt | 1 + 2 files changed, 99 insertions(+), 44 deletions(-) diff --git a/appshortcuts/src/main/java/de/mm20/launcher2/appshortcuts/AppShortcutRepository.kt b/appshortcuts/src/main/java/de/mm20/launcher2/appshortcuts/AppShortcutRepository.kt index 753ca0c0..8868d84d 100644 --- a/appshortcuts/src/main/java/de/mm20/launcher2/appshortcuts/AppShortcutRepository.kt +++ b/appshortcuts/src/main/java/de/mm20/launcher2/appshortcuts/AppShortcutRepository.kt @@ -4,7 +4,11 @@ import android.content.Context import android.content.pm.LauncherActivityInfo import android.content.pm.LauncherApps import android.content.pm.PackageManager +import android.content.pm.ShortcutInfo +import android.os.Handler +import android.os.Looper import android.os.Process +import android.os.UserHandle import android.util.Log import androidx.core.content.getSystemService import de.mm20.launcher2.ktx.normalize @@ -12,11 +16,11 @@ import de.mm20.launcher2.permissions.PermissionGroup import de.mm20.launcher2.permissions.PermissionsManager import de.mm20.launcher2.preferences.LauncherDataStore import de.mm20.launcher2.search.data.AppShortcut +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.channelFlow -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.Job +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.* import kotlinx.coroutines.withContext import org.apache.commons.text.similarity.FuzzyScore import java.util.* @@ -38,6 +42,8 @@ internal class AppShortcutRepositoryImpl( private val dataStore: LauncherDataStore, ) : AppShortcutRepository { + private val scope = CoroutineScope(Dispatchers.Default + Job()) + override suspend fun getShortcutsForActivity( launcherActivityInfo: LauncherActivityInfo, count: Int, @@ -84,51 +90,99 @@ internal class AppShortcutRepositoryImpl( return@collectLatest } - val launcherApps = - context.getSystemService() ?: return@collectLatest send( - emptyList() - ) - - val shortcutQuery = LauncherApps.ShortcutQuery() - shortcutQuery.setQueryFlags( - LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED or - LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC or - LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST or - LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED or - LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER - ) - val shortcuts = launcherApps.getShortcuts(shortcutQuery, Process.myUserHandle()) - ?.filter { - if (it.longLabel != null) { - return@filter matches(it.longLabel.toString(), query) - } - if (it.shortLabel != null) { - return@filter matches(it.shortLabel.toString(), query) - } - return@filter false - } ?: emptyList() - - val pm = context.packageManager - - - send( - shortcuts.mapNotNull { - val label = try { - pm.getApplicationInfo(it.`package`, 0).loadLabel(pm).toString() - } catch (e: PackageManager.NameNotFoundException) { - "" - } - AppShortcut( - context, - it, - label + shortcutChangeEmitter.collectLatest { + val launcherApps = + context.getSystemService() ?: return@collectLatest send( + emptyList() ) - }.sorted() - ) + + val shortcutQuery = LauncherApps.ShortcutQuery() + shortcutQuery.setQueryFlags( + LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED or + LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC or + LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST or + LauncherApps.ShortcutQuery.FLAG_MATCH_CACHED or + LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER + ) + val shortcuts = launcherApps.getShortcuts(shortcutQuery, Process.myUserHandle()) + ?.filter { + if (it.longLabel != null) { + return@filter matches(it.longLabel.toString(), query) + } + if (it.shortLabel != null) { + return@filter matches(it.shortLabel.toString(), query) + } + return@filter false + } ?: emptyList() + + val pm = context.packageManager + + + send( + shortcuts.mapNotNull { + val label = try { + pm.getApplicationInfo(it.`package`, 0).loadLabel(pm).toString() + } catch (e: PackageManager.NameNotFoundException) { + "" + } + AppShortcut( + context, + it, + label + ) + }.sorted() + ) + } } } } + private val shortcutChangeEmitter = callbackFlow { + send(Unit) + val launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps + + val callback = object : LauncherApps.Callback() { + override fun onPackageRemoved(packageName: String?, user: UserHandle?) { + } + + override fun onPackageAdded(packageName: String?, user: UserHandle?) { + } + + override fun onPackageChanged(packageName: String?, user: UserHandle?) { + } + + override fun onPackagesAvailable( + packageNames: Array?, + user: UserHandle?, + replacing: Boolean + ) { + } + + override fun onPackagesUnavailable( + packageNames: Array?, + user: UserHandle?, + replacing: Boolean + ) { + } + + override fun onShortcutsChanged( + packageName: String, + shortcuts: MutableList, + user: UserHandle + ) { + super.onShortcutsChanged(packageName, shortcuts, user) + trySend(Unit) + } + + } + + launcherApps.registerCallback(callback, Handler(Looper.getMainLooper())) + + awaitClose { + launcherApps.unregisterCallback(callback) + } + }.shareIn(scope, SharingStarted.WhileSubscribed(500), 1) + override fun removePinnedShortcut(shortcut: AppShortcut) { val launcherApps = context.getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps if (!launcherApps.hasShortcutHostPermission()) return diff --git a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/shortcut/ShortcutItemVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/shortcut/ShortcutItemVM.kt index c6404a67..d1fa2293 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/shortcut/ShortcutItemVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/launcher/search/shortcut/ShortcutItemVM.kt @@ -29,5 +29,6 @@ class ShortcutItemVM(private val shortcut: AppShortcut) : SearchableItemVM(short fun deleteShortcut() { shortcutRepository.removePinnedShortcut(shortcut) + favoritesRepository.unpinItem(shortcut) } } \ No newline at end of file