diff --git a/app/src/main/java/de/jrpie/android/launcher/Application.kt b/app/src/main/java/de/jrpie/android/launcher/Application.kt index 25e3e07..e078cc9 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Application.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Application.kt @@ -1,14 +1,69 @@ package de.jrpie.android.launcher 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.VERSION_CODES +import android.os.UserHandle +import androidx.lifecycle.MutableLiveData import androidx.preference.PreferenceManager import de.jrpie.android.launcher.actions.TorchManager import de.jrpie.android.launcher.apps.AppInfo +import de.jrpie.android.launcher.apps.DetailedAppInfo import de.jrpie.android.launcher.preferences.LauncherPreferences class Application : android.app.Application() { + val apps = MutableLiveData>() + + // 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?, p1: UserHandle?, p2: Boolean) { + // TODO + } + + override fun onPackagesSuspended(packageNames: Array?, user: UserHandle?) { + // TODO + } + + override fun onPackagesUnsuspended(packageNames: Array?, user: UserHandle?) { + // TODO + } + + override fun onPackagesUnavailable(p0: Array?, p1: UserHandle?, p2: Boolean) { + // TODO + } + + override fun onPackageLoadingProgressChanged( + packageName: String, + user: UserHandle, + progress: Float + ) { + // TODO + } + + override fun onShortcutsChanged( + packageName: String, + shortcuts: MutableList, + user: UserHandle + ) { + // TODO + } + } + var torchManager: TorchManager? = null private var customAppNames: HashMap? = null private val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, pref -> @@ -32,10 +87,20 @@ class Application : android.app.Application() { LauncherPreferences.getSharedPreferences() .registerOnSharedPreferenceChangeListener(listener) + + + val launcherApps = getSystemService(LAUNCHER_APPS_SERVICE) as LauncherApps + launcherApps.registerCallback(launcherAppsCallback) + + loadApps() } fun getCustomAppNames(): HashMap { return (customAppNames ?: LauncherPreferences.apps().customNames() ?: HashMap()) .also { customAppNames = it } } + + private fun loadApps() { + AsyncTask.execute { apps.postValue(getApps(packageManager, applicationContext)) } + } } diff --git a/app/src/main/java/de/jrpie/android/launcher/Functions.kt b/app/src/main/java/de/jrpie/android/launcher/Functions.kt index 890a8b6..8f192d0 100644 --- a/app/src/main/java/de/jrpie/android/launcher/Functions.kt +++ b/app/src/main/java/de/jrpie/android/launcher/Functions.kt @@ -18,13 +18,9 @@ import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.DetailedAppInfo -import de.jrpie.android.launcher.ui.list.apps.AppsRecyclerAdapter import de.jrpie.android.launcher.ui.tutorial.TutorialActivity -/* Objects used by multiple activities */ -val appsList: MutableList = ArrayList() - /* REQUEST CODES */ const val REQUEST_CHOOSE_APP = 1 @@ -84,10 +80,10 @@ fun openTutorial(context: Context) { /** - * [loadApps] is used to speed up the [AppsRecyclerAdapter] loading time, - * as it caches all the apps and allows for fast access to the data. + * Load all apps. */ -fun loadApps(packageManager: PackageManager, context: Context) { +fun getApps(packageManager: PackageManager, context: Context): MutableList { + val start = System.currentTimeMillis() val loadList = mutableListOf() val launcherApps = context.getSystemService(Service.LAUNCHER_APPS_SERVICE) as LauncherApps @@ -101,7 +97,6 @@ fun loadApps(packageManager: PackageManager, context: Context) { } } - // fallback option if (loadList.isEmpty()) { 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() } - appsList.clear() - appsList.addAll(loadList) + + val end = System.currentTimeMillis() + Log.i(LOG_TAG, "${loadList.size} apps loaded (${end - start}ms)") + + return loadList } diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt b/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt index fa031b6..958d6f9 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/HomeActivity.kt @@ -20,7 +20,6 @@ import de.jrpie.android.launcher.actions.Action import de.jrpie.android.launcher.actions.Gesture import de.jrpie.android.launcher.actions.LauncherAction import de.jrpie.android.launcher.databinding.HomeBinding -import de.jrpie.android.launcher.loadApps import de.jrpie.android.launcher.openTutorial import de.jrpie.android.launcher.preferences.LauncherPreferences import de.jrpie.android.launcher.preferences.migratePreferencesToNewVersion @@ -88,9 +87,6 @@ class HomeActivity : UIObject, AppCompatActivity(), openTutorial(this) } - // Preload apps to speed up the Apps Recycler - AsyncTask.execute { loadApps(packageManager, applicationContext) } - // Initialise layout binding = HomeBinding.inflate(layoutInflater) setContentView(binding.root) diff --git a/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/AppsRecyclerAdapter.kt b/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/AppsRecyclerAdapter.kt index 88493d7..60f8019 100644 --- a/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/AppsRecyclerAdapter.kt +++ b/app/src/main/java/de/jrpie/android/launcher/ui/list/apps/AppsRecyclerAdapter.kt @@ -4,7 +4,6 @@ import android.annotation.SuppressLint import android.app.Activity import android.content.Intent import android.graphics.Rect -import android.os.AsyncTask import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -12,16 +11,16 @@ import android.view.inputmethod.InputMethodManager import android.widget.ImageView import android.widget.PopupMenu import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.RecyclerView +import de.jrpie.android.launcher.Application import de.jrpie.android.launcher.R import de.jrpie.android.launcher.REQUEST_CHOOSE_APP import de.jrpie.android.launcher.actions.AppAction import de.jrpie.android.launcher.apps.AppFilter import de.jrpie.android.launcher.apps.AppInfo import de.jrpie.android.launcher.apps.DetailedAppInfo -import de.jrpie.android.launcher.appsList 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.ListLayout import de.jrpie.android.launcher.ui.list.ListActivity @@ -47,8 +46,16 @@ class AppsRecyclerAdapter( ) : RecyclerView.Adapter() { + private val apps = (activity.applicationContext as Application).apps private val appsListDisplayed: MutableList = mutableListOf() + init { + apps.observe(this.activity as AppCompatActivity) { + updateAppsList() + } + updateAppsList() + } + inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener { @@ -171,18 +178,6 @@ class AppsRecyclerAdapter( 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()) { if (pos >= appsListDisplayed.size) { return @@ -205,7 +200,7 @@ class AppsRecyclerAdapter( fun updateAppsList(triggerAutoLaunch: Boolean = false) { appsListDisplayed.clear() - appsListDisplayed.addAll(appFilter(appsList)) + apps.value?.let { appsListDisplayed.addAll(appFilter(it)) } if (triggerAutoLaunch && appsListDisplayed.size == 1