Show list of packages that we could restore data for

This commit is contained in:
Torsten Grote 2020-01-08 16:53:52 -03:00
parent 96a4642f4f
commit 2f352fe828
No known key found for this signature in database
GPG key ID: 3E5F77D92CF891FF
6 changed files with 119 additions and 44 deletions

View file

@ -72,5 +72,5 @@ class NotificationBackupObserver(context: Context, private val userInitiated: Bo
fun getAppName(pm: PackageManager, packageId: String): CharSequence {
if (packageId == MAGIC_PACKAGE_MANAGER) return packageId
val appInfo = pm.getApplicationInfo(packageId, 0)
return pm.getApplicationLabel(appInfo)
return pm.getApplicationLabel(appInfo) ?: packageId
}

View file

@ -0,0 +1,78 @@
package com.stevesoltys.seedvault.restore
import android.view.LayoutInflater
import android.view.View
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView.Adapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.stevesoltys.seedvault.MAGIC_PACKAGE_MANAGER
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.getAppName
import com.stevesoltys.seedvault.restore.RestoreProgressAdapter.PackageViewHolder
import java.util.*
internal class RestoreProgressAdapter : Adapter<PackageViewHolder>() {
private val items = LinkedList<String>().apply { add(MAGIC_PACKAGE_MANAGER) }
private var isComplete = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PackageViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_item_app_status, parent, false)
return PackageViewHolder(v)
}
override fun getItemCount() = items.size
override fun onBindViewHolder(holder: PackageViewHolder, position: Int) {
holder.bind(items[position], position == 0)
}
fun add(packageName: String) {
items.addFirst(packageName)
notifyItemInserted(0)
notifyItemRangeChanged(1, items.size - 1)
}
fun setComplete() {
isComplete = true
notifyItemChanged(0)
}
inner class PackageViewHolder(v: View) : ViewHolder(v) {
private val context = v.context
private val pm = context.packageManager
private val appIcon: ImageView = v.findViewById(R.id.appIcon)
private val appName: TextView = v.findViewById(R.id.appName)
private val appStatus: ImageView = v.findViewById(R.id.appStatus)
private val progressBar: ProgressBar = v.findViewById(R.id.progressBar)
init {
appStatus.setImageResource(R.drawable.ic_check_green)
}
fun bind(item: String, isLast: Boolean) {
if (item == MAGIC_PACKAGE_MANAGER) {
appIcon.setImageDrawable(pm.getApplicationIcon("android"))
appName.text = context.getString(R.string.restore_magic_package)
} else {
appIcon.setImageDrawable(pm.getApplicationIcon(item))
appName.text = getAppName(pm, item)
}
if (isLast && !isComplete) {
appStatus.visibility = INVISIBLE
progressBar.visibility = VISIBLE
} else {
appStatus.visibility = VISIBLE
progressBar.visibility = INVISIBLE
}
}
}
}

View file

@ -4,16 +4,15 @@ import android.app.Activity.RESULT_OK
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
import androidx.core.content.ContextCompat.getColor
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
import com.stevesoltys.seedvault.R
import com.stevesoltys.seedvault.getAppName
import com.stevesoltys.seedvault.isDebugBuild
import kotlinx.android.synthetic.main.fragment_restore_progress.*
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
@ -21,11 +20,27 @@ class RestoreProgressFragment : Fragment() {
private val viewModel: RestoreViewModel by sharedViewModel()
private val layoutManager = LinearLayoutManager(context)
private val adapter = RestoreProgressAdapter()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_restore_progress, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
appList.apply {
layoutManager = this@RestoreProgressFragment.layoutManager
adapter = this@RestoreProgressFragment.adapter
addItemDecoration(DividerItemDecoration(context, VERTICAL))
}
button.setOnClickListener {
requireActivity().setResult(RESULT_OK)
requireActivity().finishAfterTransition()
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
@ -37,27 +52,23 @@ class RestoreProgressFragment : Fragment() {
})
viewModel.restoreProgress.observe(this, Observer { currentPackage ->
val appName = getAppName(requireActivity().packageManager, currentPackage)
val displayName = if (isDebugBuild()) "$appName (${currentPackage})" else appName
currentPackageView.text = getString(R.string.restore_current_package, displayName)
// TODO maybe check against metadata and add packages that weren't called as failed in the end
val position = layoutManager.findFirstVisibleItemPosition()
adapter.add(currentPackage)
if (position == 0) layoutManager.scrollToPosition(0)
})
viewModel.restoreBackupResult.observe(this, Observer { finished ->
progressBar.visibility = INVISIBLE
button.visibility = VISIBLE
adapter.setComplete()
button.isEnabled = true
if (finished.hasError()) {
currentPackageView.text = finished.errorMsg
currentPackageView.setTextColor(getColor(requireContext(), R.color.red))
backupNameView.text = finished.errorMsg
backupNameView.setTextColor(getColor(requireContext(), R.color.red))
} else {
currentPackageView.text = getString(R.string.restore_finished_success)
backupNameView.text = getString(R.string.restore_finished_success)
}
activity?.window?.clearFlags(FLAG_KEEP_SCREEN_ON)
})
button.setOnClickListener {
requireActivity().setResult(RESULT_OK)
requireActivity().finishAfterTransition()
}
}
}

View file

@ -41,30 +41,16 @@
app:layout_constraintTop_toBottomOf="@+id/titleView"
tools:text="Pixel 2 XL" />
<TextView
android:id="@+id/currentPackageView"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/appList"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="16dp"
android:gravity="center_horizontal"
android:textColor="?android:textColorSecondary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/backupNameView"
tools:text="@string/restore_current_package" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_height="0dp"
android:layout_margin="16dp"
android:indeterminate="true"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/backupNameView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/currentPackageView" />
tools:listitem="@layout/list_item_app_status" />
<Button
android:id="@+id/button"
@ -74,11 +60,10 @@
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:text="@string/restore_finished_button"
android:visibility="invisible"
android:enabled="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBar"
app:layout_constraintVertical_bias="1.0"
tools:visibility="visible" />
app:layout_constraintTop_toBottomOf="@+id/appList"
app:layout_constraintVertical_bias="1.0" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -92,7 +92,8 @@
<string name="restore_next">Next</string>
<string name="restore_restoring">Restoring Backup</string>
<string name="restore_current_package">Restoring %s…</string>
<string name="restore_finished_success">Restore complete.</string>
<string name="restore_magic_package">System Package Manager</string>
<string name="restore_finished_success">Restore complete</string>
<string name="restore_finished_error">An error occurred while restoring the backup.</string>
<string name="restore_finished_button">Finish</string>
<string name="storage_internal_warning_title">Warning</string>

View file

@ -143,7 +143,7 @@ internal class ApkRestoreTest : RestoreTest() {
@Test
fun `test successful run`(@TempDir tmpDir: Path) = runBlocking {
val installResult = MutableInstallResult(1).apply {
put(packageName, ApkRestoreResult(progress = 1, total = 1, status = SUCCEEDED))
put(packageName, ApkRestoreResult(packageName, progress = 1, total = 1, status = SUCCEEDED))
}
every { strictContext.cacheDir } returns File(tmpDir.toString())