Skip to content

Commit

Permalink
Improve Installer (#519)
Browse files Browse the repository at this point in the history
  • Loading branch information
Iamlooker authored Oct 19, 2023
1 parent dfd5717 commit 8d524d3
Show file tree
Hide file tree
Showing 19 changed files with 122 additions and 116 deletions.
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
android:foregroundServiceType="dataSync" />

<service
android:name="com.looker.installer.installers.SessionInstallerService"
android:name="com.looker.installer.installers.session.SessionInstallerService"
android:exported="false" />

<service
Expand Down
3 changes: 1 addition & 2 deletions app/src/main/kotlin/com/looker/droidify/ScreenActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import android.os.Build
import android.os.Bundle
import android.os.Parcel
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
Expand Down Expand Up @@ -274,7 +273,7 @@ abstract class ScreenActivity : AppCompatActivity() {
navigateProduct(packageName)
specialIntent.cacheFileName?.also { cacheFile ->
val installItem = packageName installFrom cacheFile
lifecycleScope.launch { installer + installItem }
lifecycleScope.launch { installer install installItem }
}
}
Unit
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ object RepositoryUpdater {
authentication(repository.authentication)
}
) { read, total ->
callback(Stage.DOWNLOAD, read, total)
callback(Stage.DOWNLOAD, read.value, total.value)
}

when (result) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class DownloadService : ConnectionService<DownloadService.Binder>() {
sealed class State(val packageName: String) {
data object Idle : State("")
data class Connecting(val name: String) : State(name)
data class Downloading(val name: String, val read: Long, val total: Long?) : State(name)
data class Downloading(val name: String, val read: DataSize, val total: DataSize?) : State(name)
data class Error(val name: String) : State(name)
data class Cancel(val name: String) : State(name)
data class Success(val name: String, val release: Release) : State(name)
Expand Down Expand Up @@ -288,7 +288,7 @@ class DownloadService : ConnectionService<DownloadService.Binder>() {
|| autoInstallWithSessionInstaller
) {
val installItem = task.packageName installFrom task.release.cacheFileName
installer + installItem
installer install installItem
}
}

Expand Down Expand Up @@ -320,7 +320,7 @@ class DownloadService : ConnectionService<DownloadService.Binder>() {
notification.build()
)
} ?: run {
Log.e("DownloadService", "Invalid Download State: $state")
log("Invalid Download State: $state", "DownloadService", Log.ERROR)
}
}

Expand All @@ -337,10 +337,10 @@ class DownloadService : ConnectionService<DownloadService.Binder>() {
is State.Downloading -> {
setContentTitle(getString(stringRes.downloading_FORMAT, currentTask!!.task.name))
if (state.total != null) {
setContentText("${state.read.formatSize()} / ${state.total.formatSize()}")
setProgress(100, state.read percentBy state.total, false)
setContentText("${state.read} / ${state.total}")
setProgress(100, state.read.value percentBy state.total.value, false)
} else {
setContentText(state.read.formatSize())
setContentText(state.read.toString())
setProgress(0, 0, true)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.google.android.material.imageview.ShapeableImageView
import com.google.android.material.materialswitch.MaterialSwitch
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.snackbar.Snackbar
import com.looker.core.common.DataSize
import com.looker.core.common.extension.*
import com.looker.core.common.file.KParcelable
import com.looker.core.common.formatSize
Expand Down Expand Up @@ -92,7 +93,7 @@ class AppDetailAdapter(private val callbacks: Callbacks) :
data object Idle : Status
data object Pending : Status
data object Connecting : Status
data class Downloading(val read: Long, val total: Long?) : Status
data class Downloading(val read: DataSize, val total: DataSize?) : Status
data object PendingInstall : Status
data object Installing : Status
}
Expand Down Expand Up @@ -1251,13 +1252,13 @@ class AppDetailAdapter(private val callbacks: Callbacks) :
is Status.Downloading -> {
holder.statusText.text = context.getString(
stringRes.downloading_FORMAT, if (status.total == null)
status.read.formatSize() else "${status.read.formatSize()} / ${status.total.formatSize()}"
status.read.toString() else "${status.read} / ${status.total}"
)
holder.progress.isIndeterminate = status.total == null
if (status.total != null) {
holder.progress.progress =
(holder.progress.max.toFloat() * status.read / status.total).roundToInt()
} else Unit
(holder.progress.max.toFloat() * status.read.value / status.total.value).roundToInt()
}
}

Status.Installing -> {
Expand All @@ -1271,7 +1272,7 @@ class AppDetailAdapter(private val callbacks: Callbacks) :
}

Status.Idle -> {}
}::class
}
}
Unit
}
Expand All @@ -1283,7 +1284,7 @@ class AppDetailAdapter(private val callbacks: Callbacks) :
holder.button.apply {
isEnabled = action != null
if (action != null) {
icon = context.getDrawable(action.iconResId)
icon = context.getDrawableCompat(action.iconResId)
setText(action.titleResId)
setTextColor(
if (action == Action.CANCEL) holder.actionTintOnCancel
Expand All @@ -1294,14 +1295,13 @@ class AppDetailAdapter(private val callbacks: Callbacks) :
iconTint = if (action == Action.CANCEL) holder.actionTintOnCancel
else holder.actionTintOnNormal
} else {
icon = context.getDrawable(drawableRes.ic_cancel)
icon = context.getDrawableCompat(drawableRes.ic_cancel)
setText(stringRes.cancel)
setTextColor(holder.actionTintOnDisabled)
backgroundTintList = holder.actionTintDisabled
iconTint = holder.actionTintOnDisabled
}
}
Unit
}

ViewType.SCREENSHOT -> {
Expand Down Expand Up @@ -1572,11 +1572,9 @@ class AppDetailAdapter(private val callbacks: Callbacks) :
if (item.repoAddress != null) {
holder.repoTitle.setText(stringRes.repository_not_found)
holder.repoAddress.text = item.repoAddress
} else {

}
}
}::class
}
}

private fun formatHtml(text: String): SpannableStringBuilder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.looker.core.common.PackageName
import com.looker.core.common.extension.*
import com.looker.core.common.toPackageName
import com.looker.core.model.*
import com.looker.droidify.content.ProductPreferences
import com.looker.droidify.service.Connection
Expand All @@ -29,7 +31,8 @@ import com.looker.droidify.ui.ScreenFragment
import com.looker.droidify.ui.screenshots.ScreenshotsFragment
import com.looker.droidify.utility.extension.screenActivity
import com.looker.droidify.utility.extension.startUpdate
import com.looker.installer.model.InstallerQueueState
import com.looker.installer.model.InstallState
import com.looker.installer.model.isCancellable
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
Expand Down Expand Up @@ -88,7 +91,7 @@ class AppDetailFragment() : ScreenFragment(), AppDetailAdapter.Callbacks {
private var products = emptyList<Pair<Product, Repository>>()
private var installed: Installed? = null
private var downloading = false
private var installing = false
private var installing: InstallState? = null

private var recyclerView: RecyclerView? = null
private var detailAdapter: AppDetailAdapter? = null
Expand Down Expand Up @@ -234,7 +237,8 @@ class AppDetailFragment() : ScreenFragment(), AppDetailAdapter.Callbacks {
}

val adapterAction = when {
installing -> null
installing == InstallState.Installing -> null
installing == InstallState.Pending -> AppDetailAdapter.Action.CANCEL
downloading -> AppDetailAdapter.Action.CANCEL
else -> primaryAction.adapterAction
}
Expand Down Expand Up @@ -272,19 +276,16 @@ class AppDetailFragment() : ScreenFragment(), AppDetailAdapter.Callbacks {
}
}

private fun updateInstallState(installerState: InstallerQueueState) {
val status =
when (packageName) {
in installerState.currentItem -> AppDetailAdapter.Status.Installing
in installerState.queued -> AppDetailAdapter.Status.PendingInstall
else -> AppDetailAdapter.Status.Idle
}
val installing = status != AppDetailAdapter.Status.Idle
if (this.installing != installing) {
this.installing = installing
updateButtons()
private fun updateInstallState(installerState: Map<PackageName, InstallState>) {
val currentState = installerState[packageName.toPackageName()]
val status = when (currentState) {
InstallState.Pending -> AppDetailAdapter.Status.PendingInstall
InstallState.Installing -> AppDetailAdapter.Status.Installing
else -> AppDetailAdapter.Status.Idle
}
(recyclerView?.adapter as? AppDetailAdapter)?.status = status
installing = currentState
updateButtons()
}

private fun updateDownloadState(state: DownloadService.DownloadState) {
Expand Down Expand Up @@ -356,7 +357,9 @@ class AppDetailFragment() : ScreenFragment(), AppDetailAdapter.Callbacks {

AppDetailAdapter.Action.CANCEL -> {
val binder = downloadConnection.binder
if (downloading && binder != null) {
if (installing?.isCancellable == true) {
viewModel.removeQueue()
} else if (downloading && binder != null) {
binder.cancel(packageName)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ package com.looker.droidify.ui.app_detail
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.looker.core.common.extension.asStateFlow
import com.looker.core.common.toPackageName
import com.looker.core.datastore.SettingsRepository
import com.looker.core.model.InstalledItem
import com.looker.core.model.Product
import com.looker.core.model.Repository
import com.looker.core.common.toPackageName
import com.looker.droidify.BuildConfig
import com.looker.droidify.database.Database
import com.looker.installer.InstallManager
import com.looker.installer.model.InstallerQueueState
import com.looker.installer.model.installFrom
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
Expand All @@ -35,9 +35,7 @@ class AppDetailViewModel @Inject constructor(
_packageName = name
}

val installerState = installer
.status
.asStateFlow(InstallerQueueState.EMPTY)
val installerState = installer.state.asStateFlow()

val state by lazy {
combine(
Expand Down Expand Up @@ -66,13 +64,19 @@ class AppDetailViewModel @Inject constructor(

fun installPackage(packageName: String, fileName: String) {
viewModelScope.launch {
installer + (packageName installFrom fileName)
installer install (packageName installFrom fileName)
}
}

fun uninstallPackage() {
viewModelScope.launch {
installer - packageName.toPackageName()
installer uninstall packageName.toPackageName()
}
}

fun removeQueue() {
viewModelScope.launch {
installer remove packageName.toPackageName()
}
}

Expand Down
19 changes: 19 additions & 0 deletions core/common/src/main/java/com/looker/core/common/DataSize.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.looker.core.common

import java.util.Locale

@JvmInline
value class DataSize(val value: Long) {

companion object {
private val sizeFormats = listOf("%.0f B", "%.0f kB", "%.1f MB", "%.2f GB")
}

override fun toString(): String {
val (size, index) = generateSequence(Pair(value.toFloat(), 0)) { (size, index) ->
if (size >= 1024f)
Pair(size / 1024f, index + 1) else null
}.take(sizeFormats.size).last()
return sizeFormats[index].format(Locale.US, size)
}
}
4 changes: 2 additions & 2 deletions core/common/src/main/java/com/looker/core/common/Text.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ fun ByteArray.hex(): String = joinToString(separator = "") { byte ->
"%02x".format(Locale.US, byte.toInt() and 0xff)
}

fun Any.log(message: Any?, tag: String = this::class.java.simpleName + ".DEBUG") {
Log.d(tag, message.toString())
fun Any.log(message: Any?, tag: String = this::class.java.simpleName + ".DEBUG", type: Int = Log.DEBUG) {
Log.println(type, tag, message.toString())
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package com.looker.core.common.extension

fun <T> Set<T>.updateAsMutable(block: MutableSet<T>.() -> Unit): Set<T> {
inline fun <K, E> Map<K, E>.updateAsMutable(block: MutableMap<K, E>.() -> Unit): Map<K, E> {
return toMutableMap().apply(block)
}

inline fun <T> Set<T>.updateAsMutable(block: MutableSet<T>.() -> Unit): Set<T> {
return toMutableSet().apply(block)
}

fun <T> List<T>.updateAsMutable(block: MutableList<T>.() -> Unit): List<T> {
inline fun <T> MutableSet<T>.addAndCompute(item: T, block: (isAdded: Boolean) -> Unit): Boolean =
add(item).apply { block(this) }

inline fun <T> List<T>.updateAsMutable(block: MutableList<T>.() -> Unit): List<T> {
return toMutableList().apply(block)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import android.net.ConnectivityManager
import android.view.inputmethod.InputMethodManager
import androidx.annotation.AttrRes
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import androidx.core.content.res.ResourcesCompat
import com.looker.core.common.R

inline val Context.clipboardManager: ClipboardManager?
Expand Down Expand Up @@ -68,8 +68,8 @@ private fun Context.getDrawableFromAttr(attrResId: Int): Drawable {
return getDrawableCompat(resId)
}

private fun Context.getDrawableCompat(@DrawableRes resId: Int = R.drawable.background_border): Drawable =
ResourcesCompat.getDrawable(resources, resId, theme) ?: ContextCompat.getDrawable(this, resId)!!
fun Context.getDrawableCompat(@DrawableRes resId: Int = R.drawable.background_border): Drawable =
AppCompatResources.getDrawable(this, resId) ?: throw IllegalStateException("Cannot find drawable, ID: $resId")

fun Context.getColorFromAttr(@AttrRes attrResId: Int): ColorStateList {
val typedArray = obtainStyledAttributes(intArrayOf(attrResId))
Expand Down
3 changes: 2 additions & 1 deletion core/network/src/main/java/com/looker/network/Downloader.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.looker.network

import com.looker.core.common.DataSize
import com.looker.core.common.signature.FileValidator
import com.looker.network.header.HeadersBuilder
import java.io.File
Expand All @@ -24,4 +25,4 @@ interface Downloader {

}

typealias ProgressListener = suspend (bytesReceived: Long, contentLength: Long) -> Unit
typealias ProgressListener = suspend (bytesReceived: DataSize, contentLength: DataSize) -> Unit
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.looker.network

import com.looker.core.common.DataSize
import com.looker.core.common.extension.exceptCancellation
import com.looker.core.common.extension.size
import com.looker.core.common.signature.FileValidator
Expand Down Expand Up @@ -111,7 +112,7 @@ internal class KtorDownloader : Downloader {
}
onDownload { read, total ->
if (block != null) {
block(read + (fileSize ?: 0L), total + (fileSize ?: 0L))
block(DataSize(read + (fileSize ?: 0L)), DataSize(total + (fileSize ?: 0L)))
}
}
}
Expand Down
Loading

0 comments on commit 8d524d3

Please sign in to comment.