From 9df6f07b957ea436751b8fd28ce9cfc06cd9acaf Mon Sep 17 00:00:00 2001 From: Hamza417 <23103729+Hamza417@users.noreply.github.com> Date: Thu, 24 Jul 2025 14:33:50 +0530 Subject: [PATCH] rewrite: DataLoaderService to fix old optimization issues and crashes (cherry picked from commit 12ed82e608fbb613f165e5bdcc46aa49b9d80d62) --- .../decorations/views/LineNumberEditText.java | 2 +- .../viewmodels/PackageUtilsViewModel.kt | 179 +++-------- .../inure/services/DataLoaderService.kt | 304 ++++++------------ .../simple/inure/ui/launcher/SplashScreen.kt | 73 +---- .../app/simple/inure/ui/panels/Uninstalled.kt | 2 +- 5 files changed, 158 insertions(+), 402 deletions(-) diff --git a/app/src/main/java/app/simple/inure/decorations/views/LineNumberEditText.java b/app/src/main/java/app/simple/inure/decorations/views/LineNumberEditText.java index 32c2691f6..fc58e3b3b 100644 --- a/app/src/main/java/app/simple/inure/decorations/views/LineNumberEditText.java +++ b/app/src/main/java/app/simple/inure/decorations/views/LineNumberEditText.java @@ -13,7 +13,7 @@ import app.simple.inure.themes.manager.ThemeManager; public class LineNumberEditText extends TypeFaceEditText implements SharedPreferences.OnSharedPreferenceChangeListener { - private final String newline = System.getProperty("line.separator"); + private final String newline = System.lineSeparator(); private Rect rect; private Paint paint; diff --git a/app/src/main/java/app/simple/inure/extensions/viewmodels/PackageUtilsViewModel.kt b/app/src/main/java/app/simple/inure/extensions/viewmodels/PackageUtilsViewModel.kt index 2385118ec..3dd367b90 100644 --- a/app/src/main/java/app/simple/inure/extensions/viewmodels/PackageUtilsViewModel.kt +++ b/app/src/main/java/app/simple/inure/extensions/viewmodels/PackageUtilsViewModel.kt @@ -1,57 +1,36 @@ package app.simple.inure.extensions.viewmodels -import android.annotation.SuppressLint import android.app.Application -import android.content.BroadcastReceiver import android.content.ComponentName import android.content.Context import android.content.Intent -import android.content.IntentFilter import android.content.ServiceConnection import android.content.pm.ApplicationInfo import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.os.Build -import android.os.DeadObjectException import android.os.IBinder import android.util.Log -import androidx.localbroadcastmanager.content.LocalBroadcastManager +import androidx.lifecycle.viewModelScope import app.simple.inure.R import app.simple.inure.apk.utils.PackageUtils import app.simple.inure.apk.utils.PackageUtils.safeApplicationInfo import app.simple.inure.services.DataLoaderService import app.simple.inure.util.ArrayUtils +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch abstract class PackageUtilsViewModel(application: Application) : WrappedViewModel(application) { - private var apps: ArrayList = arrayListOf() - private var uninstalledApps: ArrayList = arrayListOf() - + private var dataLoaderService: DataLoaderService? = null private var serviceConnection: ServiceConnection? = null - @SuppressLint("StaticFieldLeak") // This is an application context - private var dataLoaderService: DataLoaderService? = null - private var broadcastReceiver: BroadcastReceiver? = null - private var intentFilter: IntentFilter = IntentFilter() - init { - intentFilter.addAction(DataLoaderService.APPS_LOADED) - intentFilter.addAction(DataLoaderService.UNINSTALLED_APPS_LOADED) - intentFilter.addAction(DataLoaderService.INSTALLED_APPS_LOADED) - intentFilter.addAction(DataLoaderService.RELOAD_APPS) - serviceConnection = object : ServiceConnection { override fun onServiceConnected(name: ComponentName?, service: IBinder?) { dataLoaderService = (service as DataLoaderService.LoaderBinder).getService() - if (dataLoaderService!!.hasDataLoaded()) { - apps = dataLoaderService!!.getInstalledApps() - uninstalledApps = dataLoaderService!!.getUninstalledApps() - - onAppsLoaded(apps) - onUninstalledAppsLoaded(uninstalledApps) - } else { - dataLoaderService!!.startLoading() - } + observeServiceFlows() + dataLoaderService?.refresh() } override fun onServiceDisconnected(name: ComponentName?) { @@ -59,65 +38,35 @@ abstract class PackageUtilsViewModel(application: Application) : WrappedViewMode } } - @Suppress("UNCHECKED_CAST") - broadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - when (intent?.action) { - DataLoaderService.APPS_LOADED -> { - apps = dataLoaderService!!.getInstalledApps().clone() as ArrayList - uninstalledApps = dataLoaderService!!.getUninstalledApps().clone() as ArrayList + applicationContext().bindService( + Intent(applicationContext(), DataLoaderService::class.java), + serviceConnection!!, + Context.BIND_AUTO_CREATE + ) + } - onAppsLoaded(apps) - onUninstalledAppsLoaded(uninstalledApps) - } - - DataLoaderService.UNINSTALLED_APPS_LOADED -> { - uninstalledApps = dataLoaderService!!.getUninstalledApps().clone() as ArrayList - onUninstalledAppsLoaded(uninstalledApps) - } - - DataLoaderService.INSTALLED_APPS_LOADED -> { - apps = dataLoaderService!!.getInstalledApps().clone() as ArrayList - onAppsLoaded(apps) - } - - DataLoaderService.RELOAD_APPS -> { - Log.d("DataLoaderService", "Reloading apps") - dataLoaderService!!.refresh() - } + private fun observeServiceFlows() { + viewModelScope.launch { + dataLoaderService?.installedApps?.collectLatest { apps -> + if (apps != null) { + onAppsLoaded(ArrayUtils.deepCopy(apps)) + } + } + } + viewModelScope.launch { + dataLoaderService?.uninstalledApps?.collectLatest { apps -> + if (apps != null) { + onUninstalledAppsLoaded(ArrayUtils.deepCopy(apps)) } } } - - LocalBroadcastManager.getInstance(applicationContext()).registerReceiver(broadcastReceiver!!, intentFilter) - applicationContext().bindService( - Intent(applicationContext(), DataLoaderService::class.java), serviceConnection!!, Context.BIND_AUTO_CREATE) - } - - fun getInstalledApps(): ArrayList { - return dataLoaderService!!.getInstalledApps() - } - - fun getUninstalledApps(): ArrayList { - return dataLoaderService!!.getUninstalledApps() - } - - fun getCompleteApps(): List { - return getInstalledApps() + getUninstalledApps() } fun refreshPackageData() { - dataLoaderService!!.refresh() - } - - fun refreshUninstalledPackageData() { - dataLoaderService!!.refreshUninstalled() - } - - fun refreshInstalledPackageData() { - dataLoaderService!!.refreshInstalled() + dataLoaderService?.refresh() } + // Utility and helper functions remain unchanged protected fun PackageManager.isPackageInstalled(packageName: String): Boolean { while (true) { try { @@ -129,7 +78,7 @@ abstract class PackageUtilsViewModel(application: Application) : WrappedViewMode return true } catch (e: PackageManager.NameNotFoundException) { return false - } catch (e: DeadObjectException) { + } catch (e: android.os.DeadObjectException) { Log.e("PackageUtilsViewModel", "isPackageInstalled: DeadObjectException") } } @@ -138,9 +87,9 @@ abstract class PackageUtilsViewModel(application: Application) : WrappedViewMode protected fun PackageManager.isPackageEnabled(packageName: String): Boolean { return try { getPackageInfo(packageName)!!.safeApplicationInfo.enabled - } catch (e: PackageManager.NameNotFoundException) { + } catch (_: PackageManager.NameNotFoundException) { false - } catch (e: NullPointerException) { + } catch (_: NullPointerException) { false } } @@ -149,17 +98,6 @@ abstract class PackageUtilsViewModel(application: Application) : WrappedViewMode return isPackageInstalled(packageName) && isPackageEnabled(packageName) } - protected fun PackageManager.getInstalledPackages(flags: Long = PackageUtils.flags): ArrayList { - val packageInfoList = ArrayList() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - packageInfoList.addAll(getInstalledPackages(PackageManager.PackageInfoFlags.of(flags))) - } else { - @Suppress("DEPRECATION") - packageInfoList.addAll(getInstalledPackages(flags.toInt())) - } - return ArrayUtils.deepCopy(packageInfoList) - } - protected fun PackageManager.getPackageInfo(packageName: String): PackageInfo? { try { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { @@ -168,7 +106,7 @@ abstract class PackageUtilsViewModel(application: Application) : WrappedViewMode try { @Suppress("DEPRECATION") getPackageInfo(packageName, PackageUtils.flags.toInt()) - } catch (e: RuntimeException) { + } catch (_: RuntimeException) { @Suppress("DEPRECATION") getPackageInfo(packageName, PackageManager.GET_META_DATA) } @@ -176,7 +114,6 @@ abstract class PackageUtilsViewModel(application: Application) : WrappedViewMode } catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() } - return null } @@ -192,67 +129,49 @@ abstract class PackageUtilsViewModel(application: Application) : WrappedViewMode } catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() } - return null } - /** - * Fetches the app's name from the package id of the same application - * @param context of the given environment - * @param applicationInfo is [ApplicationInfo] object containing app's - * information - * @return app's name as [String] - */ protected fun getApplicationName(context: Context, applicationInfo: ApplicationInfo): String { while (true) { try { return context.packageManager.getApplicationLabel(applicationInfo).toString() - } catch (e: PackageManager.NameNotFoundException) { + } catch (_: PackageManager.NameNotFoundException) { return context.getString(R.string.unknown) - } catch (e: DeadObjectException) { + } catch (_: android.os.DeadObjectException) { Log.e("PackageUtilsViewModel", "getApplicationName: DeadObjectException") } } } - protected fun ArrayList.loadPackageNames(): ArrayList { - forEach { - it.safeApplicationInfo.name = getApplicationName(applicationContext(), it.safeApplicationInfo) - } - - return this - } - open fun onUninstalledAppsLoaded(uninstalledApps: ArrayList) { - // Log.d("PackageUtilsViewModel", "onUninstalledAppsLoaded: ${uninstalledApps.size}") + // Override in subclasses } open fun onAppsLoaded(apps: ArrayList) { - // Log.d("PackageUtilsViewModel", "onAppsLoaded: ${apps.size}") + // Override in subclasses + } + + open fun getInstalledApps(): ArrayList { + return ArrayUtils.deepCopy(dataLoaderService?.installedApps?.value ?: ArrayList()) + } + + open fun getUninstalledApps(): ArrayList { + return ArrayUtils.deepCopy(dataLoaderService?.uninstalledApps?.value ?: ArrayList()) } override fun onCleared() { super.onCleared() try { serviceConnection?.let { - applicationContext().unbindService(it) + app.applicationContext.unbindService(it) } - } catch (e: java.lang.IllegalStateException) { - e.printStackTrace() - } catch (e: IllegalArgumentException) { - e.printStackTrace() - } - - try { - broadcastReceiver?.let { - LocalBroadcastManager.getInstance(applicationContext()).unregisterReceiver(it) - } - } catch (e: java.lang.IllegalStateException) { - e.printStackTrace() - } catch (e: IllegalArgumentException) { - e.printStackTrace() - } catch (e: NullPointerException) { + } catch (e: Exception) { e.printStackTrace() } } -} + + companion object { + private const val TAG = "PackageUtilsViewModel" + } +} \ No newline at end of file diff --git a/app/src/main/java/app/simple/inure/services/DataLoaderService.kt b/app/src/main/java/app/simple/inure/services/DataLoaderService.kt index cd5f18f19..112f02481 100644 --- a/app/src/main/java/app/simple/inure/services/DataLoaderService.kt +++ b/app/src/main/java/app/simple/inure/services/DataLoaderService.kt @@ -1,265 +1,191 @@ package app.simple.inure.services import android.app.Service -import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.content.IntentFilter import android.content.pm.ApplicationInfo import android.content.pm.LauncherApps import android.content.pm.PackageInfo import android.content.pm.PackageManager -import android.os.BadParcelableException import android.os.Binder import android.os.Build -import android.os.DeadObjectException -import android.os.DeadSystemException import android.os.IBinder import android.os.UserHandle import android.util.Log -import androidx.localbroadcastmanager.content.LocalBroadcastManager import app.simple.inure.R import app.simple.inure.apk.utils.PackageUtils.safeApplicationInfo import app.simple.inure.preferences.DevelopmentPreferences -import app.simple.inure.util.ArrayUtils.clone -import app.simple.inure.util.ArrayUtils.toArrayList import app.simple.inure.util.ConditionUtils.invert -import app.simple.inure.util.NullSafety.isNotNull import app.simple.inure.utils.DebloatUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import java.util.stream.Collectors class DataLoaderService : Service() { companion object { - const val UNINSTALLED_APPS_LOADED = "uninstalled_apps_loaded" - const val INSTALLED_APPS_LOADED = "installed_apps_loaded" - const val APPS_LOADED = "apps_loaded" - const val RELOAD_APPS = "reload_apps" - const val RELOAD_QUICK_APPS = "reload_quick_apps" - const val REFRESH = "refresh" - private const val TAG: String = "DataLoaderService" + + private const val INSTALLED_FLAGS = PackageManager.GET_META_DATA + + @Suppress("DEPRECATION") + private val UNINSTALLED_FLAGS = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + INSTALLED_FLAGS or PackageManager.MATCH_UNINSTALLED_PACKAGES + } else { + INSTALLED_FLAGS or PackageManager.GET_UNINSTALLED_PACKAGES + } + + const val REFRESH = "app.simple.inure.services.DataLoaderService.REFRESH" + const val RELOAD_QUICK_APPS = "app.simple.inure.services.DataLoaderService.RELOAD_QUICK_APPS" } - private var apps: ArrayList = arrayListOf() - private var uninstalledApps: ArrayList = arrayListOf() + private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + + private val _installedApps = MutableStateFlow?>(null) + val installedApps: StateFlow?> = _installedApps + + private val _uninstalledApps = MutableStateFlow?>(null) + val uninstalledApps: StateFlow?> = _uninstalledApps private var isLoading = false - private var flags = PackageManager.GET_META_DATA - private var broadcastReceiver: BroadcastReceiver? = null - private var intentFilter: IntentFilter = IntentFilter() private val launcherAppsService: LauncherApps by lazy { - getSystemService(Context.LAUNCHER_APPS_SERVICE) as LauncherApps + getSystemService(LAUNCHER_APPS_SERVICE) as LauncherApps } private var launcherAppsCallback: LauncherApps.Callback? = null inner class LoaderBinder : Binder() { - fun getService(): DataLoaderService { - return this@DataLoaderService - } + fun getService(): DataLoaderService = this@DataLoaderService } - override fun onBind(intent: Intent): IBinder { - return LoaderBinder() - } + override fun onBind(intent: Intent): IBinder = LoaderBinder() override fun onCreate() { super.onCreate() Log.d(TAG, "onCreate: Dataloader service created") - broadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - when (intent?.action) { - REFRESH -> { - refresh() - } - } - } - } - - intentFilter.addAction(REFRESH) - LocalBroadcastManager.getInstance(applicationContext).registerReceiver(broadcastReceiver!!, intentFilter) - if (launcherAppsCallback == null) { launcherAppsCallback = object : LauncherApps.Callback() { - override fun onPackageRemoved(packageName: String?, user: UserHandle?) { - Log.d(TAG, "onPackageRemoved: $packageName") - refresh() - } - - override fun onPackageAdded(packageName: String?, user: UserHandle?) { - Log.d(TAG, "onPackageAdded: $packageName") - refresh() - } - - override fun onPackageChanged(packageName: String?, user: UserHandle?) { - Log.d(TAG, "onPackageChanged: $packageName") - refresh() - } - - override fun onPackagesAvailable(packageNames: Array?, user: UserHandle?, replacing: Boolean) { - Log.d(TAG, "onPackagesAvailable: ${packageNames?.contentToString()}") - refresh() - } - - override fun onPackagesUnavailable(packageNames: Array?, user: UserHandle?, replacing: Boolean) { - Log.d(TAG, "onPackagesUnavailable: ${packageNames?.contentToString()}") - refresh() - } - + override fun onPackageRemoved(packageName: String?, user: UserHandle?) = refresh() + override fun onPackageAdded(packageName: String?, user: UserHandle?) = refresh() + override fun onPackageChanged(packageName: String?, user: UserHandle?) = refresh() + override fun onPackagesAvailable(packageNames: Array?, user: UserHandle?, replacing: Boolean) = refresh() + override fun onPackagesUnavailable(packageNames: Array?, user: UserHandle?, replacing: Boolean) = refresh() fun refresh() { if (DevelopmentPreferences.get(DevelopmentPreferences.REFRESH_APPS_LIST_USING_LAUNCHER_SERVICE)) { this@DataLoaderService.refresh() } } } - // launcherAppsService.registerCallback(launcherAppsCallback!!) - } else { - Log.i(TAG, "onCreate: LauncherApps callback already initialized") } } override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { - startLoading() + refresh() return super.onStartCommand(intent, flags, startId) } override fun onDestroy() { super.onDestroy() Log.d(TAG, "onDestroy: Dataloader service destroyed") - LocalBroadcastManager.getInstance(applicationContext).unregisterReceiver(broadcastReceiver!!) + serviceScope.cancel() if (launcherAppsCallback != null) { launcherAppsService.unregisterCallback(launcherAppsCallback) } } - fun getInstalledApps(): ArrayList { - if (apps.isNotNull() && apps.isNotEmpty()) { - @Suppress("UNCHECKED_CAST") - return apps.clone() as ArrayList - } else { - apps = loadInstalledApps() as ArrayList - return getInstalledApps() - } - } - - @Suppress("UNCHECKED_CAST") - fun getUninstalledApps(): ArrayList { - return if (uninstalledApps.isNotNull() && uninstalledApps.isNotEmpty()) { - uninstalledApps.clone() as ArrayList - } else { - loadUninstalledApps() - uninstalledApps.clone() as ArrayList - } - } - - fun startLoading() { + fun refresh() { if (isLoading.invert()) { + Log.i(TAG, "refresh: Loading installed and uninstalled apps") + isLoading = true - - CoroutineScope(Dispatchers.IO).launch { - if (apps.isEmpty()) { - apps = loadInstalledApps().clone() - } - - if (uninstalledApps.isEmpty()) { - loadUninstalledApps() - } - - // onAppsLoaded(apps.toArrayList()) - // onUninstalledAppsLoaded(uninstalledApps.toArrayList()) - - // We will init bloat list here - // Because I couldn't think of any other place - DebloatUtils.initBloatAppsSet() + serviceScope.launch { + val installed = loadInstalledApps() + val uninstalled = loadUninstalledApps() withContext(Dispatchers.Main) { - LocalBroadcastManager.getInstance(applicationContext).sendBroadcast(Intent(APPS_LOADED)) + _installedApps.value = installed + _uninstalledApps.value = uninstalled isLoading = false } + Log.i(TAG, "refresh: Loaded ${installed.size} installed and ${uninstalled.size} uninstalled apps") + + DebloatUtils.initBloatAppsSet() + } + } else { + Log.w(TAG, "refresh: Already loading apps, skipping refresh") + } + } + + private suspend fun loadInstalledApps(maxRetries: Int = 3): ArrayList { + val result = ArrayList() + repeat(maxRetries) { attempt -> + try { + val packageNames = packageManager.getInstalledPackages(0).map { it.packageName } + packageNames.chunked(100).forEach { batch -> + batch.forEach { pkg -> + try { + val info = packageManager.getPackageInfo(pkg, INSTALLED_FLAGS) + result.add(info) + } catch (_: Exception) { + } + } + } + result.forEach { + it.safeApplicationInfo.name = getApplicationName(applicationContext, it.safeApplicationInfo) + } + return result + } catch (e: Exception) { + result.clear() + e.printStackTrace() + if (attempt < maxRetries - 1) { + delay(500L) + } } } + return result } - fun refresh() { - isLoading = false - apps.clear() - uninstalledApps.clear() - startLoading() - } + private suspend fun loadUninstalledApps(maxRetries: Int = 3): ArrayList { + val result = ArrayList() - fun hasDataLoaded(): Boolean { - return apps.isNotEmpty() && uninstalledApps.isNotEmpty() - } - - private fun loadInstalledApps(): MutableList { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + repeat(maxRetries) { attempt -> try { - return packageManager.getInstalledPackages(flags).loadPackageNames() - } catch (e: DeadObjectException) { + val packageNames = packageManager.getInstalledPackages(0).map { it.packageName } + packageNames.chunked(100).forEach { batch -> + batch.forEach { pkg -> + try { + val info = packageManager.getPackageInfo(pkg, UNINSTALLED_FLAGS) + if (info.safeApplicationInfo.flags and ApplicationInfo.FLAG_INSTALLED == 0) { + result.add(info) + } + } catch (_: Exception) { + } + } + } + result.forEach { + it.safeApplicationInfo.name = getApplicationName(applicationContext, it.safeApplicationInfo) + } + return result + } catch (e: Exception) { + result.clear() e.printStackTrace() - return mutableListOf() - } catch (e: DeadSystemException) { - e.printStackTrace() - return mutableListOf() - } - } else { - try { - return packageManager.getInstalledPackages(flags).loadPackageNames() - } catch (e: DeadObjectException) { - e.printStackTrace() - return mutableListOf() + if (attempt < maxRetries - 1) { + delay(500L) + } } } + return result } - @Suppress("DEPRECATION") - private fun loadUninstalledApps() { - val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - this.flags or PackageManager.MATCH_UNINSTALLED_PACKAGES - } else { - this.flags or PackageManager.GET_UNINSTALLED_PACKAGES - } - - if (uninstalledApps.isNotEmpty()) return - - try { - uninstalledApps = packageManager.getInstalledPackages(flags).stream() - .filter { packageInfo -> packageInfo.safeApplicationInfo.flags and ApplicationInfo.FLAG_INSTALLED == 0 } - .collect(Collectors.toList()) - .loadPackageNames() - .toArrayList() - } catch (e: DeadObjectException) { - uninstalledApps = arrayListOf() - e.printStackTrace() - } catch (e: BadParcelableException) { - uninstalledApps = arrayListOf() - e.printStackTrace() - } - } - - private fun MutableList.loadPackageNames(): MutableList { - forEach { - it.safeApplicationInfo.name = getApplicationName(application.applicationContext, it.safeApplicationInfo) - } - - return this - } - - /** - * Fetches the app's name from the package id of the same application - * @param context of the given environment - * @param applicationInfo is [ApplicationInfo] object containing app's - * information - * @return app's name as [String] - */ private fun getApplicationName(context: Context, applicationInfo: ApplicationInfo): String? { return try { context.packageManager.getApplicationLabel(applicationInfo).toString() @@ -267,30 +193,4 @@ class DataLoaderService : Service() { context.getString(R.string.unknown) } } - - private fun onUninstalledAppsLoaded(uninstalledApps: ArrayList) { - Log.d("DataLoaderService", "onUninstalledAppsLoaded: ${uninstalledApps.size}") - LocalBroadcastManager.getInstance(applicationContext) - .sendBroadcast(Intent(UNINSTALLED_APPS_LOADED)) - } - - private fun onAppsLoaded(apps: ArrayList) { - Log.d("DataLoaderService", "onAppsLoaded: ${apps.size}") - LocalBroadcastManager.getInstance(applicationContext) - .sendBroadcast(Intent(INSTALLED_APPS_LOADED)) - } - - @Suppress("UNCHECKED_CAST") - fun refreshUninstalled() { - uninstalledApps.clear() - loadUninstalledApps() - onUninstalledAppsLoaded(uninstalledApps.clone() as ArrayList) - } - - @Suppress("UNCHECKED_CAST") - fun refreshInstalled() { - apps.clear() - apps = loadInstalledApps() as ArrayList - onAppsLoaded(apps.clone() as ArrayList) - } -} +} \ No newline at end of file diff --git a/app/src/main/java/app/simple/inure/ui/launcher/SplashScreen.kt b/app/src/main/java/app/simple/inure/ui/launcher/SplashScreen.kt index c48492ea3..a37c01b65 100644 --- a/app/src/main/java/app/simple/inure/ui/launcher/SplashScreen.kt +++ b/app/src/main/java/app/simple/inure/ui/launcher/SplashScreen.kt @@ -3,17 +3,11 @@ package app.simple.inure.ui.launcher import android.Manifest import android.annotation.SuppressLint import android.app.AppOpsManager -import android.content.BroadcastReceiver -import android.content.ComponentName import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.content.ServiceConnection import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.os.Environment -import android.os.IBinder import android.os.Process import android.util.Log import android.view.LayoutInflater @@ -25,7 +19,6 @@ import androidx.core.app.AppOpsManagerCompat import androidx.core.content.ContextCompat import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope -import androidx.localbroadcastmanager.content.LocalBroadcastManager import app.simple.inure.BuildConfig import app.simple.inure.R import app.simple.inure.apk.utils.PackageUtils.isPackageInstalled @@ -45,7 +38,6 @@ import app.simple.inure.preferences.MusicPreferences import app.simple.inure.preferences.SearchPreferences import app.simple.inure.preferences.SetupPreferences import app.simple.inure.preferences.TrialPreferences -import app.simple.inure.services.DataLoaderService import app.simple.inure.ui.panels.Home import app.simple.inure.util.AppUtils import app.simple.inure.util.ConditionUtils.invert @@ -87,12 +79,6 @@ class SplashScreen : ScopedFragment() { private var isTagsLoaded = false private var isDebloatLoaded = false - private var serviceConnection: ServiceConnection? = null - private var dataLoaderService: DataLoaderService? = null - private var broadcastReceiver: BroadcastReceiver? = null - - private var intentFilter: IntentFilter = IntentFilter() - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.fragment_splash_screen, container, false) } @@ -102,33 +88,6 @@ class SplashScreen : ScopedFragment() { startPostponedEnterTransition() clearSearchStates() - intentFilter.addAction(DataLoaderService.APPS_LOADED) - intentFilter.addAction(DataLoaderService.UNINSTALLED_APPS_LOADED) - intentFilter.addAction(DataLoaderService.INSTALLED_APPS_LOADED) - - broadcastReceiver = object : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - if (intent?.action == DataLoaderService.APPS_LOADED) { - proceed() - } - } - } - - serviceConnection = object : ServiceConnection { - override fun onServiceConnected(name: ComponentName?, service: IBinder?) { - dataLoaderService = (service as DataLoaderService.LoaderBinder).getService() - if (dataLoaderService?.hasDataLoaded() == true) { - proceed() - } else { - dataLoaderService?.startLoading() - } - } - - override fun onServiceDisconnected(name: ComponentName?) { - dataLoaderService = null - } - } - icon = view.findViewById(R.id.imageView) loaderImageView = view.findViewById(R.id.loader) daysLeft = view.findViewById(R.id.days_left) @@ -167,31 +126,26 @@ class SplashScreen : ScopedFragment() { } requireArguments().getBoolean(BundleConstants.skip) -> { // Second check if setup is skipped - startLoaderService() + startLoader() } !checkForPermission() -> { if (SetupPreferences.isDontShowAgain()) { // If setup not skipped open setup - startLoaderService() + startLoader() } else { openFragmentSlide(Setup.newInstance()) } } else -> { // Load all data - startLoaderService() + startLoader() } } } } - private fun startLoaderService() { - val intent = Intent(requireContext(), DataLoaderService::class.java) - requireContext().bindService(intent, serviceConnection!!, Context.BIND_AUTO_CREATE) - - if (BehaviourPreferences.isSkipLoading()) { - proceed() - } + private fun startLoader() { + proceed() postDelayed(MAX_LOADING_TIME) { // Give the service 7 seconds to load /** @@ -438,25 +392,8 @@ class SplashScreen : ScopedFragment() { } } - override fun onResume() { - super.onResume() - LocalBroadcastManager.getInstance(requireContext()).registerReceiver(broadcastReceiver!!, intentFilter) - } - override fun onDestroy() { super.onDestroy() - try { - if (serviceConnection != null) { - requireContext().unbindService(serviceConnection!!) - } - } catch (e: java.lang.IllegalArgumentException) { - e.printStackTrace() // Should crash if moving to another [Setup] fragment - } - - if (broadcastReceiver != null) { - LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(broadcastReceiver!!) - } - handler.removeCallbacksAndMessages(null) } diff --git a/app/src/main/java/app/simple/inure/ui/panels/Uninstalled.kt b/app/src/main/java/app/simple/inure/ui/panels/Uninstalled.kt index 04dd5fb4b..f54f19387 100644 --- a/app/src/main/java/app/simple/inure/ui/panels/Uninstalled.kt +++ b/app/src/main/java/app/simple/inure/ui/panels/Uninstalled.kt @@ -78,7 +78,7 @@ class Uninstalled : ScopedFragment() { } R.drawable.ic_refresh -> { showLoader(manualOverride = true) - homeViewModel.refreshUninstalledPackageData() + homeViewModel.refreshPackageData() } } }