DownloadWorker: Trigger app installation on success
* Transparent dummy activity to trigger installation of apps from notification Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -91,6 +91,11 @@
|
|||||||
<nav-graph android:value="@navigation/mobile_navigation" />
|
<nav-graph android:value="@navigation/mobile_navigation" />
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".data.activity.InstallActivity"
|
||||||
|
android:exported="false"
|
||||||
|
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
|
||||||
|
|
||||||
<service android:name=".data.service.NotificationService" />
|
<service android:name=".data.service.NotificationService" />
|
||||||
<service android:name=".data.installer.InstallerService" />
|
<service android:name=".data.installer.InstallerService" />
|
||||||
<service android:name=".data.service.UpdateService" />
|
<service android:name=".data.service.UpdateService" />
|
||||||
@@ -123,5 +128,8 @@
|
|||||||
<receiver android:name=".data.receiver.DownloadResumeReceiver" />
|
<receiver android:name=".data.receiver.DownloadResumeReceiver" />
|
||||||
<receiver android:name=".data.receiver.DownloadPauseReceiver" />
|
<receiver android:name=".data.receiver.DownloadPauseReceiver" />
|
||||||
<receiver android:name=".data.receiver.DownloadCancelReceiver" />
|
<receiver android:name=".data.receiver.DownloadCancelReceiver" />
|
||||||
|
<receiver
|
||||||
|
android:name=".data.receiver.InstallReceiver"
|
||||||
|
android:exported="false" />
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ object Constants {
|
|||||||
const val INT_EXTRA = "INT_EXTRA"
|
const val INT_EXTRA = "INT_EXTRA"
|
||||||
const val FLOAT_EXTRA = "FLOAT_EXTRA"
|
const val FLOAT_EXTRA = "FLOAT_EXTRA"
|
||||||
const val STRING_APP = "STRING_APP"
|
const val STRING_APP = "STRING_APP"
|
||||||
|
const val STRING_VERSION = "STRING_VERSION"
|
||||||
const val STRING_EXTRA = "STRING_EXTRA"
|
const val STRING_EXTRA = "STRING_EXTRA"
|
||||||
const val BROWSE_EXTRA = "BROWSE_EXTRA"
|
const val BROWSE_EXTRA = "BROWSE_EXTRA"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package com.aurora.store.data.activity
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import com.aurora.Constants
|
||||||
|
import com.aurora.store.data.installer.AppInstaller
|
||||||
|
import com.aurora.store.util.PathUtil
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
|
class InstallActivity : Activity() {
|
||||||
|
|
||||||
|
private val TAG = InstallActivity::class.java.simpleName
|
||||||
|
|
||||||
|
private lateinit var packageName: String
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
packageName = intent.extras?.getString(Constants.STRING_APP) ?: String()
|
||||||
|
val version = intent.extras?.getInt(Constants.STRING_VERSION)
|
||||||
|
if (packageName.isNotBlank() && version != null) {
|
||||||
|
try {
|
||||||
|
val downloadDir =
|
||||||
|
File(PathUtil.getAppDownloadDir(this, packageName, version).pathString)
|
||||||
|
AppInstaller.getInstance(this).getPreferredInstaller()
|
||||||
|
.install(
|
||||||
|
packageName,
|
||||||
|
downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") }
|
||||||
|
)
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
Log.e(TAG, "Failed to install $packageName")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,16 +21,32 @@ package com.aurora.store.data.receiver
|
|||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import com.aurora.Constants
|
||||||
|
import com.aurora.store.data.installer.AppInstaller
|
||||||
|
import com.aurora.store.util.PathUtil
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.io.path.pathString
|
||||||
|
|
||||||
class InstallReceiver : BroadcastReceiver() {
|
class InstallReceiver : BroadcastReceiver() {
|
||||||
|
|
||||||
|
private val TAG = InstallReceiver::class.java.simpleName
|
||||||
|
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
val extras = intent.extras
|
val packageName = intent.extras?.getString(Constants.STRING_APP) ?: String()
|
||||||
if (extras != null) {
|
val version = intent.extras?.getInt(Constants.STRING_VERSION)
|
||||||
/*val packageName = extras.getString(Constants.INTENT_PACKAGE_NAME, "")
|
if (packageName.isNotBlank() && version != null) {
|
||||||
val versionString = extras.getString(Constants.DOWNLOAD_VERSION_CODE)
|
try {
|
||||||
if (!packageName.isEmpty() && versionString != null) {
|
val downloadDir =
|
||||||
AuroraApplication.getInstaller().installSplit(packageName, versionString.toInt())
|
File(PathUtil.getAppDownloadDir(context, packageName, version).pathString)
|
||||||
}*/
|
AppInstaller.getInstance(context).getPreferredInstaller()
|
||||||
|
.install(
|
||||||
|
packageName,
|
||||||
|
downloadDir.listFiles()!!.filter { it.path.endsWith(".apk") }
|
||||||
|
)
|
||||||
|
} catch (exception: Exception) {
|
||||||
|
Log.e(TAG, "Failed to install $packageName")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ 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.work.CoroutineWorker
|
import androidx.work.CoroutineWorker
|
||||||
@@ -13,6 +14,7 @@ import androidx.work.OneTimeWorkRequestBuilder
|
|||||||
import androidx.work.OutOfQuotaPolicy
|
import androidx.work.OutOfQuotaPolicy
|
||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
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.gplayapi.data.models.App
|
import com.aurora.gplayapi.data.models.App
|
||||||
@@ -21,6 +23,7 @@ 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.util.NotificationUtil
|
import com.aurora.store.util.NotificationUtil
|
||||||
import com.aurora.store.util.PathUtil
|
import com.aurora.store.util.PathUtil
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
@@ -63,7 +66,6 @@ class DownloadWorker(private val appContext: Context, workerParams: WorkerParame
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var app: App
|
private lateinit var app: App
|
||||||
private lateinit var appDownloadDir: Path
|
|
||||||
private var downloading = false
|
private var downloading = false
|
||||||
|
|
||||||
private val TAG = DownloadWorker::class.java.simpleName
|
private val TAG = DownloadWorker::class.java.simpleName
|
||||||
@@ -81,7 +83,6 @@ class DownloadWorker(private val appContext: Context, workerParams: WorkerParame
|
|||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
try {
|
try {
|
||||||
app = gson.fromJson(inputData.getString(DOWNLOAD_DATA), App::class.java)
|
app = gson.fromJson(inputData.getString(DOWNLOAD_DATA), App::class.java)
|
||||||
appDownloadDir = Path(PathUtil.getPackageDirectory(appContext, app.packageName))
|
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Log.e(TAG, "Failed parsing requested app!", exception)
|
Log.e(TAG, "Failed parsing requested app!", exception)
|
||||||
notifyStatus(DownloadStatus.FAILED)
|
notifyStatus(DownloadStatus.FAILED)
|
||||||
@@ -101,7 +102,7 @@ class DownloadWorker(private val appContext: Context, workerParams: WorkerParame
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Download and verify all files exists
|
// Download and verify all files exists
|
||||||
Path(appDownloadDir.absolutePathString(), app.versionCode.toString()).createDirectories()
|
PathUtil.getAppDownloadDir(appContext, app.packageName, app.versionCode).createDirectories()
|
||||||
|
|
||||||
val requestList = getDownloadRequest(files)
|
val requestList = getDownloadRequest(files)
|
||||||
requestList.forEach { request ->
|
requestList.forEach { request ->
|
||||||
@@ -115,6 +116,14 @@ class DownloadWorker(private val appContext: Context, workerParams: WorkerParame
|
|||||||
// Mark download as completed
|
// Mark download as completed
|
||||||
notifyStatus(DownloadStatus.COMPLETED)
|
notifyStatus(DownloadStatus.COMPLETED)
|
||||||
Log.i(TAG, "Finished downloading ${app.packageName}")
|
Log.i(TAG, "Finished downloading ${app.packageName}")
|
||||||
|
|
||||||
|
// Notify for installation
|
||||||
|
Intent(appContext, InstallReceiver::class.java).also {
|
||||||
|
it.putExtra(Constants.STRING_APP, app.packageName)
|
||||||
|
it.putExtra(Constants.STRING_VERSION, app.versionCode)
|
||||||
|
appContext.sendBroadcast(it)
|
||||||
|
|
||||||
|
}
|
||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ import com.aurora.extensions.isMAndAbove
|
|||||||
import com.aurora.gplayapi.data.models.App
|
import com.aurora.gplayapi.data.models.App
|
||||||
import com.aurora.store.MainActivity
|
import com.aurora.store.MainActivity
|
||||||
import com.aurora.store.R
|
import com.aurora.store.R
|
||||||
|
import com.aurora.store.data.activity.InstallActivity
|
||||||
import com.aurora.store.data.model.DownloadStatus
|
import com.aurora.store.data.model.DownloadStatus
|
||||||
import com.aurora.store.data.receiver.DownloadCancelReceiver
|
import com.aurora.store.data.receiver.DownloadCancelReceiver
|
||||||
import com.aurora.store.data.receiver.DownloadPauseReceiver
|
import com.aurora.store.data.receiver.DownloadPauseReceiver
|
||||||
import com.aurora.store.data.receiver.DownloadResumeReceiver
|
import com.aurora.store.data.receiver.DownloadResumeReceiver
|
||||||
import com.aurora.store.data.receiver.InstallReceiver
|
|
||||||
import com.tonyodev.fetch2.Download
|
import com.tonyodev.fetch2.Download
|
||||||
import com.tonyodev.fetch2.FetchGroup
|
import com.tonyodev.fetch2.FetchGroup
|
||||||
import com.tonyodev.fetch2.Status
|
import com.tonyodev.fetch2.Status
|
||||||
@@ -231,6 +231,13 @@ object NotificationUtil {
|
|||||||
builder.setAutoCancel(true)
|
builder.setAutoCancel(true)
|
||||||
builder.setCategory(Notification.CATEGORY_STATUS)
|
builder.setCategory(Notification.CATEGORY_STATUS)
|
||||||
builder.setContentIntent(getContentIntentForDetails(context, app))
|
builder.setContentIntent(getContentIntentForDetails(context, app))
|
||||||
|
builder.addAction(
|
||||||
|
NotificationCompat.Action.Builder(
|
||||||
|
R.drawable.ic_install,
|
||||||
|
context.getString(R.string.action_install),
|
||||||
|
getInstallIntent(context, app.packageName, app.versionCode)
|
||||||
|
).build()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
DownloadStatus.DOWNLOADING, DownloadStatus.QUEUED -> {
|
DownloadStatus.DOWNLOADING, DownloadStatus.QUEUED -> {
|
||||||
@@ -314,17 +321,22 @@ object NotificationUtil {
|
|||||||
.createPendingIntent()
|
.createPendingIntent()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getInstallIntent(context: Context, packageName: String): PendingIntent {
|
private fun getInstallIntent(
|
||||||
val intent = Intent(context, InstallReceiver::class.java)
|
context: Context,
|
||||||
intent.putExtra(Constants.STRING_EXTRA, packageName)
|
packageName: String,
|
||||||
val flags = if (isMAndAbove())
|
version: Int
|
||||||
|
): PendingIntent {
|
||||||
|
val intent = Intent(context, InstallActivity::class.java).apply {
|
||||||
|
putExtra(Constants.STRING_APP, packageName)
|
||||||
|
putExtra(Constants.STRING_VERSION, version)
|
||||||
|
}
|
||||||
|
val flags = if (isMAndAbove()) {
|
||||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||||
else PendingIntent.FLAG_CANCEL_CURRENT
|
} else {
|
||||||
return PendingIntent.getBroadcast(
|
PendingIntent.FLAG_CANCEL_CURRENT
|
||||||
context,
|
}
|
||||||
packageName.hashCode(),
|
return PendingIntent.getActivity(
|
||||||
intent,
|
context, packageName.hashCode(), intent, flags
|
||||||
flags
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ import android.os.Environment
|
|||||||
import com.aurora.extensions.isRAndAbove
|
import com.aurora.extensions.isRAndAbove
|
||||||
import com.aurora.gplayapi.data.models.App
|
import com.aurora.gplayapi.data.models.App
|
||||||
import com.aurora.gplayapi.data.models.File
|
import com.aurora.gplayapi.data.models.File
|
||||||
|
import java.nio.file.Path
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
import kotlin.io.path.Path
|
||||||
|
|
||||||
fun Context.getInternalBaseDirectory(): String {
|
fun Context.getInternalBaseDirectory(): String {
|
||||||
return (getExternalFilesDir(null) ?: filesDir).path
|
return (getExternalFilesDir(null) ?: filesDir).path
|
||||||
@@ -52,6 +54,10 @@ object PathUtil {
|
|||||||
return getPackageDirectory(context, packageName) + "/$versionCode"
|
return getPackageDirectory(context, packageName) + "/$versionCode"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getAppDownloadDir(context: Context, packageName: String, versionCode: Int): Path {
|
||||||
|
return Path(getPackageDirectory(context, packageName), versionCode.toString())
|
||||||
|
}
|
||||||
|
|
||||||
fun getApkDownloadFile(context: Context, app: App, file: File): String {
|
fun getApkDownloadFile(context: Context, app: App, file: File): String {
|
||||||
return getVersionDirectory(context, app.packageName, app.versionCode) + "/${file.name}"
|
return getVersionDirectory(context, app.packageName, app.versionCode) + "/${file.name}"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user