From 87dc309d35cd398a771a2e9f4394e26ab894fbe1 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Wed, 27 Dec 2023 20:51:38 +0530 Subject: [PATCH] PackageManagerReceiver: Rework package install actions Notify on package installation and delete the downloaded directory Signed-off-by: Aayush Gupta --- .../aurora/extensions/BroadcastReceiver.kt | 26 ++++++++ .../data/receiver/PackageManagerReceiver.kt | 61 ++++++++++++------- .../com/aurora/store/util/NotificationUtil.kt | 19 ++++++ 3 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 app/src/main/java/com/aurora/extensions/BroadcastReceiver.kt diff --git a/app/src/main/java/com/aurora/extensions/BroadcastReceiver.kt b/app/src/main/java/com/aurora/extensions/BroadcastReceiver.kt new file mode 100644 index 000000000..26d07a950 --- /dev/null +++ b/app/src/main/java/com/aurora/extensions/BroadcastReceiver.kt @@ -0,0 +1,26 @@ +package com.aurora.extensions + +import android.content.BroadcastReceiver +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +@OptIn(DelicateCoroutinesApi::class) +fun BroadcastReceiver.goAsync( + context: CoroutineContext = EmptyCoroutineContext, + block: suspend CoroutineScope.() -> Unit +) { + val pendingResult = goAsync() + GlobalScope.launch(context) { + try { + block() + } finally { + pendingResult.finish() + cancel() + } + } +} diff --git a/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt b/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt index b5f22ae3b..94fb45b1a 100644 --- a/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt +++ b/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt @@ -19,29 +19,53 @@ package com.aurora.store.data.receiver +import android.app.NotificationManager import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import com.aurora.store.BuildConfig +import android.util.Log +import com.aurora.extensions.goAsync import com.aurora.store.data.event.BusEvent.InstallEvent import com.aurora.store.data.event.BusEvent.UninstallEvent import com.aurora.store.data.installer.AppInstaller +import com.aurora.store.data.model.DownloadStatus +import com.aurora.store.data.room.download.Download +import com.aurora.store.util.DownloadWorkerUtil +import com.aurora.store.util.NotificationUtil import com.aurora.store.util.PathUtil import com.aurora.store.util.Preferences +import com.aurora.store.util.Preferences.PREFERENCE_AUTO_DELETE import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.firstOrNull import org.greenrobot.eventbus.EventBus -import java.io.File @AndroidEntryPoint open class PackageManagerReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { + private val TAG = PackageManagerReceiver::class.java.simpleName + + @Inject + lateinit var downloadWorkerUtil: DownloadWorkerUtil + + override fun onReceive(context: Context, intent: Intent) = goAsync { if (intent.action != null && intent.data != null) { val packageName = intent.data!!.encodedSchemeSpecificPart when (intent.action) { Intent.ACTION_PACKAGE_ADDED -> { + Log.i(TAG, "Installed $packageName") EventBus.getDefault().post(InstallEvent(packageName, "")) + + downloadWorkerUtil.downloadsList.filter { it.isNotEmpty() }.firstOrNull() + ?.find { it.packageName == packageName && it.status == DownloadStatus.COMPLETED } + ?.let { + notifyInstallation(context, it) + if (Preferences.getBoolean(context, PREFERENCE_AUTO_DELETE)) { + clearDownloads(context, it) + } + } } Intent.ACTION_PACKAGE_REMOVED -> { @@ -53,29 +77,22 @@ open class PackageManagerReceiver : BroadcastReceiver() { AppInstaller.getInstance(context) .getPreferredInstaller() .removeFromInstallQueue(packageName) - - val isAutoDeleteAPKEnabled = Preferences.getBoolean( - context, - Preferences.PREFERENCE_AUTO_DELETE - ) - - if (isAutoDeleteAPKEnabled) - clearDownloads(context, packageName) - - //Clear self update apk - if (packageName == BuildConfig.APPLICATION_ID) - clearDownloads(context, packageName) } } - private fun clearDownloads(context: Context, packageName: String) { + private fun clearDownloads(context: Context, download: Download) { try { - val rootDirPath = PathUtil.getPackageDirectory(context, packageName) - val rootDir = File(rootDirPath) - if (rootDir.exists()) - rootDir.deleteRecursively() - } catch (e: Exception) { - + PathUtil.getAppDownloadDir(context, download.packageName, download.versionCode) + .deleteRecursively() + } catch (exception: Exception) { + Log.e(TAG, "Failed to delete $download.packageName's downloads", exception) } } + + private fun notifyInstallation(context: Context, download: Download) { + val notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + val notification = NotificationUtil.getInstallNotification(context, download) + notificationManager.notify(download.packageName.hashCode(), notification) + } } diff --git a/app/src/main/java/com/aurora/store/util/NotificationUtil.kt b/app/src/main/java/com/aurora/store/util/NotificationUtil.kt index 1c6a6afcf..19d2c0955 100644 --- a/app/src/main/java/com/aurora/store/util/NotificationUtil.kt +++ b/app/src/main/java/com/aurora/store/util/NotificationUtil.kt @@ -163,6 +163,25 @@ object NotificationUtil { return builder.build() } + fun getInstallNotification(context: Context, download: AuroraDownload): Notification { + val builder = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ALERT) + + // Set big icon for download + try { + val bitmap = BitmapFactory.decodeStream(URL(download.iconURL).openStream()) + builder.setLargeIcon(bitmap) + } catch (exception: Exception) { + Log.i(TAG, "Failed to set big icon", exception) + } + + return builder.setSmallIcon(R.drawable.ic_install) + .setColor(context.getStyledAttributeColor(R.color.colorAccent)) + .setContentTitle(download.displayName) + .setContentText(context.getString(R.string.installer_status_success)) + .setContentIntent(getContentIntentForDetails(context, download.packageName)) + .build() + } + fun getInstallerStatusNotification(context: Context, app: App, content: String?): Notification { val builder = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ALERT).apply {