Expose app status information to screen readers
This is for backup, restore and re-install status.
This commit is contained in:
parent
976e898656
commit
49c9425166
5 changed files with 60 additions and 12 deletions
|
@ -1,5 +1,6 @@
|
||||||
package com.stevesoltys.seedvault.restore.install
|
package com.stevesoltys.seedvault.restore.install
|
||||||
|
|
||||||
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
|
@ -44,7 +45,8 @@ internal class InstallProgressAdapter(
|
||||||
return if (finished) finishedComparator.compare(item1, item2)
|
return if (finished) finishedComparator.compare(item1, item2)
|
||||||
else item1.compareTo(item2)
|
else item1.compareTo(item2)
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
)
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppInstallViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppInstallViewHolder {
|
||||||
val v = LayoutInflater.from(parent.context)
|
val v = LayoutInflater.from(parent.context)
|
||||||
|
@ -79,15 +81,23 @@ internal class InstallProgressAdapter(
|
||||||
IN_PROGRESS -> {
|
IN_PROGRESS -> {
|
||||||
appStatus.visibility = INVISIBLE
|
appStatus.visibility = INVISIBLE
|
||||||
progressBar.visibility = VISIBLE
|
progressBar.visibility = VISIBLE
|
||||||
|
if (SDK_INT >= 30) {
|
||||||
|
progressBar.stateDescription =
|
||||||
|
context.getString(R.string.restore_app_status_installing)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SUCCEEDED -> {
|
SUCCEEDED -> {
|
||||||
appStatus.setImageResource(R.drawable.ic_check_green)
|
appStatus.setImageResource(R.drawable.ic_check_green)
|
||||||
appStatus.visibility = VISIBLE
|
appStatus.visibility = VISIBLE
|
||||||
|
appStatus.contentDescription =
|
||||||
|
context.getString(R.string.restore_app_status_installed)
|
||||||
progressBar.visibility = INVISIBLE
|
progressBar.visibility = INVISIBLE
|
||||||
}
|
}
|
||||||
FAILED -> {
|
FAILED -> {
|
||||||
appStatus.setImageResource(R.drawable.ic_error_red)
|
appStatus.setImageResource(R.drawable.ic_error_red)
|
||||||
appStatus.visibility = VISIBLE
|
appStatus.visibility = VISIBLE
|
||||||
|
appStatus.contentDescription =
|
||||||
|
context.getString(R.string.restore_app_status_install_error)
|
||||||
progressBar.visibility = INVISIBLE
|
progressBar.visibility = INVISIBLE
|
||||||
if (finished) {
|
if (finished) {
|
||||||
v.background = clickableBackground
|
v.background = clickableBackground
|
||||||
|
@ -100,6 +110,8 @@ internal class InstallProgressAdapter(
|
||||||
}
|
}
|
||||||
FAILED_SYSTEM_APP -> {
|
FAILED_SYSTEM_APP -> {
|
||||||
appStatus.setImageResource(R.drawable.ic_error_red)
|
appStatus.setImageResource(R.drawable.ic_error_red)
|
||||||
|
appStatus.contentDescription =
|
||||||
|
context.getString(R.string.restore_app_status_install_error)
|
||||||
appStatus.visibility = VISIBLE
|
appStatus.visibility = VISIBLE
|
||||||
progressBar.visibility = INVISIBLE
|
progressBar.visibility = INVISIBLE
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,17 +60,17 @@ class InstallProgressFragment : Fragment(), InstallItemListener {
|
||||||
button.setText(R.string.restore_next)
|
button.setText(R.string.restore_next)
|
||||||
button.setOnClickListener { viewModel.onNextClickedAfterInstallingApps() }
|
button.setOnClickListener { viewModel.onNextClickedAfterInstallingApps() }
|
||||||
|
|
||||||
viewModel.chosenRestorableBackup.observe(viewLifecycleOwner, { restorableBackup ->
|
viewModel.chosenRestorableBackup.observe(viewLifecycleOwner) { restorableBackup ->
|
||||||
backupNameView.text = restorableBackup.name
|
backupNameView.text = restorableBackup.name
|
||||||
})
|
}
|
||||||
|
|
||||||
viewModel.installResult.observe(viewLifecycleOwner, { result ->
|
viewModel.installResult.observe(viewLifecycleOwner) { result ->
|
||||||
onInstallResult(result)
|
onInstallResult(result)
|
||||||
})
|
}
|
||||||
|
|
||||||
viewModel.nextButtonEnabled.observe(viewLifecycleOwner, { enabled ->
|
viewModel.nextButtonEnabled.observe(viewLifecycleOwner) { enabled ->
|
||||||
button.isEnabled = enabled
|
button.isEnabled = enabled
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onInstallResult(installResult: InstallResult) {
|
private fun onInstallResult(installResult: InstallResult) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.stevesoltys.seedvault.ui
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build.VERSION.SDK_INT
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
import android.view.View.INVISIBLE
|
import android.view.View.INVISIBLE
|
||||||
|
@ -39,21 +40,45 @@ internal abstract class AppViewHolder(protected val v: View) : RecyclerView.View
|
||||||
appInfo.visibility = GONE
|
appInfo.visibility = GONE
|
||||||
appStatus.visibility = INVISIBLE
|
appStatus.visibility = INVISIBLE
|
||||||
progressBar.visibility = VISIBLE
|
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 {
|
} else {
|
||||||
appStatus.visibility = VISIBLE
|
appStatus.visibility = VISIBLE
|
||||||
progressBar.visibility = INVISIBLE
|
progressBar.visibility = INVISIBLE
|
||||||
appInfo.visibility = GONE
|
appInfo.visibility = GONE
|
||||||
|
val contentDescription: String?
|
||||||
when (state) {
|
when (state) {
|
||||||
SUCCEEDED -> appStatus.setImageResource(R.drawable.ic_check_green)
|
SUCCEEDED -> {
|
||||||
FAILED -> appStatus.setImageResource(R.drawable.ic_error_red)
|
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 -> {
|
else -> {
|
||||||
appStatus.setImageResource(R.drawable.ic_warning_yellow)
|
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 =
|
appInfo.text =
|
||||||
if (isRestore) state.getRestoreText(context)
|
if (isRestore) state.getRestoreText(context)
|
||||||
else state.getBackupText(context)
|
else state.getBackupText(context)
|
||||||
appInfo.visibility = VISIBLE
|
appInfo.visibility = VISIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
appStatus.contentDescription = contentDescription
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,21 +4,22 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:selectableItemBackground"
|
|
||||||
android:layout_marginStart="40dp"
|
android:layout_marginStart="40dp"
|
||||||
android:layout_marginEnd="40dp"
|
android:layout_marginEnd="40dp"
|
||||||
|
android:background="?android:selectableItemBackground"
|
||||||
android:paddingTop="8dp"
|
android:paddingTop="8dp"
|
||||||
android:paddingBottom="8dp">
|
android:paddingBottom="8dp"
|
||||||
|
android:screenReaderFocusable="true">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/appIcon"
|
android:id="@+id/appIcon"
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
android:layout_height="42dp"
|
android:layout_height="42dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:ignore="ContentDescription"
|
|
||||||
tools:srcCompat="@tools:sample/avatars" />
|
tools:srcCompat="@tools:sample/avatars" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -72,6 +73,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
|
android:focusable="false"
|
||||||
android:visibility="invisible"
|
android:visibility="invisible"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
|
|
@ -141,6 +141,9 @@
|
||||||
<!-- This text gets shown for apps that the OS did not try to backup for whatever reason e.g. no backup was run yet -->
|
<!-- This text gets shown for apps that the OS did not try to backup for whatever reason e.g. no backup was run yet -->
|
||||||
<string name="backup_app_not_yet_backed_up">Waiting to back up…</string>
|
<string name="backup_app_not_yet_backed_up">Waiting to back up…</string>
|
||||||
<string name="restore_app_not_yet_backed_up">Was not yet backed up</string>
|
<string name="restore_app_not_yet_backed_up">Was not yet backed up</string>
|
||||||
|
<string name="backup_app_in_progress">Backing up</string>
|
||||||
|
<string name="backup_app_success">Backed up</string>
|
||||||
|
<string name="backup_app_warning">Backup warning</string>
|
||||||
<string name="backup_app_was_stopped">Not backed up as it wasn\'t used recently</string>
|
<string name="backup_app_was_stopped">Not backed up as it wasn\'t used recently</string>
|
||||||
<string name="restore_app_was_stopped">Was not backed up as it hadn\'t been used recently</string>
|
<string name="restore_app_was_stopped">Was not backed up as it hadn\'t been used recently</string>
|
||||||
<string name="backup_app_no_data">App reported no data for backup</string>
|
<string name="backup_app_no_data">App reported no data for backup</string>
|
||||||
|
@ -161,6 +164,12 @@
|
||||||
<string name="restore_set_error">An error occurred while loading the backups.</string>
|
<string name="restore_set_error">An error occurred while loading the backups.</string>
|
||||||
<string name="restore_set_empty_result">No suitable backups found at given location.\n\nThis is most likely due to a wrong recovery code or a storage error.</string>
|
<string name="restore_set_empty_result">No suitable backups found at given location.\n\nThis is most likely due to a wrong recovery code or a storage error.</string>
|
||||||
<string name="restore_installing_packages">Re-installing apps</string>
|
<string name="restore_installing_packages">Re-installing apps</string>
|
||||||
|
<string name="restore_app_status_installing">Re-installing</string>
|
||||||
|
<string name="restore_app_status_installed">Re-installed</string>
|
||||||
|
<string name="restore_app_status_install_error">Could not install</string>
|
||||||
|
<string name="restore_app_status_restored">Data restored</string>
|
||||||
|
<string name="restore_app_status_failed">Restore failed</string>
|
||||||
|
<string name="restore_app_status_warning">Restore warning</string>
|
||||||
<string name="restore_installing_error_title">Some apps not installed</string>
|
<string name="restore_installing_error_title">Some apps not installed</string>
|
||||||
<string name="restore_installing_error_message">Data can only be restored if an app is installed.\n\nTap failed apps to try to install them manually before proceeding.</string>
|
<string name="restore_installing_error_message">Data can only be restored if an app is installed.\n\nTap failed apps to try to install them manually before proceeding.</string>
|
||||||
<string name="restore_installing_tap_to_install">Tap to install</string>
|
<string name="restore_installing_tap_to_install">Tap to install</string>
|
||||||
|
|
Loading…
Reference in a new issue