DownloadWorker: Move app installation logic to new onSuccess method
Move app installation logic to onSuccess method in worker under a NonCancellable context and convert the receiver class to be a generic status handler for anything except success which should be handled in PackageManagerReceiver. Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -135,7 +135,7 @@
|
|||||||
</provider>
|
</provider>
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".data.receiver.InstallReceiver"
|
android:name=".data.receiver.InstallerStatusReceiver"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import android.net.Uri
|
|||||||
import androidx.core.content.FileProvider
|
import androidx.core.content.FileProvider
|
||||||
import com.aurora.extensions.isSAndAbove
|
import com.aurora.extensions.isSAndAbove
|
||||||
import com.aurora.store.BuildConfig
|
import com.aurora.store.BuildConfig
|
||||||
import com.aurora.store.data.receiver.InstallReceiver
|
import com.aurora.store.data.receiver.InstallerStatusReceiver
|
||||||
import com.aurora.store.util.Log
|
import com.aurora.store.util.Log
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -62,8 +62,8 @@ abstract class SessionInstallerBase(context: Context) : InstallerBase(context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val callBackIntent = Intent(context, InstallReceiver::class.java).apply {
|
val callBackIntent = Intent(context, InstallerStatusReceiver::class.java).apply {
|
||||||
action = InstallReceiver.ACTION_INSTALL_STATUS
|
action = InstallerStatusReceiver.ACTION_INSTALL_STATUS
|
||||||
setPackage(context.packageName)
|
setPackage(context.packageName)
|
||||||
putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName)
|
putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName)
|
||||||
addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
|
addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
|
||||||
|
|||||||
@@ -25,91 +25,56 @@ import android.content.Intent
|
|||||||
import android.content.pm.PackageInstaller
|
import android.content.pm.PackageInstaller
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.content.IntentCompat
|
import androidx.core.content.IntentCompat
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
|
||||||
import com.aurora.Constants
|
|
||||||
import com.aurora.gplayapi.data.models.App
|
import com.aurora.gplayapi.data.models.App
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
import com.aurora.store.data.event.InstallerEvent
|
import com.aurora.store.data.event.InstallerEvent
|
||||||
import com.aurora.store.data.installer.AppInstaller
|
import com.aurora.store.data.installer.AppInstaller
|
||||||
|
import com.aurora.store.util.CommonUtil.inForeground
|
||||||
import com.aurora.store.util.NotificationUtil
|
import com.aurora.store.util.NotificationUtil
|
||||||
import com.aurora.store.util.PathUtil
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import java.io.File
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class InstallReceiver : BroadcastReceiver() {
|
class InstallerStatusReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ACTION_INSTALL_APP = "com.aurora.store.data.receiver.InstallReceiver.INSTALL_APP"
|
|
||||||
const val ACTION_INSTALL_STATUS =
|
const val ACTION_INSTALL_STATUS =
|
||||||
"com.aurora.store.data.receiver.InstallReceiver.INSTALL_STATUS"
|
"com.aurora.store.data.receiver.InstallReceiver.INSTALL_STATUS"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val TAG = InstallReceiver::class.java.simpleName
|
private val TAG = InstallerStatusReceiver::class.java.simpleName
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
when (intent.action) {
|
if (intent.action == ACTION_INSTALL_STATUS) {
|
||||||
ACTION_INSTALL_APP -> {
|
val packageName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME)
|
||||||
val packageName = intent.extras?.getString(Constants.STRING_APP) ?: String()
|
val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1)
|
||||||
val version = intent.extras?.getInt(Constants.STRING_VERSION)
|
val extra = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)
|
||||||
if (packageName.isNotBlank() && version != null) {
|
|
||||||
try {
|
|
||||||
val downloadDir =
|
|
||||||
File(PathUtil.getAppDownloadDir(context, packageName, version).path)
|
|
||||||
AppInstaller.getInstance(context).getPreferredInstaller()
|
|
||||||
.install(
|
|
||||||
packageName,
|
|
||||||
downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") }
|
|
||||||
)
|
|
||||||
} catch (exception: Exception) {
|
|
||||||
Log.e(TAG, "Failed to install $packageName")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ACTION_INSTALL_STATUS -> {
|
// Exit early if package was successfully installed, nothing to do
|
||||||
val packageName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME)
|
if (status == PackageInstaller.STATUS_SUCCESS) return
|
||||||
val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1)
|
|
||||||
val extra = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)
|
|
||||||
|
|
||||||
if (inForeground() && status == PackageInstaller.STATUS_PENDING_USER_ACTION) {
|
if (inForeground() && status == PackageInstaller.STATUS_PENDING_USER_ACTION) {
|
||||||
promptUser(intent, context)
|
promptUser(intent, context)
|
||||||
} else {
|
} else {
|
||||||
postStatus(status, packageName, extra, context)
|
postStatus(status, packageName, extra, context)
|
||||||
notifyInstallation(context, packageName!!, status)
|
notifyUser(context, packageName!!, status)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyInstallation(context: Context, packageName: String, status: Int) {
|
private fun notifyUser(context: Context, packageName: String, status: Int) {
|
||||||
val notificationManager =
|
val notificationManager =
|
||||||
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||||
val content = if (status == PackageInstaller.STATUS_SUCCESS) {
|
val notification = NotificationUtil.getInstallerStatusNotification(
|
||||||
context.getString(R.string.installer_status_success)
|
|
||||||
} else {
|
|
||||||
AppInstaller.getErrorString(context, status)
|
|
||||||
}
|
|
||||||
val notification = NotificationUtil.getInstallNotification(
|
|
||||||
context,
|
context,
|
||||||
App(packageName).apply {
|
App(packageName),
|
||||||
if (status == PackageInstaller.STATUS_SUCCESS) {
|
AppInstaller.getErrorString(context, status)
|
||||||
val appInfo = context.packageManager.getApplicationInfo(packageName, 0)
|
|
||||||
displayName = context.packageManager.getApplicationLabel(appInfo).toString()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
content
|
|
||||||
)
|
)
|
||||||
notificationManager.notify(packageName.hashCode(), notification)
|
notificationManager.notify(packageName.hashCode(), notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun promptUser(intent: Intent, context: Context) {
|
private fun promptUser(intent: Intent, context: Context) {
|
||||||
val confirmationIntent =
|
IntentCompat.getParcelableExtra(intent, Intent.EXTRA_INTENT, Intent::class.java)?.let {
|
||||||
IntentCompat.getParcelableExtra(intent, Intent.EXTRA_INTENT, Intent::class.java)
|
|
||||||
|
|
||||||
confirmationIntent?.let {
|
|
||||||
it.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
|
it.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
|
||||||
it.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, "com.android.vending")
|
it.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, "com.android.vending")
|
||||||
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
@@ -153,8 +118,4 @@ class InstallReceiver : BroadcastReceiver() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun inForeground(): Boolean {
|
|
||||||
return ProcessLifecycleOwner.get().lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -3,24 +3,22 @@ package com.aurora.store.data.work
|
|||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.hilt.work.HiltWorker
|
import androidx.hilt.work.HiltWorker
|
||||||
import androidx.work.CoroutineWorker
|
import androidx.work.CoroutineWorker
|
||||||
import androidx.work.ForegroundInfo
|
import androidx.work.ForegroundInfo
|
||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import com.aurora.Constants
|
|
||||||
import com.aurora.extensions.copyTo
|
import com.aurora.extensions.copyTo
|
||||||
import com.aurora.extensions.isQAndAbove
|
import com.aurora.extensions.isQAndAbove
|
||||||
import com.aurora.extensions.requiresObbDir
|
import com.aurora.extensions.requiresObbDir
|
||||||
import com.aurora.gplayapi.helpers.PurchaseHelper
|
import com.aurora.gplayapi.helpers.PurchaseHelper
|
||||||
|
import com.aurora.store.data.installer.AppInstaller
|
||||||
import com.aurora.store.data.model.DownloadInfo
|
import com.aurora.store.data.model.DownloadInfo
|
||||||
import com.aurora.store.data.model.DownloadStatus
|
import com.aurora.store.data.model.DownloadStatus
|
||||||
import com.aurora.store.data.model.Request
|
import com.aurora.store.data.model.Request
|
||||||
import com.aurora.store.data.network.HttpClient
|
import com.aurora.store.data.network.HttpClient
|
||||||
import com.aurora.store.data.providers.AuthProvider
|
import com.aurora.store.data.providers.AuthProvider
|
||||||
import com.aurora.store.data.receiver.InstallReceiver
|
|
||||||
import com.aurora.store.data.room.download.Download
|
import com.aurora.store.data.room.download.Download
|
||||||
import com.aurora.store.data.room.download.DownloadDao
|
import com.aurora.store.data.room.download.DownloadDao
|
||||||
import com.aurora.store.util.DownloadWorkerUtil
|
import com.aurora.store.util.DownloadWorkerUtil
|
||||||
@@ -143,17 +141,30 @@ class DownloadWorker @AssistedInject constructor(
|
|||||||
// Mark download as completed
|
// Mark download as completed
|
||||||
notifyStatus(DownloadStatus.COMPLETED)
|
notifyStatus(DownloadStatus.COMPLETED)
|
||||||
Log.i(TAG, "Finished downloading ${download.packageName}")
|
Log.i(TAG, "Finished downloading ${download.packageName}")
|
||||||
|
onSuccess()
|
||||||
// Notify for installation
|
|
||||||
Intent(appContext, InstallReceiver::class.java).also {
|
|
||||||
it.action = InstallReceiver.ACTION_INSTALL_APP
|
|
||||||
it.putExtra(Constants.STRING_APP, download.packageName)
|
|
||||||
it.putExtra(Constants.STRING_VERSION, download.versionCode)
|
|
||||||
appContext.sendBroadcast(it)
|
|
||||||
}
|
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun onSuccess() {
|
||||||
|
withContext(NonCancellable) {
|
||||||
|
try {
|
||||||
|
val downloadDir = PathUtil.getAppDownloadDir(
|
||||||
|
appContext,
|
||||||
|
download.packageName,
|
||||||
|
download.versionCode
|
||||||
|
)
|
||||||
|
AppInstaller.getInstance(appContext)
|
||||||
|
.getPreferredInstaller()
|
||||||
|
.install(
|
||||||
|
download.packageName,
|
||||||
|
downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") }
|
||||||
|
)
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
Log.e(TAG, "Failed to install ${download.packageName}", exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun onFailure() {
|
private suspend fun onFailure() {
|
||||||
withContext(NonCancellable) {
|
withContext(NonCancellable) {
|
||||||
Log.i(TAG, "Cleaning up!")
|
Log.i(TAG, "Cleaning up!")
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ object NotificationUtil {
|
|||||||
return builder.build()
|
return builder.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getInstallNotification(context: Context, app: App, content: String?): Notification {
|
fun getInstallerStatusNotification(context: Context, app: App, content: String?): Notification {
|
||||||
val builder =
|
val builder =
|
||||||
NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ALERT).apply {
|
NotificationCompat.Builder(context, Constants.NOTIFICATION_CHANNEL_ALERT).apply {
|
||||||
color = context.getStyledAttributeColor(R.color.colorAccent)
|
color = context.getStyledAttributeColor(R.color.colorAccent)
|
||||||
|
|||||||
Reference in New Issue
Block a user