use of android.view.accessibility.AccessibilityNodeProvider in project android_frameworks_base by crdroidandroid.
the class GridView method layoutChildren.
@Override
protected void layoutChildren() {
final boolean blockLayoutRequests = mBlockLayoutRequests;
if (!blockLayoutRequests) {
mBlockLayoutRequests = true;
}
try {
super.layoutChildren();
invalidate();
if (mAdapter == null) {
resetList();
invokeOnItemScrollListener();
return;
}
final int childrenTop = mListPadding.top;
final int childrenBottom = mBottom - mTop - mListPadding.bottom;
int childCount = getChildCount();
int index;
int delta = 0;
View sel;
View oldSel = null;
View oldFirst = null;
View newSel = null;
// Remember stuff we will need down below
switch(mLayoutMode) {
case LAYOUT_SET_SELECTION:
index = mNextSelectedPosition - mFirstPosition;
if (index >= 0 && index < childCount) {
newSel = getChildAt(index);
}
break;
case LAYOUT_FORCE_TOP:
case LAYOUT_FORCE_BOTTOM:
case LAYOUT_SPECIFIC:
case LAYOUT_SYNC:
break;
case LAYOUT_MOVE_SELECTION:
if (mNextSelectedPosition >= 0) {
delta = mNextSelectedPosition - mSelectedPosition;
}
break;
default:
// Remember the previously selected view
index = mSelectedPosition - mFirstPosition;
if (index >= 0 && index < childCount) {
oldSel = getChildAt(index);
}
// Remember the previous first child
oldFirst = getChildAt(0);
}
boolean dataChanged = mDataChanged;
if (dataChanged) {
handleDataChanged();
}
// and calling it a day
if (mItemCount == 0) {
resetList();
invokeOnItemScrollListener();
return;
}
setSelectedPositionInt(mNextSelectedPosition);
AccessibilityNodeInfo accessibilityFocusLayoutRestoreNode = null;
View accessibilityFocusLayoutRestoreView = null;
int accessibilityFocusPosition = INVALID_POSITION;
// Remember which child, if any, had accessibility focus. This must
// occur before recycling any views, since that will clear
// accessibility focus.
final ViewRootImpl viewRootImpl = getViewRootImpl();
if (viewRootImpl != null) {
final View focusHost = viewRootImpl.getAccessibilityFocusedHost();
if (focusHost != null) {
final View focusChild = getAccessibilityFocusedChild(focusHost);
if (focusChild != null) {
if (!dataChanged || focusChild.hasTransientState() || mAdapterHasStableIds) {
// The views won't be changing, so try to maintain
// focus on the current host and virtual view.
accessibilityFocusLayoutRestoreView = focusHost;
accessibilityFocusLayoutRestoreNode = viewRootImpl.getAccessibilityFocusedVirtualView();
}
// Try to maintain focus at the same position.
accessibilityFocusPosition = getPositionForView(focusChild);
}
}
}
// Pull all children into the RecycleBin.
// These views will be reused if possible
final int firstPosition = mFirstPosition;
final RecycleBin recycleBin = mRecycler;
if (dataChanged) {
for (int i = 0; i < childCount; i++) {
recycleBin.addScrapView(getChildAt(i), firstPosition + i);
}
} else {
recycleBin.fillActiveViews(childCount, firstPosition);
}
// Clear out old views
detachAllViewsFromParent();
recycleBin.removeSkippedScrap();
switch(mLayoutMode) {
case LAYOUT_SET_SELECTION:
if (newSel != null) {
sel = fillFromSelection(newSel.getTop(), childrenTop, childrenBottom);
} else {
sel = fillSelection(childrenTop, childrenBottom);
}
break;
case LAYOUT_FORCE_TOP:
mFirstPosition = 0;
sel = fillFromTop(childrenTop);
adjustViewsUpOrDown();
break;
case LAYOUT_FORCE_BOTTOM:
sel = fillUp(mItemCount - 1, childrenBottom);
adjustViewsUpOrDown();
break;
case LAYOUT_SPECIFIC:
sel = fillSpecific(mSelectedPosition, mSpecificTop);
break;
case LAYOUT_SYNC:
sel = fillSpecific(mSyncPosition, mSpecificTop);
break;
case LAYOUT_MOVE_SELECTION:
// Move the selection relative to its old position
sel = moveSelection(delta, childrenTop, childrenBottom);
break;
default:
if (childCount == 0) {
if (!mStackFromBottom) {
setSelectedPositionInt(mAdapter == null || isInTouchMode() ? INVALID_POSITION : 0);
sel = fillFromTop(childrenTop);
} else {
final int last = mItemCount - 1;
setSelectedPositionInt(mAdapter == null || isInTouchMode() ? INVALID_POSITION : last);
sel = fillFromBottom(last, childrenBottom);
}
} else {
if (mSelectedPosition >= 0 && mSelectedPosition < mItemCount) {
sel = fillSpecific(mSelectedPosition, oldSel == null ? childrenTop : oldSel.getTop());
} else if (mFirstPosition < mItemCount) {
sel = fillSpecific(mFirstPosition, oldFirst == null ? childrenTop : oldFirst.getTop());
} else {
sel = fillSpecific(0, childrenTop);
}
}
break;
}
// Flush any cached views that did not get reused above
recycleBin.scrapActiveViews();
if (sel != null) {
positionSelector(INVALID_POSITION, sel);
mSelectedTop = sel.getTop();
} else {
final boolean inTouchMode = mTouchMode > TOUCH_MODE_DOWN && mTouchMode < TOUCH_MODE_SCROLL;
if (inTouchMode) {
// If the user's finger is down, select the motion position.
final View child = getChildAt(mMotionPosition - mFirstPosition);
if (child != null) {
positionSelector(mMotionPosition, child);
}
} else if (mSelectedPosition != INVALID_POSITION) {
// If we had previously positioned the selector somewhere,
// put it back there. It might not match up with the data,
// but it's transitioning out so it's not a big deal.
final View child = getChildAt(mSelectorPosition - mFirstPosition);
if (child != null) {
positionSelector(mSelectorPosition, child);
}
} else {
// Otherwise, clear selection.
mSelectedTop = 0;
mSelectorRect.setEmpty();
}
}
// Attempt to restore accessibility focus, if necessary.
if (viewRootImpl != null) {
final View newAccessibilityFocusedView = viewRootImpl.getAccessibilityFocusedHost();
if (newAccessibilityFocusedView == null) {
if (accessibilityFocusLayoutRestoreView != null && accessibilityFocusLayoutRestoreView.isAttachedToWindow()) {
final AccessibilityNodeProvider provider = accessibilityFocusLayoutRestoreView.getAccessibilityNodeProvider();
if (accessibilityFocusLayoutRestoreNode != null && provider != null) {
final int virtualViewId = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityFocusLayoutRestoreNode.getSourceNodeId());
provider.performAction(virtualViewId, AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null);
} else {
accessibilityFocusLayoutRestoreView.requestAccessibilityFocus();
}
} else if (accessibilityFocusPosition != INVALID_POSITION) {
// Bound the position within the visible children.
final int position = MathUtils.constrain(accessibilityFocusPosition - mFirstPosition, 0, getChildCount() - 1);
final View restoreView = getChildAt(position);
if (restoreView != null) {
restoreView.requestAccessibilityFocus();
}
}
}
}
mLayoutMode = LAYOUT_NORMAL;
mDataChanged = false;
if (mPositionScrollAfterLayout != null) {
post(mPositionScrollAfterLayout);
mPositionScrollAfterLayout = null;
}
mNeedSync = false;
setNextSelectedPositionInt(mSelectedPosition);
updateScrollIndicators();
if (mItemCount > 0) {
checkSelectionChanged();
}
invokeOnItemScrollListener();
} finally {
if (!blockLayoutRequests) {
mBlockLayoutRequests = false;
}
}
}
use of android.view.accessibility.AccessibilityNodeProvider in project android_frameworks_base by DirtyUnicorns.
the class AccessibilityInteractionController method performAccessibilityActionUiThread.
private void performAccessibilityActionUiThread(Message message) {
final int flags = message.arg1;
final int accessibilityViewId = message.arg2;
SomeArgs args = (SomeArgs) message.obj;
final int virtualDescendantId = args.argi1;
final int action = args.argi2;
final int interactionId = args.argi3;
final IAccessibilityInteractionConnectionCallback callback = (IAccessibilityInteractionConnectionCallback) args.arg1;
Bundle arguments = (Bundle) args.arg2;
args.recycle();
boolean succeeded = false;
try {
if (mViewRootImpl.mView == null || mViewRootImpl.mAttachInfo == null || mViewRootImpl.mStopped || mViewRootImpl.mPausedForTransition) {
return;
}
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
View target = null;
if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
target = findViewByAccessibilityId(accessibilityViewId);
} else {
target = mViewRootImpl.mView;
}
if (target != null && isShown(target)) {
AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
if (provider != null) {
if (virtualDescendantId != AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
succeeded = provider.performAction(virtualDescendantId, action, arguments);
} else {
succeeded = provider.performAction(AccessibilityNodeProvider.HOST_VIEW_ID, action, arguments);
}
} else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
succeeded = target.performAccessibilityAction(action, arguments);
}
}
} finally {
try {
mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = 0;
callback.setPerformAccessibilityActionResult(succeeded, interactionId);
} catch (RemoteException re) {
/* ignore - the other side will time out */
}
}
}
use of android.view.accessibility.AccessibilityNodeProvider in project android_frameworks_base by DirtyUnicorns.
the class ViewRootImpl method getAccessibilityFocusedRect.
private boolean getAccessibilityFocusedRect(Rect bounds) {
final AccessibilityManager manager = AccessibilityManager.getInstance(mView.mContext);
if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) {
return false;
}
final View host = mAccessibilityFocusedHost;
if (host == null || host.mAttachInfo == null) {
return false;
}
final AccessibilityNodeProvider provider = host.getAccessibilityNodeProvider();
if (provider == null) {
host.getBoundsOnScreen(bounds, true);
} else if (mAccessibilityFocusedVirtualView != null) {
mAccessibilityFocusedVirtualView.getBoundsInScreen(bounds);
} else {
return false;
}
// Transform the rect into window-relative coordinates.
final AttachInfo attachInfo = mAttachInfo;
bounds.offset(0, attachInfo.mViewRootImpl.mScrollY);
bounds.offset(-attachInfo.mWindowLeft, -attachInfo.mWindowTop);
if (!bounds.intersect(0, 0, attachInfo.mViewRootImpl.mWidth, attachInfo.mViewRootImpl.mHeight)) {
// If no intersection, set bounds to empty.
bounds.setEmpty();
}
return !bounds.isEmpty();
}
use of android.view.accessibility.AccessibilityNodeProvider in project android_frameworks_base by DirtyUnicorns.
the class ViewRootImpl method setAccessibilityFocus.
void setAccessibilityFocus(View view, AccessibilityNodeInfo node) {
// to clear the focus and invalidate the virtual view bounds.
if (mAccessibilityFocusedVirtualView != null) {
AccessibilityNodeInfo focusNode = mAccessibilityFocusedVirtualView;
View focusHost = mAccessibilityFocusedHost;
// Wipe the state of the current accessibility focus since
// the call into the provider to clear accessibility focus
// will fire an accessibility event which will end up calling
// this method and we want to have clean state when this
// invocation happens.
mAccessibilityFocusedHost = null;
mAccessibilityFocusedVirtualView = null;
// Clear accessibility focus on the host after clearing state since
// this method may be reentrant.
focusHost.clearAccessibilityFocusNoCallbacks(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
AccessibilityNodeProvider provider = focusHost.getAccessibilityNodeProvider();
if (provider != null) {
// Invalidate the area of the cleared accessibility focus.
focusNode.getBoundsInParent(mTempRect);
focusHost.invalidate(mTempRect);
// Clear accessibility focus in the virtual node.
final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(focusNode.getSourceNodeId());
provider.performAction(virtualNodeId, AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS, null);
}
focusNode.recycle();
}
if ((mAccessibilityFocusedHost != null) && (mAccessibilityFocusedHost != view)) {
// Clear accessibility focus in the view.
mAccessibilityFocusedHost.clearAccessibilityFocusNoCallbacks(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS);
}
// Set the new focus host and node.
mAccessibilityFocusedHost = view;
mAccessibilityFocusedVirtualView = node;
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.invalidateRoot();
}
}
use of android.view.accessibility.AccessibilityNodeProvider in project android_frameworks_base by DirtyUnicorns.
the class ViewRootImpl method handleWindowContentChangedEvent.
/**
* Updates the focused virtual view, when necessary, in response to a
* content changed event.
* <p>
* This is necessary to get updated bounds after a position change.
*
* @param event an accessibility event of type
* {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
*/
private void handleWindowContentChangedEvent(AccessibilityEvent event) {
final View focusedHost = mAccessibilityFocusedHost;
if (focusedHost == null || mAccessibilityFocusedVirtualView == null) {
// No virtual view focused, nothing to do here.
return;
}
final AccessibilityNodeProvider provider = focusedHost.getAccessibilityNodeProvider();
if (provider == null) {
// Error state: virtual view with no provider. Clear focus.
mAccessibilityFocusedHost = null;
mAccessibilityFocusedVirtualView = null;
focusedHost.clearAccessibilityFocusNoCallbacks(0);
return;
}
// We only care about change types that may affect the bounds of the
// focused virtual view.
final int changes = event.getContentChangeTypes();
if ((changes & AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) == 0 && changes != AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED) {
return;
}
final long eventSourceNodeId = event.getSourceNodeId();
final int changedViewId = AccessibilityNodeInfo.getAccessibilityViewId(eventSourceNodeId);
// Search up the tree for subtree containment.
boolean hostInSubtree = false;
View root = mAccessibilityFocusedHost;
while (root != null && !hostInSubtree) {
if (changedViewId == root.getAccessibilityViewId()) {
hostInSubtree = true;
} else {
final ViewParent parent = root.getParent();
if (parent instanceof View) {
root = (View) parent;
} else {
root = null;
}
}
}
// We care only about changes in subtrees containing the host view.
if (!hostInSubtree) {
return;
}
final long focusedSourceNodeId = mAccessibilityFocusedVirtualView.getSourceNodeId();
int focusedChildId = AccessibilityNodeInfo.getVirtualDescendantId(focusedSourceNodeId);
if (focusedChildId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
// TODO: Should we clear the focused virtual view?
focusedChildId = AccessibilityNodeProvider.HOST_VIEW_ID;
}
// Refresh the node for the focused virtual view.
final Rect oldBounds = mTempRect;
mAccessibilityFocusedVirtualView.getBoundsInScreen(oldBounds);
mAccessibilityFocusedVirtualView = provider.createAccessibilityNodeInfo(focusedChildId);
if (mAccessibilityFocusedVirtualView == null) {
// Error state: The node no longer exists. Clear focus.
mAccessibilityFocusedHost = null;
focusedHost.clearAccessibilityFocusNoCallbacks(0);
// This will probably fail, but try to keep the provider's internal
// state consistent by clearing focus.
provider.performAction(focusedChildId, AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS.getId(), null);
invalidateRectOnScreen(oldBounds);
} else {
// The node was refreshed, invalidate bounds if necessary.
final Rect newBounds = mAccessibilityFocusedVirtualView.getBoundsInScreen();
if (!oldBounds.equals(newBounds)) {
oldBounds.union(newBounds);
invalidateRectOnScreen(oldBounds);
}
}
}
Aggregations