diff options
| author | 2024-08-24 03:13:40 +0000 | |
|---|---|---|
| committer | 2024-10-09 17:51:39 +0000 | |
| commit | 212800a6ff56a216e92ee430d87480f5aec50e4c (patch) | |
| tree | 348e8f72e7629177ac8f0548fa34cdece4196463 | |
| parent | 79d663532e23deb4798782c3ee16a7b835ed9862 (diff) | |
Add tri-state checked api
Design doc: https://docs.google.com/document/d/1vUzX7eSbIw_0N0kD5cYO09almUzYB7YhHNRhZcfKfXo/edit?usp=sharing
Test: CTS test added
Flag: android.view.accessibility.tri_state_checked
Bug: 333784774
Change-Id: Ifc8eee777740397d089ad242daa711bfc224722d
5 files changed, 151 insertions, 6 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 00541afeea99..98e2dba84634 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -54919,6 +54919,7 @@ package android.view.accessibility { method public void setPackageName(CharSequence); method public void setSpeechStateChangeTypes(int); method public void writeToParcel(android.os.Parcel, int); + field @FlaggedApi("android.view.accessibility.tri_state_checked") public static final int CONTENT_CHANGE_TYPE_CHECKED = 8192; // 0x2000 field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4 field public static final int CONTENT_CHANGE_TYPE_CONTENT_INVALID = 1024; // 0x400 field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200 @@ -55064,6 +55065,7 @@ package android.view.accessibility { method @Deprecated public void getBoundsInParent(android.graphics.Rect); method public void getBoundsInScreen(android.graphics.Rect); method public void getBoundsInWindow(@NonNull android.graphics.Rect); + method @FlaggedApi("android.view.accessibility.tri_state_checked") public int getChecked(); method public android.view.accessibility.AccessibilityNodeInfo getChild(int); method @Nullable public android.view.accessibility.AccessibilityNodeInfo getChild(int, int); method public int getChildCount(); @@ -55106,7 +55108,7 @@ package android.view.accessibility { method public boolean isAccessibilityDataSensitive(); method public boolean isAccessibilityFocused(); method public boolean isCheckable(); - method public boolean isChecked(); + method @Deprecated @FlaggedApi("android.view.accessibility.tri_state_checked") public boolean isChecked(); method public boolean isClickable(); method public boolean isContentInvalid(); method public boolean isContextClickable(); @@ -55151,7 +55153,8 @@ package android.view.accessibility { method public void setBoundsInWindow(@NonNull android.graphics.Rect); method public void setCanOpenPopup(boolean); method public void setCheckable(boolean); - method public void setChecked(boolean); + method @Deprecated @FlaggedApi("android.view.accessibility.tri_state_checked") public void setChecked(boolean); + method @FlaggedApi("android.view.accessibility.tri_state_checked") public void setChecked(int); method public void setClassName(CharSequence); method public void setClickable(boolean); method public void setCollectionInfo(android.view.accessibility.AccessibilityNodeInfo.CollectionInfo); @@ -55247,6 +55250,9 @@ package android.view.accessibility { field public static final int ACTION_SELECT = 4; // 0x4 field public static final int ACTION_SET_SELECTION = 131072; // 0x20000 field public static final int ACTION_SET_TEXT = 2097152; // 0x200000 + field @FlaggedApi("android.view.accessibility.tri_state_checked") public static final int CHECKED_STATE_FALSE = 0; // 0x0 + field @FlaggedApi("android.view.accessibility.tri_state_checked") public static final int CHECKED_STATE_PARTIAL = 2; // 0x2 + field @FlaggedApi("android.view.accessibility.tri_state_checked") public static final int CHECKED_STATE_TRUE = 1; // 0x1 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"; diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java index a43906f30ff7..dfac244fcc0d 100644 --- a/core/java/android/view/accessibility/AccessibilityEvent.java +++ b/core/java/android/view/accessibility/AccessibilityEvent.java @@ -16,6 +16,7 @@ package android.view.accessibility; +import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; @@ -784,6 +785,19 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par */ public static final int CONTENT_CHANGE_TYPE_ENABLED = 1 << 12; + /** + * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event: + * The source node changed its checked state, which is returned by + * {@link AccessibilityNodeInfo#getChecked()}. + * The view changing its checked state should call + * {@link AccessibilityNodeInfo#setChecked(int)} and then send this event. + * + * @see AccessibilityNodeInfo#getChecked() + * @see AccessibilityNodeInfo#setChecked(int) + */ + @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED) + public static final int CONTENT_CHANGE_TYPE_CHECKED = 1 << 13; + // Speech state change types. /** Change type for {@link #TYPE_SPEECH_STATE_CHANGE} event: another service is speaking. */ diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index fe6aafbd7e16..c5ca059d1cea 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -860,6 +860,37 @@ public class AccessibilityNodeInfo implements Parcelable { public static final String EXTRA_DATA_REQUESTED_KEY = "android.view.accessibility.AccessibilityNodeInfo.extra_data_requested"; + // Tri-state checked states. + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "CHECKED_STATE" }, value = { + CHECKED_STATE_FALSE, + CHECKED_STATE_TRUE, + CHECKED_STATE_PARTIAL + }) + public @interface CheckedState {} + + /** + * This node is not checked. + */ + @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED) + public static final int CHECKED_STATE_FALSE = 0; + + /** + * This node is checked. + */ + @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED) + public static final int CHECKED_STATE_TRUE = 1; + + /** + * This node is partially checked. For example, + * when a checkbox owns a number of sub-options and they have + * different states, then the main checkbox is in a partially-checked state. + */ + @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED) + public static final int CHECKED_STATE_PARTIAL = 2; + // Boolean attributes. private static final int BOOLEAN_PROPERTY_CHECKABLE = 1 /* << 0 */; @@ -1038,6 +1069,10 @@ public class AccessibilityNodeInfo implements Parcelable { private IBinder mLeashedParent; private long mLeashedParentNodeId = UNDEFINED_NODE_ID; + // TODO(b/369951517) Initialize mChecked explicitly with + // the CHECKED_FALSE state when flagging is removed. + private int mChecked; + /** * Creates a new {@link AccessibilityNodeInfo}. */ @@ -2319,28 +2354,100 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * Gets whether this node is checked. + * Gets whether this node is checked. This is only meaningful + * when {@link #isCheckable()} returns {@code true}. + * + * @deprecated Use {@link #getChecked()} instead. * * @return True if the node is checked. */ + @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED) + @Deprecated public boolean isChecked() { return getBooleanProperty(BOOLEAN_PROPERTY_CHECKED); } /** - * Sets whether this node is checked. + * Sets whether this node is checked. This is only meaningful + * when {@link #isCheckable()} returns {@code true}. * <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> * + * @deprecated Use {@link #setChecked(int)} instead. + * * @param checked True if the node is checked. * * @throws IllegalStateException If called from an AccessibilityService. */ + @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED) + @Deprecated public void setChecked(boolean checked) { setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked); + if (Flags.triStateChecked()) { + mChecked = checked ? CHECKED_STATE_TRUE : CHECKED_STATE_FALSE; + } + } + + /** + * Gets the checked state of this node. This is only meaningful + * when {@link #isCheckable()} returns {@code true}. + * + * @see #setCheckable(boolean) + * @see #isCheckable() + * @see #setChecked(int) + * + * @return The checked state, one of: + * <ul> + * <li>{@link #CHECKED_STATE_FALSE} + * <li>{@link #CHECKED_STATE_TRUE} + * <li>{@link #CHECKED_STATE_PARTIAL} + * </ul> + */ + @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED) + public @CheckedState int getChecked() { + return mChecked; + } + + /** + * Sets the checked state of this node. This is only meaningful + * when {@link #isCheckable()} returns {@code true}. + * <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> + * + * @see #setCheckable(boolean) + * @see #isCheckable() + * @see #getChecked() + * + * @param checked The checked state. One of + * <ul> + * <li>{@link #CHECKED_STATE_FALSE} + * <li>{@link #CHECKED_STATE_TRUE} + * <li>{@link #CHECKED_STATE_PARTIAL} + * </ul> + * + * @throws IllegalStateException If called from an AccessibilityService. + * @throws IllegalArgumentException if checked is not one of {@link #CHECKED_STATE_FALSE}, + * {@link #CHECKED_STATE_TRUE}, or {@link #CHECKED_STATE_PARTIAL}. + */ + @FlaggedApi(Flags.FLAG_TRI_STATE_CHECKED) + public void setChecked(@CheckedState int checked) { + enforceNotSealed(); + switch (checked) { + case CHECKED_STATE_FALSE: + case CHECKED_STATE_TRUE: + case CHECKED_STATE_PARTIAL: + mChecked = checked; + break; + default: + throw new IllegalArgumentException("Unknown checked argument: " + checked); + } + setBooleanProperty(BOOLEAN_PROPERTY_CHECKED, checked == CHECKED_STATE_TRUE); } /** @@ -4515,6 +4622,10 @@ public class AccessibilityNodeInfo implements Parcelable { if (mLeashedParentNodeId != DEFAULT.mLeashedParentNodeId) { nonDefaultFields |= bitAt(fieldIndex); } + fieldIndex++; + if (mChecked != DEFAULT.mChecked) { + nonDefaultFields |= bitAt(fieldIndex); + } int totalFields = fieldIndex; parcel.writeLong(nonDefaultFields); @@ -4683,6 +4794,9 @@ public class AccessibilityNodeInfo implements Parcelable { if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeLong(mLeashedParentNodeId); } + if (isBitSet(nonDefaultFields, fieldIndex++)) { + parcel.writeInt(mChecked); + } if (DEBUG) { fieldIndex--; @@ -4771,6 +4885,7 @@ public class AccessibilityNodeInfo implements Parcelable { mLeashedChild = other.mLeashedChild; mLeashedParent = other.mLeashedParent; mLeashedParentNodeId = other.mLeashedParentNodeId; + mChecked = other.mChecked; } private void initCopyInfos(AccessibilityNodeInfo other) { @@ -4960,6 +5075,9 @@ public class AccessibilityNodeInfo implements Parcelable { if (isBitSet(nonDefaultFields, fieldIndex++)) { mLeashedParentNodeId = parcel.readLong(); } + if (isBitSet(nonDefaultFields, fieldIndex++)) { + mChecked = parcel.readInt(); + } mSealed = sealed; } diff --git a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig index 69cbb9b2bfb8..8ffae845de1f 100644 --- a/core/java/android/view/accessibility/flags/accessibility_flags.aconfig +++ b/core/java/android/view/accessibility/flags/accessibility_flags.aconfig @@ -219,6 +219,13 @@ flag { } flag { + name: "tri_state_checked" + namespace: "accessibility" + description: "Feature flag for adding tri-state checked api" + bug: "333784774" +} + +flag { name: "warning_use_default_dialog_type" namespace: "accessibility" description: "Uses the default type for the A11yService warning dialog, instead of SYSTEM_ALERT_DIALOG" @@ -226,4 +233,4 @@ flag { metadata { purpose: PURPOSE_BUGFIX } -} + } diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java index 6e563ff44478..da202b63d0f1 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 = 44; + private static final int NUM_MARSHALLED_PROPERTIES = 45; /** * The number of properties that are purposely not marshalled |