Enable fetching of app download urls in the background (AppDetailsActivity.kt), force granting of all permissions in OnboardingActivity.kt by disabling finish until PermissionsFragment.kt notifies successfully granted permissions, handle currently installing apps better by saving them in multi-thread proof list in UpdateService.kt, add own notification group for UpdateService.kt and all required UpdateService.kt strings, add ability to pass file list to service installer for more advanced, non-system service installers, save downloaded files in getExternalFilesDir by default for more useful file list for more advanced, non-system service installers without compromising security because of Android's restrictions on the Android/data directory
This commit is contained in:
@@ -37,6 +37,7 @@ object Constants {
|
||||
|
||||
const val NOTIFICATION_CHANNEL_ALERT = "NOTIFICATION_CHANNEL_ALERT"
|
||||
const val NOTIFICATION_CHANNEL_GENERAL = "NOTIFICATION_CHANNEL_GENERAL"
|
||||
const val NOTIFICATION_CHANNEL_UPDATER_SERVICE = "NOTIFICATION_CHANNEL_UPDATER_SERVICE"
|
||||
|
||||
const val URL_DISPENSER = "http://goolag.store:1337/api/auth"
|
||||
|
||||
|
||||
@@ -73,8 +73,17 @@ class ServiceInstaller(context: Context) : InstallerBase(context) {
|
||||
}
|
||||
}
|
||||
}
|
||||
val fileList = files.map {
|
||||
when (it) {
|
||||
is File -> it.absolutePath
|
||||
is String -> File(it).absolutePath
|
||||
else -> {
|
||||
throw Exception("Invalid data, expecting listOf() File or String")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xInstall(packageName, uriList)
|
||||
xInstall(packageName, uriList, fileList)
|
||||
}
|
||||
else -> {
|
||||
postError(
|
||||
@@ -168,7 +177,7 @@ class ServiceInstaller(context: Context) : InstallerBase(context) {
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
private fun xInstall(packageName: String, uriList: List<Uri>) {
|
||||
private fun xInstall(packageName: String, uriList: List<Uri>, fileList: List<String>) {
|
||||
executor.execute {
|
||||
var readyWithAction = false
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
@@ -205,17 +214,39 @@ class ServiceInstaller(context: Context) : InstallerBase(context) {
|
||||
}
|
||||
|
||||
try {
|
||||
service.installSplitPackageX(
|
||||
packageName,
|
||||
uriList,
|
||||
ACTION_INSTALL_REPLACE_EXISTING,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
callback
|
||||
)
|
||||
} catch (e: RemoteException) {
|
||||
removeFromInstallQueue(packageName)
|
||||
readyWithAction = true
|
||||
postError(packageName, e.localizedMessage, e.stackTraceToString())
|
||||
if (service.isMoreMethodImplemented) {
|
||||
try {
|
||||
service.installSplitPackageMore(
|
||||
packageName,
|
||||
uriList,
|
||||
ACTION_INSTALL_REPLACE_EXISTING,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
callback,
|
||||
fileList
|
||||
)
|
||||
} catch (e: RemoteException) {
|
||||
removeFromInstallQueue(packageName)
|
||||
readyWithAction = true
|
||||
postError(packageName, e.localizedMessage, e.stackTraceToString())
|
||||
}
|
||||
} else {
|
||||
throw Exception("New method not implemented")
|
||||
}
|
||||
} catch (th: Throwable) {
|
||||
th.printStackTrace()
|
||||
try {
|
||||
service.installSplitPackageX(
|
||||
packageName,
|
||||
uriList,
|
||||
ACTION_INSTALL_REPLACE_EXISTING,
|
||||
BuildConfig.APPLICATION_ID,
|
||||
callback
|
||||
)
|
||||
} catch (e: RemoteException) {
|
||||
removeFromInstallQueue(packageName)
|
||||
readyWithAction = true
|
||||
postError(packageName, e.localizedMessage, e.stackTraceToString())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
removeFromInstallQueue(packageName)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.aurora.store.data.service
|
||||
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
|
||||
interface AppMetadataStatusListener {
|
||||
fun onAppMetadataStatusError(reason: String, app: App)
|
||||
}
|
||||
@@ -161,6 +161,13 @@ class NotificationService : Service() {
|
||||
NotificationManager.IMPORTANCE_MIN
|
||||
)
|
||||
)
|
||||
channels.add(
|
||||
NotificationChannel(
|
||||
Constants.NOTIFICATION_CHANNEL_UPDATER_SERVICE,
|
||||
getString(R.string.notification_channel_updater_service),
|
||||
NotificationManager.IMPORTANCE_MIN
|
||||
)
|
||||
)
|
||||
notificationManager.createNotificationChannels(channels)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,16 +10,18 @@ import androidx.lifecycle.LifecycleService
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.aurora.Constants
|
||||
import com.aurora.extensions.stackTraceToString
|
||||
import com.aurora.extensions.toast
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.AuthData
|
||||
import com.aurora.gplayapi.exceptions.ApiException
|
||||
import com.aurora.gplayapi.helpers.PurchaseHelper
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.data.downloader.DownloadManager
|
||||
import com.aurora.store.data.downloader.RequestBuilder
|
||||
import com.aurora.store.data.downloader.getGroupId
|
||||
import com.aurora.store.data.event.InstallerEvent
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.model.UpdateFile
|
||||
import com.aurora.store.data.network.HttpClient
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
import com.aurora.store.util.Log
|
||||
import com.tonyodev.fetch2.*
|
||||
@@ -34,7 +36,7 @@ import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import kotlin.concurrent.timerTask
|
||||
|
||||
class UpdateService: LifecycleService() {
|
||||
@@ -44,9 +46,9 @@ class UpdateService: LifecycleService() {
|
||||
private lateinit var fetchListener: FetchGroupListener
|
||||
private var fetchActiveDownloadObserver = object : FetchObserver<Boolean> {
|
||||
override fun onChanged(data: Boolean, reason: Reason) {
|
||||
if (!data && !installing.get() && listeners.isEmpty()) {
|
||||
if (!data && installing.isEmpty() && fetchListeners.isEmpty() && appMetadataListeners.isEmpty()) {
|
||||
Handler(Looper.getMainLooper()).postDelayed ({
|
||||
if (!installing.get() && listeners.isEmpty()) {
|
||||
if (installing.isEmpty() && fetchListeners.isEmpty() && appMetadataListeners.isEmpty()) {
|
||||
stopSelf()
|
||||
}
|
||||
}, 5 * 1000)
|
||||
@@ -55,9 +57,13 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
private var hasActiveDownloadObserver = false
|
||||
|
||||
private val listeners: ArrayList<FetchGroupListener> = ArrayList()
|
||||
private val fetchListeners: ArrayList<FetchGroupListener> = ArrayList()
|
||||
|
||||
private val pendingEvents: MutableMap</*groupId: */Int, AppDownloadStatus> = mutableMapOf()
|
||||
private val fetchPendingEvents: MutableMap</*groupId: */Int, AppDownloadStatus> = mutableMapOf()
|
||||
|
||||
private val appMetadataListeners: ArrayList<AppMetadataStatusListener> = ArrayList()
|
||||
|
||||
private val appMetadataPendingEvents: ArrayList<AppMetadataStatus> = ArrayList()
|
||||
|
||||
var liveUpdateData: MutableLiveData<MutableMap<Int, UpdateFile>> = MutableLiveData()
|
||||
|
||||
@@ -67,7 +73,7 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
}
|
||||
|
||||
private var installing: AtomicBoolean = AtomicBoolean()
|
||||
private var installing = CopyOnWriteArrayList<String>()
|
||||
|
||||
|
||||
private lateinit var purchaseHelper: PurchaseHelper
|
||||
@@ -79,19 +85,21 @@ class UpdateService: LifecycleService() {
|
||||
val isCancelled: Boolean = false,
|
||||
val isComplete: Boolean = false)
|
||||
|
||||
data class AppMetadataStatus(val reason: String, val app: App)
|
||||
|
||||
@get:RequiresApi(Build.VERSION_CODES.O)
|
||||
private val notification: Notification
|
||||
get() {
|
||||
val notificationBuilder =
|
||||
NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNEL_GENERAL)
|
||||
NotificationCompat.Builder(this, Constants.NOTIFICATION_CHANNEL_UPDATER_SERVICE)
|
||||
return getNotification(notificationBuilder)
|
||||
}
|
||||
|
||||
private fun getNotification(builder: NotificationCompat.Builder): Notification {
|
||||
return builder.setAutoCancel(true)
|
||||
.setColor(ContextCompat.getColor(this, R.color.colorAccent))
|
||||
.setContentTitle("Updating apps")
|
||||
.setContentText("Updating apps in the background")
|
||||
.setContentTitle(getString(R.string.app_updater_service_notif_title))
|
||||
.setContentText(getString(R.string.app_updater_service_notif_text))
|
||||
.setOngoing(true)
|
||||
.setSmallIcon(R.drawable.ic_notification_outlined)
|
||||
.build()
|
||||
@@ -105,22 +113,25 @@ class UpdateService: LifecycleService() {
|
||||
val notification = getNotification(
|
||||
NotificationCompat.Builder(
|
||||
this,
|
||||
Constants.NOTIFICATION_CHANNEL_GENERAL
|
||||
Constants.NOTIFICATION_CHANNEL_UPDATER_SERVICE
|
||||
)
|
||||
)
|
||||
startForeground(1, notification)
|
||||
}
|
||||
EventBus.getDefault().register(this)
|
||||
authData = AuthProvider.with(this).getAuthData()
|
||||
purchaseHelper = PurchaseHelper(authData)
|
||||
purchaseHelper = PurchaseHelper(authData).using(HttpClient.getPreferredClient())
|
||||
downloadManager = DownloadManager.with(this)
|
||||
fetch = downloadManager.fetch
|
||||
fetchListener = object : FetchGroupListener {
|
||||
|
||||
override fun onAdded(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onAdded(groupId, download, fetchGroup)
|
||||
}
|
||||
if (download.tag != null) {
|
||||
installing.remove(download.tag)
|
||||
}
|
||||
if (!hasActiveDownloadObserver) {
|
||||
hasActiveDownloadObserver = true
|
||||
fetch.addActiveDownloadsObserver(true, fetchActiveDownloadObserver)
|
||||
@@ -128,7 +139,7 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
|
||||
override fun onAdded(download: Download) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onAdded(download)
|
||||
}
|
||||
}
|
||||
@@ -140,49 +151,49 @@ class UpdateService: LifecycleService() {
|
||||
downloadedBytesPerSecond: Long,
|
||||
fetchGroup: FetchGroup
|
||||
) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onProgress(groupId, download, etaInMilliSeconds, downloadedBytesPerSecond, fetchGroup)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProgress(download: Download, etaInMilliSeconds: Long, downloadedBytesPerSecond: Long) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onProgress(download, etaInMilliSeconds, downloadedBytesPerSecond)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueued(groupId: Int, download: Download, waitingNetwork: Boolean, fetchGroup: FetchGroup) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onQueued(groupId, download, waitingNetwork, fetchGroup)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueued(download: Download, waitingOnNetwork: Boolean) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onQueued(download, waitingOnNetwork)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRemoved(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onRemoved(groupId, download, fetchGroup)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRemoved(download: Download) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onRemoved(download)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResumed(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onResumed(groupId, download, fetchGroup)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResumed(download: Download) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onResumed(download)
|
||||
}
|
||||
}
|
||||
@@ -194,7 +205,7 @@ class UpdateService: LifecycleService() {
|
||||
totalBlocks: Int,
|
||||
fetchGroup: FetchGroup
|
||||
) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onStarted(
|
||||
groupId,
|
||||
download,
|
||||
@@ -205,7 +216,7 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
|
||||
override fun onStarted(download: Download, downloadBlocks: List<DownloadBlock>, totalBlocks: Int) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onStarted(
|
||||
download,
|
||||
downloadBlocks,
|
||||
@@ -214,23 +225,23 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
|
||||
override fun onWaitingNetwork(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onWaitingNetwork(groupId, download, fetchGroup)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onWaitingNetwork(download: Download) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onWaitingNetwork(download)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCompleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onCompleted(groupId, download, fetchGroup)
|
||||
}
|
||||
if (listeners.isEmpty()) {
|
||||
pendingEvents[groupId] = AppDownloadStatus(download, fetchGroup, isComplete = true)
|
||||
if (fetchListeners.isEmpty()) {
|
||||
fetchPendingEvents[groupId] = AppDownloadStatus(download, fetchGroup, isComplete = true)
|
||||
}
|
||||
if (fetchGroup.groupDownloadProgress == 100) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
@@ -246,35 +257,37 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
|
||||
override fun onCompleted(download: Download) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onCompleted(download)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelled(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onCancelled(groupId, download, fetchGroup)
|
||||
}
|
||||
if (listeners.isEmpty()) {
|
||||
pendingEvents[groupId] = AppDownloadStatus(download, fetchGroup, isCancelled = true)
|
||||
if (fetchListeners.isEmpty()) {
|
||||
fetchPendingEvents[groupId] = AppDownloadStatus(download, fetchGroup, isCancelled = true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancelled(download: Download) {
|
||||
TODO("Not yet implemented")
|
||||
fetchListeners.forEach {
|
||||
it.onCancelled(download)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDeleted(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onDeleted(groupId, download, fetchGroup)
|
||||
}
|
||||
if (listeners.isEmpty()) {
|
||||
pendingEvents[groupId] = AppDownloadStatus(download, fetchGroup, isCancelled = true)
|
||||
if (fetchListeners.isEmpty()) {
|
||||
fetchPendingEvents[groupId] = AppDownloadStatus(download, fetchGroup, isCancelled = true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDeleted(download: Download) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onDeleted(download)
|
||||
}
|
||||
}
|
||||
@@ -286,7 +299,7 @@ class UpdateService: LifecycleService() {
|
||||
totalBlocks: Int,
|
||||
fetchGroup: FetchGroup
|
||||
) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onDownloadBlockUpdated(
|
||||
groupId,
|
||||
download,
|
||||
@@ -298,7 +311,7 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
|
||||
override fun onDownloadBlockUpdated(download: Download, downloadBlock: DownloadBlock, totalBlocks: Int) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onDownloadBlockUpdated(
|
||||
download,
|
||||
downloadBlock,
|
||||
@@ -314,7 +327,7 @@ class UpdateService: LifecycleService() {
|
||||
throwable: Throwable?,
|
||||
fetchGroup: FetchGroup
|
||||
) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onError(
|
||||
groupId,
|
||||
download,
|
||||
@@ -326,7 +339,7 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
|
||||
override fun onError(download: Download, error: Error, throwable: Throwable?) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onError(
|
||||
download,
|
||||
error,
|
||||
@@ -336,13 +349,13 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
|
||||
override fun onPaused(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onPaused(groupId, download, fetchGroup)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPaused(download: Download) {
|
||||
listeners.forEach {
|
||||
fetchListeners.forEach {
|
||||
it.onPaused(download)
|
||||
}
|
||||
}
|
||||
@@ -355,8 +368,8 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
}
|
||||
|
||||
fun updateApp(app: App) {
|
||||
installing.set(true)
|
||||
fun updateApp(app: App, removeExisiting: Boolean = false) {
|
||||
installing.add(app.packageName)
|
||||
task {
|
||||
val files = purchaseHelper.purchase(
|
||||
app.packageName,
|
||||
@@ -364,27 +377,70 @@ class UpdateService: LifecycleService() {
|
||||
app.offerType
|
||||
)
|
||||
|
||||
files.map { RequestBuilder.buildRequest(this, app, it) }
|
||||
} successUi {
|
||||
val requests = it.filter { request -> request.url.isNotEmpty() }.toList()
|
||||
files.filter { it.url.isNotEmpty() }
|
||||
.map { RequestBuilder.buildRequest(this, app, it) }
|
||||
.toList()
|
||||
} successUi { requests ->
|
||||
if (requests.isNotEmpty()) {
|
||||
if (removeExisiting) {
|
||||
/*Remove old fetch group if downloaded earlier, mostly in case of updates*/
|
||||
fetch.deleteGroup(app.getGroupId(this))
|
||||
}
|
||||
fetch.enqueue(requests) {
|
||||
Log.i("Updating ${app.displayName}")
|
||||
}
|
||||
} else {
|
||||
toast("Failed to update ${app.displayName}")
|
||||
installing.remove(app.packageName)
|
||||
Log.e("Failed to download : ${app.displayName}")
|
||||
appMetadataListeners.forEach {
|
||||
it.onAppMetadataStatusError(getString(R.string.purchase_session_expired), app)
|
||||
}
|
||||
|
||||
if (appMetadataListeners.isEmpty()) {
|
||||
appMetadataPendingEvents.add(AppMetadataStatus(getString(R.string.purchase_session_expired), app))
|
||||
}
|
||||
}
|
||||
} failUi {
|
||||
Log.e("Failed to update ${app.displayName}")
|
||||
} failUi { failException ->
|
||||
installing.remove(app.packageName)
|
||||
var reason = "Unknown"
|
||||
|
||||
when (failException) {
|
||||
is ApiException.AppNotPurchased -> {
|
||||
reason = getString(R.string.purchase_invalid)
|
||||
}
|
||||
|
||||
is ApiException.AppNotFound -> {
|
||||
reason = getString(R.string.purchase_not_found)
|
||||
}
|
||||
|
||||
is ApiException.AppNotSupported -> {
|
||||
reason = getString(R.string.purchase_unsupported)
|
||||
}
|
||||
|
||||
is ApiException.EmptyDownloads -> {
|
||||
reason = getString(R.string.purchase_no_file)
|
||||
}
|
||||
}
|
||||
|
||||
appMetadataListeners.forEach {
|
||||
it.onAppMetadataStatusError(reason, app)
|
||||
}
|
||||
|
||||
if (appMetadataListeners.isEmpty()) {
|
||||
appMetadataPendingEvents.add(AppMetadataStatus(reason, app))
|
||||
}
|
||||
|
||||
|
||||
Log.e("Failed to purchase ${app.displayName} : $reason")
|
||||
}
|
||||
}
|
||||
|
||||
var timer: Timer? = null
|
||||
val timerTaskRun: Runnable = Runnable {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
if (!installing.get() && listeners.isEmpty()) {
|
||||
if (installing.isEmpty() && fetchListeners.isEmpty() && appMetadataListeners.isEmpty()) {
|
||||
fetch.hasActiveDownloads(true) { hasActiveDownloads ->
|
||||
if (!hasActiveDownloads && !installing.get() && listeners.isEmpty()) {
|
||||
if (!hasActiveDownloads && installing.isEmpty() && fetchListeners.isEmpty() && appMetadataListeners.isEmpty()) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
stopSelf()
|
||||
}
|
||||
@@ -396,8 +452,8 @@ class UpdateService: LifecycleService() {
|
||||
|
||||
@Synchronized
|
||||
private fun install(packageName: String, files: List<Download>?) {
|
||||
installing.add(packageName)
|
||||
files?.let { downloads ->
|
||||
installing.set(true)
|
||||
var filesExist = true
|
||||
|
||||
downloads.forEach { download ->
|
||||
@@ -431,7 +487,16 @@ class UpdateService: LifecycleService() {
|
||||
fun onEventBackgroundThreadExec(event: Any) {
|
||||
when (event) {
|
||||
is InstallerEvent.Success,
|
||||
is InstallerEvent.Cancelled,
|
||||
is InstallerEvent.Failed -> {
|
||||
when (event) {
|
||||
is InstallerEvent.Success -> event.packageName
|
||||
is InstallerEvent.Cancelled -> event.packageName
|
||||
is InstallerEvent.Failed -> event.packageName
|
||||
else -> null
|
||||
}?.run {
|
||||
installing.remove(this)
|
||||
}
|
||||
synchronized(timerLock) {
|
||||
if (timer != null) {
|
||||
timer!!.cancel()
|
||||
@@ -440,8 +505,7 @@ class UpdateService: LifecycleService() {
|
||||
if (timer == null) {
|
||||
timer = Timer()
|
||||
}
|
||||
installing.set(false)
|
||||
timer!!.schedule(timerTask { timerTaskRun.run() }, 10 * 1000)
|
||||
timer!!.schedule(timerTask { timerTaskRun.run() }, 5 * 1000)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
@@ -450,9 +514,9 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
}
|
||||
|
||||
fun registerListener(listener: FetchGroupListener) {
|
||||
listeners.add(listener)
|
||||
val iterator = pendingEvents.iterator()
|
||||
fun registerFetchListener(listener: FetchGroupListener) {
|
||||
fetchListeners.add(listener)
|
||||
val iterator = fetchPendingEvents.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val item = iterator.next()
|
||||
if (item.value.isCancelled && !item.value.isComplete) {
|
||||
@@ -464,8 +528,22 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
}
|
||||
|
||||
fun unregisterListener(listener: AbstractFetchGroupListener) {
|
||||
listeners.remove(listener)
|
||||
fun registerAppMetadataListener(listener: AppMetadataStatusListener) {
|
||||
appMetadataListeners.add(listener)
|
||||
val iterator = appMetadataPendingEvents.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val item = iterator.next()
|
||||
listener.onAppMetadataStatusError(item.reason, item.app)
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
|
||||
fun unregisterAppMetadataListener(listener: AppMetadataStatusListener) {
|
||||
appMetadataListeners.remove(listener)
|
||||
}
|
||||
|
||||
fun unregisterFetchListener(listener: AbstractFetchGroupListener) {
|
||||
fetchListeners.remove(listener)
|
||||
}
|
||||
|
||||
private var binder: UpdateServiceBinder = UpdateServiceBinder()
|
||||
@@ -476,15 +554,16 @@ class UpdateService: LifecycleService() {
|
||||
}
|
||||
|
||||
override fun onUnbind(intent: Intent?): Boolean {
|
||||
listeners.clear()
|
||||
if (!installing.get()) {
|
||||
fetch.hasActiveDownloads(true, { hasActiveDownloads ->
|
||||
if (!hasActiveDownloads && !installing.get() && listeners.isEmpty()) {
|
||||
fetchListeners.clear()
|
||||
appMetadataListeners.clear()
|
||||
if (installing.isEmpty()) {
|
||||
fetch.hasActiveDownloads(true) { hasActiveDownloads ->
|
||||
if (!hasActiveDownloads && installing.isEmpty() && fetchListeners.isEmpty() && appMetadataListeners.isEmpty()) {
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
stopSelf()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.File
|
||||
|
||||
fun Context.getInternalBaseDirectory(): String {
|
||||
return filesDir.path
|
||||
return (getExternalFilesDir(null) ?: filesDir).path
|
||||
}
|
||||
|
||||
object PathUtil {
|
||||
|
||||
@@ -35,21 +35,18 @@ import com.aurora.Constants
|
||||
import com.aurora.extensions.*
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.AuthData
|
||||
import com.aurora.gplayapi.data.models.File
|
||||
import com.aurora.gplayapi.exceptions.ApiException
|
||||
import com.aurora.gplayapi.helpers.AppDetailsHelper
|
||||
import com.aurora.gplayapi.helpers.PurchaseHelper
|
||||
import com.aurora.store.MainActivity
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.State
|
||||
import com.aurora.store.data.downloader.DownloadManager
|
||||
import com.aurora.store.data.downloader.RequestBuilder
|
||||
import com.aurora.store.data.downloader.getGroupId
|
||||
import com.aurora.store.data.event.BusEvent
|
||||
import com.aurora.store.data.event.InstallerEvent
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.network.HttpClient
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
import com.aurora.store.data.service.AppMetadataStatusListener
|
||||
import com.aurora.store.data.service.UpdateService
|
||||
import com.aurora.store.databinding.ActivityDetailsBinding
|
||||
import com.aurora.store.util.*
|
||||
@@ -69,7 +66,6 @@ import org.apache.commons.io.FileUtils
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import java.util.*
|
||||
|
||||
class AppDetailsActivity : BaseDetailsActivity() {
|
||||
|
||||
@@ -78,14 +74,18 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
||||
|
||||
private lateinit var authData: AuthData
|
||||
private lateinit var app: App
|
||||
private var fetch: Fetch? = null
|
||||
private var downloadManager: DownloadManager? = null
|
||||
|
||||
private var updateService: UpdateService? = null
|
||||
private var pendingAddListener = true
|
||||
private var serviceConnection = object : ServiceConnection {
|
||||
override fun onServiceConnected(name: ComponentName, binder: IBinder) {
|
||||
updateService = (binder as UpdateService.UpdateServiceBinder).getUpdateService()
|
||||
if (::fetchGroupListener.isInitialized) {
|
||||
updateService!!.registerListener(fetchGroupListener)
|
||||
if (::fetchGroupListener.isInitialized && ::appMetadataListener.isInitialized) {
|
||||
updateService!!.registerFetchListener(fetchGroupListener)
|
||||
// appMetadataListener needs to be initialized after the fetchGroupListener
|
||||
updateService!!.registerAppMetadataListener(appMetadataListener)
|
||||
pendingAddListener = false
|
||||
}
|
||||
}
|
||||
@@ -95,6 +95,7 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
||||
}
|
||||
}
|
||||
private lateinit var fetchGroupListener: FetchGroupListener
|
||||
private lateinit var appMetadataListener: AppMetadataStatusListener
|
||||
private lateinit var completionMarker: java.io.File
|
||||
private lateinit var inProgressMarker: java.io.File
|
||||
|
||||
@@ -448,14 +449,14 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
||||
private fun startDownload() {
|
||||
when (status) {
|
||||
Status.PAUSED -> {
|
||||
updateService?.fetch?.resumeGroup(app.getGroupId(this@AppDetailsActivity))
|
||||
fetch?.resumeGroup(app.getGroupId(this@AppDetailsActivity))
|
||||
}
|
||||
Status.DOWNLOADING -> {
|
||||
flip(1)
|
||||
toast("Already downloading")
|
||||
}
|
||||
Status.COMPLETED -> {
|
||||
updateService?.fetch?.getFetchGroup(app.getGroupId(this@AppDetailsActivity)) {
|
||||
fetch?.getFetchGroup(app.getGroupId(this@AppDetailsActivity)) {
|
||||
verifyAndInstall(it.downloads)
|
||||
}
|
||||
}
|
||||
@@ -466,91 +467,15 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
||||
}
|
||||
|
||||
private fun purchase() {
|
||||
bottomSheetBehavior.isHideable = false
|
||||
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
|
||||
updateActionState(State.PROGRESS)
|
||||
|
||||
task {
|
||||
val authData = AuthProvider
|
||||
.with(this)
|
||||
.getAuthData()
|
||||
|
||||
PurchaseHelper(authData)
|
||||
.using(HttpClient.getPreferredClient())
|
||||
.purchase(app.packageName, app.versionCode, app.offerType)
|
||||
} successUi { files ->
|
||||
if (files.isNotEmpty()) {
|
||||
var hasOBB = false
|
||||
|
||||
files.forEach { file ->
|
||||
if (file.type == File.FileType.OBB || file.type == File.FileType.PATCH) {
|
||||
hasOBB = true
|
||||
}
|
||||
}
|
||||
|
||||
if (hasOBB)
|
||||
enqueueWithStoragePermission(files)
|
||||
else
|
||||
enqueue(files)
|
||||
} else {
|
||||
Log.e("Failed to download : ${app.displayName}")
|
||||
updateActionState(State.IDLE)
|
||||
}
|
||||
} failUi {
|
||||
updateActionState(State.IDLE)
|
||||
var reason = "Unknown"
|
||||
|
||||
when (it) {
|
||||
is ApiException.AppNotPurchased -> {
|
||||
reason = getString(R.string.purchase_invalid)
|
||||
}
|
||||
|
||||
is ApiException.AppNotFound -> {
|
||||
reason = getString(R.string.purchase_not_found)
|
||||
}
|
||||
|
||||
is ApiException.AppNotSupported -> {
|
||||
reason = getString(R.string.purchase_unsupported)
|
||||
}
|
||||
|
||||
is ApiException.EmptyDownloads -> {
|
||||
reason = getString(R.string.purchase_no_file)
|
||||
}
|
||||
}
|
||||
|
||||
expandBottomSheet(reason)
|
||||
|
||||
Log.e("Failed to purchase ${app.displayName} : $reason")
|
||||
}
|
||||
}
|
||||
|
||||
private fun enqueueWithStoragePermission(files: List<File>) = runWithPermissions(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
) {
|
||||
enqueue(files)
|
||||
}
|
||||
|
||||
private fun enqueue(files: List<File>) {
|
||||
val requestList = files
|
||||
.filter { it.url.isNotEmpty() }
|
||||
.map {
|
||||
RequestBuilder.buildRequest(this, app, it)
|
||||
}
|
||||
.toList()
|
||||
|
||||
if (requestList.isNotEmpty()) {
|
||||
/*Remove old fetch group if downloaded earlier, mostly in case of updates*/
|
||||
updateService?.fetch?.deleteGroup(app.getGroupId(this@AppDetailsActivity))
|
||||
|
||||
/*Enqueue new fetch group*/
|
||||
updateService?.fetch?.enqueue(
|
||||
requestList
|
||||
) {
|
||||
status = Status.ADDED
|
||||
Log.i("Downloading Apks : %s", app.displayName)
|
||||
}
|
||||
} else {
|
||||
updateActionState(State.IDLE)
|
||||
expandBottomSheet(getString(R.string.purchase_session_expired))
|
||||
runWithPermissions(
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
) {
|
||||
updateService?.updateApp(app, removeExisiting = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,11 +485,18 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
||||
downloadedBytesPerSecond: Long
|
||||
) {
|
||||
runOnUiThread {
|
||||
if (isInstalled) {
|
||||
return@runOnUiThread
|
||||
}
|
||||
val progress = if (fetchGroup.groupDownloadProgress > 0)
|
||||
fetchGroup.groupDownloadProgress
|
||||
else
|
||||
0
|
||||
|
||||
if (progress == 100) {
|
||||
B.layoutDetailsInstall.btnDownload.setText(getString(R.string.action_installing))
|
||||
return@runOnUiThread
|
||||
}
|
||||
B.layoutDetailsInstall.apply {
|
||||
txtProgressPercent.text = ("${progress}%")
|
||||
|
||||
@@ -662,13 +594,17 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
||||
}
|
||||
|
||||
private fun attachFetch() {
|
||||
updateService?.fetch?.getFetchGroup(app.getGroupId(this@AppDetailsActivity)) { fetchGroup: FetchGroup ->
|
||||
if (fetch == null) {
|
||||
downloadManager = DownloadManager.with(this)
|
||||
fetch = downloadManager!!.fetch
|
||||
}
|
||||
fetch?.getFetchGroup(app.getGroupId(this@AppDetailsActivity)) { fetchGroup: FetchGroup ->
|
||||
if (fetchGroup.groupDownloadProgress == 100 && fetchGroup.completedDownloads.isNotEmpty()) {
|
||||
status = Status.COMPLETED
|
||||
} else if (updateService?.downloadManager?.isDownloading(fetchGroup) == true) {
|
||||
} else if (downloadManager?.isDownloading(fetchGroup) == true) {
|
||||
status = Status.DOWNLOADING
|
||||
flip(1)
|
||||
} else if (updateService?.downloadManager?.isCanceled(fetchGroup) == true) {
|
||||
} else if (downloadManager?.isCanceled(fetchGroup) == true) {
|
||||
status = Status.CANCELLED
|
||||
} else if (fetchGroup.pausedDownloads.isNotEmpty()) {
|
||||
status = Status.PAUSED
|
||||
@@ -679,6 +615,12 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
||||
|
||||
fetchGroupListener = object : AbstractFetchGroupListener() {
|
||||
|
||||
override fun onAdded(groupId: Int, download: Download, fetchGroup: FetchGroup) {
|
||||
if (groupId == app.getGroupId(this@AppDetailsActivity)) {
|
||||
status = download.status
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStarted(
|
||||
groupId: Int,
|
||||
download: Download,
|
||||
@@ -745,9 +687,6 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
}
|
||||
runOnUiThread {
|
||||
B.layoutDetailsInstall.btnDownload.setText(getString(R.string.action_installing))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -774,16 +713,27 @@ class AppDetailsActivity : BaseDetailsActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
appMetadataListener = object : AppMetadataStatusListener {
|
||||
override fun onAppMetadataStatusError(reason: String, app: App) {
|
||||
if (app.packageName == this@AppDetailsActivity.app.packageName) {
|
||||
updateActionState(State.IDLE)
|
||||
expandBottomSheet(reason)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getUpdateServiceInstance()
|
||||
|
||||
B.layoutDetailsInstall.imgCancel.setOnClickListener {
|
||||
updateService?.fetch?.cancelGroup(
|
||||
fetch?.cancelGroup(
|
||||
app.getGroupId(this@AppDetailsActivity)
|
||||
)
|
||||
}
|
||||
if (pendingAddListener && updateService != null) {
|
||||
pendingAddListener = false
|
||||
updateService!!.registerListener(fetchGroupListener)
|
||||
updateService!!.registerFetchListener(fetchGroupListener)
|
||||
// appMetadataListener needs to be initialized after the fetchGroupListener
|
||||
updateService!!.registerAppMetadataListener(appMetadataListener)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.aurora.store.R
|
||||
import com.aurora.store.data.downloader.DownloadManager
|
||||
import com.aurora.store.data.model.DownloadFile
|
||||
import com.aurora.store.databinding.ActivityDownloadBinding
|
||||
import com.aurora.store.util.Preferences
|
||||
import com.aurora.store.view.epoxy.views.DownloadViewModel_
|
||||
import com.aurora.store.view.epoxy.views.app.NoAppViewModel_
|
||||
import com.aurora.store.view.ui.commons.BaseActivity
|
||||
@@ -156,10 +157,12 @@ class DownloadActivity : BaseActivity() {
|
||||
}
|
||||
R.id.action_clear_completed -> {
|
||||
fetch.removeAllWithStatus(Status.COMPLETED)
|
||||
Preferences.getPrefs(this).edit().remove(Preferences.PREFERENCE_UNIQUE_GROUP_IDS).apply()
|
||||
return true
|
||||
}
|
||||
R.id.action_force_clear_all -> {
|
||||
fetch.deleteAll()
|
||||
Preferences.getPrefs(this).edit().remove(Preferences.PREFERENCE_UNIQUE_GROUP_IDS).apply()
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,21 +113,8 @@ class OnboardingActivity : BaseActivity() {
|
||||
B.viewpager2.registerOnPageChangeCallback(object : OnPageChangeCallback() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
runOnUiThread {
|
||||
B.btnBackward.isEnabled = position != 0
|
||||
if (position == 4) {
|
||||
B.btnForward.text = getString(R.string.action_finish)
|
||||
B.btnForward.setOnClickListener {
|
||||
save(PREFERENCE_INTRO, true)
|
||||
open(SplashActivity::class.java, true)
|
||||
}
|
||||
} else {
|
||||
B.btnForward.text = getString(R.string.action_next)
|
||||
B.btnForward.setOnClickListener {
|
||||
B.viewpager2.setCurrentItem(
|
||||
B.viewpager2.currentItem + 1, true
|
||||
)
|
||||
}
|
||||
}
|
||||
lastPosition = position
|
||||
refreshButtonState()
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -145,6 +132,32 @@ class OnboardingActivity : BaseActivity() {
|
||||
B.viewpager2.setCurrentItem(B.viewpager2.currentItem - 1, true)
|
||||
}
|
||||
|
||||
var lastPosition = 0
|
||||
|
||||
fun refreshButtonState() {
|
||||
B.btnBackward.isEnabled = lastPosition != 0
|
||||
if (lastPosition == 4) {
|
||||
B.btnForward.text = getString(R.string.action_finish)
|
||||
B.btnForward.setOnClickListener {
|
||||
save(PREFERENCE_INTRO, true)
|
||||
open(SplashActivity::class.java, true)
|
||||
}
|
||||
for (fragment in supportFragmentManager.fragments) {
|
||||
if (fragment is PermissionsFragment) {
|
||||
B.btnForward.isEnabled = fragment.canGoForward()
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
B.btnForward.text = getString(R.string.action_next)
|
||||
B.btnForward.setOnClickListener {
|
||||
B.viewpager2.setCurrentItem(
|
||||
B.viewpager2.currentItem + 1, true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
if (B.viewpager2.currentItem == 0) {
|
||||
super.onBackPressed()
|
||||
|
||||
@@ -91,6 +91,21 @@ class PermissionsFragment : BaseFragment() {
|
||||
)
|
||||
|
||||
B.epoxyRecycler.withModels {
|
||||
val writeExternalStorage = ActivityCompat.checkSelfPermission(
|
||||
requireContext(),
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
val storageManager = if (isRAndAbove()) Environment.isExternalStorageManager() else true
|
||||
val canInstallPackages = if (isOAndAbove()) requireContext().packageManager.canRequestPackageInstalls() else true
|
||||
canGoForward = writeExternalStorage && storageManager && canInstallPackages
|
||||
if (canGoForwardInitial == null) {
|
||||
canGoForwardInitial = canGoForward
|
||||
}
|
||||
if (canGoForward && canGoForwardInitial == false) {
|
||||
if (activity is OnboardingActivity) {
|
||||
(activity!! as OnboardingActivity).refreshButtonState()
|
||||
}
|
||||
}
|
||||
setFilterDuplicates(true)
|
||||
installerList.forEach {
|
||||
add(
|
||||
@@ -99,12 +114,9 @@ class PermissionsFragment : BaseFragment() {
|
||||
.permission(it)
|
||||
.isGranted(
|
||||
when (it.id) {
|
||||
0 -> ActivityCompat.checkSelfPermission(
|
||||
requireContext(),
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
) == PackageManager.PERMISSION_GRANTED
|
||||
1 -> if (isRAndAbove()) Environment.isExternalStorageManager() else true
|
||||
2 -> if (isOAndAbove()) requireContext().packageManager.canRequestPackageInstalls() else true
|
||||
0 -> writeExternalStorage
|
||||
1 -> storageManager
|
||||
2 -> canInstallPackages
|
||||
else -> false
|
||||
}
|
||||
)
|
||||
@@ -164,4 +176,11 @@ class PermissionsFragment : BaseFragment() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var canGoForward = false
|
||||
private var canGoForwardInitial: Boolean? = null
|
||||
|
||||
fun canGoForward(): Boolean {
|
||||
return canGoForward
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,7 @@
|
||||
|
||||
package com.aurora.store.view.ui.updates
|
||||
|
||||
import android.app.Application
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.os.Bundle
|
||||
@@ -32,18 +30,12 @@ import android.view.ViewGroup
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.aurora.Constants
|
||||
import com.aurora.extensions.stackTraceToString
|
||||
import com.aurora.extensions.toast
|
||||
import com.aurora.gplayapi.data.models.App
|
||||
import com.aurora.gplayapi.data.models.AuthData
|
||||
import com.aurora.gplayapi.helpers.PurchaseHelper
|
||||
import com.aurora.store.R
|
||||
import com.aurora.store.State
|
||||
import com.aurora.store.data.downloader.DownloadManager
|
||||
import com.aurora.store.data.downloader.RequestBuilder
|
||||
import com.aurora.store.data.downloader.getGroupId
|
||||
import com.aurora.store.data.installer.AppInstaller
|
||||
import com.aurora.store.data.model.UpdateFile
|
||||
import com.aurora.store.data.providers.AuthProvider
|
||||
import com.aurora.store.data.service.UpdateService
|
||||
import com.aurora.store.databinding.FragmentUpdatesBinding
|
||||
import com.aurora.store.util.Log
|
||||
@@ -56,11 +48,8 @@ import com.aurora.store.view.ui.sheets.AppMenuSheet
|
||||
import com.aurora.store.viewmodel.all.UpdatesViewModel
|
||||
import com.tonyodev.fetch2.AbstractFetchGroupListener
|
||||
import com.tonyodev.fetch2.Download
|
||||
import com.tonyodev.fetch2.Fetch
|
||||
import com.tonyodev.fetch2.FetchGroup
|
||||
import nl.komponents.kovenant.task
|
||||
import nl.komponents.kovenant.ui.failUi
|
||||
import nl.komponents.kovenant.ui.successUi
|
||||
import org.apache.commons.io.FileUtils
|
||||
|
||||
class UpdatesFragment : BaseFragment() {
|
||||
@@ -72,7 +61,7 @@ class UpdatesFragment : BaseFragment() {
|
||||
private var serviceConnection = object : ServiceConnection {
|
||||
override fun onServiceConnected(name: ComponentName, binder: IBinder) {
|
||||
updateService = (binder as UpdateService.UpdateServiceBinder).getUpdateService()
|
||||
updateService!!.registerListener(fetchListener)
|
||||
updateService!!.registerFetchListener(fetchListener)
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName) {
|
||||
@@ -158,12 +147,12 @@ class UpdatesFragment : BaseFragment() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
VM.liveUpdateData.observe(viewLifecycleOwner, {
|
||||
VM.liveUpdateData.observe(viewLifecycleOwner) {
|
||||
updateFileMap = it
|
||||
updateController(updateFileMap)
|
||||
B.swipeRefreshLayout.isRefreshing = false
|
||||
updateService?.liveUpdateData?.postValue(updateFileMap)
|
||||
})
|
||||
}
|
||||
|
||||
B.swipeRefreshLayout.setOnRefreshListener {
|
||||
VM.observe()
|
||||
|
||||
Reference in New Issue
Block a user