From 577965f9c28943b438401756ae3dbd2b0ba2e26b Mon Sep 17 00:00:00 2001 From: Pat Manning Date: Tue, 5 Mar 2024 15:18:56 +0000 Subject: [PATCH] Add Settings for vector-specific PointerIcon fill colors. Bug: 305193969 Test: PointerIconLoadingTest Flag: com.android.systemui.enable_vector_cursor_a11y_settings Change-Id: I84b4a6d5fde48309c2e3374963f92b8246167628 --- .../pointer_icon_fill_style_background.xml | 22 +++ res/layout/pointer_icon_fill_style_layout.xml | 102 +++++++++++ res/values/dimens.xml | 6 + res/values/strings.xml | 12 ++ res/xml/trackpad_settings.xml | 7 + .../PointerFillStylePreference.java | 160 ++++++++++++++++++ .../PointerFillStylePreferenceController.java | 67 ++++++++ 7 files changed, 376 insertions(+) create mode 100644 res/drawable/pointer_icon_fill_style_background.xml create mode 100644 res/layout/pointer_icon_fill_style_layout.xml create mode 100644 src/com/android/settings/inputmethod/PointerFillStylePreference.java create mode 100644 src/com/android/settings/inputmethod/PointerFillStylePreferenceController.java diff --git a/res/drawable/pointer_icon_fill_style_background.xml b/res/drawable/pointer_icon_fill_style_background.xml new file mode 100644 index 00000000000..1e98cf5c17f --- /dev/null +++ b/res/drawable/pointer_icon_fill_style_background.xml @@ -0,0 +1,22 @@ + + + + + + diff --git a/res/layout/pointer_icon_fill_style_layout.xml b/res/layout/pointer_icon_fill_style_layout.xml new file mode 100644 index 00000000000..1fa9baf7de4 --- /dev/null +++ b/res/layout/pointer_icon_fill_style_layout.xml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index 402fd042fab..c72c17d79b2 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -174,6 +174,12 @@ 28dp 16sp + + 52dp + 8dp + 1dp + 3dp + 40dp 14sp diff --git a/res/values/strings.xml b/res/values/strings.xml index f15137a66e8..479709f3c8c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4466,6 +4466,18 @@ Tap the bottom right corner of the touchpad for more options Pointer speed + + Pointer fill style + + Change pointer fill style to black + + Change pointer fill style to green + + Change pointer fill style to yellow + + Change pointer fill style to pink + + Change pointer fill style to blue Learn touchpad gestures diff --git a/res/xml/trackpad_settings.xml b/res/xml/trackpad_settings.xml index fcd43a575c9..1eb16b73156 100644 --- a/res/xml/trackpad_settings.xml +++ b/res/xml/trackpad_settings.xml @@ -62,6 +62,13 @@ android:selectable="false" settings:controller="com.android.settings.inputmethod.TrackpadPointerSpeedPreferenceController"/> + + true); + } + + int currentStyle = getPreferenceDataStore().getInt(Settings.System.POINTER_FILL_STYLE, + POINTER_ICON_VECTOR_STYLE_FILL_BLACK); + initStyleButton(holder, R.id.button_black, POINTER_ICON_VECTOR_STYLE_FILL_BLACK, + currentStyle); + initStyleButton(holder, R.id.button_green, POINTER_ICON_VECTOR_STYLE_FILL_GREEN, + currentStyle); + initStyleButton(holder, R.id.button_yellow, POINTER_ICON_VECTOR_STYLE_FILL_YELLOW, + currentStyle); + initStyleButton(holder, R.id.button_pink, POINTER_ICON_VECTOR_STYLE_FILL_PINK, + currentStyle); + initStyleButton(holder, R.id.button_blue, POINTER_ICON_VECTOR_STYLE_FILL_BLUE, + currentStyle); + } + + private void initStyleButton(@NonNull PreferenceViewHolder holder, int id, int style, + int currentStyle) { + ImageView button = (ImageView) holder.findViewById(id); + if (button == null) { + return; + } + int[] attrs = {com.android.internal.R.attr.pointerIconVectorFill}; + try (TypedArray ta = getContext().obtainStyledAttributes( + PointerIcon.vectorFillStyleToResource(style), attrs)) { + button.setBackground(getBackgroundSelector(ta.getColor(0, Color.BLACK))); + } + button.setForeground(getForegroundDrawable(style, currentStyle)); + button.setForegroundGravity(Gravity.CENTER); + button.setOnClickListener( + (v) -> { + getPreferenceDataStore().putInt(Settings.System.POINTER_FILL_STYLE, style); + setButtonChecked(id); + }); + button.setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_ARROW)); + } + + // Generate background instead of defining in XML so we can use res color from the platform. + private StateListDrawable getBackgroundSelector(int color) { + StateListDrawable background = new StateListDrawable(); + Resources res = getContext().getResources(); + int ovalSize = res.getDimensionPixelSize(R.dimen.pointer_fill_style_circle_diameter); + background.setBounds(0, 0, ovalSize, ovalSize); + + // Add hovered state first! The order states are added matters for a StateListDrawable. + GradientDrawable hoveredOval = new GradientDrawable(); + hoveredOval.setColor(color); + int textColor = Utils.getColorAttr(getContext(), + com.android.internal.R.attr.materialColorOutline).getDefaultColor(); + hoveredOval.setStroke( + res.getDimensionPixelSize(R.dimen.pointer_fill_style_shape_hovered_stroke), + textColor); + hoveredOval.setSize(ovalSize, ovalSize); + hoveredOval.setBounds(0, 0, ovalSize, ovalSize); + hoveredOval.setCornerRadius(ovalSize / 2f); + background.addState(new int[]{android.R.attr.state_hovered}, hoveredOval); + + GradientDrawable defaultOval = new GradientDrawable(); + defaultOval.setColor(color); + defaultOval.setStroke( + res.getDimensionPixelSize(R.dimen.pointer_fill_style_shape_default_stroke), + textColor); + defaultOval.setSize(ovalSize, ovalSize); + defaultOval.setBounds(0, 0, ovalSize, ovalSize); + defaultOval.setCornerRadius(ovalSize / 2f); + background.addState(StateSet.WILD_CARD, defaultOval); + + return background; + } + + private Drawable getForegroundDrawable(int style, int currentStyle) { + Resources res = getContext().getResources(); + int ovalSize = res.getDimensionPixelSize(R.dimen.pointer_fill_style_circle_diameter); + Drawable checkMark = getContext().getDrawable(R.drawable.ic_check_24dp); + int padding = res.getDimensionPixelSize(R.dimen.pointer_fill_style_circle_padding) / 2; + checkMark.setBounds(padding, padding, ovalSize - padding, ovalSize - padding); + checkMark.setColorFilter(new BlendModeColorFilter(Color.WHITE, BlendMode.SRC_IN)); + checkMark.setAlpha(style == currentStyle ? 255 : 0); + return checkMark; + } + + private void setButtonChecked(int id) { + if (mButtonHolder == null) { + return; + } + for (int i = 0; i < mButtonHolder.getChildCount(); i++) { + View child = mButtonHolder.getChildAt(i); + if (child != null) { + child.getForeground().setAlpha(child.getId() == id ? 255 : 0); + } + } + } +} diff --git a/src/com/android/settings/inputmethod/PointerFillStylePreferenceController.java b/src/com/android/settings/inputmethod/PointerFillStylePreferenceController.java new file mode 100644 index 00000000000..5abc3833405 --- /dev/null +++ b/src/com/android/settings/inputmethod/PointerFillStylePreferenceController.java @@ -0,0 +1,67 @@ +/* + * Copyright 2024 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.android.settings.inputmethod; + +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceDataStore; +import androidx.preference.PreferenceScreen; + +import com.android.settings.core.BasePreferenceController; + +public class PointerFillStylePreferenceController extends BasePreferenceController { + + @VisibleForTesting + static final String KEY_POINTER_FILL_STYLE = "pointer_fill_style"; + + public PointerFillStylePreferenceController(@NonNull Context context) { + super(context, KEY_POINTER_FILL_STYLE); + } + + @AvailabilityStatus + public int getAvailabilityStatus() { + return android.view.flags.Flags.enableVectorCursorA11ySettings() ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + Preference pointerFillStylePreference = screen.findPreference(KEY_POINTER_FILL_STYLE); + if (pointerFillStylePreference == null) { + return; + } + pointerFillStylePreference.setPreferenceDataStore(new PreferenceDataStore() { + @Override + public void putInt(@NonNull String key, int value) { + Settings.System.putIntForUser(mContext.getContentResolver(), key, value, + UserHandle.USER_CURRENT); + } + + @Override + public int getInt(@NonNull String key, int defValue) { + return Settings.System.getIntForUser(mContext.getContentResolver(), key, defValue, + UserHandle.USER_CURRENT); + } + }); + } +}