下面列出了怎么用android.view.accessibility.AccessibilityEvent的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Called when the user clicks on a day. Handles callbacks to the
* {@link OnDayClickListener} if one is set.
*
* @param day the day that was clicked
*/
private boolean onDayClicked(int day) {
if (!isValidDayOfMonth(day) || !isDayEnabled(day)) {
return false;
}
if (mOnDayClickListener != null) {
final Calendar date = Calendar.getInstance();
date.set(mYear, mMonth, day);
mOnDayClickListener.onDayClick(this, date);
}
// This is a no-op if accessibility is turned off.
mTouchHelper.sendEventForVirtualView(day, AccessibilityEvent.TYPE_VIEW_CLICKED);
return true;
}
private void scheduleAnnouncement(AccessibilityEvent event, EventId eventId) {
// Scrolling a ViewPager2 also scrolls its tabs. Suppress the tab scroll announcement if the
// scheduled announcement originates from a page scroll, so the page position announcement isn't
// stopped. There's only a small possibility that this suppressed event comes from an unrelated
// HorizontalScrollView within the 500ms time frame.
if (Role.getSourceRole(eventToAnnounce) == Role.ROLE_PAGER) {
if (Role.getSourceRole(event) == Role.ROLE_HORIZONTAL_SCROLL_VIEW) {
return;
}
}
clearCachedEvent();
eventToAnnounce = AccessibilityEvent.obtain(event);
this.eventId = eventId;
delayHandler.removeMessages();
delayHandler.delay(
(Role.getSourceRole(event) == Role.ROLE_PAGER)
? DELAY_PAGE_FEEDBACK
: DELAY_SCROLL_FEEDBACK,
null);
}
private void updateAmPmControl() {
if (is24Hour()) {
if (mAmPmSpinner != null) {
mAmPmSpinner.setVisibility(View.GONE);
} else {
mAmPmButton.setVisibility(View.GONE);
}
} else {
int index = mIsAm ? Calendar.AM : Calendar.PM;
if (mAmPmSpinner != null) {
mAmPmSpinner.setValue(index);
mAmPmSpinner.setVisibility(View.VISIBLE);
} else {
mAmPmButton.setText(mAmPmStrings[index]);
mAmPmButton.setVisibility(View.VISIBLE);
}
}
mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
// ViewPagers should only report accessibility info for the current page,
// otherwise things get very confusing.
// TODO: Should this note something about the paging container?
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == VISIBLE) {
final ItemInfo ii = infoForChild(child);
if (ii != null && ii.position == mCurItem &&
child.dispatchPopulateAccessibilityEvent(event)) {
return true;
}
}
}
return false;
}
@Override
public void setSelected(final boolean selected) {
final boolean changed = isSelected() != selected;
super.setSelected(selected);
if (changed && selected && Build.VERSION.SDK_INT < 16) {
// Pre-JB we need to manually send the TYPE_VIEW_SELECTED event
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
// Always dispatch this to the child views, regardless of whether the value has
// changed
if (textView != null) {
textView.setSelected(selected);
}
if (iconView != null) {
iconView.setSelected(selected);
}
if (customView != null) {
customView.setSelected(selected);
}
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
// Dispatch scroll events from this ViewPager.
if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED) {
return super.dispatchPopulateAccessibilityEvent(event);
}
// Dispatch all other accessibility events from the current page.
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == VISIBLE) {
final ItemInfo ii = infoForChild(child);
if (ii != null && ii.position == mCurItem &&
child.dispatchPopulateAccessibilityEvent(event)) {
return true;
}
}
}
return false;
}
private int getClickType(AccessibilityEvent event) {
int type = event.getEventType();
long time = event.getEventTime();
long id = getSourceNodeId(event);
if (type != TYPE_VIEW_CLICKED) {
mLastClickTime = time;
mLastSourceNodeId = -1;
return type;
}
if (id == -1) {
mLastClickTime = time;
mLastSourceNodeId = -1;
return type;
}
if (type == TYPE_VIEW_CLICKED && time - mLastClickTime <= double_click_interval && id == mLastSourceNodeId) {
mLastClickTime = -1;
mLastSourceNodeId = -1;
return TYPE_VIEW_DOUBLD_CLICKED;
} else {
mLastClickTime = time;
mLastSourceNodeId = id;
return type;
}
}
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
switch (event.getEventType()) {
case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
Parcelable parcelable = event.getParcelableData();
if (parcelable instanceof Notification) {
if (Device.hasJellyBeanMR2Api()) {
// No need to use the accessibility service
// instead of NotificationListener.
return;
}
Notification notification = (Notification) parcelable;
OpenNotification openNotification = OpenNotification.newInstance(notification);
NotificationPresenter.getInstance().postNotificationFromMain(this, openNotification, 0);
}
break;
}
}
@Override
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
// Dispatch scroll events from this ViewPager.
if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED) {
return super.dispatchPopulateAccessibilityEvent(event);
}
// Dispatch all other accessibility events from the current page.
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == VISIBLE) {
final ItemInfo ii = infoForChild(child);
if (ii != null && ii.position == mCurItem &&
child.dispatchPopulateAccessibilityEvent(event)) {
return true;
}
}
}
return false;
}
void selectionChanged() {
if (mOnItemSelectedListener != null) {
if (mInLayout || mBlockLayoutRequests) {
// If we are in a layout traversal, defer notification
// by posting. This ensures that the view tree is
// in a consistent state and is able to accomodate
// new layout or invalidate requests.
if (mSelectionNotifier == null) {
mSelectionNotifier = new SelectionNotifier();
}
post(mSelectionNotifier);
} else {
fireOnSelected();
}
}
// we fire selection events here not in View
if (mSelectedPosition != ListView.INVALID_POSITION && isShown() && !isInTouchMode()) {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
}
private void updateAmPmControl() {
if (is24HourView()) {
if (mAmPmSpinner != null) {
mAmPmSpinner.setVisibility(View.GONE);
} else {
mAmPmButton.setVisibility(View.GONE);
}
} else {
int index = mIsAm ? Calendar.AM : Calendar.PM;
if (mAmPmSpinner != null) {
mAmPmSpinner.setValue(index);
mAmPmSpinner.setVisibility(View.VISIBLE);
} else {
mAmPmButton.setText(mAmPmStrings[index]);
mAmPmButton.setVisibility(View.VISIBLE);
}
}
mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
void selectionChanged() {
if (mOnItemSelectedListener != null) {
if (mInLayout || mBlockLayoutRequests) {
// If we are in a layout traversal, defer notification
// by posting. This ensures that the view tree is
// in a consistent state and is able to accomodate
// new layout or invalidate requests.
if (mSelectionNotifier == null) {
mSelectionNotifier = new SelectionNotifier();
}
post(mSelectionNotifier);
} else {
fireOnSelected();
}
}
// we fire selection events here not in View
if (mSelectedPosition != ListView.INVALID_POSITION && isShown() && !isInTouchMode()) {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
}
}
/**
* Constructs and returns an {@link AccessibilityEvent} populated with
* information about the specified item.
*
* @param virtualViewId The virtual view id for the item for which to
* construct an event.
* @param eventType The type of event to construct.
* @return An {@link AccessibilityEvent} populated with information about
* the specified item.
*/
private AccessibilityEvent getEventForVirtualViewId(int virtualViewId, int eventType) {
final AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
// Ensure the client has good defaults.
event.setEnabled(true);
event.setClassName(mHost.getClass().getName() + DEFAULT_CLASS_NAME);
// Allow the client to populate the event.
populateEventForVirtualViewId(virtualViewId, event);
if (event.getText().isEmpty() && TextUtils.isEmpty(event.getContentDescription())) {
throw new RuntimeException(
"You must add text or a content description in populateEventForItem()");
}
// Don't allow the client to override these properties.
event.setPackageName(mHost.getContext().getPackageName());
// Virtual view hierarchies are only supported in API 16+.
final AccessibilityRecordCompat record = new AccessibilityRecordCompat(event);
record.setSource(mHost, virtualViewId);
return event;
}
/**
* set text into input text at USSD widget
*
* @param event AccessibilityEvent
* @param data Any String
*/
private static void setTextIntoField(AccessibilityEvent event, String data) {
USSDController ussdController = USSDController.instance;
Bundle arguments = new Bundle();
arguments.putCharSequence(
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, data);
for (AccessibilityNodeInfo leaf : getLeaves(event)) {
if (leaf.getClassName().equals("android.widget.EditText")
&& !leaf.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments)) {
ClipboardManager clipboardManager = ((ClipboardManager) ussdController.context
.getSystemService(Context.CLIPBOARD_SERVICE));
if (clipboardManager != null) {
clipboardManager.setPrimaryClip(ClipData.newPlainText("text", data));
}
leaf.performAction(AccessibilityNodeInfo.ACTION_PASTE);
}
}
}
@Override
public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
AccessibilityEvent event) {
if (!filter(child)) {
return super.onRequestSendAccessibilityEvent(host, child, event);
}
return false;
}
@Override
public boolean requestSendAccessibilityEvent(
ViewParent parent, View child, AccessibilityEvent event) {
// Emulate what ViewRootImpl does in ICS and above.
if (child == null) {
return false;
}
final AccessibilityManager manager = (AccessibilityManager) child.getContext()
.getSystemService(Context.ACCESSIBILITY_SERVICE);
manager.sendAccessibilityEvent(event);
return true;
}
public static boolean isFromVolumeControlPanel(AccessibilityEvent event) {
// Volume slider case.
// TODO: Find better way to handle volume slider.
CharSequence sourceClassName = event.getClassName();
boolean isVolumeInAndroidP =
BuildVersionUtils.isAtLeastP()
&& TextUtils.equals(sourceClassName, VOLUME_CONTROLS_CLASS_IN_ANDROID_P);
boolean isVolumeInAndroidO =
BuildVersionUtils.isAtLeastO()
&& (!BuildVersionUtils.isAtLeastP())
&& TextUtils.equals(sourceClassName, DIALOG_CLASS_NAME);
return isVolumeInAndroidO || isVolumeInAndroidP;
}
private void sendAccessibilityEventForVirtualText(int eventType) {
AccessibilityManager acm = (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
if (acm.isEnabled()) {
AccessibilityEvent event = AccessibilityEvent.obtain(eventType);
mInputText.onInitializeAccessibilityEvent(event);
mInputText.onPopulateAccessibilityEvent(event);
event.setSource(NumberPicker.this, VIRTUAL_VIEW_ID_INPUT);
requestSendAccessibilityEvent(NumberPicker.this, event);
}
}
private void onViewFocused(AccessibilityEvent event, AccessibilityNodeInfo rootNode) {
if(mEvent != null && event != null) {
// Store Text Input.
AccEvent accEvent = new AccEvent(event, rootNode);
accEvent.setFieldValue(AccEvent.TEXT, mEvent.text);
this.output(accEvent);
}
this.mEvent = null;
}
public void onNotificationChanged(AccessibilityEvent event) {
List<CharSequence> texts = event.getText();
if (texts.isEmpty())
return;
for (CharSequence text : texts) {
String string = text + "";
Log.w(TAG, "Notification text: " + string);
if (string.equals("你的帐号在电脑登录"))
return;
StringBuilder builder = new StringBuilder(string);
int i1 = string.indexOf("[特别关注]");
int i2 = string.indexOf("[有新回复]");
if (i1 != -1 && i1 + 6 < string.length())
builder.delete(i1, i1 + 6);
if (i2 != -1 && i2 + 6 < string.length())
builder.delete(i2, i2 + 6);
string = builder.toString();
int i = string.indexOf(':');
if (i < 1) {
Log.d(TAG, "Notification does not contains ':'");
return;
}
title = string.substring(0, i);
message = string.substring(i + 2);
subName = title;
//是群消息
int j = title.indexOf('(');
if (j > 0 && title.charAt(i - 1) == ')') {
message = string.substring(i + 1);
subName = title.substring(0, j);
title = title.substring(j + 1, i - 1);
}
addMsg(true);
}
}
@Override
public boolean performAction(int virtualViewId, int action, Bundle arguments) {
if (virtualViewId == View.NO_ID) {
return ViewCompat.performAccessibilityAction(mParentView, action, arguments);
}
final T item = getItemForId(virtualViewId);
if (item == null) {
return false;
}
boolean handled = false;
switch (action) {
case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:
if (mFocusedItemId != virtualViewId) {
mFocusedItemId = virtualViewId;
sendEventForItem(item, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
handled = true;
}
break;
case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
if (mFocusedItemId == virtualViewId) {
mFocusedItemId = INVALID_ID;
sendEventForItem(item, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
handled = true;
}
break;
}
handled |= performActionForItem(item, action, arguments);
return handled;
}
/**
* Gets target child node from the source AdapterView node.
*
* <p><strong>Note:</strong> Caller is responsible for recycling the returned node.
*/
private static @Nullable AccessibilityNodeInfoCompat getTargetChildFromAdapterView(
AccessibilityEvent event) {
AccessibilityNodeInfoCompat sourceNode = null;
try {
sourceNode = AccessibilityNodeInfoUtils.toCompat(event.getSource());
if (sourceNode == null) {
return null;
}
if (event.getItemCount() <= 0
|| event.getFromIndex() < 0
|| event.getCurrentItemIndex() < 0) {
return null;
}
int index = event.getCurrentItemIndex() - event.getFromIndex();
if (index < 0 || index >= sourceNode.getChildCount()) {
return null;
}
AccessibilityNodeInfoCompat targetChildNode = sourceNode.getChild(index);
// TODO: Think about to replace childNode check with sourceNode check.
if ((targetChildNode == null)
|| !AccessibilityNodeInfoUtils.isTopLevelScrollItem(targetChildNode)) {
AccessibilityNodeInfoUtils.recycleNodes(targetChildNode);
return null;
} else {
return targetChildNode;
}
} finally {
AccessibilityNodeInfoUtils.recycleNodes(sourceNode);
}
}
@Override
public void scrollToAndFocus() {
ViewGroup parent = (ViewGroup) getParent();
if (parent != null) parent.requestChildFocus(this, this);
requestFocus();
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
}
@Override
public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(host, event);
event.setClassName(RecyclerView.class.getName());
if (host instanceof RecyclerView) {
RecyclerView rv = (RecyclerView) host;
if (rv.getLayoutManager() != null) {
rv.getLayoutManager().onInitializeAccessibilityEvent(event);
}
}
}
/**
* Processes an <code>event</code> by asking the {@link Compositor} to match it against its rules
* and in case an utterance is generated it is spoken. This method is responsible for recycling of
* the processed event.
*
* @param event The event to process.
*/
private void processAndRecycleEvent(AccessibilityEvent event, EventId eventId) {
if (event == null) {
return;
}
LogUtils.d(TAG, "Processing event: %s", event);
eventFilter.sendEvent(event, eventId);
event.recycle();
}
/**
* Opens the drawer immediately.
*
* @see #toggle()
* @see #close()
* @see #animateOpen()
*/
public void open() {
openDrawer();
invalidate();
requestLayout();
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
@Override
public boolean handleMessage(Message msg) {
switch(msg.what) {
case MSG_VIEW_SCROLLED:
mMsgViewScrolledQueued = false;
mEventSender.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
break;
default:
throw new IllegalStateException(
"AccessibilityInjector: unhandled message: " + msg.what);
}
return true;
}
@Override
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
if (super.onRequestSendAccessibilityEvent(child, event)) {
// Add a record for ourselves as well.
AccessibilityEvent record = AccessibilityEvent.obtain();
onInitializeAccessibilityEvent(record);
// Populate with the text of the requesting child.
child.dispatchPopulateAccessibilityEvent(record);
event.appendRecord(record);
return true;
}
return false;
}
void dispatchOnDrawerClosed(View drawerView) {
final LayoutParams lp = (LayoutParams) drawerView.getLayoutParams();
if (lp.knownOpen) {
lp.knownOpen = false;
if (mListener != null) {
mListener.onDrawerClosed(drawerView);
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
}
}
@Override
public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(host, event);
event.setClassName(ViewPager.class.getName());
final AccessibilityRecordCompat recordCompat = AccessibilityRecordCompat.obtain();
recordCompat.setScrollable(canScroll());
if (event.getEventType() == AccessibilityEventCompat.TYPE_VIEW_SCROLLED
&& mAdapter != null) {
recordCompat.setItemCount(mAdapter.getCount());
recordCompat.setFromIndex(mCurItem);
recordCompat.setToIndex(mCurItem);
}
}