diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml index 5d184faca..608220a53 100644 --- a/samples/ApiDemos/AndroidManifest.xml +++ b/samples/ApiDemos/AndroidManifest.xml @@ -995,16 +995,6 @@ - - - - - - - - diff --git a/samples/ApiDemos/res/layout/accessibility_node_provider.xml b/samples/ApiDemos/res/layout/accessibility_node_provider.xml deleted file mode 100644 index cc10c9cd2..000000000 --- a/samples/ApiDemos/res/layout/accessibility_node_provider.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - diff --git a/samples/ApiDemos/res/values/strings.xml b/samples/ApiDemos/res/values/strings.xml index 8fd182a7f..d81f76920 100644 --- a/samples/ApiDemos/res/values/strings.xml +++ b/samples/ApiDemos/res/values/strings.xml @@ -1427,10 +1427,6 @@ - Accessibility/Accessibility Node Provider - Enable TalkBack and Explore-by-touch from accessibility - settings. Then touch the colored squares. - Accessibility/Accessibility Service ClockBack diff --git a/samples/ApiDemos/src/com/example/android/apis/accessibility/AccessibilityNodeProviderActivity.java b/samples/ApiDemos/src/com/example/android/apis/accessibility/AccessibilityNodeProviderActivity.java deleted file mode 100644 index 1ca036a55..000000000 --- a/samples/ApiDemos/src/com/example/android/apis/accessibility/AccessibilityNodeProviderActivity.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.apis.accessibility; - -import com.example.android.apis.R; - -import android.app.Activity; -import android.app.Service; -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.os.Bundle; -import android.text.TextUtils; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.accessibility.AccessibilityEvent; -import android.view.accessibility.AccessibilityManager; -import android.view.accessibility.AccessibilityNodeInfo; -import android.view.accessibility.AccessibilityNodeProvider; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - * This sample demonstrates how a View can expose a virtual view sub-tree - * rooted at it. A virtual sub-tree is composed of imaginary Views - * that are reported as a part of the view hierarchy for accessibility - * purposes. This enables custom views that draw complex content to report - * them selves as a tree of virtual views, thus conveying their logical - * structure. - *

- * For example, a View may draw a monthly calendar as a grid of days while - * each such day may contains some events. From a perspective of the View - * hierarchy the calendar is composed of a single View but an accessibility - * service would benefit of traversing the logical structure of the calendar - * by examining each day and each event on that day. - *

- */ -public class AccessibilityNodeProviderActivity extends Activity { - /** Called when the activity is first created. */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.accessibility_node_provider); - } - - /** - * This class presents a View that is composed of three virtual children - * each of which is drawn with a different color and represents a region - * of the View that has different semantics compared to other such regions. - * While the virtual view tree exposed by this class is one level deep - * for simplicity, there is no bound on the complexity of that virtual - * sub-tree. - */ - public static class VirtualSubtreeRootView extends View { - - /** Paint object for drawing the virtual sub-tree */ - private final Paint mPaint = new Paint(); - - /** Temporary rectangle to minimize object creation. */ - private final Rect mTempRect = new Rect(); - - /** Handle to the system accessibility service. */ - private final AccessibilityManager mAccessibilityManager; - - /** The virtual children of this View. */ - private final List mChildren = new ArrayList(); - - /** The instance of the node provider for the virtual tree - lazily instantiated. */ - private AccessibilityNodeProvider mAccessibilityNodeProvider; - - /** The last hovered child used for event dispatching. */ - private VirtualView mLastHoveredChild; - - public VirtualSubtreeRootView(Context context, AttributeSet attrs) { - super(context, attrs); - mAccessibilityManager = (AccessibilityManager) context.getSystemService( - Service.ACCESSIBILITY_SERVICE); - createVirtualChildren(); - } - - /** - * {@inheritDoc} - */ - @Override - public AccessibilityNodeProvider getAccessibilityNodeProvider() { - // Instantiate the provide only when requested. Since the system - // will call this method multiple times it is a good practice to - // cache the provider instance. - if (mAccessibilityNodeProvider == null) { - mAccessibilityNodeProvider = new VirtualDescendantsProvider(); - } - return mAccessibilityNodeProvider; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean dispatchHoverEvent(MotionEvent event) { - // This implementation assumes that the virtual children - // cannot overlap and are always visible. Do NOT use this - // code as a reference of how to implement hover event - // dispatch. Instead, refer to ViewGroup#dispatchHoverEvent. - boolean handled = false; - List children = mChildren; - final int childCount = children.size(); - for (int i = 0; i < childCount; i++) { - VirtualView child = children.get(i); - Rect childBounds = child.mBounds; - final int childCoordsX = (int) event.getX() + getScrollX(); - final int childCoordsY = (int) event.getY() + getScrollY(); - if (!childBounds.contains(childCoordsX, childCoordsY)) { - continue; - } - final int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_HOVER_ENTER: { - mLastHoveredChild = child; - handled |= onHoverVirtualView(child, event); - event.setAction(action); - } break; - case MotionEvent.ACTION_HOVER_MOVE: { - if (child == mLastHoveredChild) { - handled |= onHoverVirtualView(child, event); - event.setAction(action); - } else { - MotionEvent eventNoHistory = event.getHistorySize() > 0 - ? MotionEvent.obtainNoHistory(event) : event; - eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); - onHoverVirtualView(mLastHoveredChild, eventNoHistory); - eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); - onHoverVirtualView(child, eventNoHistory); - mLastHoveredChild = child; - eventNoHistory.setAction(MotionEvent.ACTION_HOVER_MOVE); - handled |= onHoverVirtualView(child, eventNoHistory); - if (eventNoHistory != event) { - eventNoHistory.recycle(); - } else { - event.setAction(action); - } - } - } break; - case MotionEvent.ACTION_HOVER_EXIT: { - mLastHoveredChild = null; - handled |= onHoverVirtualView(child, event); - event.setAction(action); - } break; - } - } - if (!handled) { - handled |= onHoverEvent(event); - } - return handled; - } - - /** - * {@inheritDoc} - */ - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - // The virtual children are ordered horizontally next to - // each other and take the entire space of this View. - int offsetX = 0; - List children = mChildren; - final int childCount = children.size(); - for (int i = 0; i < childCount; i++) { - VirtualView child = children.get(i); - Rect childBounds = child.mBounds; - childBounds.set(offsetX, 0, offsetX + childBounds.width(), childBounds.height()); - offsetX += childBounds.width(); - } - } - - /** - * {@inheritDoc} - */ - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // The virtual children are ordered horizontally next to - // each other and take the entire space of this View. - int width = 0; - int height = 0; - List children = mChildren; - final int childCount = children.size(); - for (int i = 0; i < childCount; i++) { - VirtualView child = children.get(i); - width += child.mBounds.width(); - height = Math.max(height, child.mBounds.height()); - } - setMeasuredDimension(width, height); - } - - /** - * {@inheritDoc} - */ - @Override - protected void onDraw(Canvas canvas) { - // Draw the virtual children with the reusable Paint object - // and with the bounds and color which are child specific. - Rect drawingRect = mTempRect; - List children = mChildren; - final int childCount = children.size(); - for (int i = 0; i < childCount; i++) { - VirtualView child = children.get(i); - drawingRect.set(child.mBounds); - mPaint.setColor(child.mColor); - mPaint.setAlpha(child.mAlpha); - canvas.drawRect(drawingRect, mPaint); - } - } - - /** - * Creates the virtual children of this View. - */ - private void createVirtualChildren() { - // The virtual portion of the tree is one level deep. Note - // that implementations can use any way of representing and - // drawing virtual view. - VirtualView firstChild = new VirtualView(0, new Rect(0, 0, 150, 150), Color.RED, - "Virtual view 1"); - mChildren.add(firstChild); - VirtualView secondChild = new VirtualView(1, new Rect(0, 0, 150, 150), Color.GREEN, - "Virtual view 2"); - mChildren.add(secondChild); - VirtualView thirdChild = new VirtualView(2, new Rect(0, 0, 150, 150), Color.BLUE, - "Virtual view 3"); - mChildren.add(thirdChild); - } - - /** - * Set the selected state of a virtual view. - * - * @param virtualView The virtual view whose selected state to set. - * @param selected Whether the virtual view is selected. - */ - private void setVirtualViewSelected(VirtualView virtualView, boolean selected) { - virtualView.mAlpha = selected ? VirtualView.ALPHA_SELECTED : VirtualView.ALPHA_NOT_SELECTED; - } - - /** - * Handle a hover over a virtual view. - * - * @param virtualView The virtual view over which is hovered. - * @param event The event to dispatch. - * @return Whether the event was handled. - */ - private boolean onHoverVirtualView(VirtualView virtualView, MotionEvent event) { - // The implementation of hover event dispatch can be implemented - // in any way that is found suitable. However, each virtual View - // should fire a corresponding accessibility event whose source - // is that virtual view. Accessibility services get the event source - // as the entry point of the APIs for querying the window content. - final int action = event.getAction(); - switch (action) { - case MotionEvent.ACTION_HOVER_ENTER: { - sendAccessibilityEventForVirtualView(virtualView, - AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); - } break; - case MotionEvent.ACTION_HOVER_EXIT: { - sendAccessibilityEventForVirtualView(virtualView, - AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); - } break; - } - return true; - } - - /** - * Sends a properly initialized accessibility event for a virtual view.. - * - * @param virtualView The virtual view. - * @param eventType The type of the event to send. - */ - private void sendAccessibilityEventForVirtualView(VirtualView virtualView, int eventType) { - // If touch exploration, i.e. the user gets feedback while touching - // the screen, is enabled we fire accessibility events. - if (mAccessibilityManager.isTouchExplorationEnabled()) { - AccessibilityEvent event = AccessibilityEvent.obtain(eventType); - event.setPackageName(getContext().getPackageName()); - event.setClassName(virtualView.getClass().getName()); - event.setSource(VirtualSubtreeRootView.this, virtualView.mId); - event.getText().add(virtualView.mText); - getParent().requestSendAccessibilityEvent(VirtualSubtreeRootView.this, event); - } - } - - /** - * Finds a virtual view given its id. - * - * @param id The virtual view id. - * @return The found virtual view. - */ - private VirtualView findVirtualViewById(int id) { - List children = mChildren; - final int childCount = children.size(); - for (int i = 0; i < childCount; i++) { - VirtualView child = children.get(i); - if (child.mId == id) { - return child; - } - } - return null; - } - - /** - * Represents a virtual View. - */ - private class VirtualView { - public static final int ALPHA_SELECTED = 255; - public static final int ALPHA_NOT_SELECTED = 127; - - public final int mId; - public final int mColor; - public final Rect mBounds; - public final String mText; - public int mAlpha; - - public VirtualView(int id, Rect bounds, int color, String text) { - mId = id; - mColor = color; - mBounds = bounds; - mText = text; - mAlpha = ALPHA_NOT_SELECTED; - } - } - - /** - * This is the provider that exposes the virtual View tree to accessibility - * services. From the perspective of an accessibility service the - * {@link AccessibilityNodeInfo}s it receives while exploring the sub-tree - * rooted at this View will be the same as the ones it received while - * exploring a View containing a sub-tree composed of real Views. - */ - private class VirtualDescendantsProvider extends AccessibilityNodeProvider { - - /** - * {@inheritDoc} - */ - @Override - public AccessibilityNodeInfo createAccessibilityNodeInfo(int virtualViewId) { - AccessibilityNodeInfo info = null; - if (virtualViewId == View.NO_ID) { - // We are requested to create an AccessibilityNodeInfo describing - // this View, i.e. the root of the virtual sub-tree. Note that the - // host View has an AccessibilityNodeProvider which means that this - // provider is responsible for creating the node info for that root. - info = AccessibilityNodeInfo.obtain(VirtualSubtreeRootView.this); - onInitializeAccessibilityNodeInfo(info); - // Add the virtual children of the root View. - List children = mChildren; - final int childCount = children.size(); - for (int i = 0; i < childCount; i++) { - VirtualView child = children.get(i); - info.addChild(VirtualSubtreeRootView.this, child.mId); - } - } else { - // Find the view that corresponds to the given id. - VirtualView virtualView = findVirtualViewById(virtualViewId); - if (virtualView == null) { - return null; - } - // Obtain and initialize an AccessibilityNodeInfo with - // information about the virtual view. - info = AccessibilityNodeInfo.obtain(); - info.addAction(AccessibilityNodeInfo.ACTION_SELECT); - info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); - info.setPackageName(getContext().getPackageName()); - info.setClassName(virtualView.getClass().getName()); - info.setSource(VirtualSubtreeRootView.this, virtualViewId); - info.setBoundsInParent(virtualView.mBounds); - info.setParent(VirtualSubtreeRootView.this); - info.setText(virtualView.mText); - } - return info; - } - - /** - * {@inheritDoc} - */ - @Override - public List findAccessibilityNodeInfosByText(String searched, - int virtualViewId) { - if (TextUtils.isEmpty(searched)) { - return Collections.emptyList(); - } - String searchedLowerCase = searched.toLowerCase(); - List result = null; - if (virtualViewId == View.NO_ID) { - // If the search is from the root, i.e. this View, go over the virtual - // children and look for ones that contain the searched string since - // this View does not contain text itself. - List children = mChildren; - final int childCount = children.size(); - for (int i = 0; i < childCount; i++) { - VirtualView child = children.get(i); - String textToLowerCase = child.mText.toLowerCase(); - if (textToLowerCase.contains(searchedLowerCase)) { - if (result == null) { - result = new ArrayList(); - } - result.add(createAccessibilityNodeInfo(child.mId)); - } - } - } else { - // If the search is from a virtual view, find the view. Since the tree - // is one level deep we add a node info for the child to the result if - // the child contains the searched text. - VirtualView virtualView = findVirtualViewById(virtualViewId); - if (virtualView != null) { - String textToLowerCase = virtualView.mText.toLowerCase(); - if (textToLowerCase.contains(searchedLowerCase)) { - result = new ArrayList(); - result.add(createAccessibilityNodeInfo(virtualViewId)); - } - } - } - if (result == null) { - return Collections.emptyList(); - } - return result; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean performAction(int virtualViewId, int action, Bundle arguments) { - if (virtualViewId == View.NO_ID) { - // Perform the action on the host View. - switch (action) { - case AccessibilityNodeInfo.ACTION_SELECT: - if (!isSelected()) { - setSelected(true); - return isSelected(); - } - break; - case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: - if (isSelected()) { - setSelected(false); - return !isSelected(); - } - break; - } - } else { - // Find the view that corresponds to the given id. - VirtualView child = findVirtualViewById(virtualViewId); - if (child == null) { - return false; - } - // Perform the action on a virtual view. - switch (action) { - case AccessibilityNodeInfo.ACTION_SELECT: - setVirtualViewSelected(child, true); - invalidate(); - return true; - case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: - setVirtualViewSelected(child, false); - invalidate(); - return true; - } - } - return false; - } - } - } -} diff --git a/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html b/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html index df54e966b..1324f8682 100644 --- a/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html +++ b/samples/ApiDemos/src/com/example/android/apis/accessibility/_index.html @@ -21,12 +21,6 @@ xml files, and adding additional information to AccessibilityEvents using AccessibilityRecords. -
Accessibility Node Provider
-
Demonstrates how to develop an accessibility node provider which manages a virtual - View tree reported to accessibility services. The virtual subtree is rooted at a View - that draws complex content and reports itself as a tree of virtual views, thus conveying - its logical structure. -