diff --git a/res/drawable/storage_progress_bar.xml b/res/drawable/storage_progress_bar.xml new file mode 100644 index 00000000000..3232230e7b4 --- /dev/null +++ b/res/drawable/storage_progress_bar.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/storage_item.xml b/res/layout/storage_item.xml index 3b58759baf0..98bedfe34dc 100644 --- a/res/layout/storage_item.xml +++ b/res/layout/storage_item.xml @@ -74,7 +74,8 @@ android:max="100" android:layout_below="@android:id/title" app:layout_constraintTop_toBottomOf="@android:id/title" - style="?android:attr/progressBarStyleHorizontal" /> + style="?android:attr/progressBarStyleHorizontal" + android:progressDrawable="@drawable/storage_progress_bar" /> 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/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml index 8c948ff11da..4f7a494509b 100644 --- a/res/xml/mobile_network_settings.xml +++ b/res/xml/mobile_network_settings.xml @@ -52,7 +52,6 @@ android:key="mobile_network_spn" android:title="@string/mobile_network_spn_title" android:summary="@string/summary_placeholder" - android:selectable="false" settings:controller="com.android.settings.network.telephony.MobileNetworkSpnPreferenceController" settings:allowDividerAbove="true" /> @@ -60,7 +59,6 @@ android:key="phone_number" android:title="@string/status_number" android:summary="@string/summary_placeholder" - android:selectable="false" settings:controller="com.android.settings.network.telephony.MobileNetworkPhoneNumberPreferenceController" settings:allowDividerBelow="true" settings:enableCopying="true"/> diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml index 1a9e646b509..abcb48547a0 100644 --- a/res/xml/my_device_info.xml +++ b/res/xml/my_device_info.xml @@ -57,7 +57,6 @@ android:order="3" android:title="@string/status_number" android:summary="@string/summary_placeholder" - android:selectable="false" settings:isPreferenceVisible="@bool/config_show_sim_info" settings:controller="com.android.settings.deviceinfo.PhoneNumberPreferenceController" settings:enableCopying="true"/> diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml index 6c2b8d48b66..92c5171ed80 100644 --- a/res/xml/storage_dashboard_fragment.xml +++ b/res/xml/storage_dashboard_fragment.xml @@ -38,7 +38,7 @@ android:icon="@drawable/ic_storage" android:order="3" settings:controller="com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController"/> - 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/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index f201b1ab037..e1272a8b82a 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -286,7 +286,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme final SatelliteSettingPreferenceController satelliteSettingPreferenceController = use( SatelliteSettingPreferenceController.class); if (satelliteSettingPreferenceController != null) { - satelliteSettingPreferenceController.init(mSubId); + satelliteSettingPreferenceController.initialize(mSubId); } use(ApnPreferenceController.class).init(mSubId); diff --git a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java index fd82e5c77f4..5ee1dd96e03 100644 --- a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java +++ b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java @@ -160,7 +160,7 @@ public class SatelliteSettingPreferenceController extends * * @param subId subscription ID. */ - public void init(int subId) { + public void initialize(int subId) { logd("init(), subId=" + subId); mSubId = subId; mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId); 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/network/telephony/SatelliteSettingsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java index 8fcb32e493d..2c11647e1e7 100644 --- a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java @@ -48,7 +48,6 @@ import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.android.internal.telephony.flags.Flags; -import com.android.settings.R; import com.android.settings.network.CarrierConfigCache; import org.junit.Before; @@ -167,7 +166,7 @@ public class SatelliteSettingsPreferenceControllerTest { @Test @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) public void onResume_registerTelephonyCallback_success() { - mController.init(TEST_SUB_ID); + mController.initialize(TEST_SUB_ID); mController.onResume(null); verify(mTelephonyManager).registerTelephonyCallback(any(), any()); @@ -176,7 +175,7 @@ public class SatelliteSettingsPreferenceControllerTest { @Test @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) public void getAvailabilityStatus_unregisterTelephonyCallback_success() { - mController.init(TEST_SUB_ID); + mController.initialize(TEST_SUB_ID); mController.onPause(null); verify(mTelephonyManager).unregisterTelephonyCallback(any()); @@ -185,7 +184,7 @@ public class SatelliteSettingsPreferenceControllerTest { @Test @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) public void getAvailabilityStatus_hasServiceDataType_showDataUi() { - mController.init(TEST_SUB_ID); + mController.initialize(TEST_SUB_ID); Preference preference = new Preference(mContext); preference.setKey(KEY); preference.setTitle("test title"); @@ -194,14 +193,13 @@ public class SatelliteSettingsPreferenceControllerTest { mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged( new int[]{SERVICE_TYPE_SMS, SERVICE_TYPE_DATA}); - assertThat(preference.getTitle()).isEqualTo( - mContext.getString(R.string.title_satellite_setting_connectivity)); + assertThat(preference.getTitle()).isEqualTo("Satellite connectivity"); } @Test @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) public void getAvailabilityStatus_onlyHasServiceSmsType_showSmsUi() { - mController.init(TEST_SUB_ID); + mController.initialize(TEST_SUB_ID); Preference preference = new Preference(mContext); preference.setKey(KEY); preference.setTitle("test title"); @@ -210,8 +208,7 @@ public class SatelliteSettingsPreferenceControllerTest { mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged( new int[]{SERVICE_TYPE_SMS}); - assertThat(preference.getTitle()).isEqualTo( - mContext.getString(R.string.satellite_setting_title)); + assertThat(preference.getTitle()).isEqualTo("Satellite messaging"); } @Test @@ -220,14 +217,14 @@ public class SatelliteSettingsPreferenceControllerTest { mCarrierConfig.putBoolean( KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false); - mController.init(TEST_SUB_ID); + mController.initialize(TEST_SUB_ID); Preference preference = new Preference(mContext); preference.setKey(KEY); preference.setTitle("test title"); mController.updateState(preference); assertThat(preference.getSummary()).isEqualTo( - mContext.getString(R.string.satellite_setting_summary_without_entitlement)); + "Send and receive text messages by satellite. Contact your carrier for details."); } @Test @@ -239,7 +236,7 @@ public class SatelliteSettingsPreferenceControllerTest { mCarrierConfig.putInt( CarrierConfigManager.KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT, CARRIER_ROAMING_NTN_CONNECT_MANUAL); - mController.init(TEST_SUB_ID); + mController.initialize(TEST_SUB_ID); PreferenceManager preferenceManager = new PreferenceManager(mContext); PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext); Preference preference = new Preference(mContext); @@ -250,7 +247,7 @@ public class SatelliteSettingsPreferenceControllerTest { mController.displayPreference(preferenceScreen); assertThat(preference.getSummary()).isEqualTo( - mContext.getString(R.string.satellite_setting_enabled_summary)); + "Send and receive text messages by satellite. Included with your account."); } @Test @@ -262,7 +259,7 @@ public class SatelliteSettingsPreferenceControllerTest { mCarrierConfig.putInt( CarrierConfigManager.KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT, CARRIER_ROAMING_NTN_CONNECT_MANUAL); - mController.init(TEST_SUB_ID); + mController.initialize(TEST_SUB_ID); PreferenceManager preferenceManager = new PreferenceManager(mContext); PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext); Preference preference = new Preference(mContext); @@ -273,6 +270,6 @@ public class SatelliteSettingsPreferenceControllerTest { mController.displayPreference(preferenceScreen); assertThat(preference.getSummary()).isEqualTo( - mContext.getString(R.string.satellite_setting_disabled_summary)); + "Send and receive text messages by satellite. Not included with your account."); } } 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; + } }