diff --git a/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt index d185fd14b..99e5ed78a 100644 --- a/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/AppInstaller.kt @@ -26,9 +26,10 @@ import com.aurora.store.R import com.aurora.store.util.Preferences import com.aurora.store.util.Preferences.PREFERENCE_INSTALLER_ID -open class AppInstaller constructor(var context: Context) { +open class AppInstaller private constructor(var context: Context) { companion object { + private var instance: AppInstaller? = null fun getErrorString(context: Context, status: Int): String { return when (status) { PackageInstaller.STATUS_FAILURE_ABORTED -> context.getString(R.string.installer_status_user_action) @@ -40,22 +41,50 @@ open class AppInstaller constructor(var context: Context) { else -> context.getString(R.string.installer_status_failure) } } + fun getInstance(context: Context): AppInstaller { + if (instance == null) { + instance = AppInstaller(context.applicationContext) + } + return instance!! + } } + val choiceAndInstaller = HashMap() + fun getPreferredInstaller(): IInstaller { val prefValue = Preferences.getInteger( context, PREFERENCE_INSTALLER_ID ) + if (choiceAndInstaller.containsKey(prefValue)) { + return choiceAndInstaller[prefValue]!! + } + return when (prefValue) { - 1 -> NativeInstaller(context) - 2 -> RootInstaller(context) - 3 -> ServiceInstaller(context) + 1 -> { + val installer = NativeInstaller(context) + choiceAndInstaller[prefValue] = installer + installer + } + 2 -> { + val installer = RootInstaller(context) + choiceAndInstaller[prefValue] = installer + installer + } + 3 -> { + val installer = ServiceInstaller(context) + choiceAndInstaller[prefValue] = installer + installer + } else -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - SessionInstaller(context) + val installer = SessionInstaller(context) + choiceAndInstaller[prefValue] = installer + installer } else { - NativeInstaller(context) + val installer = NativeInstaller(context) + choiceAndInstaller[prefValue] = installer + installer } } } diff --git a/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt b/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt index f996fe90a..239da7237 100644 --- a/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt +++ b/app/src/main/java/com/aurora/store/data/installer/ServiceInstaller.kt @@ -25,9 +25,7 @@ import android.content.Intent import android.content.ServiceConnection import android.content.pm.PackageInstaller import android.net.Uri -import android.os.Build -import android.os.IBinder -import android.os.RemoteException +import android.os.* import androidx.annotation.RequiresApi import androidx.core.content.FileProvider import com.aurora.services.IPrivilegedCallback @@ -41,10 +39,14 @@ import com.aurora.store.util.Log import com.aurora.store.util.PackageUtil import org.greenrobot.eventbus.EventBus import java.io.File +import java.util.concurrent.LinkedBlockingQueue +import java.util.concurrent.ThreadPoolExecutor +import java.util.concurrent.TimeUnit class ServiceInstaller(context: Context) : InstallerBase(context) { private lateinit var serviceConnection: ServiceConnection + private val executor = ThreadPoolExecutor(0, 1, 30L, TimeUnit.SECONDS, LinkedBlockingQueue()) companion object { const val ACTION_INSTALL_REPLACE_EXISTING = 2 @@ -85,134 +87,168 @@ class ServiceInstaller(context: Context) : InstallerBase(context) { } override fun uninstall(packageName: String) { - val serviceConnection = object : ServiceConnection { - override fun onServiceConnected(name: ComponentName, binder: IBinder) { - AuroraApplication.enqueuedInstalls.add(packageName) - val service = IPrivilegedService.Stub.asInterface(binder) - - if (service.hasPrivilegedPermissions()) { - Log.i(context.getString(R.string.installer_service_available)) - - val callback = object : IPrivilegedCallback.Stub() { - - override fun handleResult(packageName: String, returnCode: Int) { - + executor.execute { + var readyWithAction = false + Handler(Looper.getMainLooper()).post { + serviceConnection = object : ServiceConnection { + override fun onServiceConnected(name: ComponentName, binder: IBinder) { + if (isAlreadyQueued(packageName)) { + if (::serviceConnection.isInitialized) { + context.unbindService(serviceConnection) + } + readyWithAction = true + return } + AuroraApplication.enqueuedInstalls.add(packageName) + val service = IPrivilegedService.Stub.asInterface(binder) - override fun handleResultX( - packageName: String, - returnCode: Int, - extra: String? - ) { + if (service.hasPrivilegedPermissions()) { + Log.i(context.getString(R.string.installer_service_available)) + + val callback = object : IPrivilegedCallback.Stub() { + + override fun handleResult(packageName: String, returnCode: Int) { + + } + + override fun handleResultX( + packageName: String, + returnCode: Int, + extra: String? + ) { + removeFromInstallQueue(packageName) + readyWithAction = true + handleCallbackUninstall(packageName, returnCode, extra) + } + } + + try { + service.deletePackageX( + packageName, + 2, + BuildConfig.APPLICATION_ID, + callback + ) + } catch (e: RemoteException) { + Log.e("Failed to connect Aurora Services") + removeFromInstallQueue(packageName) + readyWithAction = true + } + } else { removeFromInstallQueue(packageName) - handleCallbackUninstall(packageName, returnCode, extra) + readyWithAction = true + postError( + packageName, + context.getString(R.string.installer_status_failure), + context.getString(R.string.installer_service_misconfigured) + ) } } - try { - service.deletePackageX( - packageName, - 2, - BuildConfig.APPLICATION_ID, - callback - ) - } catch (e: RemoteException) { - Log.e("Failed to connect Aurora Services") + override fun onServiceDisconnected(name: ComponentName) { + removeFromInstallQueue(packageName) + Log.e("Disconnected from Aurora Services") + readyWithAction = true } - } else { - postError( - packageName, - context.getString(R.string.installer_status_failure), - context.getString(R.string.installer_service_misconfigured) - ) - removeFromInstallQueue(packageName) } - } - override fun onServiceDisconnected(name: ComponentName) { - removeFromInstallQueue(packageName) - Log.e("Disconnected from Aurora Services") + val intent = Intent(PRIVILEGED_EXTENSION_SERVICE_INTENT) + intent.setPackage(PRIVILEGED_EXTENSION_PACKAGE_NAME) + + context.bindService( + intent, + serviceConnection, + Context.BIND_AUTO_CREATE + ) + } + while (!readyWithAction) { + Thread.sleep(1000) } } - - val intent = Intent(PRIVILEGED_EXTENSION_SERVICE_INTENT) - intent.setPackage(PRIVILEGED_EXTENSION_PACKAGE_NAME) - - context.bindService( - intent, - serviceConnection, - Context.BIND_AUTO_CREATE - ) } @RequiresApi(Build.VERSION_CODES.LOLLIPOP) private fun xInstall(packageName: String, uriList: List) { - serviceConnection = object : ServiceConnection { - override fun onServiceConnected(name: ComponentName, binder: IBinder) { - if (isAlreadyQueued(packageName)) { - if (::serviceConnection.isInitialized) { - context.unbindService(serviceConnection) - } - return - } - AuroraApplication.enqueuedInstalls.add(packageName) - val service = IPrivilegedService.Stub.asInterface(binder) - - if (service.hasPrivilegedPermissions()) { - Log.i(context.getString(R.string.installer_service_available)) - - val callback = object : IPrivilegedCallback.Stub() { - - override fun handleResult(packageName: String, returnCode: Int) { - + executor.execute { + var readyWithAction = false + Handler(Looper.getMainLooper()).post { + serviceConnection = object : ServiceConnection { + override fun onServiceConnected(name: ComponentName, binder: IBinder) { + if (isAlreadyQueued(packageName)) { + if (::serviceConnection.isInitialized) { + context.unbindService(serviceConnection) + } + readyWithAction = true + return } + AuroraApplication.enqueuedInstalls.add(packageName) + val service = IPrivilegedService.Stub.asInterface(binder) - override fun handleResultX( - packageName: String, - returnCode: Int, - extra: String? - ) { + if (service.hasPrivilegedPermissions()) { + Log.i(context.getString(R.string.installer_service_available)) + + val callback = object : IPrivilegedCallback.Stub() { + + override fun handleResult(packageName: String, returnCode: Int) { + + } + + override fun handleResultX( + packageName: String, + returnCode: Int, + extra: String? + ) { + removeFromInstallQueue(packageName) + readyWithAction = true + handleCallback(packageName, returnCode, extra) + } + } + + 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) - handleCallback(packageName, returnCode, extra) + readyWithAction = true + postError( + packageName, + context.getString(R.string.installer_status_failure), + context.getString(R.string.installer_service_misconfigured) + ) } } - try { - service.installSplitPackageX( - packageName, - uriList, - ACTION_INSTALL_REPLACE_EXISTING, - BuildConfig.APPLICATION_ID, - callback - ) - } catch (e: RemoteException) { + override fun onServiceDisconnected(name: ComponentName) { removeFromInstallQueue(packageName) - postError(packageName, e.localizedMessage, e.stackTraceToString()) + readyWithAction = true + Log.e("Disconnected from Aurora Services") } - } else { - postError( - packageName, - context.getString(R.string.installer_status_failure), - context.getString(R.string.installer_service_misconfigured) - ) - removeFromInstallQueue(packageName) } - } - override fun onServiceDisconnected(name: ComponentName) { - removeFromInstallQueue(packageName) - Log.e("Disconnected from Aurora Services") + val intent = Intent(PRIVILEGED_EXTENSION_SERVICE_INTENT) + intent.setPackage(PRIVILEGED_EXTENSION_PACKAGE_NAME) + + context.bindService( + intent, + serviceConnection, + Context.BIND_AUTO_CREATE + ) } + while (!readyWithAction) { + Thread.sleep(1000) + } + Log.i("Services Callback : install wait done") } - - val intent = Intent(PRIVILEGED_EXTENSION_SERVICE_INTENT) - intent.setPackage(PRIVILEGED_EXTENSION_PACKAGE_NAME) - - context.bindService( - intent, - serviceConnection, - Context.BIND_AUTO_CREATE - ) } private fun handleCallbackUninstall(packageName: String, returnCode: Int, extra: String?) { diff --git a/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt b/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt index 51f3ad1d0..5fe1cfdc0 100644 --- a/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt +++ b/app/src/main/java/com/aurora/store/data/receiver/PackageManagerReceiver.kt @@ -50,7 +50,7 @@ open class PackageManagerReceiver : BroadcastReceiver() { } //Clear installation queue - AppInstaller(context) + AppInstaller.getInstance(context) .getPreferredInstaller() .removeFromInstallQueue(packageName) diff --git a/app/src/main/java/com/aurora/store/data/service/NotificationService.kt b/app/src/main/java/com/aurora/store/data/service/NotificationService.kt index 205f6ed03..e1f8ffd02 100644 --- a/app/src/main/java/com/aurora/store/data/service/NotificationService.kt +++ b/app/src/main/java/com/aurora/store/data/service/NotificationService.kt @@ -401,7 +401,7 @@ class NotificationService : Service() { @Synchronized private fun install(packageName: String, files: List) { - AppInstaller(this) + AppInstaller.getInstance(this) .getPreferredInstaller() .install( packageName, diff --git a/app/src/main/java/com/aurora/store/data/service/UpdateService.kt b/app/src/main/java/com/aurora/store/data/service/UpdateService.kt index 216f2dad9..9b9ab47f5 100644 --- a/app/src/main/java/com/aurora/store/data/service/UpdateService.kt +++ b/app/src/main/java/com/aurora/store/data/service/UpdateService.kt @@ -17,32 +17,31 @@ 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.RequestGroupIdBuilder -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.providers.AuthProvider import com.aurora.store.util.Log import com.tonyodev.fetch2.* +import com.tonyodev.fetch2core.DownloadBlock import com.tonyodev.fetch2core.FetchObserver import com.tonyodev.fetch2core.Reason import nl.komponents.kovenant.task -import nl.komponents.kovenant.then import nl.komponents.kovenant.ui.failUi import nl.komponents.kovenant.ui.successUi import org.apache.commons.io.FileUtils 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 kotlin.collections.ArrayList import kotlin.concurrent.timerTask class UpdateService: LifecycleService() { lateinit var fetch: Fetch - private lateinit var fetchListener: AbstractFetchGroupListener + lateinit var downloadManager: DownloadManager + private lateinit var fetchListener: FetchGroupListener private var fetchActiveDownloadObserver = object : FetchObserver { override fun onChanged(data: Boolean, reason: Reason) { if (!data && !installing.get() && listeners.isEmpty()) { @@ -56,7 +55,7 @@ class UpdateService: LifecycleService() { } private var hasActiveDownloadObserver = false - private val listeners: ArrayList = ArrayList() + private val listeners: ArrayList = ArrayList() private val pendingEvents: MutableMap = mutableMapOf() @@ -114,8 +113,9 @@ class UpdateService: LifecycleService() { EventBus.getDefault().register(this) authData = AuthProvider.with(this).getAuthData() purchaseHelper = PurchaseHelper(authData) - fetch = DownloadManager.with(this).fetch - fetchListener = object : AbstractFetchGroupListener() { + downloadManager = DownloadManager.with(this) + fetch = downloadManager.fetch + fetchListener = object : FetchGroupListener { override fun onAdded(groupId: Int, download: Download, fetchGroup: FetchGroup) { listeners.forEach { @@ -127,6 +127,12 @@ class UpdateService: LifecycleService() { } } + override fun onAdded(download: Download) { + listeners.forEach { + it.onAdded(download) + } + } + override fun onProgress( groupId: Int, download: Download, @@ -139,6 +145,86 @@ class UpdateService: LifecycleService() { } } + override fun onProgress(download: Download, etaInMilliSeconds: Long, downloadedBytesPerSecond: Long) { + listeners.forEach { + it.onProgress(download, etaInMilliSeconds, downloadedBytesPerSecond) + } + } + + override fun onQueued(groupId: Int, download: Download, waitingNetwork: Boolean, fetchGroup: FetchGroup) { + listeners.forEach { + it.onQueued(groupId, download, waitingNetwork, fetchGroup) + } + } + + override fun onQueued(download: Download, waitingOnNetwork: Boolean) { + listeners.forEach { + it.onQueued(download, waitingOnNetwork) + } + } + + override fun onRemoved(groupId: Int, download: Download, fetchGroup: FetchGroup) { + listeners.forEach { + it.onRemoved(groupId, download, fetchGroup) + } + } + + override fun onRemoved(download: Download) { + listeners.forEach { + it.onRemoved(download) + } + } + + override fun onResumed(groupId: Int, download: Download, fetchGroup: FetchGroup) { + listeners.forEach { + it.onResumed(groupId, download, fetchGroup) + } + } + + override fun onResumed(download: Download) { + listeners.forEach { + it.onResumed(download) + } + } + + override fun onStarted( + groupId: Int, + download: Download, + downloadBlocks: List, + totalBlocks: Int, + fetchGroup: FetchGroup + ) { + listeners.forEach { + it.onStarted( + groupId, + download, + downloadBlocks, + totalBlocks, + fetchGroup) + } + } + + override fun onStarted(download: Download, downloadBlocks: List, totalBlocks: Int) { + listeners.forEach { + it.onStarted( + download, + downloadBlocks, + totalBlocks) + } + } + + override fun onWaitingNetwork(groupId: Int, download: Download, fetchGroup: FetchGroup) { + listeners.forEach { + it.onWaitingNetwork(groupId, download, fetchGroup) + } + } + + override fun onWaitingNetwork(download: Download) { + listeners.forEach { + it.onWaitingNetwork(download) + } + } + override fun onCompleted(groupId: Int, download: Download, fetchGroup: FetchGroup) { listeners.forEach { it.onCompleted(groupId, download, fetchGroup) @@ -146,7 +232,7 @@ class UpdateService: LifecycleService() { if (listeners.isEmpty()) { pendingEvents[groupId] = AppDownloadStatus(download, fetchGroup, isComplete = true) } - if (fetchGroup.groupDownloadProgress == 100 || fetchGroup.groupDownloadProgress == -1) { + if (fetchGroup.groupDownloadProgress == 100) { Handler(Looper.getMainLooper()).post { try { install(download.tag!!, fetchGroup.downloads) @@ -159,6 +245,12 @@ class UpdateService: LifecycleService() { }*/ } + override fun onCompleted(download: Download) { + listeners.forEach { + it.onCompleted(download) + } + } + override fun onCancelled(groupId: Int, download: Download, fetchGroup: FetchGroup) { listeners.forEach { it.onCancelled(groupId, download, fetchGroup) @@ -168,6 +260,10 @@ class UpdateService: LifecycleService() { } } + override fun onCancelled(download: Download) { + TODO("Not yet implemented") + } + override fun onDeleted(groupId: Int, download: Download, fetchGroup: FetchGroup) { listeners.forEach { it.onDeleted(groupId, download, fetchGroup) @@ -176,6 +272,80 @@ class UpdateService: LifecycleService() { pendingEvents[groupId] = AppDownloadStatus(download, fetchGroup, isCancelled = true) } } + + override fun onDeleted(download: Download) { + listeners.forEach { + it.onDeleted(download) + } + } + + override fun onDownloadBlockUpdated( + groupId: Int, + download: Download, + downloadBlock: DownloadBlock, + totalBlocks: Int, + fetchGroup: FetchGroup + ) { + listeners.forEach { + it.onDownloadBlockUpdated( + groupId, + download, + downloadBlock, + totalBlocks, + fetchGroup + ) + } + } + + override fun onDownloadBlockUpdated(download: Download, downloadBlock: DownloadBlock, totalBlocks: Int) { + listeners.forEach { + it.onDownloadBlockUpdated( + download, + downloadBlock, + totalBlocks + ) + } + } + + override fun onError( + groupId: Int, + download: Download, + error: Error, + throwable: Throwable?, + fetchGroup: FetchGroup + ) { + listeners.forEach { + it.onError( + groupId, + download, + error, + throwable, + fetchGroup + ) + } + } + + override fun onError(download: Download, error: Error, throwable: Throwable?) { + listeners.forEach { + it.onError( + download, + error, + throwable + ) + } + } + + override fun onPaused(groupId: Int, download: Download, fetchGroup: FetchGroup) { + listeners.forEach { + it.onPaused(groupId, download, fetchGroup) + } + } + + override fun onPaused(download: Download) { + listeners.forEach { + it.onPaused(download) + } + } } /*liveUpdateData.observe(this) { updateData -> @@ -210,16 +380,16 @@ class UpdateService: LifecycleService() { } var timer: Timer? = null - val timerTask: TimerTask = timerTask { + val timerTaskRun: Runnable = Runnable { Handler(Looper.getMainLooper()).post { if (!installing.get() && listeners.isEmpty()) { - fetch.hasActiveDownloads(true, { hasActiveDownloads -> + fetch.hasActiveDownloads(true) { hasActiveDownloads -> if (!hasActiveDownloads && !installing.get() && listeners.isEmpty()) { Handler(Looper.getMainLooper()).post { stopSelf() } } - }) + } } } } @@ -237,7 +407,7 @@ class UpdateService: LifecycleService() { if (filesExist) { task { try { - val installer = AppInstaller(this) + val installer = AppInstaller.getInstance(this) .getPreferredInstaller() installer.install( packageName, @@ -255,30 +425,24 @@ class UpdateService: LifecycleService() { } } - @Subscribe() - fun onEventMainThreadExec(event: Any) { + var timerLock = Object() + + @Subscribe(threadMode = ThreadMode.BACKGROUND) + fun onEventBackgroundThreadExec(event: Any) { when (event) { - is InstallerEvent.Success -> { - if (timer != null) { - timer!!.cancel() - timer = null - } - if (timer == null) { - timer = Timer() - } - installing.set(false) - timer!!.schedule(timerTask, 10 * 1000) - } + is InstallerEvent.Success, is InstallerEvent.Failed -> { - if (timer != null) { - timer!!.cancel() - timer = null + synchronized(timerLock) { + if (timer != null) { + timer!!.cancel() + timer = null + } + if (timer == null) { + timer = Timer() + } + installing.set(false) + timer!!.schedule(timerTask { timerTaskRun.run() }, 10 * 1000) } - if (timer == null) { - timer = Timer() - } - installing.set(false) - timer!!.schedule(timerTask, 10 * 1000) } else -> { @@ -286,7 +450,7 @@ class UpdateService: LifecycleService() { } } - fun registerListener(listener: AbstractFetchGroupListener) { + fun registerListener(listener: FetchGroupListener) { listeners.add(listener) val iterator = pendingEvents.iterator() while (iterator.hasNext()) { diff --git a/app/src/main/java/com/aurora/store/view/ui/details/AppDetailsActivity.kt b/app/src/main/java/com/aurora/store/view/ui/details/AppDetailsActivity.kt index a5e1c977f..3c69194c1 100644 --- a/app/src/main/java/com/aurora/store/view/ui/details/AppDetailsActivity.kt +++ b/app/src/main/java/com/aurora/store/view/ui/details/AppDetailsActivity.kt @@ -21,9 +21,12 @@ package com.aurora.store.view.ui.details import android.Manifest import android.content.ActivityNotFoundException +import android.content.ComponentName import android.content.Intent +import android.content.ServiceConnection import android.os.Build import android.os.Bundle +import android.os.IBinder import android.view.Menu import android.view.MenuItem import android.view.View @@ -47,6 +50,7 @@ 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.UpdateService import com.aurora.store.databinding.ActivityDetailsBinding import com.aurora.store.util.* import com.aurora.store.view.ui.downloads.DownloadActivity @@ -74,8 +78,22 @@ class AppDetailsActivity : BaseDetailsActivity() { private lateinit var authData: AuthData private lateinit var app: App - private lateinit var downloadManager: DownloadManager - private lateinit var fetch: Fetch + + 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) + pendingAddListener = false + } + } + + override fun onServiceDisconnected(name: ComponentName) { + updateService = null + } + } private lateinit var fetchGroupListener: FetchGroupListener private lateinit var completionMarker: java.io.File private lateinit var inProgressMarker: java.io.File @@ -166,9 +184,8 @@ class AppDetailsActivity : BaseDetailsActivity() { } override fun onResume() { - if (!isLAndAbove()) { - checkAndSetupInstall() - } + getUpdateServiceInstance() + checkAndSetupInstall() super.onResume() } @@ -207,11 +224,14 @@ class AppDetailsActivity : BaseDetailsActivity() { } } + private var uninstallActionEnabled = false + override fun onCreateOptionsMenu(menu: Menu?): Boolean { menuInflater.inflate(R.menu.menu_details, menu) if (::app.isInitialized) { val installed = PackageUtil.isInstalled(this, app.packageName) menu?.findItem(R.id.action_uninstall)?.isVisible = installed + uninstallActionEnabled = installed } return true } @@ -306,7 +326,7 @@ class AppDetailsActivity : BaseDetailsActivity() { showDialog(R.string.title_installer, R.string.dialog_desc_native_split) } else { task { - AppInstaller(this) + AppInstaller.getInstance(this) .getPreferredInstaller() .install( app.packageName, @@ -325,7 +345,7 @@ class AppDetailsActivity : BaseDetailsActivity() { @Synchronized private fun uninstallApp() { task { - AppInstaller(this) + AppInstaller.getInstance(this) .getPreferredInstaller() .uninstall(app.packageName) } @@ -428,14 +448,14 @@ class AppDetailsActivity : BaseDetailsActivity() { private fun startDownload() { when (status) { Status.PAUSED -> { - fetch.resumeGroup(app.getGroupId(this@AppDetailsActivity)) + updateService?.fetch?.resumeGroup(app.getGroupId(this@AppDetailsActivity)) } Status.DOWNLOADING -> { flip(1) toast("Already downloading") } Status.COMPLETED -> { - fetch.getFetchGroup(app.getGroupId(this@AppDetailsActivity)) { + updateService?.fetch?.getFetchGroup(app.getGroupId(this@AppDetailsActivity)) { verifyAndInstall(it.downloads) } } @@ -519,10 +539,10 @@ class AppDetailsActivity : BaseDetailsActivity() { if (requestList.isNotEmpty()) { /*Remove old fetch group if downloaded earlier, mostly in case of updates*/ - fetch.deleteGroup(app.getGroupId(this@AppDetailsActivity)) + updateService?.fetch?.deleteGroup(app.getGroupId(this@AppDetailsActivity)) /*Enqueue new fetch group*/ - fetch.enqueue( + updateService?.fetch?.enqueue( requestList ) { status = Status.ADDED @@ -604,6 +624,9 @@ class AppDetailsActivity : BaseDetailsActivity() { btn.setText(R.string.action_open) btn.addOnClickListener { openApp() } } + if (!uninstallActionEnabled) { + invalidateOptionsMenu() + } } else { if (app.isFree) { btn.setText(R.string.action_install) @@ -619,6 +642,9 @@ class AppDetailsActivity : BaseDetailsActivity() { startDownload() } } + if (uninstallActionEnabled) { + invalidateOptionsMenu() + } } } } @@ -636,16 +662,13 @@ class AppDetailsActivity : BaseDetailsActivity() { } private fun attachFetch() { - downloadManager = DownloadManager.with(this) - fetch = downloadManager.fetch - - fetch.getFetchGroup(app.getGroupId(this@AppDetailsActivity)) { fetchGroup: FetchGroup -> + updateService?.fetch?.getFetchGroup(app.getGroupId(this@AppDetailsActivity)) { fetchGroup: FetchGroup -> if (fetchGroup.groupDownloadProgress == 100 && fetchGroup.completedDownloads.isNotEmpty()) { status = Status.COMPLETED - } else if (downloadManager.isDownloading(fetchGroup)) { + } else if (updateService?.downloadManager?.isDownloading(fetchGroup) == true) { status = Status.DOWNLOADING flip(1) - } else if (downloadManager.isCanceled(fetchGroup)) { + } else if (updateService?.downloadManager?.isCanceled(fetchGroup) == true) { status = Status.CANCELLED } else if (fetchGroup.pausedDownloads.isNotEmpty()) { status = Status.PAUSED @@ -716,12 +739,14 @@ class AppDetailsActivity : BaseDetailsActivity() { status = download.status flip(0) updateProgress(fetchGroup, -1, -1) - inProgressMarker.delete() - completionMarker.createNewFile() try { - verifyAndInstall(fetchGroup.downloads) - } catch (e: Exception) { - Log.e(e.stackTraceToString()) + inProgressMarker.delete() + completionMarker.createNewFile() + } catch (ex: Exception) { + ex.printStackTrace() + } + runOnUiThread { + B.layoutDetailsInstall.btnDownload.setText(getString(R.string.action_installing)) } } } @@ -749,13 +774,45 @@ class AppDetailsActivity : BaseDetailsActivity() { } } - fetch.addListener(fetchGroupListener) + getUpdateServiceInstance() B.layoutDetailsInstall.imgCancel.setOnClickListener { - fetch.cancelGroup( + updateService?.fetch?.cancelGroup( app.getGroupId(this@AppDetailsActivity) ) } + if (pendingAddListener && updateService != null) { + pendingAddListener = false + updateService!!.registerListener(fetchGroupListener) + } + } + + fun getUpdateServiceInstance() { + if (updateService == null) { + val intent = Intent(this, UpdateService::class.java) + startService(intent) + bindService( + intent, + serviceConnection, + 0 + ) + } + } + + override fun onPause() { + if (updateService != null) { + updateService = null + unbindService(serviceConnection) + } + super.onPause() + } + + override fun onDestroy() { + super.onDestroy() + if (updateService != null) { + updateService = null + unbindService(serviceConnection) + } } private fun attachBottomSheet() { diff --git a/app/src/main/java/com/aurora/store/view/ui/sheets/AppMenuSheet.kt b/app/src/main/java/com/aurora/store/view/ui/sheets/AppMenuSheet.kt index 310e86df9..29a9cf221 100644 --- a/app/src/main/java/com/aurora/store/view/ui/sheets/AppMenuSheet.kt +++ b/app/src/main/java/com/aurora/store/view/ui/sheets/AppMenuSheet.kt @@ -108,7 +108,7 @@ class AppMenuSheet : BaseBottomSheet() { R.id.action_uninstall -> { task { - AppInstaller(requireContext()) + AppInstaller.getInstance(requireContext()) .getPreferredInstaller().uninstall(app.packageName) } } diff --git a/app/src/main/java/com/aurora/store/view/ui/updates/UpdatesFragment.kt b/app/src/main/java/com/aurora/store/view/ui/updates/UpdatesFragment.kt index 407b482ac..196a6f1fc 100644 --- a/app/src/main/java/com/aurora/store/view/ui/updates/UpdatesFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/updates/UpdatesFragment.kt @@ -285,7 +285,7 @@ class UpdatesFragment : BaseFragment() { if (filesExist) { task { - AppInstaller(requireContext()) + AppInstaller.getInstance(requireContext()) .getPreferredInstaller() .install( packageName,