package com.android.utils;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.text.TextUtils;
import android.view.accessibility.AccessibilityNodeInfo;
import com.android.talkback.R;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Utility methods for managing AccessibilityNodeInfo Roles.
*/
public class Role {
@IntDef({ROLE_NONE, ROLE_BUTTON, ROLE_CHECK_BOX, ROLE_DROP_DOWN_LIST, ROLE_EDIT_TEXT,
ROLE_GRID, ROLE_IMAGE, ROLE_IMAGE_BUTTON, ROLE_LIST, ROLE_PAGER, ROLE_RADIO_BUTTON,
ROLE_SEEK_CONTROL, ROLE_SWITCH, ROLE_TAB_BAR, ROLE_TOGGLE_BUTTON, ROLE_VIEW_GROUP,
ROLE_WEB_VIEW})
@Retention(RetentionPolicy.SOURCE)
public @interface RoleName {}
public static final int ROLE_NONE = 0;
public static final int ROLE_BUTTON = 1;
public static final int ROLE_CHECK_BOX = 2;
public static final int ROLE_DROP_DOWN_LIST = 3;
public static final int ROLE_EDIT_TEXT = 4;
public static final int ROLE_GRID = 5;
public static final int ROLE_IMAGE = 6;
public static final int ROLE_IMAGE_BUTTON = 7;
public static final int ROLE_LIST = 8;
public static final int ROLE_PAGER = 16;
public static final int ROLE_RADIO_BUTTON = 9;
public static final int ROLE_SEEK_CONTROL = 10;
public static final int ROLE_SWITCH = 11;
public static final int ROLE_TAB_BAR = 12;
public static final int ROLE_TOGGLE_BUTTON = 13;
public static final int ROLE_VIEW_GROUP = 14;
public static final int ROLE_WEB_VIEW = 15;
public static @RoleName int getRole(AccessibilityNodeInfoCompat node) {
if (nodeMatchesClassByType(node,
android.support.v4.view.ViewPager.class)) {
return ROLE_PAGER;
}
if (nodeMatchesClassByType(node, android.webkit.WebView.class)) {
return ROLE_WEB_VIEW;
}
if (nodeMatchesClassByType(node, android.widget.Spinner.class)) {
return ROLE_DROP_DOWN_LIST;
}
if (nodeMatchesClassByType(node, android.widget.Switch.class)) {
return ROLE_SWITCH;
}
if (nodeMatchesClassByType(node, android.widget.ToggleButton.class)) {
return ROLE_TOGGLE_BUTTON;
}
if (nodeMatchesClassByType(node, android.widget.ImageView.class)) {
return node.isClickable() ? ROLE_IMAGE_BUTTON : ROLE_IMAGE;
}
if (nodeMatchesClassByType(node, android.widget.RadioButton.class)) {
return ROLE_RADIO_BUTTON;
}
if (nodeMatchesClassByType(node, android.widget.CompoundButton.class)) {
return ROLE_CHECK_BOX;
}
if (nodeMatchesClassByType(node, android.widget.Button.class)) {
return ROLE_BUTTON;
}
if (nodeMatchesClassByType(node, android.widget.EditText.class)) {
return ROLE_EDIT_TEXT;
}
if (nodeMatchesClassByType(node, android.widget.SeekBar.class)) {
return ROLE_SEEK_CONTROL;
}
if (nodeMatchesClassByType(node, android.widget.GridView.class)) {
return ROLE_GRID;
}
if (nodeMatchesClassByType(node, android.widget.TabWidget.class)) {
return ROLE_TAB_BAR;
}
if (nodeMatchesClassByType(node, android.widget.AbsListView.class)) {
return ROLE_LIST;
}
if (node != null && node.getCollectionInfo() != null) {
AccessibilityNodeInfoCompat.CollectionInfoCompat collection = node.getCollectionInfo();
if (collection.getRowCount() > 1 && collection.getColumnCount() > 1) {
return ROLE_GRID;
} else {
return ROLE_LIST;
}
}
if (nodeMatchesClassByType(node, android.view.ViewGroup.class)) {
return ROLE_VIEW_GROUP;
}
return ROLE_NONE;
}
public static @RoleName int getRole(AccessibilityNodeInfo node) {
if (node == null) {
return Role.ROLE_NONE;
}
AccessibilityNodeInfoCompat nodeCompat = new AccessibilityNodeInfoCompat(node);
return getRole(nodeCompat);
}
/**
* Convenience method for getting the role description of a given node or falling back to a
* default TalkBack-provided role text. If neither is available, returns {@code null}.
*/
public static @Nullable CharSequence getRoleDescriptionOrDefault(Context context,
AccessibilityNodeInfoCompat node) {
CharSequence roleDescription = node.getRoleDescription();
if (!TextUtils.isEmpty(roleDescription)) {
return roleDescription;
}
@RoleName int role = getRole(node);
switch (role) {
case ROLE_BUTTON:
return context.getString(R.string.value_button);
case ROLE_CHECK_BOX:
return context.getString(R.string.value_checkbox);
case ROLE_DROP_DOWN_LIST:
return context.getString(R.string.value_spinner);
case ROLE_EDIT_TEXT:
return context.getString(R.string.value_edit_box);
case ROLE_GRID:
return context.getString(R.string.value_gridview);
case ROLE_IMAGE:
return context.getString(R.string.value_image);
case ROLE_IMAGE_BUTTON:
return context.getString(R.string.value_button); // Same as ROLE_BUTTON.
case ROLE_LIST:
return context.getString(R.string.value_listview);
case ROLE_PAGER:
return context.getString(R.string.value_pager);
case ROLE_RADIO_BUTTON:
return context.getString(R.string.value_radio_button);
case ROLE_SEEK_CONTROL:
return context.getString(R.string.value_seek_bar);
case ROLE_SWITCH:
return context.getString(R.string.value_switch);
case ROLE_TAB_BAR:
return context.getString(R.string.value_tabwidget);
case ROLE_TOGGLE_BUTTON:
return context.getString(R.string.value_switch); // Same as ROLE_SWITCH.
}
// Roles missing strings: ROLE_VIEW_GROUP, ROLE_WEB_VIEW.
return null;
}
private static boolean nodeMatchesClassByType(AccessibilityNodeInfoCompat node,
Class<?> referenceClass) {
return node != null &&
ClassLoadingCache.checkInstanceOf(node.getClassName(), referenceClass);
}
}