22
Android Accessibility Ascii @ KKBOX https://www.facebook.com/asciiss

Android Accessibility

Embed Size (px)

Citation preview

Page 1: Android Accessibility

Android Accessibility

Ascii @ KKBOXhttps://www.facebook.com/asciiss

Page 2: Android Accessibility

Accessibility

Screen reader (TalkBack)

Braille support (BrailleBack)

放大手勢 (連敲 3 下)

輕觸並按住的延遲時間 (for 技體障礙)

more ...

Page 3: Android Accessibility

TalkBack

起始畫面Android 4.0 用手指畫矩型Android 4.1 以上雙指長按

設定協助工具 -> TalkBack

Page 4: Android Accessibility

快速啟動 TalkBack

步驟一:按住電源鍵直到聽見音效步驟二:雙指觸碰螢幕直至聽見音效

Page 5: Android Accessibility

TalkBack 常用手勢

選擇 (Hover):單擊

開啟 (Click):雙擊

捲動:雙指向上、下、左、右滑動

選擇上 or 下一項:單指向上、下、左、右滑動

回主畫面:單指上滑 + 左滑

返回:單指下滑 + 左滑

最近畫面:單指左滑 + 上滑

Notification:單指右滑 + 下滑

Page 6: Android Accessibility

Labeling User Interface Elements

android:contentDescriptionTextView ( contentDescription > text > hint )

ImageView

ImageButton

CheckBox

android:hint

EditText ( text > hint > contentDescription )

Page 7: Android Accessibility

Enabling view focus

setFocusable()

isFocusable()

requestFocus()

android:nextFocusDown

android:nextFocusLeft

android:nextFocusRight

Page 8: Android Accessibility

Common Issues Demo

https://github.com/AsciiHuang/AndroidAccessibilityPractices

Page 9: Android Accessibility

ArrayAdapter

listView.setAdapter(new ArrayAdapter<String>(

getActionBar().getThemedContext(),

android.R.layout.simple_list_item_activated_1,

android.R.id.text1,

new String[] {

“Custom View”,

“Bad List”,

“Grid And Navigation”,

}));

// How to set android:contentDescription attribute ?

Page 10: Android Accessibility

BaseAdapter

@Override

public View getView(int position, View convertView, ViewGroup parent) {

if (convertView == null) {

convertView = inflater.inflate(

android.R.layout.simple_list_item_activated_1,

parent, false);

}

((TextView) convertView).setText(drawerItems[position]);

convertView.setContentDescription(drawerItemDescriptions[position]);

return convertView;

}

Page 11: Android Accessibility

Basic Accessibility

public View getView(int position, View convertView, ViewGroup parent) {

ViewHolder viewHolder = new ViewHolder();

getViewHolder(convertView);

viewHolder.title.setText(Constant.Titles[position]);

viewHolder.subTitle.setText(Constant.SubTitles[position]);

String strDescription = String.format("%s, %s, %s",

Constant.Titles[position],

context.getString(R.string.artist), // 歌手 or Artist

Constant.SubTitles[position]);

convertView.setContentDescription(strDescription);

return convertView;

}

Page 12: Android Accessibility

AccessibilityNodeInfosetFocusable

setScrollable

setCheckable

AccessibilityEventsetChecked

setItemCount

setFromIndex

Custom View

Page 13: Android Accessibility

Custom View

AccessibilityDelegatesendAccessibilityEvent

dispatchPopulateAccessibilityEvent

onPopulateAccessibilityEvent

onInitializeAccessibilityNodeInfo

onInitializeAccessibilityEvent

Page 14: Android Accessibility

Custom View

public class CustomView extends View {

...

@Override

public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {

super.onInitializeAccessibilityNodeInfo(info);

}

...

}

Page 15: Android Accessibility

Custom Viewpublic class CustomView extends View {

public CustomView(Context context, AttributeSet attrs) {

super(context, attrs);

setAccessibilityDelegate(new CustomDelegate());

}

}

public class CustomDelegate extends View.AccessibilityDelegate {

@Override

public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) {

return super.dispatchPopulateAccessibilityEvent(host, event);

}

}

Page 16: Android Accessibility

AccessibilityDelegate

private AccessibilityDelegate accessibilityDelegate = new AccessibilityDelegate() {

@Override

public void sendAccessibilityEvent(View host, int eventType) {

// 計算 currentIndex

}

@Override

public boolean dispatchPopulateAccessibilityEvent(View, AccessibilityEvent) {

int type = event.getEventType();

if (type == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED) {

event.getText().add("總共 10 項, 目前顯示第 " + (currentIndex + 1) +

" 項.");

}

return super.dispatchPopulateAccessibilityEvent(host, event);

}

};

Page 17: Android Accessibility

AccessibilityNodeInfoprotected int currentIndex = 0;

public void sendAccessibilityEvent(View host, int eventType) {

if (eventType == AccessibilityEvent.TYPE_VIEW_SCROLLED) {

currentIndex = mHScrollView.getScrollX() / 900;

}

super.sendAccessibilityEvent(host, eventType);

}

public boolean dispatchPopulateAccessibilityEvent(View host,AccessibilityEvent event) {

if (event.getEventType() == TYPE_VIEW_ACCESSIBILITY_FOCUSED) {

event.getText().add("向左或向右滑動可選擇不同圖片");

}

return super.dispatchPopulateAccessibilityEvent(host, event);

}

Page 18: Android Accessibility

AccessibilityNodeInfopublic void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {

event.setScrollable(true);

event.setItemCount(10);

event.setFromIndex(currentIndex);

super.onInitializeAccessibilityEvent(host, event);

}

public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {

info.setScrollable(true);

super.onInitializeAccessibilityNodeInfo(host, info);

}

Page 19: Android Accessibility

AccessibilityNodeInfoprivate boolean mChecked = false;

public View onCreateView(LayoutInflater, ViewGroup, Bundle) {

btn.setOnClickListener(onChangeContentBClicked);

btn.setAccessibilityDelegate(buttonAccessibilityDelegate);

}

private View.OnClickListener onChangeContentBClicked = new View.OnClickListener() {

@Override

public void onClick(View v) {

mChecked = !mChecked;

}

};

Page 20: Android Accessibility

AccessibilityNodeInfoprivate AccessibilityDelegate buttonAccessibilityDelegate = new AccessibilityDelegate() {

@Override

public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {

super.onInitializeAccessibilityEvent(host, event);

event.setChecked(mChecked);

}

@Override

public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {

super.onInitializeAccessibilityNodeInfo(host, info);

info.setCheckable(true);

info.setChecked(mChecked);

}

};

Page 21: Android Accessibility

announceForAccessibility

public boolean onHoverEvent(MotionEvent event) {

int currentPos = getBlock(event.getX(), event.getY());

if (currentPos != prePos) {

prePos = currentPos;

if (currentPos == 0) {

announceForAccessibility("左上方"); // API 16

} else if (currentPos == 1) {

announceForAccessibility("左下方");

} ...

}

return super.onHoverEvent(event);

}

Page 22: Android Accessibility

Reference

https://github.com/aduggin/android-accessibility

https://www.youtube.com/watch?v=BPXqsPeCneA

https://www.youtube.com/watch?v=q3HliaMjL38

https://developer.android.com/guide/topics/ui/accessibility/index.html

http://developer.android.com/design/patterns/accessibility.html

https://github.com/googlesamples/android-BasicAccessibility