mirror of
https://github.com/Aviortheking/Neo-Store.git
synced 2025-06-15 20:09:19 +00:00
Improve install notifications, improve DefaultInstaller, misc. clean-up
Installer notifications have their own channel, their tags have been fixed, and the timeout has been properly set instead of using sleep. Ensured that DefaultInstaller's sessions use unique file names. Also improved error handling by including broken pipes and by preventing post-copy operations if an error has occurred. Some cleaning up has been done in Common, DownloadService, and SyncService. A few changes have been cherry-picked from master.
This commit is contained in:
@ -11,10 +11,12 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
|
||||
class DefaultInstaller(context: Context) : BaseInstaller(context) {
|
||||
|
||||
private val sessionInstaller = context.packageManager.packageInstaller
|
||||
private val packageManager = context.packageManager
|
||||
private val sessionInstaller = packageManager.packageInstaller
|
||||
private val intent = Intent(context, InstallerService::class.java)
|
||||
|
||||
companion object {
|
||||
@ -48,27 +50,48 @@ class DefaultInstaller(context: Context) : BaseInstaller(context) {
|
||||
override suspend fun uninstall(packageName: String) = mDefaultUninstaller(packageName)
|
||||
|
||||
private fun mDefaultInstaller(cacheFile: File) {
|
||||
// clean up inactive sessions
|
||||
sessionInstaller.mySessions
|
||||
.filter { session -> !session.isActive }
|
||||
.forEach { session -> sessionInstaller.abandonSession(session.sessionId) }
|
||||
|
||||
// start new session
|
||||
val id = sessionInstaller.createSession(sessionParams)
|
||||
|
||||
val session = sessionInstaller.openSession(id)
|
||||
|
||||
// get package name
|
||||
val packageInfo = packageManager.getPackageArchiveInfo(cacheFile.absolutePath, 0)
|
||||
val packageName = packageInfo?.packageName ?: "unknown-package"
|
||||
|
||||
// error flags
|
||||
var hasErrors = false
|
||||
|
||||
session.use { activeSession ->
|
||||
activeSession.openWrite("package", 0, cacheFile.length()).use { packageStream ->
|
||||
activeSession.openWrite(packageName, 0, cacheFile.length()).use { packageStream ->
|
||||
try {
|
||||
cacheFile.inputStream().use { fileStream ->
|
||||
fileStream.copyTo(packageStream)
|
||||
}
|
||||
} catch (error: FileNotFoundException) {
|
||||
Log.w("DefaultInstaller", "Cache file for DefaultInstaller does not seem to exist.")
|
||||
} catch (e: FileNotFoundException) {
|
||||
Log.w(
|
||||
"DefaultInstaller",
|
||||
"Cache file for DefaultInstaller does not seem to exist."
|
||||
)
|
||||
hasErrors = true
|
||||
} catch (e: IOException) {
|
||||
Log.w(
|
||||
"DefaultInstaller",
|
||||
"Failed to perform cache to package copy due to a bad pipe."
|
||||
)
|
||||
hasErrors = true
|
||||
}
|
||||
}
|
||||
|
||||
val pendingIntent = PendingIntent.getService(context, id, intent, flags)
|
||||
|
||||
session.commit(pendingIntent.intentSender)
|
||||
}
|
||||
cacheFile.delete()
|
||||
|
||||
if (!hasErrors) {
|
||||
session.commit(PendingIntent.getService(context, id, intent, flags).intentSender)
|
||||
cacheFile.delete()
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun mDefaultUninstaller(packageName: String) {
|
||||
|
@ -1,16 +1,17 @@
|
||||
package com.looker.droidify.installer
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
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 com.looker.droidify.Common.NOTIFICATION_CHANNEL_DOWNLOADING
|
||||
import com.looker.droidify.Common.NOTIFICATION_ID_DOWNLOADING
|
||||
import com.looker.droidify.Common.NOTIFICATION_CHANNEL_INSTALLER
|
||||
import com.looker.droidify.Common.NOTIFICATION_ID_INSTALLER
|
||||
import com.looker.droidify.R
|
||||
import com.looker.droidify.MainActivity
|
||||
import com.looker.droidify.utility.Utils
|
||||
@ -27,6 +28,20 @@ class InstallerService : Service() {
|
||||
const val KEY_ACTION = "installerAction"
|
||||
const val KEY_APP_NAME = "appName"
|
||||
const val ACTION_UNINSTALL = "uninstall"
|
||||
private const val INSTALLED_NOTIFICATION_TIMEOUT: Long = 10000
|
||||
private const val NOTIFICATION_TAG_PREFIX = "install-"
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
if (Android.sdk(26)) {
|
||||
NotificationChannel(
|
||||
NOTIFICATION_CHANNEL_INSTALLER,
|
||||
getString(R.string.syncing), NotificationManager.IMPORTANCE_LOW
|
||||
)
|
||||
.let(notificationManager::createNotificationChannel)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
@ -61,12 +76,18 @@ class InstallerService : Service() {
|
||||
private fun notifyStatus(intent: Intent) {
|
||||
// unpack from intent
|
||||
val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1)
|
||||
val name = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME)
|
||||
val sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
|
||||
|
||||
// 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 = intent.getStringExtra(KEY_APP_NAME)
|
||||
val appLabel = session?.appLabel ?: intent.getStringExtra(KEY_APP_NAME)
|
||||
?: try {
|
||||
if (name != null) packageManager.getApplicationLabel(
|
||||
packageManager.getApplicationInfo(
|
||||
@ -78,11 +99,11 @@ class InstallerService : Service() {
|
||||
null
|
||||
}
|
||||
|
||||
val notificationTag = "download-$name"
|
||||
val notificationTag = "${NOTIFICATION_TAG_PREFIX}$name"
|
||||
|
||||
// start building
|
||||
val builder = NotificationCompat
|
||||
.Builder(this, NOTIFICATION_CHANNEL_DOWNLOADING)
|
||||
.Builder(this, NOTIFICATION_CHANNEL_INSTALLER)
|
||||
.setAutoCancel(true)
|
||||
.setColor(
|
||||
ContextThemeWrapper(this, R.style.Theme_Main_Light)
|
||||
@ -93,7 +114,7 @@ class InstallerService : Service() {
|
||||
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
|
||||
// request user action with "downloaded" notification that triggers a working prompt
|
||||
notificationManager.notify(
|
||||
notificationTag, NOTIFICATION_ID_DOWNLOADING, builder
|
||||
notificationTag, NOTIFICATION_ID_INSTALLER, builder
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
.setContentIntent(installIntent(intent))
|
||||
.setContentTitle(getString(R.string.downloaded_FORMAT, appLabel))
|
||||
@ -104,20 +125,19 @@ class InstallerService : Service() {
|
||||
PackageInstaller.STATUS_SUCCESS -> {
|
||||
if (installerAction == ACTION_UNINSTALL)
|
||||
// remove any notification for this app
|
||||
notificationManager.cancel(notificationTag, NOTIFICATION_ID_DOWNLOADING)
|
||||
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_DOWNLOADING,
|
||||
NOTIFICATION_ID_INSTALLER,
|
||||
notification
|
||||
)
|
||||
Thread.sleep(5000)
|
||||
notificationManager.cancel(notificationTag, NOTIFICATION_ID_DOWNLOADING)
|
||||
}
|
||||
}
|
||||
PackageInstaller.STATUS_FAILURE_ABORTED -> {
|
||||
@ -132,7 +152,7 @@ class InstallerService : Service() {
|
||||
.build()
|
||||
notificationManager.notify(
|
||||
notificationTag,
|
||||
NOTIFICATION_ID_DOWNLOADING,
|
||||
NOTIFICATION_ID_INSTALLER,
|
||||
notification
|
||||
)
|
||||
}
|
||||
@ -163,7 +183,6 @@ class InstallerService : Service() {
|
||||
0,
|
||||
Intent(this, MainActivity::class.java)
|
||||
.setAction(MainActivity.ACTION_INSTALL)
|
||||
.setData(Uri.parse("package:$name"))
|
||||
.putExtra(Intent.EXTRA_INTENT, promptIntent)
|
||||
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
|
||||
if (Android.sdk(23)) PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
|
Reference in New Issue
Block a user