From dca5863ba8ad7813b3868fc52cce8ea27d1da9ac Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Wed, 25 Oct 2023 13:38:06 +0530 Subject: [PATCH] NotificationUtil: Move notification related logic into separate Util class Signed-off-by: Aayush Gupta --- .../com/aurora/store/AuroraApplication.kt | 47 +--- .../store/data/service/NotificationService.kt | 203 +------------- .../com/aurora/store/util/NotificationUtil.kt | 265 ++++++++++++++++++ 3 files changed, 273 insertions(+), 242 deletions(-) create mode 100644 app/src/main/java/com/aurora/store/util/NotificationUtil.kt diff --git a/app/src/main/java/com/aurora/store/AuroraApplication.kt b/app/src/main/java/com/aurora/store/AuroraApplication.kt index 787acf0ac..9e0ecbfb9 100644 --- a/app/src/main/java/com/aurora/store/AuroraApplication.kt +++ b/app/src/main/java/com/aurora/store/AuroraApplication.kt @@ -21,16 +21,13 @@ package com.aurora.store import android.app.Application -import android.app.NotificationChannel -import android.app.NotificationManager -import android.os.Build import androidx.core.content.ContextCompat -import com.aurora.Constants import com.aurora.extensions.isPAndAbove import com.aurora.store.data.downloader.DownloadManager import com.aurora.store.data.receiver.PackageManagerReceiver import com.aurora.store.data.service.NotificationService import com.aurora.store.util.CommonUtil +import com.aurora.store.util.NotificationUtil import com.aurora.store.util.PackageUtil import com.tonyodev.fetch2.Fetch import org.lsposed.hiddenapibypass.HiddenApiBypass @@ -53,8 +50,7 @@ class AuroraApplication : Application() { } //Create Notification Channels : General & Alert - createNotificationChannel() - + NotificationUtil.createNotificationChannel(this) NotificationService.startService(this) fetch = DownloadManager.with(this).fetch @@ -70,43 +66,4 @@ class AuroraApplication : Application() { CommonUtil.cleanupInstallationSessions(applicationContext) } - private fun createNotificationChannel() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager - val channels = ArrayList() - channels.add( - NotificationChannel( - Constants.NOTIFICATION_CHANNEL_ALERT, - getString(R.string.notification_channel_alert), - NotificationManager.IMPORTANCE_HIGH - ).apply { - setSound(null, null) - } - ) - channels.add( - NotificationChannel( - Constants.NOTIFICATION_CHANNEL_GENERAL, - getString(R.string.notification_channel_general), - NotificationManager.IMPORTANCE_MIN - ) - ) - channels.add( - NotificationChannel( - Constants.NOTIFICATION_CHANNEL_UPDATER_SERVICE, - getString(R.string.notification_channel_updater_service), - NotificationManager.IMPORTANCE_MIN - ) - ) - channels.add( - NotificationChannel( - Constants.NOTIFICATION_CHANNEL_UPDATES, - getString(R.string.notification_channel_updates), - NotificationManager.IMPORTANCE_DEFAULT - ).apply { - setSound(null, null) - } - ) - notificationManager.createNotificationChannels(channels) - } - } } diff --git a/app/src/main/java/com/aurora/store/data/service/NotificationService.kt b/app/src/main/java/com/aurora/store/data/service/NotificationService.kt index 954f48038..7bf7d96d4 100644 --- a/app/src/main/java/com/aurora/store/data/service/NotificationService.kt +++ b/app/src/main/java/com/aurora/store/data/service/NotificationService.kt @@ -20,36 +20,21 @@ package com.aurora.store.data.service -import android.app.Notification import android.app.NotificationManager -import android.app.PendingIntent import android.app.Service import android.content.Context import android.content.Intent -import android.graphics.Color import android.os.IBinder import android.util.ArrayMap -import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat -import androidx.core.content.ContextCompat -import androidx.core.os.bundleOf -import androidx.navigation.NavDeepLinkBuilder import com.aurora.Constants -import com.aurora.extensions.getStyledAttributeColor -import com.aurora.extensions.isMAndAbove import com.aurora.gplayapi.data.models.App -import com.aurora.store.MainActivity -import com.aurora.store.R import com.aurora.store.data.downloader.DownloadManager import com.aurora.store.data.downloader.RequestGroupIdBuilder import com.aurora.store.data.event.InstallerEvent import com.aurora.store.data.installer.AppInstaller -import com.aurora.store.data.receiver.DownloadCancelReceiver -import com.aurora.store.data.receiver.DownloadPauseReceiver -import com.aurora.store.data.receiver.DownloadResumeReceiver -import com.aurora.store.data.receiver.InstallReceiver -import com.aurora.store.util.CommonUtil import com.aurora.store.util.Log +import com.aurora.store.util.NotificationUtil import com.google.gson.Gson import com.google.gson.GsonBuilder import com.tonyodev.fetch2.AbstractFetchGroupListener @@ -58,9 +43,9 @@ import com.tonyodev.fetch2.Error import com.tonyodev.fetch2.Fetch import com.tonyodev.fetch2.FetchGroup import com.tonyodev.fetch2.Status +import java.lang.reflect.Modifier import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe -import java.lang.reflect.Modifier class NotificationService : Service() { @@ -149,10 +134,8 @@ class NotificationService : Service() { } private fun showNotification(groupId: Int, download: Download, fetchGroup: FetchGroup) { - val status = download.status - //Ignore notifications for completion of sub-parts of a bundled apk - if (status == Status.COMPLETED && fetchGroup.groupDownloadProgress < 100) + if (download.status == Status.COMPLETED && fetchGroup.groupDownloadProgress < 100) return //synchronized(appMap) { @@ -169,187 +152,20 @@ class NotificationService : Service() { if (app == null) return - if (status == Status.DELETED) { + if (download.status == Status.DELETED) { notificationManager.cancel(app.id) return } - val builder = NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNEL_GENERAL) - builder.setContentTitle(app.displayName) - builder.setSmallIcon(R.drawable.ic_notification_outlined) - builder.color = ContextCompat.getColor(this, R.color.colorAccent) - builder.setWhen(download.created) - builder.setContentIntent(getContentIntentForDownloads()) - - when (status) { - Status.PAUSED -> { - builder.setSmallIcon(R.drawable.ic_download_pause) - builder.setContentText(getString(R.string.download_paused)) - } - Status.CANCELLED -> { - builder.setSmallIcon(R.drawable.ic_download_cancel) - builder.setContentText(getString(R.string.download_canceled)) - builder.color = Color.RED - } - Status.FAILED -> - { - builder.setSmallIcon(R.drawable.ic_download_fail) - builder.setContentText(getString(R.string.download_failed)) - builder.color = Color.RED - } - Status.COMPLETED -> if (fetchGroup.groupDownloadProgress == 100) { - builder.setSmallIcon(android.R.drawable.stat_sys_download_done) - builder.setContentText(getString(R.string.download_completed)) - } - else -> { - builder.setSmallIcon(android.R.drawable.stat_sys_download) - builder.setContentText(getString(R.string.download_metadata)) - } - } - val progress = fetchGroup.groupDownloadProgress - val progressBigText = NotificationCompat.BigTextStyle() - - when (status) { - Status.QUEUED -> { - builder.setProgress(100, 0, true) - progressBigText.bigText(getString(R.string.download_queued)) - builder.setStyle(progressBigText) - } - - Status.DOWNLOADING -> { - val speedString: String = - CommonUtil.humanReadableByteSpeed(download.downloadedBytesPerSecond, true) - progressBigText.bigText( - getString( - R.string.download_progress, - fetchGroup.completedDownloads.size + 1, - fetchGroup.downloads.size, - speedString - ) - ) - builder.setStyle(progressBigText) - builder.addAction( - NotificationCompat.Action.Builder( - R.drawable.ic_download_pause, - getString(R.string.action_pause), - getPauseIntent(groupId) - ).build() - ) - builder.addAction( - NotificationCompat.Action.Builder( - R.drawable.ic_download_cancel, - getString(R.string.action_cancel), - getCancelIntent(groupId) - ).build() - ) - if (progress < 0) builder.setProgress( - 100, - 0, - true - ) else builder.setProgress(100, progress, false) - } - - Status.PAUSED -> { - progressBigText.bigText( - getString( - R.string.download_paused, - fetchGroup.completedDownloads.size, - fetchGroup.downloads.size - ) - ) - builder.setStyle(progressBigText) - builder.addAction( - NotificationCompat.Action.Builder( - R.drawable.ic_download_pause, - getString(R.string.action_resume), - getResumeIntent(groupId) - ).build() - ) - } - - Status.COMPLETED -> if (fetchGroup.groupDownloadProgress == 100) { - builder.setAutoCancel(true) - builder.setContentIntent(getContentIntentForDetails(app)) - builder.setStyle(progressBigText) - } - else -> { - - } - } - - when (status) { - Status.DOWNLOADING -> builder.setCategory(Notification.CATEGORY_PROGRESS) - Status.FAILED, Status.CANCELLED -> builder.setCategory(Notification.CATEGORY_ERROR) - else -> builder.setCategory(Notification.CATEGORY_STATUS) - } - if (NotificationManagerCompat.from(this).areNotificationsEnabled()) { notificationManager.notify( app.packageName, app.id, - builder.build() + NotificationUtil.getDownloadNotification(this, app, groupId, download, fetchGroup) ) } } - private fun getPauseIntent(groupId: Int): PendingIntent { - val intent = Intent(this, DownloadPauseReceiver::class.java) - intent.putExtra(Constants.FETCH_GROUP_ID, groupId) - val flags = if (isMAndAbove()) - PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE - else PendingIntent.FLAG_CANCEL_CURRENT - return PendingIntent.getBroadcast(this, groupId, intent, flags) - } - - private fun getResumeIntent(groupId: Int): PendingIntent { - val intent = Intent(this, DownloadResumeReceiver::class.java) - intent.putExtra(Constants.FETCH_GROUP_ID, groupId) - val flags = if (isMAndAbove()) - PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE - else PendingIntent.FLAG_CANCEL_CURRENT - return PendingIntent.getBroadcast(this, groupId, intent, flags) - } - - private fun getCancelIntent(groupId: Int): PendingIntent { - val intent = Intent(this, DownloadCancelReceiver::class.java) - intent.putExtra(Constants.FETCH_GROUP_ID, groupId) - val flags = if (isMAndAbove()) - PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE - else PendingIntent.FLAG_CANCEL_CURRENT - return PendingIntent.getBroadcast(this, groupId, intent, flags) - } - - private fun getContentIntentForDetails(app: App?): PendingIntent { - return NavDeepLinkBuilder(this) - .setGraph(R.navigation.mobile_navigation) - .setDestination(R.id.appDetailsFragment) - .setComponentName(MainActivity::class.java) - .setArguments(bundleOf("packageName" to app!!.packageName)) - .createPendingIntent() - } - - private fun getContentIntentForDownloads(): PendingIntent { - return NavDeepLinkBuilder(this) - .setGraph(R.navigation.mobile_navigation) - .setDestination(R.id.downloadFragment) - .setComponentName(MainActivity::class.java) - .createPendingIntent() - } - - private fun getInstallIntent(packageName: String): PendingIntent { - val intent = Intent(this, InstallReceiver::class.java) - intent.putExtra(Constants.STRING_EXTRA, packageName) - val flags = if (isMAndAbove()) - PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE - else PendingIntent.FLAG_CANCEL_CURRENT - return PendingIntent.getBroadcast( - this, - packageName.hashCode(), - intent, - flags - ) - } - @Subscribe() fun onEventMainThread(event: Any) { when (event) { @@ -398,18 +214,11 @@ class NotificationService : Service() { } private fun notifyInstallationStatus(app: App, status: String?) { - val builder = NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNEL_ALERT) - builder.color = getStyledAttributeColor(R.color.colorAccent) - builder.setSmallIcon(R.drawable.ic_install) - builder.setContentTitle(app.displayName) - builder.setContentText(status) - builder.setSubText(app.packageName) - if (NotificationManagerCompat.from(this).areNotificationsEnabled()) { notificationManager.notify( app.packageName, app.id, - builder.build() + NotificationUtil.getInstallNotification(this, app, status) ) } } diff --git a/app/src/main/java/com/aurora/store/util/NotificationUtil.kt b/app/src/main/java/com/aurora/store/util/NotificationUtil.kt new file mode 100644 index 000000000..5e3d65fec --- /dev/null +++ b/app/src/main/java/com/aurora/store/util/NotificationUtil.kt @@ -0,0 +1,265 @@ +package com.aurora.store.util + +import android.app.Application +import android.app.Notification +import android.app.NotificationChannel +import android.app.NotificationManager +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.os.Build +import androidx.core.app.NotificationCompat +import androidx.core.content.ContextCompat +import androidx.core.os.bundleOf +import androidx.navigation.NavDeepLinkBuilder +import com.aurora.Constants +import com.aurora.extensions.getStyledAttributeColor +import com.aurora.extensions.isMAndAbove +import com.aurora.gplayapi.data.models.App +import com.aurora.store.MainActivity +import com.aurora.store.R +import com.aurora.store.data.receiver.DownloadCancelReceiver +import com.aurora.store.data.receiver.DownloadPauseReceiver +import com.aurora.store.data.receiver.DownloadResumeReceiver +import com.aurora.store.data.receiver.InstallReceiver +import com.tonyodev.fetch2.Download +import com.tonyodev.fetch2.FetchGroup +import com.tonyodev.fetch2.Status + +object NotificationUtil { + + fun createNotificationChannel(context: Context) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val notificationManager = + context.getSystemService(Application.NOTIFICATION_SERVICE) as NotificationManager + val channels = ArrayList() + channels.add( + NotificationChannel( + Constants.NOTIFICATION_CHANNEL_ALERT, + context.getString(R.string.notification_channel_alert), + NotificationManager.IMPORTANCE_HIGH + ).apply { + setSound(null, null) + } + ) + channels.add( + NotificationChannel( + Constants.NOTIFICATION_CHANNEL_GENERAL, + context.getString(R.string.notification_channel_general), + NotificationManager.IMPORTANCE_MIN + ) + ) + channels.add( + NotificationChannel( + Constants.NOTIFICATION_CHANNEL_UPDATER_SERVICE, + context.getString(R.string.notification_channel_updater_service), + NotificationManager.IMPORTANCE_MIN + ) + ) + channels.add( + NotificationChannel( + Constants.NOTIFICATION_CHANNEL_UPDATES, + context.getString(R.string.notification_channel_updates), + NotificationManager.IMPORTANCE_DEFAULT + ).apply { + setSound(null, null) + } + ) + notificationManager.createNotificationChannels(channels) + } + } + + fun getDownloadNotification( + context: Context, + app: App, + groupId: Int, + download: Download, + fetchGroup: FetchGroup + ): Notification { + val status = download.status + + val builder = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_GENERAL) + builder.setContentTitle(app.displayName) + builder.setSmallIcon(R.drawable.ic_notification_outlined) + builder.color = ContextCompat.getColor(context, R.color.colorAccent) + builder.setWhen(download.created) + builder.setContentIntent(getContentIntentForDownloads(context)) + + when (status) { + Status.PAUSED -> { + builder.setSmallIcon(R.drawable.ic_download_pause) + builder.setContentText(context.getString(R.string.download_paused)) + } + + Status.CANCELLED -> { + builder.setSmallIcon(R.drawable.ic_download_cancel) + builder.setContentText(context.getString(R.string.download_canceled)) + builder.color = Color.RED + } + + Status.FAILED -> { + builder.setSmallIcon(R.drawable.ic_download_fail) + builder.setContentText(context.getString(R.string.download_failed)) + builder.color = Color.RED + } + + Status.COMPLETED -> if (fetchGroup.groupDownloadProgress == 100) { + builder.setSmallIcon(android.R.drawable.stat_sys_download_done) + builder.setContentText(context.getString(R.string.download_completed)) + } + + else -> { + builder.setSmallIcon(android.R.drawable.stat_sys_download) + builder.setContentText(context.getString(R.string.download_metadata)) + } + } + val progress = fetchGroup.groupDownloadProgress + val progressBigText = NotificationCompat.BigTextStyle() + + when (status) { + Status.QUEUED -> { + builder.setProgress(100, 0, true) + progressBigText.bigText(context.getString(R.string.download_queued)) + builder.setStyle(progressBigText) + } + + Status.DOWNLOADING -> { + val speedString: String = + CommonUtil.humanReadableByteSpeed(download.downloadedBytesPerSecond, true) + progressBigText.bigText( + context.getString( + R.string.download_progress, + fetchGroup.completedDownloads.size + 1, + fetchGroup.downloads.size, + speedString + ) + ) + builder.setStyle(progressBigText) + builder.addAction( + NotificationCompat.Action.Builder( + R.drawable.ic_download_pause, + context.getString(R.string.action_pause), + getPauseIntent(context, groupId) + ).build() + ) + builder.addAction( + NotificationCompat.Action.Builder( + R.drawable.ic_download_cancel, + context.getString(R.string.action_cancel), + getCancelIntent(context, groupId) + ).build() + ) + if (progress < 0) builder.setProgress( + 100, + 0, + true + ) else builder.setProgress(100, progress, false) + } + + Status.PAUSED -> { + progressBigText.bigText( + context.getString( + R.string.download_paused, + fetchGroup.completedDownloads.size, + fetchGroup.downloads.size + ) + ) + builder.setStyle(progressBigText) + builder.addAction( + NotificationCompat.Action.Builder( + R.drawable.ic_download_pause, + context.getString(R.string.action_resume), + getResumeIntent(context, groupId) + ).build() + ) + } + + Status.COMPLETED -> if (fetchGroup.groupDownloadProgress == 100) { + builder.setAutoCancel(true) + builder.setContentIntent(getContentIntentForDetails(context, app)) + builder.setStyle(progressBigText) + } + + else -> { + + } + } + + when (status) { + Status.DOWNLOADING -> builder.setCategory(Notification.CATEGORY_PROGRESS) + Status.FAILED, Status.CANCELLED -> builder.setCategory(Notification.CATEGORY_ERROR) + else -> builder.setCategory(Notification.CATEGORY_STATUS) + } + + return builder.build() + } + + fun getInstallNotification(context: Context, app: App, content: String?): Notification { + val builder = NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ALERT) + builder.color = context.getStyledAttributeColor(R.color.colorAccent) + builder.setSmallIcon(R.drawable.ic_install) + builder.setContentTitle(app.displayName) + builder.setContentText(content) + builder.setSubText(app.packageName) + return builder.build() + } + + private fun getPauseIntent(context: Context, groupId: Int): PendingIntent { + val intent = Intent(context, DownloadPauseReceiver::class.java) + intent.putExtra(Constants.FETCH_GROUP_ID, groupId) + val flags = if (isMAndAbove()) + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE + else PendingIntent.FLAG_CANCEL_CURRENT + return PendingIntent.getBroadcast(context, groupId, intent, flags) + } + + private fun getResumeIntent(context: Context, groupId: Int): PendingIntent { + val intent = Intent(context, DownloadResumeReceiver::class.java) + intent.putExtra(Constants.FETCH_GROUP_ID, groupId) + val flags = if (isMAndAbove()) + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE + else PendingIntent.FLAG_CANCEL_CURRENT + return PendingIntent.getBroadcast(context, groupId, intent, flags) + } + + private fun getCancelIntent(context: Context, groupId: Int): PendingIntent { + val intent = Intent(context, DownloadCancelReceiver::class.java) + intent.putExtra(Constants.FETCH_GROUP_ID, groupId) + val flags = if (isMAndAbove()) + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE + else PendingIntent.FLAG_CANCEL_CURRENT + return PendingIntent.getBroadcast(context, groupId, intent, flags) + } + + private fun getContentIntentForDetails(context: Context, app: App?): PendingIntent { + return NavDeepLinkBuilder(context) + .setGraph(R.navigation.mobile_navigation) + .setDestination(R.id.appDetailsFragment) + .setComponentName(MainActivity::class.java) + .setArguments(bundleOf("packageName" to app!!.packageName)) + .createPendingIntent() + } + + private fun getContentIntentForDownloads(context: Context): PendingIntent { + return NavDeepLinkBuilder(context) + .setGraph(R.navigation.mobile_navigation) + .setDestination(R.id.downloadFragment) + .setComponentName(MainActivity::class.java) + .createPendingIntent() + } + + private fun getInstallIntent(context: Context, packageName: String): PendingIntent { + val intent = Intent(context, InstallReceiver::class.java) + intent.putExtra(Constants.STRING_EXTRA, packageName) + val flags = if (isMAndAbove()) + PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE + else PendingIntent.FLAG_CANCEL_CURRENT + return PendingIntent.getBroadcast( + context, + packageName.hashCode(), + intent, + flags + ) + } +}