From 49c9425166df0b2888ac2c8fd54cb330990cdf13 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Thu, 23 Jun 2022 11:08:01 -0300 Subject: [PATCH] Expose app status information to screen readers This is for backup, restore and re-install status. --- .../restore/install/InstallProgressAdapter.kt | 14 ++++++++- .../install/InstallProgressFragment.kt | 12 ++++---- .../stevesoltys/seedvault/ui/AppViewHolder.kt | 29 +++++++++++++++++-- .../main/res/layout/list_item_app_status.xml | 8 +++-- app/src/main/res/values/strings.xml | 9 ++++++ 5 files changed, 60 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressAdapter.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressAdapter.kt index 40e7ca10..ff08bad4 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressAdapter.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressAdapter.kt @@ -1,5 +1,6 @@ package com.stevesoltys.seedvault.restore.install +import android.os.Build.VERSION.SDK_INT import android.view.LayoutInflater import android.view.View import android.view.View.GONE @@ -44,7 +45,8 @@ internal class InstallProgressAdapter( return if (finished) finishedComparator.compare(item1, item2) else item1.compareTo(item2) } - }) + } + ) override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppInstallViewHolder { val v = LayoutInflater.from(parent.context) @@ -79,15 +81,23 @@ internal class InstallProgressAdapter( IN_PROGRESS -> { appStatus.visibility = INVISIBLE progressBar.visibility = VISIBLE + if (SDK_INT >= 30) { + progressBar.stateDescription = + context.getString(R.string.restore_app_status_installing) + } } SUCCEEDED -> { appStatus.setImageResource(R.drawable.ic_check_green) appStatus.visibility = VISIBLE + appStatus.contentDescription = + context.getString(R.string.restore_app_status_installed) progressBar.visibility = INVISIBLE } FAILED -> { appStatus.setImageResource(R.drawable.ic_error_red) appStatus.visibility = VISIBLE + appStatus.contentDescription = + context.getString(R.string.restore_app_status_install_error) progressBar.visibility = INVISIBLE if (finished) { v.background = clickableBackground @@ -100,6 +110,8 @@ internal class InstallProgressAdapter( } FAILED_SYSTEM_APP -> { appStatus.setImageResource(R.drawable.ic_error_red) + appStatus.contentDescription = + context.getString(R.string.restore_app_status_install_error) appStatus.visibility = VISIBLE progressBar.visibility = INVISIBLE } diff --git a/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt b/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt index 0bdfc507..c78d47a2 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/restore/install/InstallProgressFragment.kt @@ -60,17 +60,17 @@ class InstallProgressFragment : Fragment(), InstallItemListener { button.setText(R.string.restore_next) button.setOnClickListener { viewModel.onNextClickedAfterInstallingApps() } - viewModel.chosenRestorableBackup.observe(viewLifecycleOwner, { restorableBackup -> + viewModel.chosenRestorableBackup.observe(viewLifecycleOwner) { restorableBackup -> backupNameView.text = restorableBackup.name - }) + } - viewModel.installResult.observe(viewLifecycleOwner, { result -> + viewModel.installResult.observe(viewLifecycleOwner) { result -> onInstallResult(result) - }) + } - viewModel.nextButtonEnabled.observe(viewLifecycleOwner, { enabled -> + viewModel.nextButtonEnabled.observe(viewLifecycleOwner) { enabled -> button.isEnabled = enabled - }) + } } private fun onInstallResult(installResult: InstallResult) { diff --git a/app/src/main/java/com/stevesoltys/seedvault/ui/AppViewHolder.kt b/app/src/main/java/com/stevesoltys/seedvault/ui/AppViewHolder.kt index b3165204..e17800d7 100644 --- a/app/src/main/java/com/stevesoltys/seedvault/ui/AppViewHolder.kt +++ b/app/src/main/java/com/stevesoltys/seedvault/ui/AppViewHolder.kt @@ -2,6 +2,7 @@ package com.stevesoltys.seedvault.ui import android.content.Context import android.content.pm.PackageManager +import android.os.Build.VERSION.SDK_INT import android.view.View import android.view.View.GONE import android.view.View.INVISIBLE @@ -39,21 +40,45 @@ internal abstract class AppViewHolder(protected val v: View) : RecyclerView.View appInfo.visibility = GONE appStatus.visibility = INVISIBLE progressBar.visibility = VISIBLE + if (SDK_INT >= 30) { + progressBar.stateDescription = context.getString( + if (isRestore) R.string.restore_restoring + else R.string.backup_app_in_progress + ) + } } else { appStatus.visibility = VISIBLE progressBar.visibility = INVISIBLE appInfo.visibility = GONE + val contentDescription: String? when (state) { - SUCCEEDED -> appStatus.setImageResource(R.drawable.ic_check_green) - FAILED -> appStatus.setImageResource(R.drawable.ic_error_red) + SUCCEEDED -> { + appStatus.setImageResource(R.drawable.ic_check_green) + contentDescription = context.getString( + if (isRestore) R.string.restore_app_status_restored + else R.string.backup_app_success + ) + } + FAILED -> { + appStatus.setImageResource(R.drawable.ic_error_red) + contentDescription = context.getString( + if (isRestore) R.string.restore_app_status_failed + else R.string.notification_failed_title + ) + } else -> { appStatus.setImageResource(R.drawable.ic_warning_yellow) + contentDescription = context.getString( + if (isRestore) R.string.restore_app_status_warning + else R.string.backup_app_warning + ) appInfo.text = if (isRestore) state.getRestoreText(context) else state.getBackupText(context) appInfo.visibility = VISIBLE } } + appStatus.contentDescription = contentDescription } } diff --git a/app/src/main/res/layout/list_item_app_status.xml b/app/src/main/res/layout/list_item_app_status.xml index 434e5081..5d630c7e 100644 --- a/app/src/main/res/layout/list_item_app_status.xml +++ b/app/src/main/res/layout/list_item_app_status.xml @@ -4,21 +4,22 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?android:selectableItemBackground" android:layout_marginStart="40dp" android:layout_marginEnd="40dp" + android:background="?android:selectableItemBackground" android:paddingTop="8dp" - android:paddingBottom="8dp"> + android:paddingBottom="8dp" + android:screenReaderFocusable="true"> Waiting to back up… Was not yet backed up + Backing up + Backed up + Backup warning Not backed up as it wasn\'t used recently Was not backed up as it hadn\'t been used recently App reported no data for backup @@ -161,6 +164,12 @@ An error occurred while loading the backups. No suitable backups found at given location.\n\nThis is most likely due to a wrong recovery code or a storage error. Re-installing apps + Re-installing + Re-installed + Could not install + Data restored + Restore failed + Restore warning Some apps not installed Data can only be restored if an app is installed.\n\nTap failed apps to try to install them manually before proceeding. Tap to install