Skip to content

Commit

Permalink
Merge pull request #4454 from owncloud/feature/name_role_value_access…
Browse files Browse the repository at this point in the history
…ibility

[a11y] 11.4.1.2 Name-role value
  • Loading branch information
Aitorbp authored Aug 27, 2024
2 parents a4cd5d9 + 4e99414 commit 3541973
Show file tree
Hide file tree
Showing 20 changed files with 254 additions and 48 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ ownCloud admins and users.
* Enhancement - Improved accessibility of information and relationships: [#4362](https://github.com/owncloud/android/issues/4362)
* Enhancement - Changed the color of some elements to improve accessibility: [#4364](https://github.com/owncloud/android/issues/4364)
* Enhancement - Improved SearchView accessibility: [#4365](https://github.com/owncloud/android/issues/4365)
* Enhancement - Roles added to some elements to improve accessibility: [#4373](https://github.com/owncloud/android/issues/4373)
* Enhancement - Hardware keyboard support: [#4438](https://github.com/owncloud/android/pull/4438)
* Enhancement - Hardware keyboard support for passcode view: [#4447](https://github.com/owncloud/android/issues/4447)

Expand Down Expand Up @@ -88,6 +89,14 @@ ownCloud admins and users.
https://github.com/owncloud/android/issues/4365
https://github.com/owncloud/android/pull/4433

* Enhancement - Roles added to some elements to improve accessibility: [#4373](https://github.com/owncloud/android/issues/4373)

Roles have been added to specific elements within the following views: Toolbar,
Spaces, Drawer Menu, Manage accounts and Floating Action Button.

https://github.com/owncloud/android/issues/4373
https://github.com/owncloud/android/pull/4454

* Enhancement - Hardware keyboard support: [#4438](https://github.com/owncloud/android/pull/4438)

Navigation via hardware keyboard has been improved so that now focus order has a
Expand Down
6 changes: 6 additions & 0 deletions changelog/unreleased/4454
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Roles added to some elements to improve accessibility

Roles have been added to specific elements within the following views: Toolbar, Spaces, Drawer Menu, Manage accounts and Floating Action Button.

https://github.com/owncloud/android/issues/4373
https://github.com/owncloud/android/pull/4454
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* ownCloud Android client application
*
* @author Aitor Ballesteros Pavón
*
* Copyright (C) 2024 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.owncloud.android.extensions

import android.view.View
import androidx.core.view.AccessibilityDelegateCompat
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat

fun View.setAccessibilityRole(className: Class<*>? = null, roleDescription: String? = null) {
ViewCompat.setAccessibilityDelegate(this, object : AccessibilityDelegateCompat() {
override fun onInitializeAccessibilityNodeInfo(v: View, info: AccessibilityNodeInfoCompat) {
super.onInitializeAccessibilityNodeInfo(v, info)
className?.let { info.className = it.name }
roleDescription?.let { info.roleDescription = it }
}
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ import android.accounts.Account
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import androidx.recyclerview.widget.RecyclerView
import com.owncloud.android.R
import com.owncloud.android.databinding.AccountActionBinding
import com.owncloud.android.databinding.AccountItemBinding
import com.owncloud.android.extensions.setAccessibilityRole
import com.owncloud.android.lib.common.OwnCloudAccount
import com.owncloud.android.presentation.authentication.AccountUtils
import com.owncloud.android.presentation.avatar.AvatarUtils
Expand All @@ -46,6 +48,7 @@ class ManageAccountsAdapter(private val accountListener: AccountAdapterListener)
return if (viewType == AccountManagementRecyclerItemViewType.ITEM_VIEW_ACCOUNT.ordinal) {
val view = inflater.inflate(R.layout.account_item, parent, false)
view.filterTouchesWhenObscured = PreferenceUtils.shouldDisallowTouchesWithOtherVisibleWindows(parent.context)
view.setAccessibilityRole(className = Button::class.java)
AccountManagementViewHolder(view)
} else {
val view = inflater.inflate(R.layout.account_action, parent, false)
Expand Down Expand Up @@ -119,6 +122,7 @@ class ManageAccountsAdapter(private val accountListener: AccountAdapterListener)
is NewAccountViewHolder -> {
holder.binding.icon.setImageResource(R.drawable.ic_account_plus)
holder.binding.name.setText(R.string.prefs_add_account)
holder.binding.name.setAccessibilityRole(className = Button::class.java)

// bind action listener
holder.binding.constraintLayoutAction.setOnClickListener {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
* ownCloud Android client application
*
* @author Abel García de Prada
* Copyright (C) 2020 ownCloud GmbH.
* @author Aitor Ballesteros Pavón
*
* Copyright (C) 2024 ownCloud GmbH.
* <p>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
Expand All @@ -21,13 +23,20 @@ package com.owncloud.android.presentation.files
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.AccessibilityDelegateCompat
import androidx.core.view.ViewCompat
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
import com.owncloud.android.R
import com.owncloud.android.data.providers.SharedPreferencesProvider
import com.owncloud.android.data.providers.implementation.OCSharedPreferencesProvider
import com.owncloud.android.databinding.SortOptionsLayoutBinding
import com.owncloud.android.extensions.setAccessibilityRole
import com.owncloud.android.presentation.files.SortOrder.Companion.PREF_FILE_LIST_SORT_ORDER
import com.owncloud.android.presentation.files.SortOrder.SORT_ORDER_ASCENDING
import com.owncloud.android.presentation.files.SortType.Companion.PREF_FILE_LIST_SORT_TYPE

class SortOptionsView @JvmOverloads constructor(
Expand Down Expand Up @@ -75,7 +84,7 @@ class SortOptionsView @JvmOverloads constructor(
// Select sort type and order according to preferences.
sortTypeSelected = SortType.values()[sharedPreferencesProvider.getInt(PREF_FILE_LIST_SORT_TYPE, SortType.SORT_TYPE_BY_NAME.ordinal)]
sortOrderSelected = SortOrder.values()[sharedPreferencesProvider.getInt(PREF_FILE_LIST_SORT_ORDER, SortOrder.SORT_ORDER_ASCENDING.ordinal)]

binding.sortTypeTitle.setAccessibilityRole(className = Button::class.java)
binding.sortTypeSelector.setOnClickListener {
onSortOptionsListener?.onSortTypeListener(
sortTypeSelected,
Expand All @@ -87,6 +96,18 @@ class SortOptionsView @JvmOverloads constructor(
viewTypeSelected.getOppositeViewType()
)
}
ViewCompat.setAccessibilityDelegate(binding.sortTypeSelector, object : AccessibilityDelegateCompat() {
override fun onInitializeAccessibilityNodeInfo(v: View, info: AccessibilityNodeInfoCompat) {
super.onInitializeAccessibilityNodeInfo(v, info)
val sortTitleText = binding.sortTypeTitle.text
if (sortOrderSelected == SORT_ORDER_ASCENDING) {
binding.sortTypeTitle.contentDescription = context.getString(R.string.content_description_sort_by_name_ascending, sortTitleText)
} else {
binding.sortTypeTitle.contentDescription = context.getString(R.string.content_description_sort_by_name_descending, sortTitleText)
}
}
})

}

fun selectAdditionalView(additionalView: AdditionalView) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ import android.accounts.Account
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
Expand Down Expand Up @@ -219,10 +219,6 @@ class FileDetailsFragment : FileFragment() {
fileDetailsViewModel.checkOnGoingTransfersWhenOpening()
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.file_actions_menu, menu)
}

override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
Expand All @@ -241,6 +237,20 @@ class FileDetailsFragment : FileFragment() {

val appRegistryProviders = fileDetailsViewModel.appRegistryMimeType.value?.appProviders
openInWebProviders = addOpenInWebMenuOptions(menu, openInWebProviders, appRegistryProviders)

setRolesAccessibilityToMenuItems(menu)
}

private fun setRolesAccessibilityToMenuItems(menu: Menu) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val roleAccessibilityDescription = getString(R.string.button_role_accessibility)
menu.findItem(R.id.action_rename_file).setContentDescription(
getString(R.string.common_rename) + roleAccessibilityDescription
)
menu.findItem(R.id.action_remove_file).setContentDescription(
getString(R.string.common_remove) + roleAccessibilityDescription
)
}
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
Expand Down Expand Up @@ -280,8 +281,7 @@ class MainFileListFragment : Fragment(),

showOrHideFab(requireArguments().getParcelable(ARG_FILE_LIST_OPTION)!!, requireArguments().getParcelable(ARG_INITIAL_FOLDER_TO_DISPLAY)!!)

binding.fabMain.findViewById<AddFloatingActionButton>(com.getbase.floatingactionbutton.R.id.fab_expand_menu_button).contentDescription =
getString(R.string.content_description_add_new_content)
setFabMainContentDescription()

setTextHintRootToolbar()
}
Expand Down Expand Up @@ -859,6 +859,11 @@ class MainFileListFragment : Fragment(),
fabMkdir.isFocusable = isFabExpanded()
fabNewfile.isFocusable = isFabExpanded()
fabNewshortcut.isFocusable = isFabExpanded()
if (fabMain.isExpanded) {
binding.fabMain.findViewById<AddFloatingActionButton>(com.getbase.floatingactionbutton.R.id.fab_expand_menu_button).contentDescription = getString(R.string.content_description_add_new_content_expanded)
} else {
setFabMainContentDescription()
}
}
}
}
Expand Down Expand Up @@ -918,6 +923,11 @@ class MainFileListFragment : Fragment(),

fun isFabExpanded() = binding.fabMain.isExpanded

fun setFabMainContentDescription() {
binding.fabMain.findViewById<AddFloatingActionButton>(com.getbase.floatingactionbutton.R.id.fab_expand_menu_button).contentDescription =
getString(R.string.content_description_add_new_content)
}

private fun openBottomSheetToUploadFiles() {
val uploadBottomSheet = layoutInflater.inflate(R.layout.upload_bottom_sheet_fragment, null)
val dialog = BottomSheetDialog(requireContext())
Expand Down Expand Up @@ -1411,10 +1421,30 @@ class MainFileListFragment : Fragment(),
openInWebProviders = emptyMap()
}
}
setRolesAccessibilityToMenuItems()

return true
}

private fun setRolesAccessibilityToMenuItems() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val roleAccessibilityDescription = getString(R.string.button_role_accessibility)
menu?.apply {
findItem(R.id.file_action_select_all)?.contentDescription = getString(R.string.actionbar_select_all) + roleAccessibilityDescription
findItem(R.id.action_select_inverse)?.contentDescription = getString(R.string.actionbar_select_inverse) + roleAccessibilityDescription
findItem(R.id.action_open_file_with)?.contentDescription = getString(R.string.actionbar_open_with) + roleAccessibilityDescription
findItem(R.id.action_rename_file)?.contentDescription = getString(R.string.common_rename) + roleAccessibilityDescription
findItem(R.id.action_move)?.contentDescription = getString(R.string.actionbar_move) + roleAccessibilityDescription
findItem(R.id.action_copy)?.contentDescription = getString(R.string.copy) + roleAccessibilityDescription
findItem(R.id.action_send_file)?.contentDescription = getString(R.string.actionbar_send_file) + roleAccessibilityDescription
findItem(R.id.action_set_available_offline)?.contentDescription = getString(R.string.set_available_offline) + roleAccessibilityDescription
findItem(R.id.action_unset_available_offline)?.contentDescription = getString(R.string.unset_available_offline) + roleAccessibilityDescription
findItem(R.id.action_see_details)?.contentDescription = getString(R.string.actionbar_see_details) + roleAccessibilityDescription
findItem(R.id.action_remove_file)?.contentDescription = getString(R.string.common_remove) + roleAccessibilityDescription
}
}
}

override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
return onFileActionChosen(item?.itemId)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.CompoundButton
import android.widget.TextView
import androidx.appcompat.widget.SwitchCompat
Expand All @@ -55,6 +56,7 @@ import com.owncloud.android.domain.sharing.shares.model.OCShare
import com.owncloud.android.domain.utils.Event.EventObserver
import com.owncloud.android.extensions.avoidScreenshotsIfNeeded
import com.owncloud.android.extensions.parseError
import com.owncloud.android.extensions.setAccessibilityRole
import com.owncloud.android.extensions.showMessageInSnackbar
import com.owncloud.android.lib.resources.shares.RemoteShare
import com.owncloud.android.lib.resources.status.OwnCloudVersion
Expand Down Expand Up @@ -122,6 +124,7 @@ class PublicShareDialogFragment : DialogFragment() {
val expirationDateValueInMillis: Long
get() {
var publicLinkExpirationDateInMillis: Long = -1
binding.shareViaLinkExpirationValue.setAccessibilityRole(className = Button::class.java)
val expirationDate = binding.shareViaLinkExpirationValue.text.toString()
if (expirationDate.isNotEmpty()) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
*
* @author Juan Carlos Garrote Gascón
* @author Manuel Plazas Palacio
* @author Aitor Balleteros Pavón
*
* Copyright (C) 2023 ownCloud GmbH.
* Copyright (C) 2024 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
Expand All @@ -23,6 +24,7 @@ package com.owncloud.android.presentation.spaces

import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.Button
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
Expand All @@ -31,6 +33,7 @@ import coil.load
import com.owncloud.android.R
import com.owncloud.android.databinding.SpacesListItemBinding
import com.owncloud.android.domain.spaces.model.OCSpace
import com.owncloud.android.extensions.setAccessibilityRole
import com.owncloud.android.presentation.thumbnails.ThumbnailsRequester
import com.owncloud.android.utils.PreferenceUtils

Expand All @@ -54,6 +57,7 @@ class SpacesListAdapter(
spacesListItemCard.setOnClickListener {
listener.onItemClick(space)
}
spacesListItemCard.setAccessibilityRole(className = Button::class.java)

if (space.isPersonal) {
spacesListItemName.text = holder.itemView.context.getString(R.string.bottom_nav_personal)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import com.owncloud.android.domain.utils.Event
import com.owncloud.android.extensions.goToUrl
import com.owncloud.android.extensions.openPrivacyPolicy
import com.owncloud.android.extensions.sendEmailOrOpenFeedbackDialogAction
import com.owncloud.android.extensions.setAccessibilityRole
import com.owncloud.android.lib.common.OwnCloudAccount
import com.owncloud.android.presentation.authentication.AccountUtils
import com.owncloud.android.presentation.avatar.AvatarUtils
Expand Down Expand Up @@ -112,10 +113,12 @@ abstract class DrawerActivity : ToolbarActivity() {
getDrawerLinkIcon()?.apply {
isVisible = true
setOnClickListener { openDrawerLink() }
setAccessibilityRole(roleDescription = context.getString(R.string.link_role_accessibility))
}
getDrawerLinkText()?.apply {
isVisible = true
setOnClickListener { openDrawerLink() }
setAccessibilityRole(roleDescription = context.getString(R.string.link_role_accessibility))
}
} else {
getDrawerLogo()?.setImageResource(R.drawable.drawer_logo)
Expand Down Expand Up @@ -189,6 +192,7 @@ abstract class DrawerActivity : ToolbarActivity() {
}
true
}
setRolesAccessibilityToMenuItems()
}

fun setCheckedItemAtBottomBar(checkedMenuItem: Int) {
Expand Down Expand Up @@ -415,6 +419,19 @@ abstract class DrawerActivity : ToolbarActivity() {
}, Handler(), false)
}

private fun setRolesAccessibilityToMenuItems() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val navViewMenu = getNavView()?.menu ?: return
val roleAccessibilityDescription = getString(R.string.button_role_accessibility)
navViewMenu.apply {
findItem(R.id.nav_settings)?.contentDescription = getString(R.string.actionbar_settings) + roleAccessibilityDescription
findItem(R.id.drawer_menu_feedback)?.contentDescription = getString(R.string.drawer_feedback) + roleAccessibilityDescription
findItem(R.id.drawer_menu_help)?.contentDescription = getString(R.string.prefs_help) + roleAccessibilityDescription
findItem(R.id.drawer_menu_privacy_policy)?.contentDescription = getString(R.string.prefs_privacy_policy) + roleAccessibilityDescription
}
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
Expand Down
Loading

0 comments on commit 3541973

Please sign in to comment.