diff --git a/res/xml/mouse_settings.xml b/res/xml/mouse_settings.xml new file mode 100644 index 00000000000..bb6d1a04f4b --- /dev/null +++ b/res/xml/mouse_settings.xml @@ -0,0 +1,34 @@ + + + + + + + + + diff --git a/res/xml/system_dashboard_fragment.xml b/res/xml/system_dashboard_fragment.xml index 621a3253a83..83cdf64fc00 100644 --- a/res/xml/system_dashboard_fragment.xml +++ b/res/xml/system_dashboard_fragment.xml @@ -43,8 +43,8 @@ android:summary="@string/trackpad_settings_summary" android:icon="@drawable/ic_settings_trackpad" android:order="-254" - android:fragment="com.android.settings.inputmethod.TrackpadSettings" - settings:controller="com.android.settings.inputmethod.TrackpadSettingsController"/> + android:fragment="com.android.settings.inputmethod.TouchpadAndMouseSettings" + settings:controller="com.android.settings.inputmethod.TouchpadAndMouseSettingsController"/> + + + + + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 01fa54853cf..1a2e8eb138b 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -136,7 +136,7 @@ import com.android.settings.inputmethod.ModifierKeysSettings; import com.android.settings.inputmethod.NewKeyboardLayoutEnabledLocalesFragment; import com.android.settings.inputmethod.PhysicalKeyboardFragment; import com.android.settings.inputmethod.SpellCheckersSettings; -import com.android.settings.inputmethod.TrackpadSettings; +import com.android.settings.inputmethod.TouchpadAndMouseSettings; import com.android.settings.inputmethod.UserDictionaryList; import com.android.settings.inputmethod.UserDictionarySettings; import com.android.settings.language.LanguageSettings; @@ -237,7 +237,7 @@ public class SettingsGateway { KeyboardSettings.class.getName(), ModifierKeysSettings.class.getName(), NewKeyboardLayoutEnabledLocalesFragment.class.getName(), - TrackpadSettings.class.getName(), + TouchpadAndMouseSettings.class.getName(), SpellCheckersSettings.class.getName(), UserDictionaryList.class.getName(), UserDictionarySettings.class.getName(), diff --git a/src/com/android/settings/inputmethod/InputDeviceSettingsController.java b/src/com/android/settings/inputmethod/InputDeviceSettingsController.java new file mode 100644 index 00000000000..cbaad934363 --- /dev/null +++ b/src/com/android/settings/inputmethod/InputDeviceSettingsController.java @@ -0,0 +1,83 @@ +/* + * 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.hardware.input.InputManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.preference.Preference; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; + +public abstract class InputDeviceSettingsController extends BasePreferenceController + implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop, + InputManager.InputDeviceListener { + + private final InputManager mIm; + + @Nullable + private Preference mPreference; + + public InputDeviceSettingsController(@NonNull Context context, @NonNull String key) { + super(context, key); + mIm = context.getSystemService(InputManager.class); + } + + @Override + public void onInputDeviceAdded(int deviceId) { + updateEntry(); + } + + @Override + public void onInputDeviceRemoved(int deviceId) { + updateEntry(); + } + + @Override + public void onInputDeviceChanged(int deviceId) { + updateEntry(); + } + + @Override + public void onStart() { + mIm.registerInputDeviceListener(this, null); + } + + @Override + public void onStop() { + mIm.unregisterInputDeviceListener(this); + } + + @Override + public void updateState(Preference preference) { + mPreference = preference; + updateEntry(); + } + + private void updateEntry() { + if (mPreference == null) { + return; + } + mPreference.setVisible(isAvailable()); + } +} diff --git a/src/com/android/settings/inputmethod/MouseSettingFragment.java b/src/com/android/settings/inputmethod/MouseSettingFragment.java new file mode 100644 index 00000000000..de9e3e0592e --- /dev/null +++ b/src/com/android/settings/inputmethod/MouseSettingFragment.java @@ -0,0 +1,55 @@ +/* + * 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.app.settings.SettingsEnums; +import android.content.Context; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.keyboard.Flags; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.search.SearchIndexable; + +@SearchIndexable +public class MouseSettingFragment extends DashboardFragment { + private static final String TAG = MouseSettingFragment.class.getSimpleName(); + + @Override + protected int getPreferenceScreenResId() { + return R.xml.mouse_settings; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.SETTINGS_KEYBOARD_MOUSE; + } + + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.mouse_settings) { + @Override + protected boolean isPageSearchEnabled(Context context) { + return Flags.keyboardAndTouchpadA11yNewPageEnabled() + && InputPeripheralsSettingsUtils.isMouse(); + } + }; +} diff --git a/src/com/android/settings/inputmethod/MouseSettingsController.java b/src/com/android/settings/inputmethod/MouseSettingsController.java new file mode 100644 index 00000000000..ef9191e8dd0 --- /dev/null +++ b/src/com/android/settings/inputmethod/MouseSettingsController.java @@ -0,0 +1,40 @@ +/* + * 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 androidx.annotation.NonNull; + +import com.android.settings.keyboard.Flags; + +public class MouseSettingsController extends InputDeviceSettingsController { + + public MouseSettingsController(@NonNull Context context, @NonNull String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + boolean isFeatureOn = Flags.keyboardAndTouchpadA11yNewPageEnabled(); + boolean isPointerCustomizationEnabled = + android.view.flags.Flags.enableVectorCursorA11ySettings(); + boolean isMouse = InputPeripheralsSettingsUtils.isMouse(); + return (isFeatureOn && isPointerCustomizationEnabled && isMouse) ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } +} diff --git a/src/com/android/settings/inputmethod/TrackpadSettings.java b/src/com/android/settings/inputmethod/TouchpadAndMouseSettings.java similarity index 88% rename from src/com/android/settings/inputmethod/TrackpadSettings.java rename to src/com/android/settings/inputmethod/TouchpadAndMouseSettings.java index 757a9540957..14c580b541f 100644 --- a/src/com/android/settings/inputmethod/TrackpadSettings.java +++ b/src/com/android/settings/inputmethod/TouchpadAndMouseSettings.java @@ -29,9 +29,9 @@ import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.search.SearchIndexable; @SearchIndexable -public class TrackpadSettings extends DashboardFragment { +public class TouchpadAndMouseSettings extends DashboardFragment { - private static final String TAG = "TrackpadSettings"; + private static final String TAG = TouchpadAndMouseSettings.class.getSimpleName(); @Override public void onAttach(@NonNull Context context) { @@ -58,11 +58,11 @@ public class TrackpadSettings extends DashboardFragment { @Override protected int getPreferenceScreenResId() { - return R.xml.trackpad_settings; + return R.xml.touchpad_and_mouse_settings; } public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider(R.xml.trackpad_settings) { + new BaseSearchIndexProvider(R.xml.touchpad_and_mouse_settings) { @Override protected boolean isPageSearchEnabled(Context context) { return FeatureFlagUtils diff --git a/src/com/android/settings/inputmethod/TrackpadSettingsController.java b/src/com/android/settings/inputmethod/TouchpadAndMouseSettingsController.java similarity index 91% rename from src/com/android/settings/inputmethod/TrackpadSettingsController.java rename to src/com/android/settings/inputmethod/TouchpadAndMouseSettingsController.java index ba2ab99c092..86e044c4291 100644 --- a/src/com/android/settings/inputmethod/TrackpadSettingsController.java +++ b/src/com/android/settings/inputmethod/TouchpadAndMouseSettingsController.java @@ -20,6 +20,8 @@ import android.content.Context; import android.hardware.input.InputManager; import android.util.FeatureFlagUtils; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.preference.Preference; import com.android.settings.core.BasePreferenceController; @@ -28,15 +30,16 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; -public class TrackpadSettingsController extends BasePreferenceController +public class TouchpadAndMouseSettingsController extends BasePreferenceController implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop, InputManager.InputDeviceListener { private final InputManager mIm; + @Nullable private Preference mPreference; - public TrackpadSettingsController(Context context, String key) { + public TouchpadAndMouseSettingsController(@NonNull Context context, @NonNull String key) { super(context, key); mIm = context.getSystemService(InputManager.class); } diff --git a/src/com/android/settings/inputmethod/TouchpadSettingFragment.java b/src/com/android/settings/inputmethod/TouchpadSettingFragment.java new file mode 100644 index 00000000000..026357efdec --- /dev/null +++ b/src/com/android/settings/inputmethod/TouchpadSettingFragment.java @@ -0,0 +1,55 @@ +/* + * 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.app.settings.SettingsEnums; +import android.content.Context; + +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.keyboard.Flags; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.search.SearchIndexable; + +@SearchIndexable +public class TouchpadSettingFragment extends DashboardFragment { + private static final String TAG = TouchpadSettingFragment.class.getSimpleName(); + + @Override + protected int getPreferenceScreenResId() { + return R.xml.touchpad_settings; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.SETTINGS_KEYBOARDS_TOUCHPAD; + } + + public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider(R.xml.touchpad_settings) { + @Override + protected boolean isPageSearchEnabled(Context context) { + return Flags.keyboardAndTouchpadA11yNewPageEnabled() + && InputPeripheralsSettingsUtils.isTouchpad(); + } + }; +} diff --git a/src/com/android/settings/inputmethod/TouchpadSettingsController.java b/src/com/android/settings/inputmethod/TouchpadSettingsController.java new file mode 100644 index 00000000000..21c68c06283 --- /dev/null +++ b/src/com/android/settings/inputmethod/TouchpadSettingsController.java @@ -0,0 +1,37 @@ +/* + * 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 androidx.annotation.NonNull; + +import com.android.settings.keyboard.Flags; + +public class TouchpadSettingsController extends InputDeviceSettingsController { + public TouchpadSettingsController(@NonNull Context context, @NonNull String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + boolean isFeatureOn = Flags.keyboardAndTouchpadA11yNewPageEnabled(); + boolean isTouchpad = InputPeripheralsSettingsUtils.isTouchpad(); + return (isFeatureOn && isTouchpad) ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } +} diff --git a/tests/robotests/src/com/android/settings/inputmethod/MouseSettingsControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/MouseSettingsControllerTest.java new file mode 100644 index 00000000000..b5e0a843587 --- /dev/null +++ b/tests/robotests/src/com/android/settings/inputmethod/MouseSettingsControllerTest.java @@ -0,0 +1,88 @@ +/* + * 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 com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.view.InputDevice; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.keyboard.Flags; +import com.android.settings.testutils.shadow.ShadowInputDevice; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +/** Tests for {@link TouchpadSettingsController} */ +@RunWith(RobolectricTestRunner.class) +@Config(shadows = { + com.android.settings.testutils.shadow.ShadowSystemSettings.class, + ShadowInputDevice.class, +}) +public class MouseSettingsControllerTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + private static final String PREFERENCE_KEY = "keyboard_mouse_settings"; + + private Context mContext; + private MouseSettingsController mController; + + @Before + public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); + mController = new MouseSettingsController(mContext, PREFERENCE_KEY); + ShadowInputDevice.reset(); + } + + @Test + @DisableFlags(Flags.FLAG_KEYBOARD_AND_TOUCHPAD_A11Y_NEW_PAGE_ENABLED) + public void getAvailabilityStatus_flagIsDisable_returnsUnavailable() { + int deviceId = 1; + ShadowInputDevice.sDeviceIds = new int[]{deviceId}; + ShadowInputDevice.addDevice(deviceId, ShadowInputDevice.makeInputDevicebyId(deviceId)); + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE); + } + + @Test + @EnableFlags(Flags.FLAG_KEYBOARD_AND_TOUCHPAD_A11Y_NEW_PAGE_ENABLED) + public void getAvailabilityStatus_isMouse_returnsAvailable() { + int deviceId = 1; + ShadowInputDevice.sDeviceIds = new int[]{deviceId}; + InputDevice device = ShadowInputDevice.makeInputDevicebyIdWithSources(deviceId, + InputDevice.SOURCE_MOUSE); + ShadowInputDevice.addDevice(deviceId, device); + + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.AVAILABLE); + } +} diff --git a/tests/robotests/src/com/android/settings/inputmethod/TrackpadSettingsControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TouchpadAndMouseSettingsControllerTest.java similarity index 93% rename from tests/robotests/src/com/android/settings/inputmethod/TrackpadSettingsControllerTest.java rename to tests/robotests/src/com/android/settings/inputmethod/TouchpadAndMouseSettingsControllerTest.java index 727363f175c..9d3cc5ff77f 100644 --- a/tests/robotests/src/com/android/settings/inputmethod/TrackpadSettingsControllerTest.java +++ b/tests/robotests/src/com/android/settings/inputmethod/TouchpadAndMouseSettingsControllerTest.java @@ -40,26 +40,26 @@ import org.mockito.junit.MockitoRule; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; -/** Tests for {@link TrackpadSettingsController} */ +/** Tests for {@link TouchpadAndMouseSettingsController} */ @RunWith(RobolectricTestRunner.class) @Config(shadows = { com.android.settings.testutils.shadow.ShadowSystemSettings.class, ShadowInputDevice.class, }) -public class TrackpadSettingsControllerTest { +public class TouchpadAndMouseSettingsControllerTest { @Rule public MockitoRule rule = MockitoJUnit.rule(); private static final String PREFERENCE_KEY = "trackpad_settings"; private Context mContext; - private TrackpadSettingsController mController; + private TouchpadAndMouseSettingsController mController; private Preference mPreference; @Before public void setUp() { mContext = ApplicationProvider.getApplicationContext(); - mController = new TrackpadSettingsController(mContext, PREFERENCE_KEY); + mController = new TouchpadAndMouseSettingsController(mContext, PREFERENCE_KEY); mPreference = new Preference(mContext); ShadowInputDevice.reset(); } diff --git a/tests/robotests/src/com/android/settings/inputmethod/TouchpadSettingsControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TouchpadSettingsControllerTest.java new file mode 100644 index 00000000000..9f47991af14 --- /dev/null +++ b/tests/robotests/src/com/android/settings/inputmethod/TouchpadSettingsControllerTest.java @@ -0,0 +1,88 @@ +/* + * 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 com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; +import android.view.InputDevice; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.keyboard.Flags; +import com.android.settings.testutils.shadow.ShadowInputDevice; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +/** Tests for {@link TouchpadSettingsController} */ +@RunWith(RobolectricTestRunner.class) +@Config(shadows = { + com.android.settings.testutils.shadow.ShadowSystemSettings.class, + ShadowInputDevice.class, +}) +public class TouchpadSettingsControllerTest { + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule + public MockitoRule rule = MockitoJUnit.rule(); + + private static final String PREFERENCE_KEY = "keyboard_touchpad_settings"; + + private Context mContext; + private TouchpadSettingsController mController; + + @Before + public void setUp() { + mContext = ApplicationProvider.getApplicationContext(); + mController = new TouchpadSettingsController(mContext, PREFERENCE_KEY); + ShadowInputDevice.reset(); + } + + @Test + @DisableFlags(Flags.FLAG_KEYBOARD_AND_TOUCHPAD_A11Y_NEW_PAGE_ENABLED) + public void getAvailabilityStatus_flagIsDisable_returnsUnavailable() { + int deviceId = 1; + ShadowInputDevice.sDeviceIds = new int[]{deviceId}; + ShadowInputDevice.addDevice(deviceId, ShadowInputDevice.makeInputDevicebyId(deviceId)); + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE); + } + + @Test + @EnableFlags(Flags.FLAG_KEYBOARD_AND_TOUCHPAD_A11Y_NEW_PAGE_ENABLED) + public void getAvailabilityStatus_isTouchpad_returnsAvailable() { + int deviceId = 1; + ShadowInputDevice.sDeviceIds = new int[]{deviceId}; + InputDevice device = ShadowInputDevice.makeInputDevicebyIdWithSources(deviceId, + InputDevice.SOURCE_TOUCHPAD); + ShadowInputDevice.addDevice(deviceId, device); + + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.AVAILABLE); + } +}