Improve notification progress reporting

It is still somewhat buggy when d2d is on, but this is easier to resolve when moving everything to own scheduling.
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinator.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinator.kt
index 2f08867..f1dde3b 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinator.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupCoordinator.kt
@@ -426,10 +426,12 @@
             val packageName = packageInfo.packageName
             try {
                 nm.onOptOutAppBackup(packageName, i + 1, notBackedUpPackages.size)
-                val packageState =
-                    if (packageInfo.isStopped()) WAS_STOPPED else NOT_ALLOWED
+                val packageState = if (packageInfo.isStopped()) WAS_STOPPED else NOT_ALLOWED
                 val wasBackedUp = backUpApk(packageInfo, packageState)
-                if (!wasBackedUp) {
+                if (wasBackedUp) {
+                    Log.d(TAG, "Was backed up: $packageName")
+                } else {
+                    Log.d(TAG, "Not backed up: $packageName - ${packageState.name}")
                     val packageMetadata =
                         metadataManager.getPackageMetadata(packageName)
                     val oldPackageState = packageMetadata?.state
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupRequester.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupRequester.kt
index d1e195f..79c79ba 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupRequester.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/BackupRequester.kt
@@ -38,7 +38,7 @@
     private val observer = NotificationBackupObserver(
         context = context,
         backupRequester = this,
-        expectedPackages = packages.size,
+        requestedPackages = packages.size,
         appTotals = packageService.expectedAppTotals,
     )
     private val monitor = BackupMonitor()
@@ -50,6 +50,9 @@
      */
     private var packageIndex: Int = 0
 
+    /**
+     * Request the backup to happen. Should be called short after constructing this object.
+     */
     fun requestBackup(): Boolean {
         if (packageIndex != 0) error("requestBackup() called more than once!")
 
diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/PackageService.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/PackageService.kt
index a8ed0d3..7a59437 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/backup/PackageService.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/backup/PackageService.kt
@@ -128,16 +128,16 @@
         @WorkerThread
         get() {
             var appsTotal = 0
-            var appsOptOut = 0
+            var appsNotIncluded = 0
             packageManager.getInstalledPackages(GET_INSTRUMENTATION).forEach { packageInfo ->
                 if (packageInfo.isUserVisible(context)) {
                     appsTotal++
                     if (packageInfo.doesNotGetBackedUp()) {
-                        appsOptOut++
+                        appsNotIncluded++
                     }
                 }
             }
-            return ExpectedAppTotals(appsTotal, appsOptOut)
+            return ExpectedAppTotals(appsTotal, appsNotIncluded)
         }
 
     fun getVersionName(packageName: String): String? = try {
@@ -202,6 +202,7 @@
      */
     private fun PackageInfo.doesNotGetBackedUp(): Boolean {
         if (packageName == MAGIC_PACKAGE_MANAGER || applicationInfo == null) return true
+        if (packageName == plugin.providerPackageName) return true
         return !allowsBackup() || isStopped()
     }
 }
@@ -212,9 +213,11 @@
      */
     val appsTotal: Int,
     /**
-     * The number of non-system apps that has opted-out of backup.
+     * The number of non-system apps that do not get backed up.
+     * These are included here, because we'll at least back up their APKs,
+     * so at least the app itself does get restored.
      */
-    val appsOptOut: Int,
+    val appsNotGettingBackedUp: Int,
 )
 
 internal fun PackageInfo.isUserVisible(context: Context): Boolean {
diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/notification/BackupNotificationManager.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/notification/BackupNotificationManager.kt
index 2b9a0e5..f2cbd00 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/ui/notification/BackupNotificationManager.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/ui/notification/BackupNotificationManager.kt
@@ -27,6 +27,7 @@
 import com.stevesoltys.seedvault.settings.ACTION_APP_STATUS_LIST
 import com.stevesoltys.seedvault.settings.SettingsActivity
 import com.stevesoltys.seedvault.transport.backup.ExpectedAppTotals
+import kotlin.math.min
 
 private const val CHANNEL_ID_OBSERVER = "NotificationBackupObserver"
 private const val CHANNEL_ID_SUCCESS = "NotificationBackupSuccess"
@@ -92,25 +93,34 @@
         updateBackupNotification(
             infoText = "", // This passes quickly, no need to show something here
             transferred = 0,
-            expected = expectedPackages
+            expected = appTotals.appsTotal
         )
         expectedApps = expectedPackages
-        expectedOptOutApps = appTotals.appsOptOut
+        expectedOptOutApps = appTotals.appsNotGettingBackedUp
         expectedAppTotals = appTotals
+        optOutAppsDone = false
+        Log.i(TAG, "onBackupStarted $expectedApps + $expectedOptOutApps = ${appTotals.appsTotal}")
     }
 
     /**
      * This should get called before [onBackupUpdate].
+     * In case of d2d backups, this actually gets called some time after
+     * some apps were already backed up, so [onBackupUpdate] was called several times.
      */
     fun onOptOutAppBackup(packageName: String, transferred: Int, expected: Int) {
         if (optOutAppsDone) return
 
-        val text = "Opt-out APK for $packageName"
+        val text = "APK for $packageName"
         if (expectedApps == null) {
             updateBackgroundBackupNotification(text)
         } else {
             updateBackupNotification(text, transferred, expected + (expectedApps ?: 0))
+            if (expectedOptOutApps != null && expectedOptOutApps != expected) {
+                Log.w(TAG, "Number of packages not getting backed up mismatch: " +
+                    "$expectedOptOutApps != $expected")
+            }
             expectedOptOutApps = expected
+            if (transferred == expected) optOutAppsDone = true
         }
     }
 
@@ -119,12 +129,11 @@
      * this type is is expected to get called after [onOptOutAppBackup].
      */
     fun onBackupUpdate(app: CharSequence, transferred: Int) {
-        optOutAppsDone = true
         val expected = expectedApps ?: error("expectedApps is null")
         val addend = expectedOptOutApps ?: 0
         updateBackupNotification(
             infoText = app,
-            transferred = transferred + addend,
+            transferred = min(transferred + addend, expected + addend),
             expected = expected + addend
         )
     }
diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt
index ea7bc4a..4723521 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/ui/notification/NotificationBackupObserver.kt
@@ -20,7 +20,7 @@
 internal class NotificationBackupObserver(
     private val context: Context,
     private val backupRequester: BackupRequester,
-    private val expectedPackages: Int,
+    private val requestedPackages: Int,
     appTotals: ExpectedAppTotals,
 ) : IBackupObserver.Stub(), KoinComponent {
 
@@ -32,7 +32,7 @@
     init {
         // Inform the notification manager that a backup has started
         // and inform about the expected numbers, so it can compute a total.
-        nm.onBackupStarted(expectedPackages, appTotals)
+        nm.onBackupStarted(requestedPackages, appTotals)
     }
 
     /**
@@ -77,7 +77,7 @@
     override fun backupFinished(status: Int) {
         if (backupRequester.requestNext()) {
             if (isLoggable(TAG, INFO)) {
-                Log.i(TAG, "Backup finished $numPackages/$expectedPackages. Status: $status")
+                Log.i(TAG, "Backup finished $numPackages/$requestedPackages. Status: $status")
             }
             val success = status == 0
             val numBackedUp = if (success) metadataManager.getPackagesNumBackedUp() else null
@@ -89,13 +89,17 @@
     private fun showProgressNotification(packageName: String?) {
         if (packageName == null || currentPackage == packageName) return
 
-        if (isLoggable(TAG, INFO)) {
-            "Showing progress notification for $currentPackage $numPackages/$expectedPackages".let {
-                Log.i(TAG, it)
-            }
-        }
+        if (isLoggable(TAG, INFO)) Log.i(
+            TAG, "Showing progress notification for " +
+                "$currentPackage $numPackages/$requestedPackages"
+        )
         currentPackage = packageName
-        val app = getAppName(packageName)
+        val appName = getAppName(packageName)
+        val app = if (appName != packageName) {
+            "${getAppName(packageName)} ($packageName)"
+        } else {
+            packageName
+        }
         numPackages += 1
         nm.onBackupUpdate(app, numPackages)
     }