Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 0 additions & 22 deletions app/src/main/java/com/anod/appwatcher/database/AppListTable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,6 @@ interface AppListTable {
)
fun observePackagesList(): Flow<List<PackageRowPair>>

@Query(
"SELECT ${BaseColumns._ID}, ${Columns.PACKAGE_NAME} FROM $TABLE WHERE " +
"${Columns.STATUS} = ${App.STATUS_UPDATED}"
)
suspend fun loadUpdatedPackages(): List<PackageRowPair>

@Query(
"SELECT ${BaseColumns._ID}, ${Columns.PACKAGE_NAME} FROM $TABLE WHERE " +
"CASE :includeDeleted WHEN 0 THEN ${Columns.STATUS} != ${App.STATUS_DELETED} ELSE ${Columns.STATUS} >= ${App.STATUS_NORMAL} END"
Expand Down Expand Up @@ -152,22 +146,6 @@ interface AppListTable {
)
suspend fun clearUpdateStatus(rowId: Int): Int

@Query(
"UPDATE $TABLE SET " +
"${Columns.STATUS} = ${App.STATUS_NORMAL}, " +
"${Columns.SYNC_TIMESTAMP} = 0 " +
"WHERE ${Columns.PACKAGE_NAME} = :packageName AND ${Columns.STATUS} = ${App.STATUS_UPDATED}"
)
suspend fun clearUpdateStatusByPackageName(packageName: String): Int

@Query(
"UPDATE $TABLE SET " +
"${Columns.STATUS} = ${App.STATUS_NORMAL}, " +
"${Columns.SYNC_TIMESTAMP} = 0 " +
"WHERE ${BaseColumns._ID} IN (:rowIds) AND ${Columns.STATUS} = ${App.STATUS_UPDATED}"
)
suspend fun clearUpdateStatuses(rowIds: List<Int>): Int

@Query(
"UPDATE $TABLE SET " +
"${Columns.TITLE} = :title, " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@ package com.anod.appwatcher.installed
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.anod.appwatcher.database.AppsDatabase
import com.anod.appwatcher.utils.PackageChangedReceiver
import com.anod.appwatcher.utils.PackageStateCache
import com.anod.appwatcher.utils.appScope
import com.anod.appwatcher.utils.clearDisabledUpdateStatus
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.get
Expand All @@ -19,38 +17,27 @@ class PackageRemovedReceiver : BroadcastReceiver(), KoinComponent {
val action = intent?.action ?: return
val packageName = intent.data?.schemeSpecificPart ?: return
when (action) {
Intent.ACTION_PACKAGE_FULLY_REMOVED -> {
handlePackageChange(packageName, clearDisabledUpdates = false, requireStateChange = false)
}
Intent.ACTION_PACKAGE_ADDED -> {
handlePackageChange(packageName, clearDisabledUpdates = true, requireStateChange = false)
Intent.ACTION_PACKAGE_FULLY_REMOVED,
Intent.ACTION_PACKAGE_ADDED,
Intent.ACTION_PACKAGE_REPLACED -> {
handlePackageChange(packageName, requireStateChange = false)
}
Intent.ACTION_PACKAGE_CHANGED -> {
if (isApplicationPackageChange(packageName, intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST))) {
handlePackageChange(packageName, clearDisabledUpdates = true, requireStateChange = true)
handlePackageChange(packageName, requireStateChange = true)
}
}
Intent.ACTION_PACKAGE_REPLACED -> {
handlePackageChange(packageName, clearDisabledUpdates = true, requireStateChange = false)
}
}
}

private fun handlePackageChange(
packageName: String,
clearDisabledUpdates: Boolean,
requireStateChange: Boolean
) {
val pendingResult = goAsync()
appScope.launch {
try {
val packageStateRefresh = get<PackageStateCache>().refresh(packageName)
if (clearDisabledUpdates) {
get<AppsDatabase>().apps().clearDisabledUpdateStatus(
packageName = packageName,
packageState = packageStateRefresh.current
)
}
if (!requireStateChange || packageStateRefresh.changed) {
get<PackageChangedReceiver>().emit(packageName + ":" + System.currentTimeMillis())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ class SettingsViewModel : BaseFlowViewModel<SettingsViewState, SettingsViewEvent
packageName = "com.anod.appwatcher",
title = "Test",
installedVersionCode = 25,
installedEnabled = true,
isNewUpdate = true,
recentChanges = "Test notification",
uploadDate = "Now",
Expand Down
21 changes: 10 additions & 11 deletions app/src/main/java/com/anod/appwatcher/sync/SyncNotification.kt
Original file line number Diff line number Diff line change
Expand Up @@ -124,19 +124,18 @@ class SyncNotification(private val context: ApplicationContext, private val noti
}

private fun addMultipleExtraInfo(updatedApps: List<UpdatedApp>, builder: NotificationCompat.Builder) {
updatedApps.firstOrNull { it.installedVersionCode > 0 && it.versionNumber > it.installedVersionCode }
?: return

val bigText = updatedApps.joinToString(",\n") { it.title }
builder.setStyle(NotificationCompat.BigTextStyle().bigText(bigText))

val updateIntent = NotificationActivity.intent(
Uri.parse("com.anod.appwatcher://play/myapps/1"),
NotificationActivity.ACTION_MY_APPS,
context.actual)
builder.addAction(R.drawable.ic_system_update_alt_white_24dp, context.getString(R.string.noti_action_update),
PendingIntent.getActivity(context.actual, 0, updateIntent, PendingIntent.FLAG_IMMUTABLE)
)
if (updatedApps.any { it.canUpdateOnDevice && it.versionNumber > it.installedVersionCode }) {
val updateIntent = NotificationActivity.intent(
Uri.parse("com.anod.appwatcher://play/myapps/1"),
NotificationActivity.ACTION_MY_APPS,
context.actual)
builder.addAction(R.drawable.ic_system_update_alt_white_24dp, context.getString(R.string.noti_action_update),
PendingIntent.getActivity(context.actual, 0, updateIntent, PendingIntent.FLAG_IMMUTABLE)
)
}

val readIntent = NotificationActivity.intent(
Uri.parse("com.anod.appwatcher://dismiss/"),
Expand Down Expand Up @@ -165,7 +164,7 @@ class SyncNotification(private val context: ApplicationContext, private val noti
PendingIntent.getActivity(context.actual, 0, playIntent, PendingIntent.FLAG_IMMUTABLE)
)

if (update.installedVersionCode > 0) {
if (update.canUpdateOnDevice) {
val updateIntent = NotificationActivity.intent(
Uri.parse("com.anod.appwatcher://play/myapps/1"),
NotificationActivity.ACTION_MY_APPS,
Expand Down
36 changes: 6 additions & 30 deletions app/src/main/java/com/anod/appwatcher/sync/UpdateCheck.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import com.anod.appwatcher.database.entities.toApp
import com.anod.appwatcher.preferences.Preferences
import com.anod.appwatcher.utils.PackageState
import com.anod.appwatcher.utils.PackageStateCache
import com.anod.appwatcher.utils.clearDisabledUpdateStatuses
import com.anod.appwatcher.utils.compareLettersAndDigits
import com.anod.appwatcher.utils.date.UploadDateParserCache
import com.anod.appwatcher.utils.extractUploadDate
Expand Down Expand Up @@ -250,15 +249,6 @@ class UpdateCheck(
syncId: Long,
verboseDiagnostics: Boolean
): SyncResult {
val clearedDisabledUpdates = database.apps().clearDisabledUpdateStatuses(
packageStates = packageStates
)
if (clearedDisabledUpdates > 0) {
AppLog.i(
"Cleared $clearedDisabledUpdates disabled app update statuses",
"UpdateCheck"
)
}
val sortId = preferences.sortIndex
val apps = AppListTable.Queries.loadAppList(false, sortId, database.apps())
if (apps.isEmpty) {
Expand Down Expand Up @@ -658,8 +648,7 @@ class UpdateCheck(
cachedVersion = localApp.versionNumber,
installedVersion = installedInfo.versionCode,
status = localApp.status,
lastUpdatesViewed = lastUpdatesViewed,
installedEnabled = installedEnabled
lastUpdatesViewed = lastUpdatesViewed
)
if (decision == AppUpdateDecision.MARK_UPDATED) {
AppLog.i(
Expand All @@ -678,7 +667,7 @@ class UpdateCheck(
val recentChanges = releaseDoc.appDetails.recentChangesHtml ?: ""
return AppUpdateResult(
values = newApp.contentValues,
updatedApp = UpdatedApp(newApp, recentChanges, installedInfo.versionCode, true),
updatedApp = UpdatedApp(newApp, recentChanges, installedInfo.versionCode, installedEnabled, true),
persistChangelog = true,
installedVersion = installedInfo.versionCode,
installedEnabled = installedEnabled,
Expand All @@ -691,14 +680,13 @@ class UpdateCheck(
AppUpdateDecision.RESTORE_DEVICE_UPDATE ->
values.put(AppListTable.Columns.STATUS, App.STATUS_UPDATED)
AppUpdateDecision.CLEAR_INSTALLED_UPDATE,
AppUpdateDecision.CLEAR_DISABLED_UPDATE,
AppUpdateDecision.CLEAR_VIEWED_UPDATE -> {
values.put(AppListTable.Columns.STATUS, App.STATUS_NORMAL)
values.put(AppListTable.Columns.SYNC_TIMESTAMP, 0L)
}
AppUpdateDecision.KEEP_UPDATED -> {
val recentChanges = releaseDoc.appDetails.recentChangesHtml ?: ""
updatedApp = UpdatedApp(localApp, recentChanges, installedInfo.versionCode, false)
updatedApp = UpdatedApp(localApp, recentChanges, installedInfo.versionCode, installedEnabled, false)
}
AppUpdateDecision.MISSING_RESPONSE_KEEP,
AppUpdateDecision.RESPONSE_WITHOUT_DETAILS_KEEP,
Expand All @@ -708,7 +696,6 @@ class UpdateCheck(
AppUpdateDecision.MARK_UPDATED,
AppUpdateDecision.REFRESH_INSTALLED_CURRENT,
AppUpdateDecision.KEEP_DEVICE_UPDATE,
AppUpdateDecision.DISABLED_INSTALLED,
AppUpdateDecision.CURRENT -> {
}
}
Expand Down Expand Up @@ -920,10 +907,8 @@ internal enum class AppUpdateDecision(val value: String) {
RESTORE_DEVICE_UPDATE("restore-device-update"),
KEEP_DEVICE_UPDATE("keep-device-update"),
CLEAR_INSTALLED_UPDATE("clear-installed-update"),
CLEAR_DISABLED_UPDATE("clear-disabled-update"),
CLEAR_VIEWED_UPDATE("clear-viewed-update"),
KEEP_UPDATED("keep-updated"),
DISABLED_INSTALLED("disabled-installed"),
CURRENT("current");

val isSteadyState: Boolean
Expand All @@ -932,16 +917,14 @@ internal enum class AppUpdateDecision(val value: String) {
this == UNAVAILABLE_SUPPRESSED ||
this == UNAVAILABLE_ROLLBACK ||
this == KEEP_DEVICE_UPDATE ||
this == KEEP_UPDATED ||
this == DISABLED_INSTALLED
this == KEEP_UPDATED
}

internal enum class SyncDecisionSignal(val value: String) {
NONE("none"),
INVALID_MARKED_NOT_NEWER_THAN_INSTALLED("invalid-marked-not-newer-than-installed"),
DEVICE_UPDATE_RESTORED("device-update-restored"),
INSTALLED_UPDATE_CLEARED("installed-update-cleared"),
DISABLED_UPDATE_CLEARED("disabled-update-cleared")
INSTALLED_UPDATE_CLEARED("installed-update-cleared")
}

internal fun detectSyncDecisionSignal(
Expand All @@ -955,8 +938,6 @@ internal fun detectSyncDecisionSignal(
SyncDecisionSignal.DEVICE_UPDATE_RESTORED
decision == AppUpdateDecision.CLEAR_INSTALLED_UPDATE ->
SyncDecisionSignal.INSTALLED_UPDATE_CLEARED
decision == AppUpdateDecision.CLEAR_DISABLED_UPDATE ->
SyncDecisionSignal.DISABLED_UPDATE_CLEARED
else -> SyncDecisionSignal.NONE
}

Expand All @@ -965,16 +946,11 @@ internal fun selectAppUpdateDecision(
cachedVersion: Int,
installedVersion: Int,
status: Int,
lastUpdatesViewed: Boolean,
installedEnabled: Boolean
lastUpdatesViewed: Boolean
): AppUpdateDecision {
require(remoteVersion >= cachedVersion)
val isInstalled = installedVersion > 0
return when {
isInstalled && !installedEnabled && status == App.STATUS_UPDATED ->
AppUpdateDecision.CLEAR_DISABLED_UPDATE
isInstalled && !installedEnabled ->
AppUpdateDecision.DISABLED_INSTALLED
isInstalled && remoteVersion <= installedVersion && status == App.STATUS_UPDATED ->
AppUpdateDecision.CLEAR_INSTALLED_UPDATE
isInstalled && remoteVersion <= installedVersion && remoteVersion > cachedVersion ->
Expand Down
13 changes: 12 additions & 1 deletion app/src/main/java/com/anod/appwatcher/sync/UpdatedApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,28 @@ data class UpdatedApp(
val uploadDate: String,
val recentChanges: String,
val installedVersionCode: Int,
val installedEnabled: Boolean,
val isNewUpdate: Boolean,
val noNewDetails: Boolean = false
) {
constructor(appInfo: App, recentChanges: String, installedVersionCode: Int, isNewUpdate: Boolean) : this(
constructor(
appInfo: App,
recentChanges: String,
installedVersionCode: Int,
installedEnabled: Boolean,
isNewUpdate: Boolean
) : this(
appInfo.packageName,
appInfo.versionNumber,
appInfo.title,
appInfo.uploadTime,
appInfo.uploadDate,
recentChanges,
installedVersionCode,
installedEnabled,
isNewUpdate
)

val canUpdateOnDevice: Boolean
get() = installedVersionCode > 0 && installedEnabled
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.anod.appwatcher.utils
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import androidx.core.content.pm.PackageInfoCompat
import com.anod.appwatcher.database.AppListTable
import info.anodsplace.framework.content.InstalledApps
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.sync.Mutex
Expand Down Expand Up @@ -183,36 +182,4 @@ class PackageStateCache(private val packageManager: PackageManager) : PackageSta
}

internal fun Map<String, PackageState>.stateFor(packageName: String): PackageState =
get(packageName) ?: PackageState.NotInstalled

internal suspend fun AppListTable.clearDisabledUpdateStatus(
packageName: String,
packageState: PackageState
): Int = withContext(Dispatchers.IO) {
if (packageState.isInstalled && !packageState.isEnabled) {
clearUpdateStatusByPackageName(packageName)
} else {
0
}
}

internal suspend fun AppListTable.clearDisabledUpdateStatuses(
packageStates: PackageStateProvider
): Int = withContext(Dispatchers.IO) {
val updatedPackages = loadUpdatedPackages()
if (updatedPackages.isEmpty()) {
return@withContext 0
}
val states = packageStates.load(updatedPackages.map { it.packageName })
val disabledRowIds = updatedPackages.mapNotNull { row ->
val packageState = states.stateFor(row.packageName)
row.rowId.takeIf {
packageState.isInstalled && !packageState.isEnabled
}
}
var cleared = 0
for (rowIds in disabledRowIds.chunked(998)) {
cleared += clearUpdateStatuses(rowIds)
}
cleared
}
get(packageName) ?: PackageState.NotInstalled
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import com.anod.appwatcher.utils.PackageChangedReceiver
import com.anod.appwatcher.utils.PackageStateCache
import com.anod.appwatcher.utils.SyncProgress
import com.anod.appwatcher.utils.appScope
import com.anod.appwatcher.utils.clearDisabledUpdateStatuses
import com.anod.appwatcher.utils.color.MaterialColors
import com.anod.appwatcher.utils.forMyApps
import com.anod.appwatcher.utils.getInt
Expand Down Expand Up @@ -210,16 +209,6 @@ class WatchListStateViewModel(

AppLog.d("Initial state: viewState")

viewModelScope.launch {
val clearedDisabledUpdates = db.apps().clearDisabledUpdateStatuses(
packageStates = packageStates
)
if (clearedDisabledUpdates > 0) {
invalidatePagingSources()
viewState = viewState.copy(dbAppsChange = viewState.dbAppsChange + 1)
}
}

viewModelScope.launch {
syncProgressFlow(application).collect {
handleEvent(WatchListEvent.UpdateSyncProgress(syncProgress = it))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class AppItemStateTest {

assertTrue(state.installed)
assertFalse(state.showRecent)
assertEquals(Color.Black, state.color)
assertEquals(
context.getString(R.string.installed_disabled_version, "1.0", 100),
state.text
Expand Down
Loading
Loading