Add legacy self-update so v3 users can get v4 update
This commit is contained in:
@@ -150,6 +150,7 @@
|
||||
<service
|
||||
android:name="com.novoda.merlin.MerlinService"
|
||||
android:exported="false" />
|
||||
<service android:name=".data.service.SelfUpdateService" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
|
||||
@@ -32,6 +32,7 @@ object Constants {
|
||||
const val EXODUS_BASE_URL = "https://reports.exodus-privacy.eu.org/api/search/"
|
||||
const val EXODUS_REPORT_URL = "https://reports.exodus-privacy.eu.org/reports/"
|
||||
const val SHARE_URL = "http://play.google.com/store/apps/details?id="
|
||||
const val UPDATE_URL = "https://gitlab.com/AuroraOSS/AuroraStore/raw/master/updates.json"
|
||||
|
||||
const val NOTIFICATION_CHANNEL_ALERT = "NOTIFICATION_CHANNEL_ALERT"
|
||||
const val NOTIFICATION_CHANNEL_GENERAL = "NOTIFICATION_CHANNEL_GENERAL"
|
||||
|
||||
@@ -54,6 +54,20 @@ fun Context.showDialog(title: String?, message: String?) {
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.showDialog(title: String?, message: String?, listener: DialogInterface.OnDismissListener) {
|
||||
runOnUiThread {
|
||||
val backgroundColor: Int = getStyledAttributeColor(android.R.attr.colorBackground)
|
||||
val builder = MaterialAlertDialogBuilder(this).apply {
|
||||
setTitle(title)
|
||||
setMessage(message)
|
||||
setPositiveButton(android.R.string.ok) { dialog: DialogInterface, _ -> listener }
|
||||
background = ColorDrawable(backgroundColor)
|
||||
}.create()
|
||||
|
||||
builder.show()
|
||||
}
|
||||
}
|
||||
|
||||
fun Fragment.showDialog(@StringRes titleId: Int, @StringRes messageId: Int) {
|
||||
requireContext().showDialog(titleId, messageId)
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ package com.aurora.store
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
@@ -39,13 +40,15 @@ import androidx.navigation.NavController
|
||||
import androidx.navigation.NavDestination
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.navigation.ui.NavigationUI
|
||||
import com.aurora.extensions.getEmptyActivityBundle
|
||||
import com.aurora.extensions.getStyledAttributeColor
|
||||
import com.aurora.extensions.load
|
||||
import com.aurora.extensions.open
|
||||
import com.aurora.Constants
|
||||
import com.aurora.extensions.*
|
||||
import com.aurora.gplayapi.data.models.AuthData
|
||||
import com.aurora.store.data.model.SelfUpdate
|
||||
import com.aurora.store.data.network.HttpClient
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
import com.aurora.store.data.service.SelfUpdateService
|
||||
import com.aurora.store.databinding.ActivityMainBinding
|
||||
import com.aurora.store.util.CertUtil.isFDroidApp
|
||||
import com.aurora.store.util.Log
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.view.ui.about.AboutActivity
|
||||
@@ -60,7 +63,10 @@ import com.aurora.store.view.ui.search.SearchSuggestionActivity
|
||||
import com.aurora.store.view.ui.spoof.SpoofActivity
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.livinglifetechway.quickpermissions_kotlin.runWithPermissions
|
||||
import nl.komponents.kovenant.task
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
|
||||
|
||||
class MainActivity : BaseActivity() {
|
||||
@@ -116,6 +122,9 @@ class MainActivity : BaseActivity() {
|
||||
checkExternalStorageAccessPermission()
|
||||
checkExternalStorageManagerPermission()
|
||||
}
|
||||
|
||||
/* Check self update */
|
||||
checkSelfUpdate()
|
||||
}
|
||||
|
||||
private fun attachToolbar() {
|
||||
@@ -237,4 +246,63 @@ class MainActivity : BaseActivity() {
|
||||
startActivity(Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION))
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkSelfUpdate() {
|
||||
task {
|
||||
HttpClient.getPreferredClient().get(Constants.UPDATE_URL, mapOf())
|
||||
} successUi { playResponse ->
|
||||
if (playResponse.isSuccessful) {
|
||||
val selfUpdate = gson.fromJson(
|
||||
String(playResponse.responseBytes),
|
||||
SelfUpdate::class.java
|
||||
)
|
||||
|
||||
selfUpdate?.let { it ->
|
||||
if (it.versionCode > BuildConfig.VERSION_CODE) {
|
||||
if (isFDroidApp(this, BuildConfig.APPLICATION_ID)) {
|
||||
if (it.fdroidBuild.isNotEmpty()) {
|
||||
showUpdatesDialog(it)
|
||||
}
|
||||
} else if (it.auroraBuild.isNotEmpty()) {
|
||||
showUpdatesDialog(it)
|
||||
} else {
|
||||
Log.i(getString(R.string.details_no_updates))
|
||||
}
|
||||
} else {
|
||||
Log.i(getString(R.string.details_no_updates))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e("Failed to check self update")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showUpdatesDialog(selfUpdate: SelfUpdate) {
|
||||
val messages: List<String> = listOf(
|
||||
selfUpdate.versionCode.toString(),
|
||||
if (selfUpdate.changelog.isEmpty())
|
||||
getString(R.string.details_changelog_unavailable)
|
||||
else
|
||||
selfUpdate.changelog,
|
||||
getString(R.string.dialog_desc_self_update)
|
||||
)
|
||||
|
||||
val builder: MaterialAlertDialogBuilder = MaterialAlertDialogBuilder(this)
|
||||
.setTitle(getString(R.string.dialog_title_self_update))
|
||||
.setMessage(messages.joinToString(separator = "\n"))
|
||||
.setPositiveButton(getString(R.string.action_update)) { _, _ ->
|
||||
val intent = Intent(this, SelfUpdateService::class.java)
|
||||
intent.putExtra(Constants.STRING_EXTRA, gson.toJson(selfUpdate))
|
||||
startService(intent)
|
||||
}
|
||||
.setNegativeButton(getString(R.string.action_later)) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
val backGroundColor: Int = getStyledAttributeColor(android.R.attr.colorBackground)
|
||||
builder.background = ColorDrawable(backGroundColor)
|
||||
builder.create()
|
||||
builder.show()
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ class NativeInstaller(context: Context) : InstallerBase(context) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
} else {
|
||||
Log.i("Received native install request for $packageName")
|
||||
files.map {
|
||||
when (it) {
|
||||
is File -> it
|
||||
|
||||
@@ -42,7 +42,7 @@ class SessionInstaller(context: Context) : InstallerBase(context) {
|
||||
if (isAlreadyQueued(packageName)) {
|
||||
Log.i("$packageName already queued")
|
||||
} else {
|
||||
Log.i("Received service install request for $packageName")
|
||||
Log.i("Received session install request for $packageName")
|
||||
val uriList = files.map {
|
||||
when (it) {
|
||||
is File -> getUri(it)
|
||||
|
||||
39
app/src/main/java/com/aurora/store/data/model/SelfUpdate.kt
Normal file
39
app/src/main/java/com/aurora/store/data/model/SelfUpdate.kt
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Aurora Store
|
||||
* Copyright (C) 2021, Rahul Kumar Patel <whyorean@gmail.com>
|
||||
*
|
||||
* Aurora Store is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Aurora Store is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Aurora Store. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
package com.aurora.store.data.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
class SelfUpdate {
|
||||
@SerializedName("version_name")
|
||||
var versionName: String = String()
|
||||
|
||||
@SerializedName("version_code")
|
||||
var versionCode: Int = 0
|
||||
|
||||
@SerializedName("aurora_build")
|
||||
var auroraBuild: String = String()
|
||||
|
||||
@SerializedName("fdroid_build")
|
||||
var fdroidBuild: String = String()
|
||||
|
||||
@SerializedName("changelog")
|
||||
var changelog: String = String()
|
||||
}
|
||||
@@ -23,12 +23,12 @@ import android.app.NotificationManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.data.event.BusEvent.InstallEvent
|
||||
import com.aurora.store.data.event.BusEvent.UninstallEvent
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.util.PathUtil
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.util.isExternalStorageEnable
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.io.File
|
||||
|
||||
@@ -62,6 +62,10 @@ open class PackageManagerReceiver : BroadcastReceiver() {
|
||||
|
||||
if (isAutoDeleteAPKEnabled)
|
||||
clearDownloads(context, packageName)
|
||||
|
||||
//Clear self update apk
|
||||
if (packageName == BuildConfig.APPLICATION_ID)
|
||||
clearDownloads(context, packageName)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
package com.aurora.store.data.service
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.aurora.Constants
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.File
|
||||
import com.aurora.store.BuildConfig
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.downloader.DownloadManager
|
||||
import com.aurora.store.data.downloader.RequestBuilder.buildRequest
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.model.SelfUpdate
|
||||
import com.aurora.store.util.CertUtil.isFDroidApp
|
||||
import com.aurora.store.util.Log
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.tonyodev.fetch2.*
|
||||
import nl.komponents.kovenant.task
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class SelfUpdateService : Service() {
|
||||
private lateinit var app: App
|
||||
private lateinit var fetch: Fetch
|
||||
private lateinit var fetchListener: FetchListener
|
||||
|
||||
private var gson: Gson = GsonBuilder()
|
||||
.excludeFieldsWithModifiers(Modifier.STATIC, Modifier.TRANSIENT)
|
||||
.create()
|
||||
|
||||
private val hashCode = BuildConfig.APPLICATION_ID.hashCode()
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
val rawSelfUpdate = intent.getStringExtra(Constants.STRING_EXTRA)
|
||||
if (StringUtils.isNotEmpty(rawSelfUpdate)) {
|
||||
val selfUpdate = gson.fromJson(rawSelfUpdate, SelfUpdate::class.java)
|
||||
selfUpdate?.let {
|
||||
downloadAndUpdate(it)
|
||||
}
|
||||
}
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForeground(1, notification)
|
||||
} else {
|
||||
val notification = getNotification(
|
||||
NotificationCompat.Builder(
|
||||
this,
|
||||
Constants.NOTIFICATION_CHANNEL_GENERAL
|
||||
)
|
||||
)
|
||||
startForeground(1, notification)
|
||||
}
|
||||
}
|
||||
|
||||
private fun destroyService() {
|
||||
Log.d("Self-update service destroyed")
|
||||
fetch.removeListener(fetchListener)
|
||||
stopForeground(true)
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
private fun downloadAndUpdate(update: SelfUpdate) {
|
||||
app = App(BuildConfig.APPLICATION_ID)
|
||||
app.id = hashCode
|
||||
app.packageName = BuildConfig.APPLICATION_ID
|
||||
app.displayName = getString(R.string.app_name)
|
||||
app.versionName = update.versionName
|
||||
app.versionCode = update.versionCode
|
||||
|
||||
val file = File().apply {
|
||||
name = "AuroraStore.apk"
|
||||
url = if (isFDroidVariant)
|
||||
update.fdroidBuild
|
||||
else
|
||||
update.auroraBuild
|
||||
type = File.FileType.BASE
|
||||
}
|
||||
|
||||
val request = buildRequest(this, app, file)
|
||||
request.enqueueAction = EnqueueAction.REPLACE_EXISTING
|
||||
|
||||
val requestList: MutableList<Request> = ArrayList()
|
||||
requestList.add(request)
|
||||
|
||||
fetch = DownloadManager.with(this).fetch
|
||||
fetch.enqueue(requestList) {
|
||||
Log.i("Downloading latest update")
|
||||
}
|
||||
|
||||
fetchListener = getFetchListener()
|
||||
fetch.addListener(fetchListener)
|
||||
}
|
||||
|
||||
private val isFDroidVariant: Boolean
|
||||
get() = isFDroidApp(this, BuildConfig.APPLICATION_ID)
|
||||
|
||||
@get:RequiresApi(Build.VERSION_CODES.O)
|
||||
private val notification: Notification
|
||||
get() {
|
||||
val notificationBuilder =
|
||||
NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNEL_GENERAL)
|
||||
return getNotification(notificationBuilder)
|
||||
}
|
||||
|
||||
private fun getNotification(builder: NotificationCompat.Builder): Notification {
|
||||
return builder.setAutoCancel(true)
|
||||
.setColor(ContextCompat.getColor(this, R.color.colorAccent))
|
||||
.setContentTitle("Self update")
|
||||
.setContentText("Updating Aurora Store in background")
|
||||
.setOngoing(true)
|
||||
.setSmallIcon(R.drawable.ic_notification_outlined)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun getFetchListener(): FetchListener {
|
||||
return object : AbstractFetchGroupListener() {
|
||||
override fun onError(
|
||||
groupId: Int, download: Download, error: Error,
|
||||
throwable: Throwable?, fetchGroup: FetchGroup
|
||||
) {
|
||||
if (groupId == app.id) {
|
||||
Log.e("Error self-updating ${app.displayName}")
|
||||
destroyService()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCompleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
if (groupId == app.id && fetchGroup.groupDownloadProgress == 100) {
|
||||
Log.d("Calling installer ${app.displayName}")
|
||||
AppInstaller(this@SelfUpdateService).getPreferredInstaller().install(
|
||||
BuildConfig.APPLICATION_ID,
|
||||
listOf(download.file)
|
||||
)
|
||||
|
||||
task {
|
||||
TimeUnit.SECONDS.sleep(10)
|
||||
} success {
|
||||
destroyService()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelled(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
if (groupId == app.id) {
|
||||
Log.d("Self-update cancelled ${app.displayName}")
|
||||
destroyService()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,6 +238,11 @@
|
||||
<string name="device_miui_description">"Please, disable MIUI optimizations to allow installations, otherwise you can choose Root or Services installer."</string>
|
||||
<string name="device_miui_extra">"Optionally you can choose Native installer, but then you can not install bundled (split) APKs, so choice is yours."</string>
|
||||
|
||||
|
||||
<string name="dialog_title_self_update">"New update available"</string>
|
||||
<string name="dialog_desc_self_update">"Do you wish to update now ?"</string>
|
||||
<string name="list_update_all_txt_one">"update available"</string>
|
||||
|
||||
<string name="notification_channel_alert">"Quick notification"</string>
|
||||
<string name="notification_channel_general">"General notification"</string>
|
||||
<string name="notification_installation_auto">"Click to install"</string>
|
||||
|
||||
Reference in New Issue
Block a user