From 4a5626971edabf8877ad9579404a755e16b0e904 Mon Sep 17 00:00:00 2001 From: machiav3lli Date: Thu, 23 Jun 2022 00:03:42 +0200 Subject: [PATCH] Update: Pack all notify functions in NotificationUtils --- .../droidify/installer/InstallerService.kt | 107 +------ .../droidify/service/DownloadService.kt | 78 +---- .../looker/droidify/service/SyncService.kt | 92 +----- .../droidify/utility/NotificationUtils.kt | 286 ++++++++++++++++++ 4 files changed, 296 insertions(+), 267 deletions(-) create mode 100644 src/main/kotlin/com/looker/droidify/utility/NotificationUtils.kt diff --git a/src/main/kotlin/com/looker/droidify/installer/InstallerService.kt b/src/main/kotlin/com/looker/droidify/installer/InstallerService.kt index 4ddfed4a..4ef5c130 100644 --- a/src/main/kotlin/com/looker/droidify/installer/InstallerService.kt +++ b/src/main/kotlin/com/looker/droidify/installer/InstallerService.kt @@ -5,20 +5,16 @@ import android.app.NotificationManager import android.app.PendingIntent import android.content.Intent import android.content.pm.PackageInstaller -import android.content.pm.PackageManager import android.net.Uri import android.os.IBinder -import android.view.ContextThemeWrapper -import androidx.core.app.NotificationCompat import androidx.lifecycle.LifecycleService import com.looker.droidify.NOTIFICATION_CHANNEL_INSTALLER -import com.looker.droidify.NOTIFICATION_ID_INSTALLER import com.looker.droidify.R import com.looker.droidify.ui.activities.MainActivityX import com.looker.droidify.utility.Utils import com.looker.droidify.utility.extension.android.Android import com.looker.droidify.utility.extension.android.notificationManager -import com.looker.droidify.utility.extension.resources.getColorFromAttr +import com.looker.droidify.utility.notifyStatus /** * Runs during or after a PackageInstaller session in order to handle completion, failure, or @@ -29,8 +25,8 @@ class InstallerService : LifecycleService() { const val KEY_ACTION = "installerAction" const val KEY_APP_NAME = "appName" const val ACTION_UNINSTALL = "uninstall" - private const val INSTALLED_NOTIFICATION_TIMEOUT: Long = 5000 - private const val NOTIFICATION_TAG_PREFIX = "install-" + const val INSTALLED_NOTIFICATION_TIMEOUT: Long = 5000 + const val NOTIFICATION_TAG_PREFIX = "install-" } override fun onCreate() { @@ -69,99 +65,6 @@ class InstallerService : LifecycleService() { return START_NOT_STICKY } - /** - * Notifies user of installer outcome. This can be success, error, or a request for user action - * if installation cannot proceed automatically. - * - * @param intent provided by PackageInstaller to the callback service/activity. - */ - private fun notifyStatus(intent: Intent?) { - // unpack from intent - val status = intent?.getIntExtra(PackageInstaller.EXTRA_STATUS, -1) - val sessionId = intent?.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1) ?: 0 - - // get package information from session - val sessionInstaller = this.packageManager.packageInstaller - val session = if (sessionId > 0) sessionInstaller.getSessionInfo(sessionId) else null - - val name = - session?.appPackageName ?: intent?.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME) - val message = intent?.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) - val installerAction = intent?.getStringExtra(KEY_ACTION) - - // get application name for notifications - val appLabel = session?.appLabel ?: intent?.getStringExtra(KEY_APP_NAME) - ?: try { - if (name != null) packageManager.getApplicationLabel( - packageManager.getApplicationInfo( - name, - PackageManager.GET_META_DATA - ) - ) else null - } catch (_: Exception) { - null - } - - val notificationTag = "${NOTIFICATION_TAG_PREFIX}$name" - - // start building - val builder = NotificationCompat - .Builder(this, NOTIFICATION_CHANNEL_INSTALLER) - .setAutoCancel(true) - .setColor( - ContextThemeWrapper(this, R.style.Theme_Main_Light) - .getColorFromAttr(R.attr.colorPrimary).defaultColor - ) - - when (status) { - PackageInstaller.STATUS_PENDING_USER_ACTION -> { - // request user action with "downloaded" notification that triggers a working prompt - notificationManager.notify( - notificationTag, NOTIFICATION_ID_INSTALLER, builder - .setSmallIcon(android.R.drawable.stat_sys_download_done) - .setContentIntent(installIntent(intent)) - .setContentTitle(getString(R.string.downloaded_FORMAT, appLabel)) - .setContentText(getString(R.string.tap_to_install_DESC)) - .build() - ) - } - PackageInstaller.STATUS_SUCCESS -> { - if (installerAction == ACTION_UNINSTALL) - // remove any notification for this app - notificationManager.cancel(notificationTag, NOTIFICATION_ID_INSTALLER) - else { - val notification = builder - .setSmallIcon(android.R.drawable.stat_sys_download_done) - .setContentTitle(getString(R.string.installed)) - .setContentText(appLabel) - .setTimeoutAfter(INSTALLED_NOTIFICATION_TIMEOUT) - .build() - notificationManager.notify( - notificationTag, - NOTIFICATION_ID_INSTALLER, - notification - ) - } - } - PackageInstaller.STATUS_FAILURE_ABORTED -> { - // do nothing if user cancels - } - else -> { - // problem occurred when installing/uninstalling package - val notification = builder - .setSmallIcon(android.R.drawable.stat_notify_error) - .setContentTitle(getString(R.string.unknown_error_DESC)) - .setContentText(message) - .build() - notificationManager.notify( - notificationTag, - NOTIFICATION_ID_INSTALLER, - notification - ) - } - } - } - override fun onBind(intent: Intent): IBinder? { super.onBind(intent) return null @@ -177,7 +80,7 @@ class InstallerService : LifecycleService() { * @return a pending intent that can be attached to a background-accessible entry point such as * a notification */ - private fun installIntent(intent: Intent): PendingIntent { + fun installIntent(intent: Intent): PendingIntent { // prepare prompt intent val promptIntent: Intent? = intent.getParcelableExtra(Intent.EXTRA_INTENT) val name = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME) @@ -194,6 +97,4 @@ class InstallerService : LifecycleService() { else PendingIntent.FLAG_UPDATE_CURRENT ) } - - } \ No newline at end of file diff --git a/src/main/kotlin/com/looker/droidify/service/DownloadService.kt b/src/main/kotlin/com/looker/droidify/service/DownloadService.kt index 251bc2e5..afc51a4f 100644 --- a/src/main/kotlin/com/looker/droidify/service/DownloadService.kt +++ b/src/main/kotlin/com/looker/droidify/service/DownloadService.kt @@ -4,7 +4,6 @@ import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.content.Intent -import android.net.Uri import android.view.ContextThemeWrapper import androidx.core.app.NotificationCompat import com.looker.droidify.BuildConfig @@ -17,7 +16,6 @@ import com.looker.droidify.database.entity.Release import com.looker.droidify.database.entity.Repository import com.looker.droidify.installer.AppInstaller import com.looker.droidify.network.Downloader -import com.looker.droidify.ui.activities.MainActivityX import com.looker.droidify.utility.Utils import com.looker.droidify.utility.extension.android.Android import com.looker.droidify.utility.extension.android.notificationManager @@ -27,6 +25,7 @@ import com.looker.droidify.utility.extension.resources.getColorFromAttr import com.looker.droidify.utility.extension.text.formatSize import com.looker.droidify.utility.extension.text.hex import com.looker.droidify.utility.extension.text.nullIfEmpty +import com.looker.droidify.utility.showNotificationError import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.Disposable import kotlinx.coroutines.CoroutineScope @@ -68,7 +67,7 @@ class DownloadService : ConnectionService() { private val mutableStateSubject = MutableSharedFlow() - private class Task( + class Task( val packageName: String, val name: String, val release: Release, val url: String, val authentication: String, ) { @@ -181,83 +180,14 @@ class DownloadService : ConnectionService() { } } - private enum class ValidationError { INTEGRITY, FORMAT, METADATA, SIGNATURE, PERMISSIONS } + enum class ValidationError { INTEGRITY, FORMAT, METADATA, SIGNATURE, PERMISSIONS } - private sealed class ErrorType { + sealed class ErrorType { object Network : ErrorType() object Http : ErrorType() class Validation(val validateError: ValidationError) : ErrorType() } - private fun showNotificationError(task: Task, errorType: ErrorType) { - notificationManager.notify(task.notificationTag, - NOTIFICATION_ID_DOWNLOADING, - NotificationCompat - .Builder(this, NOTIFICATION_CHANNEL_DOWNLOADING) - .setAutoCancel(true) - .setSmallIcon(android.R.drawable.stat_sys_warning) - .setColor( - ContextThemeWrapper(this, R.style.Theme_Main_Light) - .getColorFromAttr(R.attr.colorPrimary).defaultColor - ) - .setContentIntent( - PendingIntent.getActivity( - this, - 0, - Intent(this, MainActivityX::class.java) - .setAction(Intent.ACTION_VIEW) - .setData(Uri.parse("package:${task.packageName}")) - .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), - if (Android.sdk(23)) - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - else - PendingIntent.FLAG_UPDATE_CURRENT - ) - ) - .apply { - when (errorType) { - is ErrorType.Network -> { - setContentTitle( - getString( - R.string.could_not_download_FORMAT, - task.name - ) - ) - setContentText(getString(R.string.network_error_DESC)) - } - is ErrorType.Http -> { - setContentTitle( - getString( - R.string.could_not_download_FORMAT, - task.name - ) - ) - setContentText(getString(R.string.http_error_DESC)) - } - is ErrorType.Validation -> { - setContentTitle( - getString( - R.string.could_not_validate_FORMAT, - task.name - ) - ) - setContentText( - getString( - when (errorType.validateError) { - ValidationError.INTEGRITY -> R.string.integrity_check_error_DESC - ValidationError.FORMAT -> R.string.file_format_error_DESC - ValidationError.METADATA -> R.string.invalid_metadata_error_DESC - ValidationError.SIGNATURE -> R.string.invalid_signature_error_DESC - ValidationError.PERMISSIONS -> R.string.invalid_permissions_error_DESC - } - ) - ) - } - }::class - } - .build()) - } - private fun publishSuccess(task: Task) { var consumed = false scope.launch { diff --git a/src/main/kotlin/com/looker/droidify/service/SyncService.kt b/src/main/kotlin/com/looker/droidify/service/SyncService.kt index 69ab940f..474fa3f2 100644 --- a/src/main/kotlin/com/looker/droidify/service/SyncService.kt +++ b/src/main/kotlin/com/looker/droidify/service/SyncService.kt @@ -6,9 +6,6 @@ import android.app.PendingIntent import android.app.job.JobParameters import android.app.job.JobService import android.content.Intent -import android.graphics.Color -import android.text.SpannableStringBuilder -import android.text.style.ForegroundColorSpan import android.view.ContextThemeWrapper import androidx.core.app.NotificationCompat import androidx.fragment.app.Fragment @@ -25,13 +22,14 @@ import com.looker.droidify.entity.Order import com.looker.droidify.entity.ProductItem import com.looker.droidify.entity.Section import com.looker.droidify.index.RepositoryUpdater -import com.looker.droidify.ui.activities.MainActivityX import com.looker.droidify.utility.RxUtils import com.looker.droidify.utility.Utils +import com.looker.droidify.utility.displayUpdatesNotification import com.looker.droidify.utility.extension.android.Android import com.looker.droidify.utility.extension.android.notificationManager import com.looker.droidify.utility.extension.resources.getColorFromAttr import com.looker.droidify.utility.extension.text.formatSize +import com.looker.droidify.utility.showNotificationError import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.schedulers.Schedulers @@ -234,33 +232,6 @@ class SyncService : ConnectionService() { } } - private fun showNotificationError(repository: Repository, exception: Exception) { - notificationManager.notify( - "repository-${repository.id}", NOTIFICATION_ID_SYNCING, NotificationCompat - .Builder(this, NOTIFICATION_CHANNEL_SYNCING) - .setSmallIcon(android.R.drawable.stat_sys_warning) - .setColor( - ContextThemeWrapper(this, R.style.Theme_Main_Light) - .getColorFromAttr(android.R.attr.colorPrimary).defaultColor - ) - .setContentTitle(getString(R.string.could_not_sync_FORMAT, repository.name)) - .setContentText( - getString( - when (exception) { - is RepositoryUpdater.UpdateException -> when (exception.errorType) { - RepositoryUpdater.ErrorType.NETWORK -> R.string.network_error_DESC - RepositoryUpdater.ErrorType.HTTP -> R.string.http_error_DESC - RepositoryUpdater.ErrorType.VALIDATION -> R.string.validation_index_error_DESC - RepositoryUpdater.ErrorType.PARSING -> R.string.parsing_index_error_DESC - } - else -> R.string.unknown_error_DESC - } - ) - ) - .build() - ) - } - private val stateNotificationBuilder by lazy { NotificationCompat .Builder(this, NOTIFICATION_CHANNEL_SYNCING) @@ -489,65 +460,6 @@ class SyncService : ConnectionService() { } } - /** - * Displays summary of available updates. - * - * @param productItems list of apps pending updates - */ - private fun displayUpdatesNotification(productItems: List) { - val maxUpdates = 5 - fun T.applyHack(callback: T.() -> Unit): T = apply(callback) - notificationManager.notify( - NOTIFICATION_ID_UPDATES, NotificationCompat - .Builder(this, NOTIFICATION_CHANNEL_UPDATES) - .setSmallIcon(R.drawable.ic_new_releases) - .setContentTitle(getString(R.string.new_updates_available)) - .setContentText( - resources.getQuantityString( - R.plurals.new_updates_DESC_FORMAT, - productItems.size, productItems.size - ) - ) - .setColor( - ContextThemeWrapper(this, R.style.Theme_Main_Light) - .getColorFromAttr(android.R.attr.colorPrimary).defaultColor - ) - .setContentIntent( - PendingIntent.getActivity( - this, - 0, - Intent(this, MainActivityX::class.java) - .setAction(MainActivityX.ACTION_UPDATES), - if (Android.sdk(23)) - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - else - PendingIntent.FLAG_UPDATE_CURRENT - ) - ) - .setStyle(NotificationCompat.InboxStyle().applyHack { - for (productItem in productItems.take(maxUpdates)) { - val builder = SpannableStringBuilder(productItem.name) - builder.setSpan( - ForegroundColorSpan(Color.BLACK), 0, builder.length, - SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE - ) - builder.append(' ').append(productItem.version) - addLine(builder) - } - if (productItems.size > maxUpdates) { - val summary = - getString(R.string.plus_more_FORMAT, productItems.size - maxUpdates) - if (Android.sdk(24)) { - addLine(summary) - } else { - setSummaryText(summary) - } - } - }) - .build() - ) - } - class Job : JobService() { private val jobScope = CoroutineScope(Dispatchers.Default) private var syncParams: JobParameters? = null diff --git a/src/main/kotlin/com/looker/droidify/utility/NotificationUtils.kt b/src/main/kotlin/com/looker/droidify/utility/NotificationUtils.kt new file mode 100644 index 00000000..a6308a68 --- /dev/null +++ b/src/main/kotlin/com/looker/droidify/utility/NotificationUtils.kt @@ -0,0 +1,286 @@ +package com.looker.droidify.utility + +import android.app.PendingIntent +import android.content.Context +import android.content.Intent +import android.content.pm.PackageInstaller +import android.content.pm.PackageManager +import android.graphics.Color +import android.net.Uri +import android.text.SpannableStringBuilder +import android.text.style.ForegroundColorSpan +import android.view.ContextThemeWrapper +import androidx.core.app.NotificationCompat +import com.looker.droidify.NOTIFICATION_CHANNEL_DOWNLOADING +import com.looker.droidify.NOTIFICATION_CHANNEL_INSTALLER +import com.looker.droidify.NOTIFICATION_CHANNEL_SYNCING +import com.looker.droidify.NOTIFICATION_CHANNEL_UPDATES +import com.looker.droidify.NOTIFICATION_ID_DOWNLOADING +import com.looker.droidify.NOTIFICATION_ID_INSTALLER +import com.looker.droidify.NOTIFICATION_ID_SYNCING +import com.looker.droidify.NOTIFICATION_ID_UPDATES +import com.looker.droidify.R +import com.looker.droidify.database.entity.Repository +import com.looker.droidify.entity.ProductItem +import com.looker.droidify.index.RepositoryUpdater +import com.looker.droidify.installer.InstallerService +import com.looker.droidify.service.DownloadService +import com.looker.droidify.ui.activities.MainActivityX +import com.looker.droidify.utility.extension.android.Android +import com.looker.droidify.utility.extension.android.notificationManager +import com.looker.droidify.utility.extension.resources.getColorFromAttr + +/** + * Displays summary of available updates. + * + * @param productItems list of apps pending updates + */ +fun Context.displayUpdatesNotification(productItems: List) { + val maxUpdates = 5 + fun T.applyHack(callback: T.() -> Unit): T = apply(callback) + notificationManager.notify( + NOTIFICATION_ID_UPDATES, NotificationCompat + .Builder(this, NOTIFICATION_CHANNEL_UPDATES) + .setSmallIcon(R.drawable.ic_new_releases) + .setContentTitle(getString(R.string.new_updates_available)) + .setContentText( + resources.getQuantityString( + R.plurals.new_updates_DESC_FORMAT, + productItems.size, productItems.size + ) + ) + .setColor( + ContextThemeWrapper(this, R.style.Theme_Main_Light) + .getColorFromAttr(android.R.attr.colorPrimary).defaultColor + ) + .setContentIntent( + PendingIntent.getActivity( + this, + 0, + Intent(this, MainActivityX::class.java) + .setAction(MainActivityX.ACTION_UPDATES) + .putExtra( + MainActivityX.EXTRA_UPDATES, + productItems.map { it.packageName }.toTypedArray() + ), + if (Android.sdk(23)) + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + else + PendingIntent.FLAG_UPDATE_CURRENT + ) + ) + .setStyle(NotificationCompat.InboxStyle().applyHack { + for (productItem in productItems.take(maxUpdates)) { + val builder = SpannableStringBuilder(productItem.name) + builder.setSpan( + ForegroundColorSpan(Color.BLACK), 0, builder.length, + SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE + ) + builder.append(' ').append(productItem.version) + addLine(builder) + } + if (productItems.size > maxUpdates) { + val summary = + getString(R.string.plus_more_FORMAT, productItems.size - maxUpdates) + if (Android.sdk(24)) { + addLine(summary) + } else { + setSummaryText(summary) + } + } + }) + .build() + ) +} + +fun Context.showNotificationError(repository: Repository, exception: Exception) { + notificationManager.notify( + "repository-${repository.id}", NOTIFICATION_ID_SYNCING, NotificationCompat + .Builder(this, NOTIFICATION_CHANNEL_SYNCING) + .setSmallIcon(android.R.drawable.stat_sys_warning) + .setColor( + ContextThemeWrapper(this, R.style.Theme_Main_Light) + .getColorFromAttr(android.R.attr.colorPrimary).defaultColor + ) + .setContentTitle(getString(R.string.could_not_sync_FORMAT, repository.name)) + .setContentText( + getString( + when (exception) { + is RepositoryUpdater.UpdateException -> when (exception.errorType) { + RepositoryUpdater.ErrorType.NETWORK -> R.string.network_error_DESC + RepositoryUpdater.ErrorType.HTTP -> R.string.http_error_DESC + RepositoryUpdater.ErrorType.VALIDATION -> R.string.validation_index_error_DESC + RepositoryUpdater.ErrorType.PARSING -> R.string.parsing_index_error_DESC + } + else -> R.string.unknown_error_DESC + } + ) + ) + .build() + ) +} + +fun Context.showNotificationError( + task: DownloadService.Task, + errorType: DownloadService.ErrorType +) { + notificationManager.notify(task.notificationTag, + NOTIFICATION_ID_DOWNLOADING, + NotificationCompat + .Builder(this, NOTIFICATION_CHANNEL_DOWNLOADING) + .setAutoCancel(true) + .setSmallIcon(android.R.drawable.stat_sys_warning) + .setColor( + ContextThemeWrapper(this, R.style.Theme_Main_Light) + .getColorFromAttr(R.attr.colorPrimary).defaultColor + ) + .setContentIntent( + PendingIntent.getActivity( + this, + 0, + Intent(this, MainActivityX::class.java) + .setAction(Intent.ACTION_VIEW) + .setData(Uri.parse("package:${task.packageName}")) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK), + if (Android.sdk(23)) + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + else + PendingIntent.FLAG_UPDATE_CURRENT + ) + ) + .apply { + when (errorType) { + is DownloadService.ErrorType.Network -> { + setContentTitle( + getString( + R.string.could_not_download_FORMAT, + task.name + ) + ) + setContentText(getString(R.string.network_error_DESC)) + } + is DownloadService.ErrorType.Http -> { + setContentTitle( + getString( + R.string.could_not_download_FORMAT, + task.name + ) + ) + setContentText(getString(R.string.http_error_DESC)) + } + is DownloadService.ErrorType.Validation -> { + setContentTitle( + getString( + R.string.could_not_validate_FORMAT, + task.name + ) + ) + setContentText( + getString( + when (errorType.validateError) { + DownloadService.ValidationError.INTEGRITY -> R.string.integrity_check_error_DESC + DownloadService.ValidationError.FORMAT -> R.string.file_format_error_DESC + DownloadService.ValidationError.METADATA -> R.string.invalid_metadata_error_DESC + DownloadService.ValidationError.SIGNATURE -> R.string.invalid_signature_error_DESC + DownloadService.ValidationError.PERMISSIONS -> R.string.invalid_permissions_error_DESC + } + ) + ) + } + }::class + } + .build()) +} + +/** + * Notifies user of installer outcome. This can be success, error, or a request for user action + * if installation cannot proceed automatically. + * + * @param intent provided by PackageInstaller to the callback service/activity. + */ +fun InstallerService.notifyStatus(intent: Intent?) { + // unpack from intent + val status = intent?.getIntExtra(PackageInstaller.EXTRA_STATUS, -1) + val sessionId = intent?.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1) ?: 0 + + // get package information from session + val sessionInstaller = this.packageManager.packageInstaller + val session = if (sessionId > 0) sessionInstaller.getSessionInfo(sessionId) else null + + val name = + session?.appPackageName ?: intent?.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME) + val message = intent?.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + val installerAction = intent?.getStringExtra(InstallerService.KEY_ACTION) + + // get application name for notifications + val appLabel = session?.appLabel ?: intent?.getStringExtra(InstallerService.KEY_APP_NAME) + ?: try { + if (name != null) packageManager.getApplicationLabel( + packageManager.getApplicationInfo( + name, + PackageManager.GET_META_DATA + ) + ) else null + } catch (_: Exception) { + null + } + + val notificationTag = "${InstallerService.NOTIFICATION_TAG_PREFIX}$name" + + // start building + val builder = NotificationCompat + .Builder(this, NOTIFICATION_CHANNEL_INSTALLER) + .setAutoCancel(true) + .setColor( + ContextThemeWrapper(this, R.style.Theme_Main_Light) + .getColorFromAttr(R.attr.colorPrimary).defaultColor + ) + + when (status) { + PackageInstaller.STATUS_PENDING_USER_ACTION -> { + // request user action with "downloaded" notification that triggers a working prompt + notificationManager.notify( + notificationTag, NOTIFICATION_ID_INSTALLER, builder + .setSmallIcon(android.R.drawable.stat_sys_download_done) + .setContentIntent(installIntent(intent)) + .setContentTitle(getString(R.string.downloaded_FORMAT, appLabel)) + .setContentText(getString(R.string.tap_to_install_DESC)) + .build() + ) + } + PackageInstaller.STATUS_SUCCESS -> { + if (installerAction == InstallerService.ACTION_UNINSTALL) + // remove any notification for this app + notificationManager.cancel(notificationTag, NOTIFICATION_ID_INSTALLER) + else { + val notification = builder + .setSmallIcon(android.R.drawable.stat_sys_download_done) + .setContentTitle(getString(R.string.installed)) + .setContentText(appLabel) + .setTimeoutAfter(InstallerService.INSTALLED_NOTIFICATION_TIMEOUT) + .build() + notificationManager.notify( + notificationTag, + NOTIFICATION_ID_INSTALLER, + notification + ) + } + } + PackageInstaller.STATUS_FAILURE_ABORTED -> { + // do nothing if user cancels + } + else -> { + // problem occurred when installing/uninstalling package + val notification = builder + .setSmallIcon(android.R.drawable.stat_notify_error) + .setContentTitle(getString(R.string.unknown_error_DESC)) + .setContentText(message) + .build() + notificationManager.notify( + notificationTag, + NOTIFICATION_ID_INSTALLER, + notification + ) + } + } +} \ No newline at end of file