Add vector-specific stroke color A11Y settings to PointerIcon.
Bug: 305193969
Test: PointerIconLoadingTest
Flag: android.view.flags.enable_vector_cursor_a11y_settings
Change-Id: Id899d1bef33715e0c0327ffbc471f9e272c5c3ad
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 57853e7..c0e46fa 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6178,6 +6178,15 @@
public static final String POINTER_FILL_STYLE = "pointer_fill_style";
/**
+ * Pointer stroke style, specified by
+ * {@link android.view.PointerIcon.PointerIconVectorStyleStroke} constants.
+ *
+ * @hide
+ */
+ @Readable
+ public static final String POINTER_STROKE_STYLE = "pointer_stroke_style";
+
+ /**
* Whether lock-to-app will be triggered by long-press on recents.
* @hide
*/
@@ -6380,6 +6389,7 @@
PRIVATE_SETTINGS.add(SIP_ASK_ME_EACH_TIME);
PRIVATE_SETTINGS.add(POINTER_SPEED);
PRIVATE_SETTINGS.add(POINTER_FILL_STYLE);
+ PRIVATE_SETTINGS.add(POINTER_STROKE_STYLE);
PRIVATE_SETTINGS.add(POINTER_SCALE);
PRIVATE_SETTINGS.add(LOCK_TO_APP_ENABLED);
PRIVATE_SETTINGS.add(EGG_MODE);
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index c302126..1535145 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -193,6 +193,25 @@
/** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_FILL_END =
POINTER_ICON_VECTOR_STYLE_FILL_BLUE;
+ /** @hide */
+ @IntDef(prefix = {"POINTER_ICON_VECTOR_STYLE_STROKE_"}, value = {
+ POINTER_ICON_VECTOR_STYLE_STROKE_WHITE,
+ POINTER_ICON_VECTOR_STYLE_STROKE_BLACK,
+ POINTER_ICON_VECTOR_STYLE_STROKE_NONE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PointerIconVectorStyleStroke {}
+
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_STROKE_WHITE = 0;
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_STROKE_BLACK = 1;
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_STROKE_NONE = 2;
+
+ // If adding PointerIconVectorStyleStroke, update END value for {@link SystemSettingsValidators}
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_STROKE_BEGIN =
+ POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
+ /** @hide */ public static final int POINTER_ICON_VECTOR_STYLE_STROKE_END =
+ POINTER_ICON_VECTOR_STYLE_STROKE_NONE;
+
/** @hide */ public static final float DEFAULT_POINTER_SCALE = 1f;
/** @hide */ public static final float LARGE_POINTER_SCALE = 2.5f;
@@ -712,6 +731,23 @@
}
/**
+ * Convert stroke style constant to resource ID.
+ *
+ * @hide
+ */
+ public static int vectorStrokeStyleToResource(@PointerIconVectorStyleStroke int strokeStyle) {
+ return switch (strokeStyle) {
+ case POINTER_ICON_VECTOR_STYLE_STROKE_BLACK ->
+ com.android.internal.R.style.PointerIconVectorStyleStrokeBlack;
+ case POINTER_ICON_VECTOR_STYLE_STROKE_WHITE ->
+ com.android.internal.R.style.PointerIconVectorStyleStrokeWhite;
+ case POINTER_ICON_VECTOR_STYLE_STROKE_NONE ->
+ com.android.internal.R.style.PointerIconVectorStyleStrokeNone;
+ default -> com.android.internal.R.style.PointerIconVectorStyleStrokeWhite;
+ };
+ }
+
+ /**
* Sets whether drop shadow will draw in the native code.
*
* @hide
diff --git a/core/proto/android/providers/settings/system.proto b/core/proto/android/providers/settings/system.proto
index 6a0ec1d..e5ced25 100644
--- a/core/proto/android/providers/settings/system.proto
+++ b/core/proto/android/providers/settings/system.proto
@@ -126,6 +126,7 @@
option (android.msg_privacy).dest = DEST_EXPLICIT;
optional SettingProto pointer_fill_style = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto pointer_stroke_style = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto pointer_scale = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
}
optional Pointer pointer = 37;
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4883827..27c6a24 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -9704,6 +9704,8 @@
<declare-styleable name="PointerIconVectorTheme">
<attr name="pointerIconVectorFill" format="color" />
<attr name="pointerIconVectorFillInverse" format="color" />
+ <attr name="pointerIconVectorStroke" format="color" />
+ <attr name="pointerIconVectorStrokeInverse" format="color" />
</declare-styleable>
<declare-styleable name="Storage">
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 50c3b1a..aabc8ca 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1527,6 +1527,24 @@
</style>
<!-- @hide -->
+ <style name="PointerIconVectorStyleStrokeWhite">
+ <item name="pointerIconVectorStroke">@color/white</item>
+ <item name="pointerIconVectorStrokeInverse">@color/black</item>
+ </style>
+
+ <!-- @hide -->
+ <style name="PointerIconVectorStyleStrokeBlack">
+ <item name="pointerIconVectorStroke">@color/black</item>
+ <item name="pointerIconVectorStrokeInverse">@color/white</item>
+ </style>
+
+ <!-- @hide -->
+ <style name="PointerIconVectorStyleStrokeNone">
+ <item name="pointerIconVectorStroke">@color/transparent</item>
+ <item name="pointerIconVectorStrokeInverse">@color/transparent</item>
+ </style>
+
+ <!-- @hide -->
<style name="aerr_list_item" parent="Widget.Material.Light.Button.Borderless">
<item name="minHeight">?attr/listPreferredItemHeightSmall</item>
<item name="textAppearance">?attr/textAppearanceListItemSmall</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 7a51abc..3def092 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1704,6 +1704,10 @@
<java-symbol type="style" name="PointerIconVectorStyleFillPink" />
<java-symbol type="style" name="PointerIconVectorStyleFillBlue" />
<java-symbol type="attr" name="pointerIconVectorFill" />
+ <java-symbol type="style" name="PointerIconVectorStyleStrokeWhite" />
+ <java-symbol type="style" name="PointerIconVectorStyleStrokeBlack" />
+ <java-symbol type="style" name="PointerIconVectorStyleStrokeNone" />
+ <java-symbol type="attr" name="pointerIconVectorStroke" />
<java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Title" />
<java-symbol type="style" name="TextAppearance.DeviceDefault.Notification.Info" />
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 00fb7a1..2cdd0ae 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -80,6 +80,7 @@
Settings.System.SIP_RECEIVE_CALLS,
Settings.System.POINTER_SPEED,
Settings.System.POINTER_FILL_STYLE,
+ Settings.System.POINTER_STROKE_STYLE,
Settings.System.POINTER_SCALE,
Settings.System.VIBRATE_ON,
Settings.System.VIBRATE_WHEN_RINGING,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 4235bc4..7b927d7 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -30,6 +30,8 @@
import static android.view.PointerIcon.LARGE_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BEGIN;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_END;
+import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_BEGIN;
+import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_END;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -213,6 +215,9 @@
VALIDATORS.put(System.POINTER_FILL_STYLE,
new InclusiveIntegerRangeValidator(POINTER_ICON_VECTOR_STYLE_FILL_BEGIN,
POINTER_ICON_VECTOR_STYLE_FILL_END));
+ VALIDATORS.put(System.POINTER_STROKE_STYLE,
+ new InclusiveIntegerRangeValidator(POINTER_ICON_VECTOR_STYLE_STROKE_BEGIN,
+ POINTER_ICON_VECTOR_STYLE_STROKE_END));
VALIDATORS.put(System.POINTER_SCALE,
new InclusiveFloatRangeValidator(DEFAULT_POINTER_SCALE, LARGE_POINTER_SCALE));
VALIDATORS.put(System.TOUCHPAD_POINTER_SPEED, new InclusiveIntegerRangeValidator(-7, 7));
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 384cb7e..cd37ad1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2916,6 +2916,9 @@
Settings.System.POINTER_FILL_STYLE,
SystemSettingsProto.Pointer.POINTER_FILL_STYLE);
dumpSetting(s, p,
+ Settings.System.POINTER_STROKE_STYLE,
+ SystemSettingsProto.Pointer.POINTER_STROKE_STYLE);
+ dumpSetting(s, p,
Settings.System.POINTER_SCALE,
SystemSettingsProto.Pointer.POINTER_SCALE);
p.end(pointerToken);
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index e5dbce9..77ab167 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3352,6 +3352,10 @@
mPointerIconCache.setPointerFillStyle(fillStyle);
}
+ void setPointerStrokeStyle(@PointerIcon.PointerIconVectorStyleStroke int strokeStyle) {
+ mPointerIconCache.setPointerStrokeStyle(strokeStyle);
+ }
+
void setPointerScale(float scale) {
mPointerIconCache.setPointerScale(scale);
}
diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java
index 593b091..000f312 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -18,6 +18,7 @@
import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
+import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
import static android.view.flags.Flags.enableVectorCursorA11ySettings;
import static com.android.input.flags.Flags.rateLimitUserActivityPokeInDispatcher;
@@ -103,6 +104,8 @@
(reason) -> updateStylusPointerIconEnabled()),
Map.entry(Settings.System.getUriFor(Settings.System.POINTER_FILL_STYLE),
(reason) -> updatePointerFillStyleFromSettings()),
+ Map.entry(Settings.System.getUriFor(Settings.System.POINTER_STROKE_STYLE),
+ (reason) -> updatePointerStrokeStyleFromSettings()),
Map.entry(Settings.System.getUriFor(Settings.System.POINTER_SCALE),
(reason) -> updatePointerScaleFromSettings()));
}
@@ -281,6 +284,17 @@
mService.setPointerFillStyle(pointerFillStyle);
}
+ private void updatePointerStrokeStyleFromSettings() {
+ if (!enableVectorCursorA11ySettings()) {
+ return;
+ }
+ final int pointerStrokeStyle = Settings.System.getIntForUser(
+ mContext.getContentResolver(), Settings.System.POINTER_STROKE_STYLE,
+ POINTER_ICON_VECTOR_STYLE_STROKE_WHITE,
+ UserHandle.USER_CURRENT);
+ mService.setPointerStrokeStyle(pointerStrokeStyle);
+ }
+
private void updatePointerScaleFromSettings() {
if (!enableVectorCursorA11ySettings()) {
return;
diff --git a/services/core/java/com/android/server/input/PointerIconCache.java b/services/core/java/com/android/server/input/PointerIconCache.java
index 44622d8..297cd68 100644
--- a/services/core/java/com/android/server/input/PointerIconCache.java
+++ b/services/core/java/com/android/server/input/PointerIconCache.java
@@ -18,6 +18,7 @@
import static android.view.PointerIcon.DEFAULT_POINTER_SCALE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
+import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
import android.annotation.NonNull;
import android.content.Context;
@@ -65,6 +66,9 @@
private @PointerIcon.PointerIconVectorStyleFill int mPointerIconFillStyle =
POINTER_ICON_VECTOR_STYLE_FILL_BLACK;
@GuardedBy("mLoadedPointerIconsByDisplayAndType")
+ private @PointerIcon.PointerIconVectorStyleStroke int mPointerIconStrokeStyle =
+ POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
+ @GuardedBy("mLoadedPointerIconsByDisplayAndType")
private float mPointerIconScale = DEFAULT_POINTER_SCALE;
private final DisplayManager.DisplayListener mDisplayListener =
@@ -120,6 +124,11 @@
mUiThreadHandler.post(() -> handleSetPointerFillStyle(fillStyle));
}
+ /** Set the stroke style for vector pointer icons. */
+ public void setPointerStrokeStyle(@PointerIcon.PointerIconVectorStyleStroke int strokeStyle) {
+ mUiThreadHandler.post(() -> handleSetPointerStrokeStyle(strokeStyle));
+ }
+
/** Set the scale for vector pointer icons. */
public void setPointerScale(float scale) {
mUiThreadHandler.post(() -> handleSetPointerScale(scale));
@@ -144,6 +153,8 @@
theme.setTo(context.getTheme());
theme.applyStyle(PointerIcon.vectorFillStyleToResource(mPointerIconFillStyle),
/* force= */ true);
+ theme.applyStyle(PointerIcon.vectorStrokeStyleToResource(mPointerIconStrokeStyle),
+ /* force= */ true);
icon = PointerIcon.getLoadedSystemIcon(new ContextThemeWrapper(context, theme),
type, mUseLargePointerIcons, mPointerIconScale);
iconsByType.put(type, icon);
@@ -224,6 +235,20 @@
}
@android.annotation.UiThread
+ private void handleSetPointerStrokeStyle(
+ @PointerIcon.PointerIconVectorStyleStroke int strokeStyle) {
+ synchronized (mLoadedPointerIconsByDisplayAndType) {
+ if (mPointerIconStrokeStyle == strokeStyle) {
+ return;
+ }
+ mPointerIconStrokeStyle = strokeStyle;
+ // Clear all cached icons on all displays.
+ mLoadedPointerIconsByDisplayAndType.clear();
+ }
+ mNative.reloadPointerIcons();
+ }
+
+ @android.annotation.UiThread
private void handleSetPointerScale(float scale) {
synchronized (mLoadedPointerIconsByDisplayAndType) {
if (mPointerIconScale == scale) {
diff --git a/tests/Input/assets/testPointerStrokeStyle.png b/tests/Input/assets/testPointerStrokeStyle.png
new file mode 100644
index 0000000..4ddde70
--- /dev/null
+++ b/tests/Input/assets/testPointerStrokeStyle.png
Binary files differ
diff --git a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
index d196b85..e0f8c6d 100644
--- a/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
+++ b/tests/Input/src/com/android/test/input/PointerIconLoadingTest.kt
@@ -88,6 +88,35 @@
theme.applyStyle(
PointerIcon.vectorFillStyleToResource(PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_GREEN),
/* force= */ true)
+ theme.applyStyle(PointerIcon.vectorStrokeStyleToResource(
+ PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_WHITE), /* force= */ true)
+
+ val pointerIcon =
+ PointerIcon.getLoadedSystemIcon(
+ ContextThemeWrapper(context, theme),
+ PointerIcon.TYPE_ARROW,
+ /* useLargeIcons= */ false,
+ /* pointerScale= */ 1f)
+
+ pointerIcon.getBitmap().assertAgainstGolden(
+ screenshotRule,
+ testName.methodName,
+ exactScreenshotMatcher
+ )
+ }
+
+ @Test
+ fun testPointerStrokeStyle() {
+ assumeTrue(enableVectorCursors())
+ assumeTrue(enableVectorCursorA11ySettings())
+
+ val theme: Resources.Theme = context.getResources().newTheme()
+ theme.setTo(context.getTheme())
+ theme.applyStyle(
+ PointerIcon.vectorFillStyleToResource(PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_BLACK),
+ /* force= */ true)
+ theme.applyStyle(PointerIcon.vectorStrokeStyleToResource(
+ PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_BLACK), /* force= */ true)
val pointerIcon =
PointerIcon.getLoadedSystemIcon(