diff --git a/res/values/strings.xml b/res/values/strings.xml index 694700c3aff..a8963b2eecb 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5167,6 +5167,8 @@ Help improve by taking a survey No surveys available + + Send feedback Downloaded apps diff --git a/src/com/android/settings/accessibility/AccessibilityFeedbackFeatureProvider.java b/src/com/android/settings/accessibility/AccessibilityFeedbackFeatureProvider.java new file mode 100644 index 00000000000..018bd2e2ec1 --- /dev/null +++ b/src/com/android/settings/accessibility/AccessibilityFeedbackFeatureProvider.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2025 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.accessibility; + +import android.content.ComponentName; + +import androidx.annotation.Nullable; + +/** + * Provider for Accessibility feedback related features. + */ +public interface AccessibilityFeedbackFeatureProvider { + + /** + * Returns value according to the {@code componentName}. + * + * @param componentName the component name of the downloaded service or activity + * @return Feedback bucket ID + */ + @Nullable + String getCategory(@Nullable ComponentName componentName); +} diff --git a/src/com/android/settings/accessibility/AccessibilityFeedbackFeatureProviderImpl.java b/src/com/android/settings/accessibility/AccessibilityFeedbackFeatureProviderImpl.java new file mode 100644 index 00000000000..917c5f64146 --- /dev/null +++ b/src/com/android/settings/accessibility/AccessibilityFeedbackFeatureProviderImpl.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2025 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.accessibility; + +import android.content.ComponentName; + +import androidx.annotation.Nullable; + +/** Default implementation of {@link AccessibilityFeedbackFeatureProvider}. */ +public class AccessibilityFeedbackFeatureProviderImpl implements + AccessibilityFeedbackFeatureProvider{ + + @Override + @Nullable + public String getCategory(@Nullable ComponentName componentName) { + return ""; + } +} diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index c0341cc5949..57eb4d5fba4 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -30,6 +30,9 @@ import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; import android.util.ArrayMap; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.accessibility.AccessibilityManager; import androidx.annotation.NonNull; @@ -101,6 +104,8 @@ public class AccessibilitySettings extends DashboardFragment implements // presentation. private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000; + static final int MENU_ID_SEND_FEEDBACK = 0; + private final Handler mHandler = new Handler(); private final Runnable mUpdateRunnable = new Runnable() { @@ -143,8 +148,9 @@ public class AccessibilitySettings extends DashboardFragment implements } }; - @VisibleForTesting - AccessibilitySettingsContentObserver mSettingsContentObserver; + private AccessibilitySettingsContentObserver mSettingsContentObserver; + + private FeedbackManager mFeedbackManager; private final Map mCategoryToPrefCategoryMap = new ArrayMap<>(); @@ -245,6 +251,24 @@ public class AccessibilitySettings extends DashboardFragment implements super.onDestroy(); } + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + if (getFeedbackManager().isAvailable()) { + menu.add(Menu.NONE, MENU_ID_SEND_FEEDBACK, Menu.NONE, + getPrefContext().getText(R.string.accessibility_send_feedback_title)); + } + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + if (item.getItemId() == MENU_ID_SEND_FEEDBACK) { + getFeedbackManager().sendFeedback(); + return true; + } + return super.onOptionsItemSelected(item); + } + @Override protected int getPreferenceScreenResId() { return R.xml.accessibility_settings; @@ -255,6 +279,18 @@ public class AccessibilitySettings extends DashboardFragment implements return TAG; } + @VisibleForTesting + void setFeedbackManager(FeedbackManager feedbackManager) { + this.mFeedbackManager = feedbackManager; + } + + private FeedbackManager getFeedbackManager() { + if (mFeedbackManager == null) { + mFeedbackManager = new FeedbackManager(getActivity()); + } + return mFeedbackManager; + } + /** * Returns the summary for the current state of this accessibilityService. * diff --git a/src/com/android/settings/accessibility/FeedbackManager.java b/src/com/android/settings/accessibility/FeedbackManager.java new file mode 100644 index 00000000000..52aefd22d31 --- /dev/null +++ b/src/com/android/settings/accessibility/FeedbackManager.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2025 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.accessibility; + +import android.app.Activity; +import android.content.ComponentName; +import android.content.Intent; +import android.text.TextUtils; + +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + +import com.android.server.accessibility.Flags; +import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.DeviceInfoUtils; + +import java.lang.ref.WeakReference; + +/** + * Manages the feedback flow. This class is responsible for checking feedback availability and + * sending feedback. Uses a WeakReference to the Activity to prevent memory leaks. + */ +public class FeedbackManager { + + static final String CATEGORY_TAG = "category_tag"; + private static final int FEEDBACK_INTENT_RESULT_CODE = 0; + + private final WeakReference mActivityWeakReference; + @Nullable private final String mReporterPackage; + @Nullable private final String mCategoryTag; + + /** + * Constructs a new FeedbackManager. + * + * @param activity The activity context. A WeakReference is used to prevent memory leaks. + */ + public FeedbackManager(@Nullable Activity activity) { + this(activity, /* componentName= */ null); + } + + /** + * Constructs a new FeedbackManager. + * + * @param activity The activity context. A WeakReference is used to prevent memory leaks. + * @param componentName The component name associated with the feedback. + */ + public FeedbackManager(@Nullable Activity activity, @Nullable ComponentName componentName) { + this(activity, + DeviceInfoUtils.getFeedbackReporterPackage(activity), + FeatureFactory.getFeatureFactory() + .getAccessibilityFeedbackFeatureProvider() + .getCategory(componentName)); + } + + /** + * Constructs a new FeedbackManager. This constructor is visible for testing. + * + * @param activity The activity context. A WeakReference is used to prevent memory leaks. + * @param reporterPackage The package name of the feedback reporter. + * @param category The feedback bucket ID. + */ + @VisibleForTesting + public FeedbackManager(@Nullable Activity activity, @Nullable String reporterPackage, + @Nullable String category) { + this.mActivityWeakReference = new WeakReference<>(activity); + this.mReporterPackage = reporterPackage; + this.mCategoryTag = category; + } + + /** + * Checks if feedback is available on the device. + * + * @return {@code true} if feedback is available, {@code false} otherwise. + */ + public boolean isAvailable() { + if (!Flags.enableLowVisionGenericFeedback()) { + return false; + } + + return !TextUtils.isEmpty(mReporterPackage) + && !TextUtils.isEmpty(mCategoryTag) + && mActivityWeakReference.get() != null; + } + + /** + * Sends feedback using the available feedback reporter. This will start the feedback + * activity. It is the responsibility of the calling activity to handle the result + * code {@link #FEEDBACK_INTENT_RESULT_CODE} if necessary. + * + * @return {@code true} if the feedback intent was successfully started, {@code false} + * otherwise. + */ + public boolean sendFeedback() { + Activity activity = mActivityWeakReference.get(); + if (!isAvailable() || activity == null) { + return false; + } + + final Intent intent = new Intent(Intent.ACTION_BUG_REPORT); + intent.setPackage(mReporterPackage); + intent.putExtra(CATEGORY_TAG, mCategoryTag); + activity.startActivityForResult(intent, FEEDBACK_INTENT_RESULT_CODE); + return true; + } +} diff --git a/src/com/android/settings/overlay/FeatureFactory.kt b/src/com/android/settings/overlay/FeatureFactory.kt index 6a419dd5fe0..46aa19b0d05 100644 --- a/src/com/android/settings/overlay/FeatureFactory.kt +++ b/src/com/android/settings/overlay/FeatureFactory.kt @@ -16,6 +16,7 @@ package com.android.settings.overlay import android.content.Context +import com.android.settings.accessibility.AccessibilityFeedbackFeatureProvider import com.android.settings.accessibility.AccessibilityMetricsFeatureProvider import com.android.settings.accessibility.AccessibilitySearchFeatureProvider import com.android.settings.accounts.AccountFeatureProvider @@ -133,6 +134,11 @@ abstract class FeatureFactory { */ abstract val securitySettingsFeatureProvider: SecuritySettingsFeatureProvider + /** + * Retrieves implementation for Accessibility feedback category feature. + */ + abstract val accessibilityFeedbackFeatureProvider: AccessibilityFeedbackFeatureProvider + /** * Retrieves implementation for Accessibility search index feature. */ diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.kt b/src/com/android/settings/overlay/FeatureFactoryImpl.kt index 22d3f1b6a4d..08abf2bd466 100644 --- a/src/com/android/settings/overlay/FeatureFactoryImpl.kt +++ b/src/com/android/settings/overlay/FeatureFactoryImpl.kt @@ -20,6 +20,8 @@ import android.content.Context import android.net.ConnectivityManager import android.net.VpnManager import android.os.UserManager +import com.android.settings.accessibility.AccessibilityFeedbackFeatureProvider +import com.android.settings.accessibility.AccessibilityFeedbackFeatureProviderImpl import com.android.settings.accessibility.AccessibilityMetricsFeatureProvider import com.android.settings.accessibility.AccessibilityMetricsFeatureProviderImpl import com.android.settings.accessibility.AccessibilitySearchFeatureProvider @@ -165,6 +167,9 @@ open class FeatureFactoryImpl : FeatureFactory() { SecuritySettingsFeatureProviderImpl() } + override val accessibilityFeedbackFeatureProvider: AccessibilityFeedbackFeatureProvider + by lazy { AccessibilityFeedbackFeatureProviderImpl() } + override val accessibilitySearchFeatureProvider: AccessibilitySearchFeatureProvider by lazy { AccessibilitySearchFeatureProviderImpl() } diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java index 91d7d91c833..e590a80b27d 100644 --- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java @@ -21,7 +21,11 @@ import static com.android.internal.accessibility.common.ShortcutConstants.UserSh import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @@ -43,6 +47,8 @@ import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; +import android.view.Menu; +import android.view.MenuItem; import android.view.accessibility.AccessibilityManager; import androidx.fragment.app.Fragment; @@ -107,13 +113,15 @@ public class AccessibilitySettingsTest { private static final String EMPTY_STRING = ""; private static final String DEFAULT_SUMMARY = "default summary"; private static final String DEFAULT_DESCRIPTION = "default description"; + private static final String DEFAULT_CATEGORY = "default category"; private static final String DEFAULT_LABEL = "default label"; private static final Boolean SERVICE_ENABLED = true; private static final Boolean SERVICE_DISABLED = false; @Rule public final MockitoRule mocks = MockitoJUnit.rule(); - @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private final Context mContext = ApplicationProvider.getApplicationContext(); @Spy private final AccessibilityServiceInfo mServiceInfo = getMockAccessibilityServiceInfo( @@ -121,7 +129,13 @@ public class AccessibilitySettingsTest { private ShadowAccessibilityManager mShadowAccessibilityManager; @Mock private LocalBluetoothManager mLocalBluetoothManager; + @Mock + private Menu mMenu; + @Mock + private MenuItem mMenuItem; + private ActivityController mActivityController; + private AccessibilitySettings mFragment; @Before @@ -438,6 +452,66 @@ public class AccessibilitySettingsTest { } + @Test + @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void onCreateOptionsMenu_enableLowVisionGenericFeedback_shouldAddSendFeedbackMenu() { + setupFragment(); + mFragment.setFeedbackManager( + new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY)); + when(mMenu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mMenuItem); + + mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null); + + verify(mMenu).add(anyInt(), eq(AccessibilitySettings.MENU_ID_SEND_FEEDBACK), + anyInt(), eq(mContext.getText(R.string.accessibility_send_feedback_title))); + } + + @Test + @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void onCreateOptionsMenu_disableLowVisionGenericFeedback_shouldNotAddSendFeedbackMenu() { + setupFragment(); + mFragment.setFeedbackManager( + new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY)); + when(mMenu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mMenuItem); + + mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null); + + verify(mMenu, never()).add(anyInt(), eq(AccessibilitySettings.MENU_ID_SEND_FEEDBACK), + anyInt(), eq(mContext.getText(R.string.accessibility_send_feedback_title))); + } + + @Test + @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void onOptionsItemSelected_enableLowVisionGenericFeedback_shouldStartSendFeedback() { + setupFragment(); + mFragment.setFeedbackManager( + new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY)); + when(mMenu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mMenuItem); + mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null); + when(mMenuItem.getItemId()).thenReturn(AccessibilitySettings.MENU_ID_SEND_FEEDBACK); + + mFragment.onOptionsItemSelected(mMenuItem); + + Intent startedIntent = shadowOf(mFragment.getActivity()).getNextStartedActivity(); + assertThat(startedIntent).isNotNull(); + } + + @Test + @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void onOptionsItemSelected_disableLowVisionGenericFeedback_shouldNotStartSendFeedback() { + setupFragment(); + mFragment.setFeedbackManager( + new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY)); + when(mMenu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mMenuItem); + mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null); + when(mMenuItem.getItemId()).thenReturn(AccessibilitySettings.MENU_ID_SEND_FEEDBACK); + + mFragment.onOptionsItemSelected(mMenuItem); + + Intent startedIntent = shadowOf(mFragment.getActivity()).getNextStartedActivity(); + assertThat(startedIntent).isNull(); + } + @Test public void testAccessibilityMenuInSystem_IncludedInInteractionControl() { mShadowAccessibilityManager.setInstalledAccessibilityServiceList( diff --git a/tests/robotests/src/com/android/settings/accessibility/FeedbackManagerTest.java b/tests/robotests/src/com/android/settings/accessibility/FeedbackManagerTest.java new file mode 100644 index 00000000000..299c020991f --- /dev/null +++ b/tests/robotests/src/com/android/settings/accessibility/FeedbackManagerTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2025 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.accessibility; + +import static com.android.settings.accessibility.FeedbackManager.CATEGORY_TAG; + +import static com.google.common.truth.Truth.assertThat; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; +import android.platform.test.flag.junit.SetFlagsRule; + +import com.android.server.accessibility.Flags; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.Shadows; + +/** Tests for {@link FeedbackManager}. */ +@RunWith(RobolectricTestRunner.class) +public class FeedbackManagerTest { + + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + + private static final String PACKAGE_NAME = "test.feedback.package"; + private static final String DEFAULT_CATEGORY = "default category"; + + private Activity mActivity; + + @Before + public void setUp() { + mActivity = Robolectric.buildActivity(Activity.class).create().get(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void isAvailable_enableLowVisionGenericFeedbackWithValidParams_returnsTrue() { + FeedbackManager feedbackManager = + new FeedbackManager(mActivity, PACKAGE_NAME, DEFAULT_CATEGORY); + + assertThat(feedbackManager.isAvailable()).isTrue(); + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void isAvailable_disableLowVisionGenericFeedback_returnsFalse() { + FeedbackManager feedbackManager = + new FeedbackManager(mActivity, PACKAGE_NAME, DEFAULT_CATEGORY); + + assertThat(feedbackManager.isAvailable()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void isAvailable_withNullCategory_returnsFalse() { + FeedbackManager feedbackManager = + new FeedbackManager(mActivity, PACKAGE_NAME, /* category= */ null); + + assertThat(feedbackManager.isAvailable()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void isAvailable_withNullReporterPackage_returnsFalse() { + FeedbackManager feedbackManager = + new FeedbackManager(mActivity, /* reporterPackage= */ null, DEFAULT_CATEGORY); + + assertThat(feedbackManager.isAvailable()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void isAvailable_withNullActivity_returnsFalse() { + FeedbackManager feedbackManager = + new FeedbackManager(/* activity= */ null, PACKAGE_NAME, DEFAULT_CATEGORY); + + assertThat(feedbackManager.isAvailable()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void sendFeedback_enableLowVisionGenericFeedbackWithValidParams_success() { + FeedbackManager feedbackManager = + new FeedbackManager(mActivity, PACKAGE_NAME, DEFAULT_CATEGORY); + + assertThat(feedbackManager.sendFeedback()).isTrue(); + + Intent startedIntent = Shadows.shadowOf(mActivity).getNextStartedActivity(); + assertThat(startedIntent).isNotNull(); + assertThat(startedIntent.getAction()).isEqualTo(Intent.ACTION_BUG_REPORT); + assertThat(startedIntent.getPackage()).isEqualTo(PACKAGE_NAME); + Bundle extras = startedIntent.getExtras(); + assertThat(extras).isNotNull(); + assertThat(extras.getString(CATEGORY_TAG)).isEqualTo(DEFAULT_CATEGORY); + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void sendFeedback_disableLowVisionGenericFeedback_returnsFalse() { + FeedbackManager feedbackManager = + new FeedbackManager(mActivity, PACKAGE_NAME, DEFAULT_CATEGORY); + + assertThat(feedbackManager.sendFeedback()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void sendFeedback_withNullCategory_returnsFalse() { + FeedbackManager feedbackManager = + new FeedbackManager(mActivity, PACKAGE_NAME, /* category= */ null); + + assertThat(feedbackManager.sendFeedback()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void sendFeedback_withNullReporterPackage_returnsFalse() { + FeedbackManager feedbackManager = + new FeedbackManager(mActivity, /* reporterPackage= */ null, DEFAULT_CATEGORY); + + assertThat(feedbackManager.sendFeedback()).isFalse(); + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK) + public void sendFeedback_withNullActivity_returnsFalse() { + FeedbackManager feedbackManager = + new FeedbackManager(/* activity= */ null, PACKAGE_NAME, DEFAULT_CATEGORY); + + assertThat(feedbackManager.sendFeedback()).isFalse(); + } +} diff --git a/tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java index cfa6357affd..c5d4c36228a 100644 --- a/tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java +++ b/tests/robotests/testutils/com/android/settings/testutils/FakeFeatureFactory.java @@ -19,6 +19,7 @@ import static org.mockito.Mockito.mock; import android.content.Context; +import com.android.settings.accessibility.AccessibilityFeedbackFeatureProvider; import com.android.settings.accessibility.AccessibilityMetricsFeatureProvider; import com.android.settings.accessibility.AccessibilitySearchFeatureProvider; import com.android.settings.accounts.AccountFeatureProvider; @@ -103,6 +104,7 @@ public class FakeFeatureFactory extends FeatureFactory { public PrivateSpaceLoginFeatureProvider mPrivateSpaceLoginFeatureProvider; public DisplayFeatureProvider mDisplayFeatureProvider; public SyncAcrossDevicesFeatureProvider mSyncAcrossDevicesFeatureProvider; + public AccessibilityFeedbackFeatureProvider mAccessibilityFeedbackFeatureProvider; /** * Call this in {@code @Before} method of the test class to use fake factory. @@ -340,5 +342,9 @@ public class FakeFeatureFactory extends FeatureFactory { public SyncAcrossDevicesFeatureProvider getSyncAcrossDevicesFeatureProvider() { return mSyncAcrossDevicesFeatureProvider; } -} + @Override + public AccessibilityFeedbackFeatureProvider getAccessibilityFeedbackFeatureProvider() { + return mAccessibilityFeedbackFeatureProvider; + } +} diff --git a/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt b/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt index 37a6abe88f1..56dd444b474 100644 --- a/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt +++ b/tests/spa_unit/src/com/android/settings/testutils/FakeFeatureFactory.kt @@ -17,6 +17,7 @@ package com.android.settings.testutils import android.content.Context +import com.android.settings.accessibility.AccessibilityFeedbackFeatureProvider import com.android.settings.accessibility.AccessibilityMetricsFeatureProvider import com.android.settings.accessibility.AccessibilitySearchFeatureProvider import com.android.settings.accounts.AccountFeatureProvider @@ -125,6 +126,8 @@ class FakeFeatureFactory : FeatureFactory() { get() = TODO("Not yet implemented") override val securitySettingsFeatureProvider: SecuritySettingsFeatureProvider get() = TODO("Not yet implemented") + override val accessibilityFeedbackFeatureProvider: AccessibilityFeedbackFeatureProvider + get() = TODO("Not yet implemented") override val accessibilitySearchFeatureProvider: AccessibilitySearchFeatureProvider get() = TODO("Not yet implemented") override val accessibilityMetricsFeatureProvider: AccessibilityMetricsFeatureProvider diff --git a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java index 46316d8626d..d77d7a4ff01 100644 --- a/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java +++ b/tests/unit/src/com/android/settings/testutils/FakeFeatureFactory.java @@ -19,6 +19,7 @@ import static org.mockito.Mockito.mock; import android.content.Context; +import com.android.settings.accessibility.AccessibilityFeedbackFeatureProvider; import com.android.settings.accessibility.AccessibilityMetricsFeatureProvider; import com.android.settings.accessibility.AccessibilitySearchFeatureProvider; import com.android.settings.accounts.AccountFeatureProvider; @@ -102,6 +103,7 @@ public class FakeFeatureFactory extends FeatureFactory { public PrivateSpaceLoginFeatureProvider mPrivateSpaceLoginFeatureProvider; public DisplayFeatureProvider mDisplayFeatureProvider; public SyncAcrossDevicesFeatureProvider mSyncAcrossDevicesFeatureProvider; + public AccessibilityFeedbackFeatureProvider mAccessibilityFeedbackFeatureProvider; /** Call this in {@code @Before} method of the test class to use fake factory. */ public static FakeFeatureFactory setupForTest() { @@ -341,4 +343,9 @@ public class FakeFeatureFactory extends FeatureFactory { public SyncAcrossDevicesFeatureProvider getSyncAcrossDevicesFeatureProvider() { return mSyncAcrossDevicesFeatureProvider; } + + @Override + public AccessibilityFeedbackFeatureProvider getAccessibilityFeedbackFeatureProvider() { + return mAccessibilityFeedbackFeatureProvider; + } }