[//]: # (Outline Slide) .left-column[ # Today's goals ] .right-column[ Reminders - Layout Part 3-4 due tomorrow at 10pm - Remember to keep commiting and pushing to your repo for backups! - Accessibility assignment is published! - Repos will be available tonight. - Remember to get in touch with course staff if you do not have access to a gitlab repo entitled `as3-accessibility-
` - *Required readings this week* - Android Accessibility in practice! Finish [Inclusive Design](inclusive-design.html#24) Intro to the Accessibility assignment ] --- class: middle, center, inverse # Accessibility on Android CSE 340, Winter 2022 --- # So you believe accessibility is important... what now? - How to add content descriptions - Making navigation work - Color contrast - Button size - Invisible Things - Testing --- # ContentDescription Talkback will "tell" what an item on the screen is if - it has a content description (`android:contentDescription="..."`) OR - is focusable (`android:focusable="true"`) OR - it is clickable (`android:clickable="true"`) OR - You have attached a `onClickListener` to the interactor. (We'll learn about this in our next class) --- # ContentDescription Use Android Lint can help find (static) problems in your code Set ContentDescription to `null` for decorative elements (such as spacers) Reminder: Don't use state (Selected) or role (Button) in the description. -- count: false - why not? --- # TextEdit .left-column[ ![:img An example screen with edit fields that show hint text, 100%, width](img/android-accessibility/hintexample.png)] ] .right-column[ Use `android:hint` to have a hint show up in the edit box (text that appears in the box but is not "really there" for the purposes of input) - If you set a `android:hint` don't also set a `contentDescription` - You *can* still set `android:labelFor` if the `TextEdit` has a `View` labeling it. ] .footnote[Image from [Material Design Text Fields](https://material.io/components/text-fields)] --- # Can group related content - Make the container for a group `android:focusable` - Android will read all the content together - Good for things like forms (label + TextEdit) or custom ViewGroups that have multiple items but no or a single interaction. - Reduces swiping - Streamlines speech output -- count: false Can also - Use `android:accessibilityTraversalBefore` when the order of traversal should not match the interactor hierarchy - Use `android:labelFor` to indicate when a `TextView` is a label for a `TextEntry` --- # Making Navigation work Things like `android:accessibilityTraversalBefore` help improve navigation So does grouping May also want to *skip* things sometimes (this happens in the assignment) - Don't use content description in this case - May also use `android:importantForAccessibility` or `android:focusable` (you'll need to read up on where and when to use these) --- # Other concerns Color contrast - If your fonts are < 18pt, or < **14pt bold**, color contrast should be >= 4.5:1. - Otherwise 3.0:1. ![:img Picture of the word Text twice on a grey background: Once with low and once with ok contrast ,60%, width](img/android-accessibility/contrast.png) But you can't count on color contrast being enough. Also use descriptive text or other redundant cues. --- # Other concerns Color contrast - If your fonts are < 18pt, or < **14pt bold**, color contrast should be >= 4.5:1. - Otherwise 3.0:1. Make your buttons big enough - 48x48dp - `android:minHeight` in `EditText` objects --- # Other concerns Color contrast - If your fonts are < 18pt, or < **14pt bold**, color contrast should be >= 4.5:1. - Otherwise 3.0:1. **Problem:** what if the color contrast is poor in an `AlertDialog` built by the system? -- count: false **Solution:** Look in `styles.xml` and you might find what the `colorAccent` is for the theme for the app. The actual value for that color, likely stored in the `colors.xml` file, can be changed to something with more contrast: example: ```xml
#D81B60
``` .footnote[Solution from [Making an AlertDialog in Android](https://suragch.medium.com/making-an-alertdialog-in-android-2045381e2edb)] --- # Invisible things **Problem:** Sometimes navigation can't get to an interactor. -- count: false **Solution:** use `android:importantForAccessibility` or `android:focusable` (you'll need to read up on where and when to use these) -- count: false **Problem:** Sometimes Android doesn't know you changed something. -- count: false **Solution:** use `[view].announceForAccessibility()` --- # How do we find all these problems? 1. Use Android Lint to help find problems ![:img Picture of the Android Lint with the menu item to invoke it (Analyze->Inspect code) highlighted ,100%, width](img/android-accessibility/lint.png) --- # How do we find all these problems? 1. Use Android Lint to help find problems 2. Use the [Accessibility Scanner](https://play.google.com/store/apps/details?id=com.google.android.apps.accessibility.auditor&hl=en_US) ![:img Picture of the Android Playstore install page for the Accessibility Scanner ,100%, width](img/android-accessibility/scanner1.png) --- # Checks for basics, such as - Overlapping clickable items - Clickable items that are too small - TextView has content description. This might interfere with screen reader reading its hint or actual content - Low contrast in image or icon or text - Items with identical speakable text - Item Label ends with redundant role information, e.g. ."Play Button". - URL link may be invalid --- # How it works - Turn it on in settings after installing - Use your app doing the things you would do anyway - Tell it you're done - View the results in the AccessibilityScanner App --- # Turn it on - Agree to authorizations - Agree to display over screens --- # Ask For Help .left-column40[ ![:img Picture the original Askforhepl app with the Accessibility Scanner running ,80%, width](img/android-accessibility/scanner2.png) ] .right-column60[ Our Case Study/Assignment will be based on an app called **Ask For Help** - App was written by Jen's daughter who was bedridden at the beginning of 8th grade (original interface shown at the left, we reimplemented it) - As a service project she created an app that would allow people to "ask for help" quickly with messages and contacts that are pre-programmed into the app. - At the start of the app, there are no messages and no contacts. You have to go to Settings to fill those in. ] --- # Use your app .left-column[ ![:img Picture the original AskForHelp app with the Accessibility Scanner running ,100%, width](img/android-accessibility/scanner2.png) ] .right-column[ - Click the check mark (Authorize if needed) - Click "Record" - Use the app - *Exit the app* so you can click "Stop" ![:img Picture the stop button for the Accessibility Scanner, 10%, width](img/android-accessibility/stop.png) ] --- # See the result in the scanner .column[ ![:img Picture the original AskForHelp app with the Accessibility Scanner running ,100%, width](img/android-accessibility/scanner3.png) ] -- .column[ ![:img Picture the original AskForHelp app with the Accessibility Scanner running ,100%, width](img/android-accessibility/scanner4.png) ] --- # See the result in the scanner .column[ ![:img Picture the original AskForHelp app with the Accessibility Scanner running ,100%, width](img/android-accessibility/scanner5.png) ] .column[ ![:img Picture the original AskForHelp app with the Accessibility Scanner running ,100%, width](img/android-accessibility/scanner6.png) ] --- # How do we find all these problems? 1. Use Android Lint to help find problems 2. Use the [Accessibility Scanner](https://play.google.com/store/apps/details?id=com.google.android.apps.accessibility.auditor&hl=en_US) 3. Test your app with TalkBack --- # Why Use Talkback Automated tools don't work. They are spectacularly good at some things and spectacularly bad at others. .left-column50[ ## Good - Can tell you if you have alt text ] .right-column50[ ## Bad - Can't tell you if it is any good ] --- # Why Use Talkback .left-column50[ ## Good - Can tell you if you have alt text - Can tell you if an item is too small
- Can tell you if contrast is bad
- ... ] .right-column50[ ## Bad - Can't tell you if it is any good - Can't tell you if you can get to it or it is in the right order - Can't tell you whether to increase font or change color - ... ] Trying it yourself is the best way to find problems. You still won't find them all but our research shows that with a checklist of known problems *and* a screen reader you will do much better than with an automated tool. --- # Using Talkback After TalkBack is on, there are two common ways to navigate: - Linear navigation: Quickly swipe right or left to navigate through screen elements in sequence. Double-tap anywhere to select. - Explore by touch: Drag your finger over the screen to hear what's under your finger. Double-tap anywhere to select. --- # Using Talkback Optional: TalkBack developer settings - Navigate to Accessibility and select TalkBack. - Select Settings > Developer settings: - Log output level: Select VERBOSE. - Display speech output: Turn on this setting to view TalkBack speech output on the screen. --- # Most automated tools check for 1. Use Android Lint to help find problems 2. Use the [Accessibility Scanner](https://play.google.com/store/apps/details?id=com.google.android.apps.accessibility.auditor&hl=en_US) 3. Test your app with TalkBack 4. Turn on [Switch Access](https://developer.android.com/guide/topics/ui/accessibility/testing#turn-on-switch-access) --- # Accessbility assignment Let's explore the base repository --- # Bundle in Accessibility Recall: a `Bundle` can be used to comunicate when switching activities. Example in `ChooseRequestsActivity` ```java // Instance variable declaration private Bundle mMessageInfo; // Instance variable initialization (in setVariables called by onCreate) mMessageInfo = new Bundle(); // Setting key/value pairs mMessageInfo.putString("last_button_pressed", "none"); // Switching activities Intent intent = new Intent(this, ChooseContactGroupsActivity.class); mMessageInfo.remove("last_button_pressed"); String request = ((TextView)view).getText().toString(); mMessageInfo.putString("last_button_pressed", request); // Attaching the bundle to the intent intent.putExtras(mMessageInfo); startActivity(intent); ``` --- # Bundle in Accessibility Recall: a `Bundle` can be used to comunicate when switching activities. Example in `ChooseContactsActivity` ```java // Instance variable declaration private Bundle mMessageInfo; // Instance variable initialization (in setVariables called by onCreate) mMessageInfo = getIntent().getExtras(); // Add things to the bundle in addNumbersToBundle and textPeople mMessageInfo.putString("contact" + (ii + 1), contactsAsString); // Get information from the bundle String textBody = mMessageInfo.getString("last_button_pressed"); String numbers = "smsto:" + mMessageInfo.getString("contact" + contactID); ``` --- # Shared Preferences Recall, we can save to and restore from `SharedPreferences` file. ```java // setting data SharedPreferences.Editor editor = getPrefs().edit(); editor.putBoolean("mLocationOn", true); editor.putInt("group_selected", mWhichGroup); editor.putString("contactGroup" + (ii + 1), contactGroup); editor.putStringSet("contact_numbers" + (ii + 1), mNumbers.get(ii)); editor.apply(); // have to force the write. // getting data, the last parameter is the default. mLocationOn = getPrefs().getBoolean("mLocationOn", true); mWhichGroup = getPrefs().getInt("group_selected", 1); String contactGroupName = getPrefs().getString("contactGroup" + (ii + 1), ""); Set
ids = getPrefs().getStringSet("contact_ids" + (ii + 1), ``` --- ## Styles Accessbility uses a new (to us) resource file `styles.xml` - Android [Styles and Themes](https://developer.android.com/guide/topics/ui/look-and-feel/themes) are used to refactor common appearances. - A style is a collection of attributes, such as color, dimensions, etc, - Can use a style to change appearance of `View` objects. Example the Settings `ImageButton` in `activity_choose_requests.xml` has an attribute `style="@style/icon"` defined in `styles.xml` ```xml ``` --- # Preview: Click Listeners What the heck is this?!?!? ```java requestButton.setOnClickListener(request -> { ... }); ``` -- count: false Or this?!?!?! ```java settings.setOnClickListener(view -> switchActivity(view.getContext(), SettingsActivity.class)); ``` -- count: false Or this!??!? ```java findViewById(R.id.addRequestRow).setOnClickListener(this::startNewRequest); ``` --- # END OF DECK