diff options
| -rw-r--r-- | api/current.txt | 9 | ||||
| -rw-r--r-- | core/java/android/view/ViewGroup.java | 25 | ||||
| -rw-r--r-- | core/java/android/view/accessibility/AccessibilityNodeInfo.java | 205 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 43 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java | 2 |
5 files changed, 276 insertions, 8 deletions
diff --git a/api/current.txt b/api/current.txt index 24478f4d06d2..d7dd2add2f23 100644 --- a/api/current.txt +++ b/api/current.txt @@ -55621,6 +55621,7 @@ package android.view.accessibility { method public CharSequence getContentDescription(); method public int getDrawingOrder(); method public CharSequence getError(); + method @Nullable public android.view.accessibility.AccessibilityNodeInfo.ExtraRenderingInfo getExtraRenderingInfo(); method public android.os.Bundle getExtras(); method public CharSequence getHintText(); method public int getInputType(); @@ -55773,6 +55774,7 @@ package android.view.accessibility { field public static final int ACTION_SET_SELECTION = 131072; // 0x20000 field public static final int ACTION_SET_TEXT = 2097152; // 0x200000 field @NonNull public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR; + field public static final String EXTRA_DATA_RENDERING_INFO_KEY = "android.view.accessibility.extra.DATA_RENDERING_INFO_KEY"; field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH"; field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX"; field public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_KEY"; @@ -55860,6 +55862,12 @@ package android.view.accessibility { method public static android.view.accessibility.AccessibilityNodeInfo.CollectionItemInfo obtain(int, int, int, int, boolean, boolean); } + public static final class AccessibilityNodeInfo.ExtraRenderingInfo { + method @Nullable public android.util.Size getLayoutParams(); + method public float getTextSizeInPx(); + method public int getTextSizeUnit(); + } + public static final class AccessibilityNodeInfo.RangeInfo { ctor public AccessibilityNodeInfo.RangeInfo(int, float, float, float); method public float getCurrent(); @@ -60842,6 +60850,7 @@ package android.widget { method @Nullable public android.graphics.drawable.Drawable getTextSelectHandleLeft(); method @Nullable public android.graphics.drawable.Drawable getTextSelectHandleRight(); method @android.view.ViewDebug.ExportedProperty(category="text") public float getTextSize(); + method public int getTextSizeUnit(); method public int getTotalPaddingBottom(); method public int getTotalPaddingEnd(); method public int getTotalPaddingLeft(); diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 0367536919cf..56f933c8a221 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -3692,6 +3692,31 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } childrenForAccessibility.clear(); } + info.setAvailableExtraData(Collections.singletonList( + AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY)); + } + + /** + * {@inheritDoc} + * + * @param info The info to which to add the extra data. Never {@code null}. + * @param extraDataKey A key specifying the type of extra data to add to the info. The + * extra data should be added to the {@link Bundle} returned by + * the info's {@link AccessibilityNodeInfo#getExtras} method. Never + * {@code null}. + * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be + * {@code null} if the service provided no arguments. + * + */ + @Override + public void addExtraDataToAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info, + @NonNull String extraDataKey, @Nullable Bundle arguments) { + if (extraDataKey.equals(AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY)) { + final AccessibilityNodeInfo.ExtraRenderingInfo extraRenderingInfo = + AccessibilityNodeInfo.ExtraRenderingInfo.obtain(); + extraRenderingInfo.setLayoutParams(getLayoutParams().width, getLayoutParams().height); + info.setExtraRenderingInfo(extraRenderingInfo); + } } @Override diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index bf2de14e6811..eb4f9db39e3e 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -50,8 +50,12 @@ import android.util.ArraySet; import android.util.Log; import android.util.LongArray; import android.util.Pools.SynchronizedPool; +import android.util.Size; +import android.util.TypedValue; import android.view.TouchDelegate; import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; import com.android.internal.R; import com.android.internal.util.CollectionUtils; @@ -634,6 +638,25 @@ public class AccessibilityNodeInfo implements Parcelable { public static final String EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH = "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH"; + /** + * Key used to request extra data for accessibility scanning tool's purposes. + * The key requests that a {@link AccessibilityNodeInfo.ExtraRenderingInfo} be added to this + * info. This request is made with {@link #refreshWithExtraData(String, Bundle)} without + * argument. + * <p> + * The data can be retrieved from the {@link ExtraRenderingInfo} returned by + * {@link #getExtraRenderingInfo()} using {@link ExtraRenderingInfo#getLayoutParams}, + * {@link ExtraRenderingInfo#getTextSizeInPx()} and + * {@link ExtraRenderingInfo#getTextSizeUnit()}. For layout params, it is supported by both + * {@link TextView} and {@link ViewGroup}. For text size and unit, it is only supported by + * {@link TextView}. + * + * @see #refreshWithExtraData(String, Bundle) + */ + + public static final String EXTRA_DATA_RENDERING_INFO_KEY = + "android.view.accessibility.extra.DATA_RENDERING_INFO_KEY"; + /** @hide */ public static final String EXTRA_DATA_REQUESTED_KEY = "android.view.accessibility.AccessibilityNodeInfo.extra_data_requested"; @@ -804,6 +827,8 @@ public class AccessibilityNodeInfo implements Parcelable { private TouchDelegateInfo mTouchDelegateInfo; + private ExtraRenderingInfo mExtraRenderingInfo; + private IBinder mLeashedChild; private IBinder mLeashedParent; private long mLeashedParentNodeId = UNDEFINED_NODE_ID; @@ -991,6 +1016,7 @@ public class AccessibilityNodeInfo implements Parcelable { * @param extraDataKey The extra data requested. Data that must be requested * with this mechanism is generally expensive to retrieve, so should only be * requested when needed. See + * {@link #EXTRA_DATA_RENDERING_INFO_KEY}, * {@link #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY} and * {@link #getAvailableExtraData()}. * @param args A bundle of arguments for the request. These depend on the particular request. @@ -1547,6 +1573,7 @@ public class AccessibilityNodeInfo implements Parcelable { * {@link #refreshWithExtraData(String, Bundle)}. * * @return An unmodifiable list of keys corresponding to extra data that can be requested. + * @see #EXTRA_DATA_RENDERING_INFO_KEY * @see #EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY */ public List<String> getAvailableExtraData() { @@ -2375,6 +2402,32 @@ public class AccessibilityNodeInfo implements Parcelable { } /** + * Gets the conformance info if the node is meant to be refreshed with extra data. + * + * @return The conformance info. + */ + @Nullable + public ExtraRenderingInfo getExtraRenderingInfo() { + return mExtraRenderingInfo; + } + + /** + * Sets the conformance info if the node is meant to be refreshed with extra data. + * <p> + * <strong>Note:</strong> Cannot be called from an + * {@link android.accessibilityservice.AccessibilityService}. + * This class is made immutable before being delivered to an AccessibilityService. + * </p> + * + * @param extraRenderingInfo The conformance info. + * @hide + */ + public void setExtraRenderingInfo(@NonNull ExtraRenderingInfo extraRenderingInfo) { + enforceNotSealed(); + mExtraRenderingInfo = extraRenderingInfo; + } + + /** * Gets if the content of this node is invalid. For example, * a date is not well-formed. * @@ -3695,6 +3748,10 @@ public class AccessibilityNodeInfo implements Parcelable { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; + if (!Objects.equals(mExtraRenderingInfo, DEFAULT.mExtraRenderingInfo)) { + nonDefaultFields |= bitAt(fieldIndex); + } + fieldIndex++; if (mLeashedChild != DEFAULT.mLeashedChild) { nonDefaultFields |= bitAt(fieldIndex); } @@ -3833,6 +3890,12 @@ public class AccessibilityNodeInfo implements Parcelable { } if (isBitSet(nonDefaultFields, fieldIndex++)) { + parcel.writeValue(mExtraRenderingInfo.getLayoutParams()); + parcel.writeFloat(mExtraRenderingInfo.getTextSizeInPx()); + parcel.writeInt(mExtraRenderingInfo.getTextSizeUnit()); + } + + if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeStrongBinder(mLeashedChild); } if (isBitSet(nonDefaultFields, fieldIndex++)) { @@ -3941,6 +4004,9 @@ public class AccessibilityNodeInfo implements Parcelable { if (mCollectionItemInfo != null) mCollectionItemInfo.recycle(); mCollectionItemInfo = (other.mCollectionItemInfo != null) ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null; + if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle(); + mExtraRenderingInfo = (other.mExtraRenderingInfo != null) + ? ExtraRenderingInfo.obtain(other.mExtraRenderingInfo) : null; } private void initCopyInfos(AccessibilityNodeInfo other) { @@ -3955,6 +4021,9 @@ public class AccessibilityNodeInfo implements Parcelable { mCollectionItemInfo = (cii == null) ? null : new CollectionItemInfo(cii.mRowIndex, cii.mRowSpan, cii.mColumnIndex, cii.mColumnSpan, cii.mHeading, cii.mSelected); + ExtraRenderingInfo ti = other.mExtraRenderingInfo; + mExtraRenderingInfo = (ti == null) ? null + : new ExtraRenderingInfo(ti); } /** @@ -4083,6 +4152,14 @@ public class AccessibilityNodeInfo implements Parcelable { } if (isBitSet(nonDefaultFields, fieldIndex++)) { + if (mExtraRenderingInfo != null) mExtraRenderingInfo.recycle(); + mExtraRenderingInfo = ExtraRenderingInfo.obtain(); + mExtraRenderingInfo.mLayoutParams = (Size) parcel.readValue(null); + mExtraRenderingInfo.mTextSizeInPx = parcel.readFloat(); + mExtraRenderingInfo.mTextSizeUnit = parcel.readInt(); + } + + if (isBitSet(nonDefaultFields, fieldIndex++)) { mLeashedChild = parcel.readStrongBinder(); } if (isBitSet(nonDefaultFields, fieldIndex++)) { @@ -5679,6 +5756,134 @@ public class AccessibilityNodeInfo implements Parcelable { } /** + * Class with information of a view useful to evaluate accessibility needs. Developers can + * refresh the node with the key {@link #EXTRA_DATA_RENDERING_INFO_KEY} to fetch the text size + * and unit if it is {@link TextView} and the height and the width of layout params from + * {@link ViewGroup} or {@link TextView}. + * + * @see #EXTRA_DATA_RENDERING_INFO_KEY + * @see #refreshWithExtraData(String, Bundle) + */ + public static final class ExtraRenderingInfo { + private static final int UNDEFINED_VALUE = -1; + private static final int MAX_POOL_SIZE = 20; + private static final SynchronizedPool<ExtraRenderingInfo> sPool = + new SynchronizedPool<>(MAX_POOL_SIZE); + + private Size mLayoutParams; + private float mTextSizeInPx = UNDEFINED_VALUE; + private int mTextSizeUnit = UNDEFINED_VALUE; + + /** + * Obtains a pooled instance. + * @hide + */ + @NonNull + public static ExtraRenderingInfo obtain() { + final ExtraRenderingInfo info = sPool.acquire(); + if (info == null) { + return new ExtraRenderingInfo(null); + } + return info; + } + + /** Obtains a pooled instance that is a clone of another one. */ + private static ExtraRenderingInfo obtain(ExtraRenderingInfo other) { + ExtraRenderingInfo extraRenderingInfo = ExtraRenderingInfo.obtain(); + extraRenderingInfo.mLayoutParams = other.mLayoutParams; + extraRenderingInfo.mTextSizeInPx = other.mTextSizeInPx; + extraRenderingInfo.mTextSizeUnit = other.mTextSizeUnit; + return extraRenderingInfo; + } + + /** + * Creates a new conformance info of a view, and this new instance is initialized from + * the given <code>other</code>. + * + * @param other The instance to clone. + */ + private ExtraRenderingInfo(@Nullable ExtraRenderingInfo other) { + if (other != null) { + mLayoutParams = other.mLayoutParams; + mTextSizeInPx = other.mTextSizeInPx; + mTextSizeUnit = other.mTextSizeUnit; + } + } + + /** + * @return a {@link Size} stores layout height and layout width of the view, + * or null otherwise. + */ + public @Nullable Size getLayoutParams() { + return mLayoutParams; + } + + /** + * Sets layout width and layout height of the view. + * + * @param width The layout width. + * @param height The layout height. + * @hide + */ + public void setLayoutParams(int width, int height) { + mLayoutParams = new Size(width, height); + } + + /** + * @return the text size of a {@code TextView}, or -1 otherwise. + */ + public float getTextSizeInPx() { + return mTextSizeInPx; + } + + /** + * Sets text size of the view. + * + * @param textSizeInPx The text size in pixels. + * @hide + */ + public void setTextSizeInPx(float textSizeInPx) { + mTextSizeInPx = textSizeInPx; + } + + /** + * @return the text size unit which type is {@link TypedValue#TYPE_DIMENSION} of a + * {@code TextView}, or -1 otherwise. + * + * @see TypedValue#TYPE_DIMENSION + */ + public int getTextSizeUnit() { + return mTextSizeUnit; + } + + /** + * Sets text size unit of the view. + * + * @param textSizeUnit The text size unit. + * @hide + */ + public void setTextSizeUnit(int textSizeUnit) { + mTextSizeUnit = textSizeUnit; + } + + /** + * Recycles this instance. + * + * <p>In most situations object pooling is not beneficial, and recycling is not necessary. + */ + void recycle() { + clear(); + sPool.release(this); + } + + private void clear() { + mLayoutParams = null; + mTextSizeInPx = UNDEFINED_VALUE; + mTextSizeUnit = UNDEFINED_VALUE; + } + } + + /** * @see android.os.Parcelable.Creator */ public static final @android.annotation.NonNull Parcelable.Creator<AccessibilityNodeInfo> CREATOR = diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 0182975c13c0..815cc5cbb10d 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -17,6 +17,7 @@ package android.widget; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; +import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY; import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH; import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX; import static android.view.accessibility.AccessibilityNodeInfo.EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY; @@ -727,6 +728,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @UnsupportedAppUsage private Layout mLayout; private boolean mLocalesChanged = false; + private int mTextSizeUnit = -1; // True if setKeyListener() has been explicitly called private boolean mListenerChanged = false; @@ -3842,6 +3844,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener ColorStateList mTextColorHint = null; ColorStateList mTextColorLink = null; int mTextSize = -1; + int mTextSizeUnit = -1; LocaleList mTextLocales = null; String mFontFamily = null; Typeface mFontTypeface = null; @@ -3869,6 +3872,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener + " mTextColorHint:" + mTextColorHint + "\n" + " mTextColorLink:" + mTextColorLink + "\n" + " mTextSize:" + mTextSize + "\n" + + " mTextSizeUnit:" + mTextSizeUnit + "\n" + " mTextLocales:" + mTextLocales + "\n" + " mFontFamily:" + mFontFamily + "\n" + " mFontTypeface:" + mFontTypeface + "\n" @@ -3980,6 +3984,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case com.android.internal.R.styleable.TextAppearance_textSize: attributes.mTextSize = appearance.getDimensionPixelSize(attr, attributes.mTextSize); + attributes.mTextSizeUnit = appearance.peekValue(attr).getComplexUnit(); break; case com.android.internal.R.styleable.TextAppearance_textLocale: final String localeString = appearance.getString(attr); @@ -4073,6 +4078,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } if (attributes.mTextSize != -1) { + mTextSizeUnit = attributes.mTextSizeUnit; setRawTextSize(attributes.mTextSize, true /* shouldRequestLayout */); } @@ -4295,6 +4301,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener r = c.getResources(); } + mTextSizeUnit = unit; setRawTextSize(TypedValue.applyDimension(unit, size, r.getDisplayMetrics()), shouldRequestLayout); } @@ -4315,6 +4322,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Gets the text size unit defined by the developer. It may be specified in resources or be + * passed as the unit argument of {@link #setTextSize(int, float)} at runtime. + * + * @return the dimension type of the text size unit originally defined. + * @see TypedValue#TYPE_DIMENSION + */ + public int getTextSizeUnit() { + return mTextSizeUnit; + } + + /** * Gets the extent by which text should be stretched horizontally. * This will usually be 1.0. * @return The horizontal scale factor. @@ -11769,8 +11787,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE); info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); - info.setAvailableExtraData( - Arrays.asList(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)); + info.setAvailableExtraData(Arrays.asList( + EXTRA_DATA_RENDERING_INFO_KEY, + EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY + )); + } else { + info.setAvailableExtraData(Arrays.asList( + EXTRA_DATA_RENDERING_INFO_KEY + )); } if (isFocused()) { @@ -11824,11 +11848,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void addExtraDataToAccessibilityNodeInfo( AccessibilityNodeInfo info, String extraDataKey, Bundle arguments) { - // The only extra data we support requires arguments. - if (arguments == null) { - return; - } - if (extraDataKey.equals(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)) { + if (arguments != null && extraDataKey.equals(EXTRA_DATA_TEXT_CHARACTER_LOCATION_KEY)) { int positionInfoStartIndex = arguments.getInt( EXTRA_DATA_TEXT_CHARACTER_LOCATION_ARG_START_INDEX, -1); int positionInfoLength = arguments.getInt( @@ -11856,6 +11876,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } info.getExtras().putParcelableArray(extraDataKey, boundingRects); + return; + } + if (extraDataKey.equals(AccessibilityNodeInfo.EXTRA_DATA_RENDERING_INFO_KEY)) { + final AccessibilityNodeInfo.ExtraRenderingInfo extraRenderingInfo = + AccessibilityNodeInfo.ExtraRenderingInfo.obtain(); + extraRenderingInfo.setLayoutParams(getLayoutParams().width, getLayoutParams().height); + extraRenderingInfo.setTextSizeInPx(getTextSize()); + extraRenderingInfo.setTextSizeUnit(getTextSizeUnit()); + info.setExtraRenderingInfo(extraRenderingInfo); } } diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java index ade1e0de7102..79e7c50e7987 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java @@ -46,7 +46,7 @@ public class AccessibilityNodeInfoTest { // The number of fields tested in the corresponding CTS AccessibilityNodeInfoTest: // See fullyPopulateAccessibilityNodeInfo, assertEqualsAccessibilityNodeInfo, // and assertAccessibilityNodeInfoCleared in that class. - private static final int NUM_MARSHALLED_PROPERTIES = 38; + private static final int NUM_MARSHALLED_PROPERTIES = 39; /** * The number of properties that are purposely not marshalled |