diff options
| author | Dianne Hackborn <hackbod@google.com> | 2015-04-01 16:45:03 -0700 |
|---|---|---|
| committer | Dianne Hackborn <hackbod@google.com> | 2015-04-01 17:08:27 -0700 |
| commit | 6251f0d42be7da54d7f1bc8f570a44883b7d9052 (patch) | |
| tree | d7e928e1d55745a3ff4771c546678e4b27fc6d1b | |
| parent | 6cedefa2e4a10724982a72e22abc349c7578902d (diff) | |
| download | frameworks_base-6251f0d42be7da54d7f1bc8f570a44883b7d9052.zip frameworks_base-6251f0d42be7da54d7f1bc8f570a44883b7d9052.tar.gz frameworks_base-6251f0d42be7da54d7f1bc8f570a44883b7d9052.tar.bz2 | |
Rework assist to walk down the view hierarchy.
Instead of collecting all of the data directly in AssistStructure,
we now have a dispatch mechanism down the hierarchy to do so.
While doing this, also added the ability to automatically collect
assist data from AccessibilityNodeProviders attached to views
(so now we see all of the data in for example Calendar).
This is a first step needed towards being able to asynchronously
populate assist data.
Change-Id: I59ee1ea104ca8207bad8df7a38195d93da1adea7
| -rw-r--r-- | api/current.txt | 24 | ||||
| -rw-r--r-- | api/system-current.txt | 24 | ||||
| -rw-r--r-- | core/java/android/app/AssistStructure.java | 444 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 140 | ||||
| -rw-r--r-- | core/java/android/view/ViewAssistStructure.java | 43 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 27 | ||||
| -rw-r--r-- | core/java/android/widget/Switch.java | 4 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 4 | ||||
| -rw-r--r-- | tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java | 10 | ||||
| -rw-r--r-- | tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java | 1 |
10 files changed, 507 insertions, 214 deletions
diff --git a/api/current.txt b/api/current.txt index ce6bbfa..6890968 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34511,6 +34511,7 @@ package android.view { method public boolean dispatchNestedPreScroll(int, int, int[], int[]); method public boolean dispatchNestedScroll(int, int, int, int, int[]); method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent); + method public void dispatchProvideAssistStructure(android.view.ViewAssistStructure); method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>); method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>); method protected void dispatchSetActivated(boolean); @@ -34767,7 +34768,8 @@ package android.view { method protected void onMeasure(int, int); method protected void onOverScrolled(int, int, boolean, boolean); method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent); - method public void onProvideAssistStructure(android.view.ViewAssistStructure, android.os.Bundle); + method public void onProvideAssistStructure(android.view.ViewAssistStructure); + method public void onProvideVirtualAssistStructure(android.view.ViewAssistStructure); method protected void onRestoreInstanceState(android.os.Parcelable); method public void onRtlPropertiesChanged(int); method protected android.os.Parcelable onSaveInstanceState(); @@ -35177,14 +35179,34 @@ package android.view { public abstract class ViewAssistStructure { ctor public ViewAssistStructure(); + method public abstract void clearExtras(); + method public abstract android.os.Bundle editExtras(); + method public abstract int getChildCount(); method public abstract java.lang.CharSequence getHint(); method public abstract java.lang.CharSequence getText(); method public abstract int getTextSelectionEnd(); method public abstract int getTextSelectionStart(); + method public abstract android.view.ViewAssistStructure newChild(int); + method public abstract void setAccessibilityFocused(boolean); + method public abstract void setActivated(boolean); + method public abstract void setCheckable(boolean); + method public abstract void setChecked(boolean); + method public abstract void setChildCount(int); + method public abstract void setClassName(java.lang.String); + method public abstract void setClickable(boolean); + method public abstract void setContentDescription(java.lang.CharSequence); + method public abstract void setDimens(int, int, int, int, int, int); + method public abstract void setEnabled(boolean); + method public abstract void setFocusable(boolean); + method public abstract void setFocused(boolean); method public abstract void setHint(java.lang.CharSequence); + method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String); + method public abstract void setLongClickable(boolean); + method public abstract void setSelected(boolean); method public abstract void setText(java.lang.CharSequence); method public abstract void setText(java.lang.CharSequence, int, int); method public abstract void setTextPaint(android.text.TextPaint); + method public abstract void setVisibility(int); } public class ViewConfiguration { diff --git a/api/system-current.txt b/api/system-current.txt index 6053603..b5b7c05 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -37053,6 +37053,7 @@ package android.view { method public boolean dispatchNestedPreScroll(int, int, int[], int[]); method public boolean dispatchNestedScroll(int, int, int, int, int[]); method public boolean dispatchPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent); + method public void dispatchProvideAssistStructure(android.view.ViewAssistStructure); method protected void dispatchRestoreInstanceState(android.util.SparseArray<android.os.Parcelable>); method protected void dispatchSaveInstanceState(android.util.SparseArray<android.os.Parcelable>); method protected void dispatchSetActivated(boolean); @@ -37309,7 +37310,8 @@ package android.view { method protected void onMeasure(int, int); method protected void onOverScrolled(int, int, boolean, boolean); method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent); - method public void onProvideAssistStructure(android.view.ViewAssistStructure, android.os.Bundle); + method public void onProvideAssistStructure(android.view.ViewAssistStructure); + method public void onProvideVirtualAssistStructure(android.view.ViewAssistStructure); method protected void onRestoreInstanceState(android.os.Parcelable); method public void onRtlPropertiesChanged(int); method protected android.os.Parcelable onSaveInstanceState(); @@ -37719,14 +37721,34 @@ package android.view { public abstract class ViewAssistStructure { ctor public ViewAssistStructure(); + method public abstract void clearExtras(); + method public abstract android.os.Bundle editExtras(); + method public abstract int getChildCount(); method public abstract java.lang.CharSequence getHint(); method public abstract java.lang.CharSequence getText(); method public abstract int getTextSelectionEnd(); method public abstract int getTextSelectionStart(); + method public abstract android.view.ViewAssistStructure newChild(int); + method public abstract void setAccessibilityFocused(boolean); + method public abstract void setActivated(boolean); + method public abstract void setCheckable(boolean); + method public abstract void setChecked(boolean); + method public abstract void setChildCount(int); + method public abstract void setClassName(java.lang.String); + method public abstract void setClickable(boolean); + method public abstract void setContentDescription(java.lang.CharSequence); + method public abstract void setDimens(int, int, int, int, int, int); + method public abstract void setEnabled(boolean); + method public abstract void setFocusable(boolean); + method public abstract void setFocused(boolean); method public abstract void setHint(java.lang.CharSequence); + method public abstract void setId(int, java.lang.String, java.lang.String, java.lang.String); + method public abstract void setLongClickable(boolean); + method public abstract void setSelected(boolean); method public abstract void setText(java.lang.CharSequence); method public abstract void setText(java.lang.CharSequence, int, int); method public abstract void setTextPaint(android.text.TextPaint); + method public abstract void setVisibility(int); } public class ViewConfiguration { diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java index c435ccb..e31c821 100644 --- a/core/java/android/app/AssistStructure.java +++ b/core/java/android/app/AssistStructure.java @@ -17,7 +17,6 @@ package android.app; import android.content.ComponentName; -import android.content.res.Resources; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; @@ -31,10 +30,8 @@ import android.text.TextUtils; import android.util.Log; import android.view.View; import android.view.ViewAssistStructure; -import android.view.ViewGroup; import android.view.ViewRootImpl; import android.view.WindowManagerGlobal; -import android.widget.Checkable; import java.util.ArrayList; @@ -56,107 +53,22 @@ final public class AssistStructure implements Parcelable { final ArrayList<WindowNode> mWindowNodes = new ArrayList<>(); - ViewAssistStructureImpl mTmpViewAssistStructureImpl = new ViewAssistStructureImpl(); - Bundle mTmpExtras = new Bundle(); + Rect mTmpRect = new Rect(); - final static class ViewAssistStructureImpl extends ViewAssistStructure { + final static class ViewNodeText { CharSequence mText; - int mTextSelectionStart = -1; - int mTextSelectionEnd = -1; - int mTextColor = ViewNode.TEXT_COLOR_UNDEFINED; - int mTextBackgroundColor = ViewNode.TEXT_COLOR_UNDEFINED; - float mTextSize = 0; - int mTextStyle = 0; - CharSequence mHint; - - @Override - public void setText(CharSequence text) { - mText = text; - mTextSelectionStart = mTextSelectionEnd = -1; - } - - @Override - public void setText(CharSequence text, int selectionStart, int selectionEnd) { - mText = text; - mTextSelectionStart = selectionStart; - mTextSelectionEnd = selectionEnd; - } - - @Override - public void setTextPaint(TextPaint paint) { - mTextColor = paint.getColor(); - mTextBackgroundColor = paint.bgColor; - mTextSize = paint.getTextSize(); - mTextStyle = 0; - Typeface tf = paint.getTypeface(); - if (tf != null) { - if (tf.isBold()) { - mTextStyle |= ViewNode.TEXT_STYLE_BOLD; - } - if (tf.isItalic()) { - mTextStyle |= ViewNode.TEXT_STYLE_ITALIC; - } - } - int pflags = paint.getFlags(); - if ((pflags& Paint.FAKE_BOLD_TEXT_FLAG) != 0) { - mTextStyle |= ViewNode.TEXT_STYLE_BOLD; - } - if ((pflags& Paint.UNDERLINE_TEXT_FLAG) != 0) { - mTextStyle |= ViewNode.TEXT_STYLE_UNDERLINE; - } - if ((pflags& Paint.STRIKE_THRU_TEXT_FLAG) != 0) { - mTextStyle |= ViewNode.TEXT_STYLE_STRIKE_THRU; - } - } - - @Override - public void setHint(CharSequence hint) { - mHint = hint; - } - - @Override - public CharSequence getText() { - return mText; - } - - @Override - public int getTextSelectionStart() { - return mTextSelectionStart; - } - - @Override - public int getTextSelectionEnd() { - return mTextSelectionEnd; - } - - @Override - public CharSequence getHint() { - return mHint; - } - } - - final static class ViewNodeTextImpl { - final CharSequence mText; - final int mTextSelectionStart; - final int mTextSelectionEnd; + int mTextSelectionStart; + int mTextSelectionEnd; int mTextColor; int mTextBackgroundColor; float mTextSize; int mTextStyle; - final String mHint; + String mHint; - ViewNodeTextImpl(ViewAssistStructureImpl data) { - mText = data.mText; - mTextSelectionStart = data.mTextSelectionStart; - mTextSelectionEnd = data.mTextSelectionEnd; - mTextColor = data.mTextColor; - mTextBackgroundColor = data.mTextBackgroundColor; - mTextSize = data.mTextSize; - mTextStyle = data.mTextStyle; - mHint = data.mHint != null ? data.mHint.toString() : null; + ViewNodeText() { } - ViewNodeTextImpl(Parcel in) { + ViewNodeText(Parcel in) { mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mTextSelectionStart = in.readInt(); mTextSelectionEnd = in.readInt(); @@ -199,7 +111,9 @@ final public class AssistStructure implements Parcelable { mWidth = rect.width(); mHeight = rect.height(); mTitle = root.getTitle(); - mRoot = new ViewNode(assist, view); + mRoot = new ViewNode(); + ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot); + view.dispatchProvideAssistStructure(builder); } WindowNode(Parcel in, PooledStringReader preader) { @@ -260,16 +174,16 @@ final public class AssistStructure implements Parcelable { public static final int TEXT_STYLE_UNDERLINE = 1<<2; public static final int TEXT_STYLE_STRIKE_THRU = 1<<3; - final int mId; - final String mIdPackage; - final String mIdType; - final String mIdEntry; - final int mX; - final int mY; - final int mScrollX; - final int mScrollY; - final int mWidth; - final int mHeight; + int mId; + String mIdPackage; + String mIdType; + String mIdEntry; + int mX; + int mY; + int mScrollX; + int mScrollY; + int mWidth; + int mHeight; static final int FLAGS_DISABLED = 0x00000001; static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE; @@ -283,104 +197,17 @@ final public class AssistStructure implements Parcelable { static final int FLAGS_CLICKABLE = 0x00004000; static final int FLAGS_LONG_CLICKABLE = 0x00200000; - final int mFlags; + int mFlags; - final String mClassName; - final CharSequence mContentDescription; + String mClassName; + CharSequence mContentDescription; - final ViewNodeTextImpl mText; - final Bundle mExtras; + ViewNodeText mText; + Bundle mExtras; - final ViewNode[] mChildren; + ViewNode[] mChildren; - ViewNode(AssistStructure assistStructure, View view) { - mId = view.getId(); - if (mId > 0 && (mId&0xff000000) != 0 && (mId&0x00ff0000) != 0 - && (mId&0x0000ffff) != 0) { - String pkg, type, entry; - try { - Resources res = view.getResources(); - entry = res.getResourceEntryName(mId); - type = res.getResourceTypeName(mId); - pkg = res.getResourcePackageName(mId); - } catch (Resources.NotFoundException e) { - entry = type = pkg = null; - } - mIdPackage = pkg; - mIdType = type; - mIdEntry = entry; - } else { - mIdPackage = mIdType = mIdEntry = null; - } - mX = view.getLeft(); - mY = view.getTop(); - mScrollX = view.getScrollX(); - mScrollY = view.getScrollY(); - mWidth = view.getWidth(); - mHeight = view.getHeight(); - int flags = view.getVisibility(); - if (!view.isEnabled()) { - flags |= FLAGS_DISABLED; - } - if (!view.isClickable()) { - flags |= FLAGS_CLICKABLE; - } - if (!view.isFocusable()) { - flags |= FLAGS_FOCUSABLE; - } - if (!view.isFocused()) { - flags |= FLAGS_FOCUSED; - } - if (!view.isAccessibilityFocused()) { - flags |= FLAGS_ACCESSIBILITY_FOCUSED; - } - if (!view.isSelected()) { - flags |= FLAGS_SELECTED; - } - if (!view.isActivated()) { - flags |= FLAGS_ACTIVATED; - } - if (!view.isLongClickable()) { - flags |= FLAGS_LONG_CLICKABLE; - } - if (view instanceof Checkable) { - flags |= FLAGS_CHECKABLE; - if (((Checkable)view).isChecked()) { - flags |= FLAGS_CHECKED; - } - } - mFlags = flags; - mClassName = view.getAccessibilityClassName().toString(); - mContentDescription = view.getContentDescription(); - final ViewAssistStructureImpl viewData = assistStructure.mTmpViewAssistStructureImpl; - final Bundle extras = assistStructure.mTmpExtras; - view.onProvideAssistStructure(viewData, extras); - if (viewData.mText != null || viewData.mHint != null) { - mText = new ViewNodeTextImpl(viewData); - assistStructure.mTmpViewAssistStructureImpl = new ViewAssistStructureImpl(); - } else { - mText = null; - } - if (!extras.isEmpty()) { - mExtras = extras; - assistStructure.mTmpExtras = new Bundle(); - } else { - mExtras = null; - } - if (view instanceof ViewGroup) { - ViewGroup vg = (ViewGroup)view; - final int NCHILDREN = vg.getChildCount(); - if (NCHILDREN > 0) { - mChildren = new ViewNode[NCHILDREN]; - for (int i=0; i<NCHILDREN; i++) { - mChildren[i] = new ViewNode(assistStructure, vg.getChildAt(i)); - } - } else { - mChildren = null; - } - } else { - mChildren = null; - } + ViewNode() { } ViewNode(Parcel in, PooledStringReader preader) { @@ -406,7 +233,7 @@ final public class AssistStructure implements Parcelable { mClassName = preader.readString(); mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); if (in.readInt() != 0) { - mText = new ViewNodeTextImpl(in); + mText = new ViewNodeText(in); } else { mText = null; } @@ -595,6 +422,221 @@ final public class AssistStructure implements Parcelable { } } + static class ViewNodeBuilder extends ViewAssistStructure { + final AssistStructure mAssist; + final ViewNode mNode; + + ViewNodeBuilder(AssistStructure assist, ViewNode node) { + mAssist = assist; + mNode = node; + } + + @Override + public void setId(int id, String packageName, String typeName, String entryName) { + mNode.mId = id; + mNode.mIdPackage = packageName; + mNode.mIdType = typeName; + mNode.mIdEntry = entryName; + } + + @Override + public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) { + mNode.mX = left; + mNode.mY = top; + mNode.mScrollX = scrollX; + mNode.mScrollY = scrollY; + mNode.mWidth = width; + mNode.mHeight = height; + } + + @Override + public void setVisibility(int visibility) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility; + } + + @Override + public void setEnabled(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_DISABLED) + | (state ? 0 : ViewNode.FLAGS_DISABLED); + } + + @Override + public void setClickable(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CLICKABLE) + | (state ? ViewNode.FLAGS_CLICKABLE : 0); + } + + @Override + public void setLongClickable(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_LONG_CLICKABLE) + | (state ? ViewNode.FLAGS_LONG_CLICKABLE : 0); + } + + @Override + public void setFocusable(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE) + | (state ? ViewNode.FLAGS_FOCUSABLE : 0); + } + + @Override + public void setFocused(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSED) + | (state ? ViewNode.FLAGS_FOCUSED : 0); + } + + @Override + public void setAccessibilityFocused(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) + | (state ? ViewNode.FLAGS_ACCESSIBILITY_FOCUSED : 0); + } + + @Override + public void setCheckable(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKABLE) + | (state ? ViewNode.FLAGS_CHECKABLE : 0); + } + + @Override + public void setChecked(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKED) + | (state ? ViewNode.FLAGS_CHECKED : 0); + } + + @Override + public void setSelected(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_SELECTED) + | (state ? ViewNode.FLAGS_SELECTED : 0); + } + + @Override + public void setActivated(boolean state) { + mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACTIVATED) + | (state ? ViewNode.FLAGS_ACTIVATED : 0); + } + + @Override + public void setClassName(String className) { + mNode.mClassName = className; + } + + @Override + public void setContentDescription(CharSequence contentDescription) { + mNode.mContentDescription = contentDescription; + } + + private final ViewNodeText getNodeText() { + if (mNode.mText != null) { + return mNode.mText; + } + mNode.mText = new ViewNodeText(); + return mNode.mText; + } + + @Override + public void setText(CharSequence text) { + ViewNodeText t = getNodeText(); + t.mText = text; + t.mTextSelectionStart = t.mTextSelectionEnd = -1; + } + + @Override + public void setText(CharSequence text, int selectionStart, int selectionEnd) { + ViewNodeText t = getNodeText(); + t.mText = text; + t.mTextSelectionStart = selectionStart; + t.mTextSelectionEnd = selectionEnd; + } + + @Override + public void setTextPaint(TextPaint paint) { + ViewNodeText t = getNodeText(); + t.mTextColor = paint.getColor(); + t.mTextBackgroundColor = paint.bgColor; + t.mTextSize = paint.getTextSize(); + t.mTextStyle = 0; + Typeface tf = paint.getTypeface(); + if (tf != null) { + if (tf.isBold()) { + t.mTextStyle |= ViewNode.TEXT_STYLE_BOLD; + } + if (tf.isItalic()) { + t.mTextStyle |= ViewNode.TEXT_STYLE_ITALIC; + } + } + int pflags = paint.getFlags(); + if ((pflags& Paint.FAKE_BOLD_TEXT_FLAG) != 0) { + t.mTextStyle |= ViewNode.TEXT_STYLE_BOLD; + } + if ((pflags& Paint.UNDERLINE_TEXT_FLAG) != 0) { + t.mTextStyle |= ViewNode.TEXT_STYLE_UNDERLINE; + } + if ((pflags& Paint.STRIKE_THRU_TEXT_FLAG) != 0) { + t.mTextStyle |= ViewNode.TEXT_STYLE_STRIKE_THRU; + } + } + + @Override + public void setHint(CharSequence hint) { + getNodeText().mHint = hint != null ? hint.toString() : null; + } + + @Override + public CharSequence getText() { + return mNode.mText != null ? mNode.mText.mText : null; + } + + @Override + public int getTextSelectionStart() { + return mNode.mText != null ? mNode.mText.mTextSelectionStart : -1; + } + + @Override + public int getTextSelectionEnd() { + return mNode.mText != null ? mNode.mText.mTextSelectionEnd : -1; + } + + @Override + public CharSequence getHint() { + return mNode.mText != null ? mNode.mText.mHint : null; + } + + @Override + public Bundle editExtras() { + if (mNode.mExtras != null) { + return mNode.mExtras; + } + mNode.mExtras = new Bundle(); + return mNode.mExtras; + } + + @Override + public void clearExtras() { + mNode.mExtras = null; + } + + @Override + public void setChildCount(int num) { + mNode.mChildren = new ViewNode[num]; + } + + @Override + public int getChildCount() { + return mNode.mChildren != null ? mNode.mChildren.length : 0; + } + + @Override + public ViewAssistStructure newChild(int index) { + ViewNode node = new ViewNode(); + mNode.mChildren[index] = node; + return new ViewNodeBuilder(mAssist, node); + } + + @Override + public Rect getTempRect() { + return mAssist.mTmpRect; + } + } + AssistStructure(Activity activity) { mActivityComponent = activity.getComponentName(); ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews( diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index a69384a..c0e253b 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -91,6 +91,7 @@ import android.view.animation.Transformation; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; +import android.widget.Checkable; import android.widget.ScrollBarDrawable; import static android.os.Build.VERSION_CODES.*; @@ -5676,10 +5677,143 @@ public class View implements Drawable.Callback, KeyEvent.Callback, /** * Called when assist structure is being retrieved from a view as part of * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. - * @param structure Additional standard structured view structure to supply. - * @param extras Non-standard extensions. + * @param structure Fill in with structured view data. The default implementation + * fills in all data that can be inferred from the view itself. + */ + public void onProvideAssistStructure(ViewAssistStructure structure) { + final int id = mID; + if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0 + && (id&0x0000ffff) != 0) { + String pkg, type, entry; + try { + final Resources res = getResources(); + entry = res.getResourceEntryName(id); + type = res.getResourceTypeName(id); + pkg = res.getResourcePackageName(id); + } catch (Resources.NotFoundException e) { + entry = type = pkg = null; + } + structure.setId(id, pkg, type, entry); + } else { + structure.setId(id, null, null, null); + } + structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight-mLeft, mBottom-mTop); + structure.setVisibility(getVisibility()); + structure.setEnabled(isEnabled()); + if (isClickable()) { + structure.setClickable(true); + } + if (isFocusable()) { + structure.setFocusable(true); + } + if (isFocused()) { + structure.setFocused(true); + } + if (isAccessibilityFocused()) { + structure.setAccessibilityFocused(true); + } + if (isSelected()) { + structure.setSelected(true); + } + if (isActivated()) { + structure.setActivated(true); + } + if (isLongClickable()) { + structure.setLongClickable(true); + } + if (this instanceof Checkable) { + structure.setCheckable(true); + if (((Checkable)this).isChecked()) { + structure.setChecked(true); + } + } + structure.setClassName(getAccessibilityClassName().toString()); + structure.setContentDescription(getContentDescription()); + } + + /** + * Called when assist structure is being retrieved from a view as part of + * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to + * generate additional virtual structure under this view. The defaullt implementation + * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the + * view's virtual accessibility nodes, if any. You can override this for a more + * optimal implementation providing this data. + */ + public void onProvideVirtualAssistStructure(ViewAssistStructure structure) { + AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); + if (provider != null) { + AccessibilityNodeInfo info = createAccessibilityNodeInfo(); + Log.i("View", "Provider of " + this + ": children=" + info.getChildCount()); + structure.setChildCount(1); + ViewAssistStructure root = structure.newChild(0); + populateVirtualAssistStructure(root, provider, info); + info.recycle(); + } + } + + private void populateVirtualAssistStructure(ViewAssistStructure structure, + AccessibilityNodeProvider provider, AccessibilityNodeInfo info) { + structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), + null, null, null); + Rect rect = structure.getTempRect(); + info.getBoundsInParent(rect); + structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); + structure.setVisibility(VISIBLE); + structure.setEnabled(info.isEnabled()); + if (info.isClickable()) { + structure.setClickable(true); + } + if (info.isFocusable()) { + structure.setFocusable(true); + } + if (info.isFocused()) { + structure.setFocused(true); + } + if (info.isAccessibilityFocused()) { + structure.setAccessibilityFocused(true); + } + if (info.isSelected()) { + structure.setSelected(true); + } + if (info.isLongClickable()) { + structure.setLongClickable(true); + } + if (info.isCheckable()) { + structure.setCheckable(true); + if (info.isChecked()) { + structure.setChecked(true); + } + } + CharSequence cname = info.getClassName(); + structure.setClassName(cname != null ? cname.toString() : null); + structure.setContentDescription(info.getContentDescription()); + Log.i("View", "vassist " + cname + " @ " + rect.toShortString() + + " text=" + info.getText() + " cd=" + info.getContentDescription()); + if (info.getText() != null || info.getError() != null) { + structure.setText(info.getText(), info.getTextSelectionStart(), + info.getTextSelectionEnd()); + } + final int NCHILDREN = info.getChildCount(); + if (NCHILDREN > 0) { + structure.setChildCount(NCHILDREN); + for (int i=0; i<NCHILDREN; i++) { + AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( + AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); + ViewAssistStructure child = structure.newChild(i); + populateVirtualAssistStructure(child, provider, cinfo); + cinfo.recycle(); + } + } + } + + /** + * Dispatch creation of {@link ViewAssistStructure} down the hierarchy. The default + * implementation calls {@link #onProvideAssistStructure} and + * {@link #onProvideVirtualAssistStructure}. */ - public void onProvideAssistStructure(ViewAssistStructure structure, Bundle extras) { + public void dispatchProvideAssistStructure(ViewAssistStructure structure) { + onProvideAssistStructure(structure); + onProvideVirtualAssistStructure(structure); } /** diff --git a/core/java/android/view/ViewAssistStructure.java b/core/java/android/view/ViewAssistStructure.java index 5132bb9..c05ed6f 100644 --- a/core/java/android/view/ViewAssistStructure.java +++ b/core/java/android/view/ViewAssistStructure.java @@ -16,6 +16,8 @@ package android.view; +import android.graphics.Rect; +import android.os.Bundle; import android.text.TextPaint; /** @@ -23,6 +25,37 @@ import android.text.TextPaint; * View.onProvideAssistStructure}. */ public abstract class ViewAssistStructure { + public abstract void setId(int id, String packageName, String typeName, String entryName); + + public abstract void setDimens(int left, int top, int scrollX, int scrollY, int width, + int height); + + public abstract void setVisibility(int visibility); + + public abstract void setEnabled(boolean state); + + public abstract void setClickable(boolean state); + + public abstract void setLongClickable(boolean state); + + public abstract void setFocusable(boolean state); + + public abstract void setFocused(boolean state); + + public abstract void setAccessibilityFocused(boolean state); + + public abstract void setCheckable(boolean state); + + public abstract void setChecked(boolean state); + + public abstract void setSelected(boolean state); + + public abstract void setActivated(boolean state); + + public abstract void setClassName(String className); + + public abstract void setContentDescription(CharSequence contentDescription); + public abstract void setText(CharSequence text); public abstract void setText(CharSequence text, int selectionStart, int selectionEnd); public abstract void setTextPaint(TextPaint paint); @@ -32,4 +65,14 @@ public abstract class ViewAssistStructure { public abstract int getTextSelectionStart(); public abstract int getTextSelectionEnd(); public abstract CharSequence getHint(); + + public abstract Bundle editExtras(); + public abstract void clearExtras(); + + public abstract void setChildCount(int num); + public abstract int getChildCount(); + public abstract ViewAssistStructure newChild(int index); + + /** @hide */ + public abstract Rect getTempRect(); } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 87f3e94..7a84bb0 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -2852,6 +2852,33 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return false; } + /** + * Dispatch creation of {@link ViewAssistStructure} down the hierarchy. This implementation + * adds in all child views of the view group, in addition to calling the default View + * implementation. + */ + public void dispatchProvideAssistStructure(ViewAssistStructure structure) { + super.dispatchProvideAssistStructure(structure); + if (structure.getChildCount() == 0) { + final int childrenCount = getChildCount(); + if (childrenCount > 0) { + structure.setChildCount(childrenCount); + final ArrayList<View> preorderedList = buildOrderedChildList(); + final boolean customOrder = preorderedList == null + && isChildrenDrawingOrderEnabled(); + final View[] children = mChildren; + for (int i=0; i<childrenCount; i++) { + final int childIndex = customOrder + ? getChildDrawingOrder(childrenCount, i) : i; + final View child = (preorderedList == null) + ? children[childIndex] : preorderedList.get(childIndex); + ViewAssistStructure cstructure = structure.newChild(i); + child.dispatchProvideAssistStructure(cstructure); + } + } + } + } + /** @hide */ @Override public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index bb290e7..ae779fe 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -1363,8 +1363,8 @@ public class Switch extends CompoundButton { } @Override - public void onProvideAssistStructure(ViewAssistStructure structure, Bundle extras) { - super.onProvideAssistStructure(structure, extras); + public void onProvideAssistStructure(ViewAssistStructure structure) { + super.onProvideAssistStructure(structure); CharSequence switchText = isChecked() ? mTextOn : mTextOff; if (!TextUtils.isEmpty(switchText)) { CharSequence oldText = structure.getText(); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 718ef93..877647d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8576,8 +8576,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override - public void onProvideAssistStructure(ViewAssistStructure structure, Bundle extras) { - super.onProvideAssistStructure(structure, extras); + public void onProvideAssistStructure(ViewAssistStructure structure) { + super.onProvideAssistStructure(structure); final boolean isPassword = hasPasswordTransformationMethod(); if (!isPassword) { structure.setText(getText(), getSelectionStart(), getSelectionEnd()); diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java index bdc1276..782d112 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java @@ -45,6 +45,7 @@ public class AssistVisualizer extends View { } public void setAssistStructure(AssistStructure as) { + mAssistStructure.dump(); mAssistStructure = as; mTextRects.clear(); final int N = as.getWindowNodeCount(); @@ -55,6 +56,7 @@ public class AssistVisualizer extends View { windowNode.getTop()); } } + Log.d(TAG, "Building text rects in " + this + ": found " + mTextRects.size()); invalidate(); } @@ -69,10 +71,11 @@ public class AssistVisualizer extends View { } int left = parentLeft+root.getLeft(); int top = parentTop+root.getTop(); - Log.d(TAG, "View " + root.getClassName() + ": " + left + ", " + top); - if (root.getText() != null) { + if (root.getText() != null || root.getContentDescription() != null) { Rect r = new Rect(left, top, left+root.getWidth(), top+root.getHeight()); - Log.d(TAG, "Text Rect " + r.toShortString() + ": " + root.getText()); + Log.d(TAG, "View " + root.getClassName() + " " + left + "," + top + " tr " + + r.toShortString() + ": " + + (root.getText() != null ? root.getText() : root.getContentDescription())); mTextRects.add(r); } final int N = root.getChildCount(); @@ -91,6 +94,7 @@ public class AssistVisualizer extends View { super.onDraw(canvas); getLocationOnScreen(mTmpLocation); final int N = mTextRects.size(); + Log.d(TAG, "Drawing text rects in " + this + ": found " + mTextRects.size()); for (int i=0; i<N; i++) { Rect r = mTextRects.get(i); canvas.drawRect(r.left-mTmpLocation[0], r.top-mTmpLocation[1], diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java index bc18ca9..ec727c4 100644 --- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java +++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java @@ -142,7 +142,6 @@ public class MainInteractionSession extends VoiceInteractionSession if (assistContext != null) { mAssistStructure = AssistStructure.getAssistStructure(assistContext); if (mAssistStructure != null) { - mAssistStructure.dump(); if (mAssistVisualizer != null) { mAssistVisualizer.setAssistStructure(mAssistStructure); } |
