Skip to content

Most visited

Recently visited

navigation

Accessibility

Android O (API level 26) introduces several new APIs to help make your custom accessibility services easier to use.

Accessibility volume

Android O introduces the STREAM_ACCESSIBILITY volume category, which allows you to control the volume of your accessibility service's audio output independently of other sounds on the device.

To use this new stream type, set the FLAG_ENABLE_ACCESSIBILITY_VOLUME option within your accessibility service. You can then change the device's accessibility audio volume by calling the adjustStreamVolume() method on the device's instance of AudioManager.

The following code snippet demonstrates how your accessibility service can use the STREAM_ACCESSIBILITY volume category:

import static android.media.AudioManager.*;

public class MyAccessibilityService extends AccessibilityService {
    private AudioManager mAudioManager =
            (AudioManager) getSystemService(AUDIO_SERVICE);

    @Override
    public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
        AccessibilityNodeInfo interactedNodeInfo =
                accessibilityEvent.getSource();
        if (interactedNodeInfo.getText().equals("Increase volume")) {
            mAudioManager.adjustStreamVolume(AudioManager.STREAM_ACCESSIBILITY,
                ADJUST_RAISE, 0);
        }
    }
}

For more information, see the What's New In Android Accessibility session video from Google I/O 2017, starting at 6:35.

Fingerprint gestures

Your accessibility service can also respond to an alternative input mechanism, directional swipes (up, down, left, and right) along a device's fingerprint sensor. To receive callbacks about these interactions, complete the following sequence of steps:

  1. Declare the USE_FINGERPRINT permission and the CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES capability.
  2. Set the FLAG_REQUEST_FINGERPRINT_GESTURES flag within the android:accessibilityFlags attribute.
  3. Register for callbacks using registerFingerprintGestureCallback().

Keep in mind that not all devices include fingerprint sensors. To identify whether a device supports the sensor, use the isHardwareDetected() method. Even on a device that includes a fingerprint sensor, your service cannot use the sensor when it's in use for authentication purposes. To identify when the sensor is available, call the isGestureDetectionAvailable() method and implement the onGestureDetectionAvailabilityChanged() callback.

The following code snippet shows an example of using fingerprint gestures to navigate around a virtual game board:

AndroidManifest.xml

<manifest ... >
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
    ...
    <application>
        <service android:name="com.example.MyFingerprintGestureService" ... >
            <meta-data
                android:name="android.accessibilityservice"
                android:resource="@xml/myfingerprintgestureservice" />
        </service>
    </application>

myfingerprintgestureservice.xml

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:accessibilityFlags=" ... |flagRequestFingerprintGestures"
    android:canRequestFingerprintGestures="true"
    ... />

MyFingerprintGestureService.java

import static android.accessibilityservice.FingerprintGestureController.*;

public class MyFingerprintGestureService extends AccessibilityService {
    private FingerprintGestureController mGestureController;
    private FingerprintGestureController
            .FingerprintGestureCallback mFingerprintGestureCallback;
    private boolean mIsGestureDetectionAvailable;

    @TargetApi(Build.VERSION_CODES.O)
    @Override
    public void onCreate() {
        mGestureController = getFingerprintGestureController();
        mIsGestureDetectionAvailable =
                mGestureController.isGestureDetectionAvailable();
    }

    @TargetApi(Build.VERSION_CODES.O)
    @Override
    protected void onServiceConnected() {
        if (mFingerprintGestureCallback != null
                || !mIsGestureDetectionAvailable) {
            return;
        }

        mFingerprintGestureCallback =
               new FingerprintGestureController.FingerprintGestureCallback() {
            @Override
            public void onGestureDetected(int gesture) {
                switch (gesture) {
                    case FINGERPRINT_GESTURE_SWIPE_DOWN:
                        moveGameCursorDown();
                        break;
                    case FINGERPRINT_GESTURE_SWIPE_LEFT:
                        moveGameCursorLeft();
                        break;
                    case FINGERPRINT_GESTURE_SWIPE_RIGHT:
                        moveGameCursorRight();
                        break;
                    case FINGERPRINT_GESTURE_SWIPE_UP:
                        moveGameCursorUp();
                        break;
                    default:
                        Log.e(MY_APP_TAG,
                                  "Error: Unknown gesture type detected!");
                        break;
                }
            }

            @Override
            public void onGestureDetectionAvailabilityChanged(boolean available) {
                mIsGestureDetectionAvailable = available;
            }
        };

        if (mFingerprintGestureCallback != null) {
            mGestureController.registerFingerprintGestureCallback(
                    mFingerprintGestureCallback, null);
        }
    }
}

For more information, see the What's New In Android Accessibility session video from Google I/O 2017, starting at 9:03.

Multilingual support

Android's text-to-speech (TTS) service can now identify and speak phrases in multiple languages within a single block of text. To enable this automatic language-switching capability in your accessibility service, wrap your strings in LocaleSpan objects, as shown in the following code snippet:

TextView localeWrappedTextView = findViewById(R.id.my_french_greeting_text);
localeWrappedTextView.setText(wrapTextInLocaleSpan("Bonjour!", Locale.FRANCE));

private SpannableStringBuilder wrapTextInLocaleSpan(
        CharSequence originalText, Locale loc) {
    SpannableStringBuilder myLocaleBuilder =
            new SpannableStringBuilder(originalText);
    myLocaleBuilder.setSpan(new LocaleSpan(loc), 0,
            originalText.length() - 1, 0);
    return myLocaleBuilder;
}

For more information, see the What's New In Android Accessibility session video from Google I/O 2017, starting at 10:59.

Accessibility shortcut

On devices running Android O, users can enable and disable their preferred accessibility service from any screen by long-pressing both volume keys at the same time. Although this shortcut enables and disables TalkBack by default, a user can configure the button to enable and disable any service, including your own, that's installed on their device.

In order for users to access your accessibility service from the accessibility shortcut, you need to request the feature at runtime, when your service starts.

For more information, see the What's New In Android Accessibility session video from Google I/O 2017, starting at 13:25.

Continued gestures

Android 7.0 (API level 24) introduced the ability for your app to perform simple gestures on behalf of the user. Android O builds off of this capability by adding support for continued gestures, or gestures containing more than one Path object.

When specifying sequences of strokes, you must specify that they belong to the same programmatic gesture by using the final argument, willContinue, in the GestureDescription.StrokeDescription constructor, as shown in the following code snippet:

// Simulates an L-shaped drag path: 200 pixels right, then 200 pixels down.
@TargetApi(Build.VERSION_CODES.O)
private void doRightThenDownDrag() {
    Path dragRightPath = new Path();
    dragRightPath.moveTo(200, 200);
    dragRightPath.lineTo(400, 200);
    long dragRightDuration = 500L; // 0.5 second

    // The starting point of the second path must match
    // the ending point of the first path.
    Path dragDownPath = new Path();
    dragDownPath.moveTo(400, 200);
    dragDownPath.lineTo(400, 400);
    long dragDownDuration = 500L;
    GestureDescription.StrokeDescription rightThenDownDrag =
            new GestureDescription.StrokeDescription(dragRightPath, 0L,
            dragRightDuration, true);
    rightThenDownDrag.continueStroke(dragDownPath, dragRightDuration,
            dragDownDuration, false);
}

For more information, see the What's New In Android Accessibility session video from Google I/O 2017, starting at 15:47.

Accessibility button

On devices that use a software-rendered navigation area and are running Android O, the right-hand side of the navigation bar now includes an accessibility button. When users press this button, they can invoke one of several enabled accessibility features and services, depending on the content currently shown on the screen.

To allow users to invoke your accessibility service using the accessibility button, add the FLAG_REQUEST_ACCESSIBILITY_BUTTON flag in an AccessibilityServiceInfo object's android:accessibilityFlags attribute. You can then register callbacks using registerAccessibilityButtonCallback().

private AccessibilityButtonController mAccessibilityButtonController;
private AccessibilityButtonController
        .AccessibilityButtonCallback mAccessibilityButtonCallback;
private boolean mIsAccessibilityButtonAvailable;

@TargetApi(Build.VERSION_CODES.O)
@Override
public void onCreate() {
    mAccessibilityButtonController = getAccessibilityButtonController();
    mIsAccessibilityButtonAvailable =
            mAccessibilityButtonController.isAccessibilityButtonAvailable();
}

@TargetApi(Build.VERSION_CODES.O)
@Override
protected void onServiceConnected() {
    if (!mIsAccessibilityButtonAvailable) {
        return;
    }

    AccessibilityServiceInfo serviceInfo = getServiceInfo();
    serviceInfo.flags
            |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
    setServiceInfo(serviceInfo);

    mAccessibilityButtonCallback =
        new AccessibilityButtonController.AccessibilityButtonCallback() {
            @Override
            public void onClicked(AccessibilityButtonController controller) {
                Log.d("MY_APP_TAG", "Accessibility button pressed!");

                // Add custom logic for your service to react to the
                // accessibility button being pressed.
            }

            @Override
            public void onAvailabilityChanged(
              AccessibilityButtonController controller, boolean available) {
                if (controller.equals(mAccessibilityButtonController)) {
                    mIsAccessibilityButtonAvailable = available;
                }
            }
        };

    if (mAccessibilityButtonCallback != null) {
        mAccessibilityButtonController.registerAccessibilityButtonCallback(
                mAccessibilityButtonCallback, null);
    }
}

For more information, see the What's New In Android Accessibility session video from Google I/O 2017, starting at 16:28.

Standardized one-sided range values

Some AccessibilityNodeInfo objects use an instance of AccessibilityNodeInfo.RangeInfo to indicate that a UI element can take on a range of values. When creating a range using RangeInfo.obtain(), or when retrieving the extreme values of the range using getMin() and getMax(), keep in mind that Android O has standardized definitions of one-sided ranges:

Text processing improvements

Android O includes text processing improvements that make it easier for your accessibility services to identify and operate on specific units of text that appear on screen.

Hint text

Android O includes several methods for interacting with a text-based object's hint text:

Word-level dictation

If your service uses a TextToSpeech object to dictate the content that appears on-screen, you can obtain more precise timing information about when text-to-speech engines begin speaking individual synthesized words, as long as the text-to-speech engine provides this information. When an engine expects to begin playing audio for a specific range of text, the text-to-speech API notifies your service that speech for the range of text is beginning using the onRangeStart() method.

If you create your own implementation of TextToSpeechService, you can support this new functionality by using the rangeStart() method.

Locations of on-screen text characters

To determine the screen coordinates for each visible character's bounding box within a TextView widget, call refreshWithExtraData(), passing in EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY as the first argument and a Bundle object as the second argument. As the method executes, the system populates the Bundle argument with a parcelable array of Rect objects. Each Rect object represents the bounding box of a particular character.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.