use LiveData to store app list

This commit is contained in:
Josia Pietsch 2024-12-20 04:18:05 +01:00
parent 3353719cc3
commit 2b7999cfdc
Signed by: jrpie
GPG key ID: E70B571D66986A2D
4 changed files with 84 additions and 30 deletions

View file

@ -1,14 +1,69 @@
package de.jrpie.android.launcher package de.jrpie.android.launcher
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.LauncherApps
import android.content.pm.ShortcutInfo
import android.os.AsyncTask
import android.os.Build import android.os.Build
import android.os.Build.VERSION_CODES import android.os.Build.VERSION_CODES
import android.os.UserHandle
import androidx.lifecycle.MutableLiveData
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import de.jrpie.android.launcher.actions.TorchManager import de.jrpie.android.launcher.actions.TorchManager
import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.AppInfo
import de.jrpie.android.launcher.apps.DetailedAppInfo
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
class Application : android.app.Application() { class Application : android.app.Application() {
val apps = MutableLiveData<List<DetailedAppInfo>>()
// TODO: only update specific apps
private val launcherAppsCallback = object : LauncherApps.Callback() {
override fun onPackageRemoved(p0: String?, p1: UserHandle?) {
loadApps()
}
override fun onPackageAdded(p0: String?, p1: UserHandle?) {
loadApps()
}
override fun onPackageChanged(p0: String?, p1: UserHandle?) {
loadApps()
}
override fun onPackagesAvailable(p0: Array<out String>?, p1: UserHandle?, p2: Boolean) {
// TODO
}
override fun onPackagesSuspended(packageNames: Array<out String>?, user: UserHandle?) {
// TODO
}
override fun onPackagesUnsuspended(packageNames: Array<out String>?, user: UserHandle?) {
// TODO
}
override fun onPackagesUnavailable(p0: Array<out String>?, p1: UserHandle?, p2: Boolean) {
// TODO
}
override fun onPackageLoadingProgressChanged(
packageName: String,
user: UserHandle,
progress: Float
) {
// TODO
}
override fun onShortcutsChanged(
packageName: String,
shortcuts: MutableList<ShortcutInfo>,
user: UserHandle
) {
// TODO
}
}
var torchManager: TorchManager? = null var torchManager: TorchManager? = null
private var customAppNames: HashMap<AppInfo, String>? = null private var customAppNames: HashMap<AppInfo, String>? = null
private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, pref -> private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, pref ->
@ -32,10 +87,20 @@ class Application : android.app.Application() {
LauncherPreferences.getSharedPreferences() LauncherPreferences.getSharedPreferences()
.registerOnSharedPreferenceChangeListener(listener) .registerOnSharedPreferenceChangeListener(listener)
val launcherApps = getSystemService(LAUNCHER_APPS_SERVICE) as LauncherApps
launcherApps.registerCallback(launcherAppsCallback)
loadApps()
} }
fun getCustomAppNames(): HashMap<AppInfo, String> { fun getCustomAppNames(): HashMap<AppInfo, String> {
return (customAppNames ?: LauncherPreferences.apps().customNames() ?: HashMap()) return (customAppNames ?: LauncherPreferences.apps().customNames() ?: HashMap())
.also { customAppNames = it } .also { customAppNames = it }
} }
private fun loadApps() {
AsyncTask.execute { apps.postValue(getApps(packageManager, applicationContext)) }
}
} }

View file

@ -18,13 +18,9 @@ import de.jrpie.android.launcher.actions.Action
import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.AppInfo
import de.jrpie.android.launcher.apps.DetailedAppInfo import de.jrpie.android.launcher.apps.DetailedAppInfo
import de.jrpie.android.launcher.ui.list.apps.AppsRecyclerAdapter
import de.jrpie.android.launcher.ui.tutorial.TutorialActivity import de.jrpie.android.launcher.ui.tutorial.TutorialActivity
/* Objects used by multiple activities */
val appsList: MutableList<DetailedAppInfo> = ArrayList()
/* REQUEST CODES */ /* REQUEST CODES */
const val REQUEST_CHOOSE_APP = 1 const val REQUEST_CHOOSE_APP = 1
@ -84,10 +80,10 @@ fun openTutorial(context: Context) {
/** /**
* [loadApps] is used to speed up the [AppsRecyclerAdapter] loading time, * Load all apps.
* as it caches all the apps and allows for fast access to the data.
*/ */
fun loadApps(packageManager: PackageManager, context: Context) { fun getApps(packageManager: PackageManager, context: Context): MutableList<DetailedAppInfo> {
val start = System.currentTimeMillis()
val loadList = mutableListOf<DetailedAppInfo>() val loadList = mutableListOf<DetailedAppInfo>()
val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps
@ -101,7 +97,6 @@ fun loadApps(packageManager: PackageManager, context: Context) {
} }
} }
// fallback option // fallback option
if (loadList.isEmpty()) { if (loadList.isEmpty()) {
Log.w(LOG_TAG, "using fallback option to load packages") Log.w(LOG_TAG, "using fallback option to load packages")
@ -119,8 +114,11 @@ fun loadApps(packageManager: PackageManager, context: Context) {
} }
} }
loadList.sortBy { it.getCustomLabel(context).toString() } loadList.sortBy { it.getCustomLabel(context).toString() }
appsList.clear()
appsList.addAll(loadList) val end = System.currentTimeMillis()
Log.i(LOG_TAG, "${loadList.size} apps loaded (${end - start}ms)")
return loadList
} }

View file

@ -20,7 +20,6 @@ import de.jrpie.android.launcher.actions.Action
import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.Gesture
import de.jrpie.android.launcher.actions.LauncherAction import de.jrpie.android.launcher.actions.LauncherAction
import de.jrpie.android.launcher.databinding.HomeBinding import de.jrpie.android.launcher.databinding.HomeBinding
import de.jrpie.android.launcher.loadApps
import de.jrpie.android.launcher.openTutorial import de.jrpie.android.launcher.openTutorial
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion
@ -88,9 +87,6 @@ class HomeActivity : UIObject, AppCompatActivity(),
openTutorial(this) openTutorial(this)
} }
// Preload apps to speed up the Apps Recycler
AsyncTask.execute { loadApps(packageManager, applicationContext) }
// Initialise layout // Initialise layout
binding = HomeBinding.inflate(layoutInflater) binding = HomeBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)

View file

@ -4,7 +4,6 @@ import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
import android.os.AsyncTask
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -12,16 +11,16 @@ import android.view.inputmethod.InputMethodManager
import android.widget.ImageView import android.widget.ImageView
import android.widget.PopupMenu import android.widget.PopupMenu
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import de.jrpie.android.launcher.Application
import de.jrpie.android.launcher.R import de.jrpie.android.launcher.R
import de.jrpie.android.launcher.REQUEST_CHOOSE_APP import de.jrpie.android.launcher.REQUEST_CHOOSE_APP
import de.jrpie.android.launcher.actions.AppAction import de.jrpie.android.launcher.actions.AppAction
import de.jrpie.android.launcher.apps.AppFilter import de.jrpie.android.launcher.apps.AppFilter
import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.AppInfo
import de.jrpie.android.launcher.apps.DetailedAppInfo import de.jrpie.android.launcher.apps.DetailedAppInfo
import de.jrpie.android.launcher.appsList
import de.jrpie.android.launcher.getUserFromId import de.jrpie.android.launcher.getUserFromId
import de.jrpie.android.launcher.loadApps
import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.LauncherPreferences
import de.jrpie.android.launcher.preferences.ListLayout import de.jrpie.android.launcher.preferences.ListLayout
import de.jrpie.android.launcher.ui.list.ListActivity import de.jrpie.android.launcher.ui.list.ListActivity
@ -47,8 +46,16 @@ class AppsRecyclerAdapter(
) : ) :
RecyclerView.Adapter<AppsRecyclerAdapter.ViewHolder>() { RecyclerView.Adapter<AppsRecyclerAdapter.ViewHolder>() {
private val apps = (activity.applicationContext as Application).apps
private val appsListDisplayed: MutableList<DetailedAppInfo> = mutableListOf() private val appsListDisplayed: MutableList<DetailedAppInfo> = mutableListOf()
init {
apps.observe(this.activity as AppCompatActivity) {
updateAppsList()
}
updateAppsList()
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
View.OnClickListener { View.OnClickListener {
@ -171,18 +178,6 @@ class AppsRecyclerAdapter(
return viewHolder return viewHolder
} }
init {
// Load the apps
if (appsList.size == 0)
loadApps(activity.packageManager, activity)
else {
AsyncTask.execute { loadApps(activity.packageManager, activity) }
notifyDataSetChanged()
}
updateAppsList()
}
fun selectItem(pos: Int, rect: Rect = Rect()) { fun selectItem(pos: Int, rect: Rect = Rect()) {
if (pos >= appsListDisplayed.size) { if (pos >= appsListDisplayed.size) {
return return
@ -205,7 +200,7 @@ class AppsRecyclerAdapter(
fun updateAppsList(triggerAutoLaunch: Boolean = false) { fun updateAppsList(triggerAutoLaunch: Boolean = false) {
appsListDisplayed.clear() appsListDisplayed.clear()
appsListDisplayed.addAll(appFilter(appsList)) apps.value?.let { appsListDisplayed.addAll(appFilter(it)) }
if (triggerAutoLaunch && if (triggerAutoLaunch &&
appsListDisplayed.size == 1 appsListDisplayed.size == 1