Add Settings for vector-specific PointerIcon stroke colors.

Bug: 305193969
Test: PointerIconLoadingTest
Flag: android.view.flags.enable_vector_cursor_a11y_settings
Change-Id: I72213e8806fed451a0edb16d497406ffae5c1a44
This commit is contained in:
Pat Manning
2024-03-07 16:41:47 +00:00
parent 9ff81e6b3a
commit 620755c293
8 changed files with 390 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?><!--
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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:orientation="vertical"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingStart="?android:attr/listPreferredItemPaddingStart">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/pointer_stroke_style_padding"
android:text="@string/pointer_stroke_style"
android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceListItem" />
<RadioGroup
android:id="@+id/button_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="@dimen/pointer_stroke_style_padding"
android:layout_marginBottom="@dimen/pointer_stroke_style_padding"
android:padding="@dimen/pointer_stroke_style_padding">
<RadioButton android:id="@+id/stroke_style_white"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/pointer_stroke_style_padding"
android:text="@string/pointer_stroke_style_name_white"/>
<RadioButton android:id="@+id/stroke_style_black"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/pointer_stroke_style_padding"
android:text="@string/pointer_stroke_style_name_black"/>
<RadioButton android:id="@+id/stroke_style_none"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/pointer_stroke_style_padding"
android:text="@string/pointer_stroke_style_name_none"/>
</RadioGroup>
</LinearLayout>

View File

@@ -179,6 +179,7 @@
<dimen name="pointer_fill_style_circle_padding">8dp</dimen> <dimen name="pointer_fill_style_circle_padding">8dp</dimen>
<dimen name="pointer_fill_style_shape_default_stroke">1dp</dimen> <dimen name="pointer_fill_style_shape_default_stroke">1dp</dimen>
<dimen name="pointer_fill_style_shape_hovered_stroke">3dp</dimen> <dimen name="pointer_fill_style_shape_hovered_stroke">3dp</dimen>
<dimen name="pointer_stroke_style_padding">8dp</dimen>
<dimen name="pointer_scale_padding">8dp</dimen> <dimen name="pointer_scale_padding">8dp</dimen>
<item name="pointer_scale_size_start" format="float" type="dimen">1.0</item> <item name="pointer_scale_size_start" format="float" type="dimen">1.0</item>
<item name="pointer_scale_size_end" format="float" type="dimen">2.5</item> <item name="pointer_scale_size_end" format="float" type="dimen">2.5</item>

View File

@@ -4501,6 +4501,14 @@
<string name="pointer_fill_style_pink_button">Change pointer fill style to pink</string> <string name="pointer_fill_style_pink_button">Change pointer fill style to pink</string>
<!-- Content description for blue pointer fill style. [CHAR LIMIT=60] --> <!-- Content description for blue pointer fill style. [CHAR LIMIT=60] -->
<string name="pointer_fill_style_blue_button">Change pointer fill style to blue</string> <string name="pointer_fill_style_blue_button">Change pointer fill style to blue</string>
<!-- Title text for mouse pointer stroke style. [CHAR LIMIT=35] -->
<string name="pointer_stroke_style">Pointer stroke style</string>
<!-- White value for pointer stroke style. [CHAR LIMIT=35] -->
<string name="pointer_stroke_style_name_white">White</string>
<!-- Black value pointer stroke style. [CHAR LIMIT=35] -->
<string name="pointer_stroke_style_name_black">Black</string>
<!-- None value for pointer stroke style. [CHAR LIMIT=35] -->
<string name="pointer_stroke_style_name_none">None</string>
<!-- Title for the button to trigger the 'touch gesture' education. [CHAR LIMIT=35] --> <!-- Title for the button to trigger the 'touch gesture' education. [CHAR LIMIT=35] -->
<string name="trackpad_touch_gesture">Learn touchpad gestures</string> <string name="trackpad_touch_gesture">Learn touchpad gestures</string>
<!-- Search keywords for "touchpad" --> <!-- Search keywords for "touchpad" -->

View File

@@ -68,6 +68,12 @@
android:order="50" android:order="50"
settings:controller="com.android.settings.inputmethod.PointerFillStylePreferenceController"/> settings:controller="com.android.settings.inputmethod.PointerFillStylePreferenceController"/>
<com.android.settings.inputmethod.PointerStrokeStylePreference
android:key="pointer_stroke_style"
android:title="@string/pointer_stroke_style"
android:order="60"
settings:controller="com.android.settings.inputmethod.PointerStrokeStylePreferenceController"/>
<com.android.settings.widget.LabeledSeekBarPreference <com.android.settings.widget.LabeledSeekBarPreference
android:key="pointer_scale" android:key="pointer_scale"
android:title="@string/pointer_scale" android:title="@string/pointer_scale"

View File

@@ -0,0 +1,75 @@
/*
* 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 static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_BLACK;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_NONE;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
import android.content.Context;
import android.provider.Settings;
import android.util.AttributeSet;
import android.view.PointerIcon;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
public class PointerStrokeStylePreference extends Preference {
public PointerStrokeStylePreference(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.pointer_icon_stroke_style_layout);
}
@Override
public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
LinearLayout buttonHolder = (LinearLayout) holder.findViewById(R.id.button_holder);
// Intercept hover events so setting row does not highlight when hovering buttons.
buttonHolder.setOnHoverListener((v, e) -> true);
int currentStroke = getPreferenceDataStore().getInt(Settings.System.POINTER_STROKE_STYLE,
POINTER_ICON_VECTOR_STYLE_STROKE_WHITE);
initRadioButton(holder, R.id.stroke_style_white, POINTER_ICON_VECTOR_STYLE_STROKE_WHITE,
currentStroke);
initRadioButton(holder, R.id.stroke_style_black, POINTER_ICON_VECTOR_STYLE_STROKE_BLACK,
currentStroke);
initRadioButton(holder, R.id.stroke_style_none, POINTER_ICON_VECTOR_STYLE_STROKE_NONE,
currentStroke);
}
private void initRadioButton(@NonNull PreferenceViewHolder holder, int id, int strokeStyle,
int currentStroke) {
RadioButton radioButton = (RadioButton) holder.findViewById(id);
if (radioButton == null) {
return;
}
radioButton.setOnCheckedChangeListener((v, isChecked) -> {
if (isChecked) {
getPreferenceDataStore().putInt(Settings.System.POINTER_STROKE_STYLE, strokeStyle);
}
});
radioButton.setChecked(currentStroke == strokeStyle);
radioButton.setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_ARROW));
}
}

View File

@@ -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 PointerStrokeStylePreferenceController extends BasePreferenceController {
@VisibleForTesting
static final String KEY_POINTER_STROKE_STYLE = "pointer_stroke_style";
public PointerStrokeStylePreferenceController(@NonNull Context context) {
super(context, KEY_POINTER_STROKE_STYLE);
}
@AvailabilityStatus
public int getAvailabilityStatus() {
return android.view.flags.Flags.enableVectorCursorA11ySettings() ? AVAILABLE
: CONDITIONALLY_UNAVAILABLE;
}
@Override
public void displayPreference(@NonNull PreferenceScreen screen) {
super.displayPreference(screen);
Preference pointerStrokeStylePreference = screen.findPreference(KEY_POINTER_STROKE_STYLE);
if (pointerStrokeStylePreference == null) {
return;
}
pointerStrokeStylePreference.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);
}
});
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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 static android.view.flags.Flags.enableVectorCursorA11ySettings;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.inputmethod.PointerStrokeStylePreferenceController.KEY_POINTER_STROKE_STYLE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
import android.content.Context;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link PointerStrokeStylePreferenceController} */
@RunWith(RobolectricTestRunner.class)
public class PointerStrokeStylePreferenceControllerTest {
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
PreferenceScreen mPreferenceScreen;
private Context mContext;
private PointerStrokeStylePreferenceController mController;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mController = new PointerStrokeStylePreferenceController(mContext);
}
@Test
public void displayPreference_initializeDataStore() {
Preference strokePreference = new Preference(mContext);
strokePreference.setKey(KEY_POINTER_STROKE_STYLE);
when(mPreferenceScreen.findPreference(eq(KEY_POINTER_STROKE_STYLE))).thenReturn(
strokePreference);
mController.displayPreference(mPreferenceScreen);
assertNotNull(strokePreference.getPreferenceDataStore());
}
@Test
public void getAvailabilityStatus_flagEnabled() {
assumeTrue(enableVectorCursorA11ySettings());
assertEquals(mController.getAvailabilityStatus(), AVAILABLE);
}
}

View File

@@ -0,0 +1,92 @@
/*
* 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 static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_BLACK;
import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_STROKE_WHITE;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
import android.provider.Settings;
import android.view.View;
import android.widget.RadioButton;
import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceViewHolder;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link PointerStrokeStylePreference} */
@RunWith(RobolectricTestRunner.class)
public class PointerStrokeStylePreferenceTest {
@Rule
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
PreferenceDataStore mPreferenceDataStore;
private Context mContext;
private PreferenceViewHolder mViewHolder;
private PointerStrokeStylePreference mPreference;
@Before
public void setUp() {
mContext = ApplicationProvider.getApplicationContext();
mPreference = new PointerStrokeStylePreference(mContext, null);
}
@Test
public void onBindViewHolder_getCurrentStrokeStyleFromDataStore() {
final View view = spy(View.inflate(mContext, mPreference.getLayoutResource(), null));
mViewHolder = PreferenceViewHolder.createInstanceForTests(view);
mPreference.setPreferenceDataStore(mPreferenceDataStore);
mPreference.onBindViewHolder(mViewHolder);
verify(mPreferenceDataStore).getInt(Settings.System.POINTER_STROKE_STYLE,
POINTER_ICON_VECTOR_STYLE_STROKE_WHITE);
}
@Test
public void setChecked_radioButtonUpdatesDataStore() {
final View view = spy(View.inflate(mContext, mPreference.getLayoutResource(), null));
mViewHolder = PreferenceViewHolder.createInstanceForTests(view);
mPreference.setPreferenceDataStore(mPreferenceDataStore);
RadioButton radioButton = (RadioButton) view.findViewById(R.id.stroke_style_black);
mPreference.onBindViewHolder(mViewHolder);
radioButton.setChecked(true);
verify(mPreferenceDataStore).getInt(Settings.System.POINTER_STROKE_STYLE,
POINTER_ICON_VECTOR_STYLE_STROKE_WHITE);
verify(mPreferenceDataStore).putInt(Settings.System.POINTER_STROKE_STYLE,
POINTER_ICON_VECTOR_STYLE_STROKE_BLACK);
}
}