mirror of
https://github.com/Aviortheking/Neo-Store.git
synced 2025-04-23 19:32:16 +00:00
Update: Pack all notify functions in NotificationUtils
This commit is contained in:
parent
981ae56c44
commit
4a5626971e
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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<DownloadService.Binder>() {
|
||||
|
||||
private val mutableStateSubject = MutableSharedFlow<State>()
|
||||
|
||||
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<DownloadService.Binder>() {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -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<SyncService.Binder>() {
|
||||
}
|
||||
}
|
||||
|
||||
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<SyncService.Binder>() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays summary of available updates.
|
||||
*
|
||||
* @param productItems list of apps pending updates
|
||||
*/
|
||||
private fun displayUpdatesNotification(productItems: List<ProductItem>) {
|
||||
val maxUpdates = 5
|
||||
fun <T> 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
|
||||
|
286
src/main/kotlin/com/looker/droidify/utility/NotificationUtils.kt
Normal file
286
src/main/kotlin/com/looker/droidify/utility/NotificationUtils.kt
Normal file
@ -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<ProductItem>) {
|
||||
val maxUpdates = 5
|
||||
fun <T> 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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user