From edfe2a3f2469bb12fb1316b44a76d29e0fae13f2 Mon Sep 17 00:00:00 2001 From: Hung-Yeh Lee Date: Tue, 26 Nov 2024 14:03:22 +0800 Subject: [PATCH 1/9] Update resolution name for screen resolution page Use "Max resolution" to avoid confusion with Full HD. Bug: 380988346 Flag: EXEMPT resource only update Test: Open settings > display > resolution Change-Id: I77923c60d9af3757d207cda9d33d9b40ccdc5462 --- res/values/strings.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index d9594b3ffdb..2aa4242a1d8 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2865,9 +2865,9 @@ High resolution - Full resolution + Max resolution - Full resolution uses more of your battery. Switching your resolution may cause some apps to restart. + Max resolution uses more of your battery. Switching your resolution may cause some apps to restart. Selected From b253005342ca469e8029d23b028616507f7cb545 Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Fri, 25 Oct 2024 15:11:56 +0000 Subject: [PATCH 2/9] Add a11y setting for disabling touchpad system gestures Screenshots: * The new setting: http://shortn/_9JL6nMS3cR * The disabled "Learn touchpad gestures" button and accompanying footer when the setting is off: http://shortn/_FTcNTQAGYj Test: disable the setting, check three- and four-finger swipes on the touchpad stop working; re-enable, check they work again Test: check the toggle and heading both hide correctly when flag is off or no touchpad is connected Test: check the "Learn touchpad gestures" button is disabled with an explanation when gestures are disabled Bug: 353947750 Bug: 374965372 Flag: com.android.hardware.input.touchpad_system_gesture_disable Change-Id: Ie7a6ea4e9ddd34710d07f78ab96598207aac4228 --- res/values/strings.xml | 12 +++++ .../accessibility_pointer_and_touchpad.xml | 13 +++++ res/xml/touchpad_and_mouse_settings.xml | 6 +++ .../inputmethod/PointerTouchpadFragment.java | 25 +++++++++ ...uchGesturesButtonPreferenceController.java | 10 +++- ...padSystemGesturesPreferenceController.java | 54 +++++++++++++++++++ ...resDisabledFooterPreferenceController.java | 35 ++++++++++++ 7 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/inputmethod/TouchpadSystemGesturesPreferenceController.java create mode 100644 src/com/android/settings/inputmethod/TrackpadGesturesDisabledFooterPreferenceController.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 6ba28533355..9d620baa85b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -4681,6 +4681,9 @@ None Learn touchpad gestures + + + Some settings are unavailable as touchpad gestures have been turned off. You can turn them on via Pointer & touchpad accessibility > Use touchpad gestures trackpad, track pad, mouse, cursor, scroll, swipe, right click, click, pointer @@ -4963,6 +4966,15 @@ Pointer color, pointer size & more Pointer color customization + + + Touchpad + + Use system gestures + + When turned off, 3- or 4-finger gestures are ignored + + touchpad, trackpad, swipe Color contrast diff --git a/res/xml/accessibility_pointer_and_touchpad.xml b/res/xml/accessibility_pointer_and_touchpad.xml index 8da41779d95..a46c8572bb5 100644 --- a/res/xml/accessibility_pointer_and_touchpad.xml +++ b/res/xml/accessibility_pointer_and_touchpad.xml @@ -46,4 +46,17 @@ settings:keywords="@string/keywords_auto_click" settings:controller="com.android.settings.accessibility.AutoclickPreferenceController"/> + + + + + + diff --git a/res/xml/touchpad_and_mouse_settings.xml b/res/xml/touchpad_and_mouse_settings.xml index cdfd398d151..b82b3a62ea3 100644 --- a/res/xml/touchpad_and_mouse_settings.xml +++ b/res/xml/touchpad_and_mouse_settings.xml @@ -96,4 +96,10 @@ android:key="trackpad_touch_gesture" android:title="@string/trackpad_touch_gesture" settings:controller="com.android.settings.inputmethod.TouchGesturesButtonPreferenceController"/> + + diff --git a/src/com/android/settings/inputmethod/PointerTouchpadFragment.java b/src/com/android/settings/inputmethod/PointerTouchpadFragment.java index 890d9b68479..441bddd2574 100644 --- a/src/com/android/settings/inputmethod/PointerTouchpadFragment.java +++ b/src/com/android/settings/inputmethod/PointerTouchpadFragment.java @@ -25,14 +25,33 @@ import android.content.Context; import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.widget.PreferenceCategoryController; +import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.search.SearchIndexable; +import java.util.List; + /** Accessibility settings for pointer and touchpad. */ @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) public class PointerTouchpadFragment extends DashboardFragment { private static final String TAG = "PointerTouchpadFragment"; + @Override + protected List createPreferenceControllers(Context context) { + return buildPreferenceControllers(context); + } + + private static List buildPreferenceControllers(Context context) { + TouchpadSystemGesturesPreferenceController systemGesturesController = + new TouchpadSystemGesturesPreferenceController( + context, "touchpad_system_gestures_enable"); + return List.of( + systemGesturesController, + new PreferenceCategoryController(context, "touchpad_category") + .setChildren(List.of(systemGesturesController))); + } + @Override public int getMetricsCategory() { return SettingsEnums.ACCESSIBILITY_POINTER_TOUCHPAD; @@ -54,5 +73,11 @@ public class PointerTouchpadFragment extends DashboardFragment { protected boolean isPageSearchEnabled(Context context) { return isTouchpad() || isMouse(); } + + @Override + public List createPreferenceControllers( + Context context) { + return buildPreferenceControllers(context); + } }; } diff --git a/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java b/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java index 5154623ade4..8b0ae4cbd26 100644 --- a/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java +++ b/src/com/android/settings/inputmethod/TouchGesturesButtonPreferenceController.java @@ -21,6 +21,7 @@ import static com.android.systemui.shared.Flags.newTouchpadGesturesTutorial; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; +import android.hardware.input.InputSettings; import android.os.UserHandle; import android.util.FeatureFlagUtils; @@ -75,7 +76,14 @@ public class TouchGesturesButtonPreferenceController extends BasePreferenceContr @Override public int getAvailabilityStatus() { boolean isTouchpad = InputPeripheralsSettingsUtils.isTouchpad(); - return isTouchpad ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + if (isTouchpad) { + // If the user's disabled touchpad system gestures in the accessibility settings, the + // tutorial won't work or be relevant, so disable the button. + return InputSettings.useTouchpadSystemGestures(mContext) ? AVAILABLE + : DISABLED_DEPENDENT_SETTING; + } else { + return CONDITIONALLY_UNAVAILABLE; + } } private void showTouchpadGestureEducation() { diff --git a/src/com/android/settings/inputmethod/TouchpadSystemGesturesPreferenceController.java b/src/com/android/settings/inputmethod/TouchpadSystemGesturesPreferenceController.java new file mode 100644 index 00000000000..9f0acb15a46 --- /dev/null +++ b/src/com/android/settings/inputmethod/TouchpadSystemGesturesPreferenceController.java @@ -0,0 +1,54 @@ +/* + * 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.InputSettings; + +import com.android.settings.R; +import com.android.settings.core.TogglePreferenceController; + +public class TouchpadSystemGesturesPreferenceController extends TogglePreferenceController { + + public TouchpadSystemGesturesPreferenceController(Context context, String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + return InputSettings.isTouchpadSystemGestureDisableFeatureFlagEnabled() + && InputPeripheralsSettingsUtils.isTouchpad() ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public boolean isChecked() { + return InputSettings.useTouchpadSystemGestures(mContext); + } + + @Override + public boolean setChecked(boolean isChecked) { + InputSettings.setTouchpadSystemGesturesEnabled(mContext, isChecked); + // TODO(b/353947750): add a metric for when the setting changes. + return true; + } + + @Override + public int getSliceHighlightMenuRes() { + return R.string.menu_key_accessibility; + } +} diff --git a/src/com/android/settings/inputmethod/TrackpadGesturesDisabledFooterPreferenceController.java b/src/com/android/settings/inputmethod/TrackpadGesturesDisabledFooterPreferenceController.java new file mode 100644 index 00000000000..1fed57e5980 --- /dev/null +++ b/src/com/android/settings/inputmethod/TrackpadGesturesDisabledFooterPreferenceController.java @@ -0,0 +1,35 @@ +/* + * 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.InputSettings; + +import com.android.settings.core.BasePreferenceController; + +public class TrackpadGesturesDisabledFooterPreferenceController extends BasePreferenceController { + + public TrackpadGesturesDisabledFooterPreferenceController(Context context, String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + return InputSettings.useTouchpadSystemGestures(mContext) ? CONDITIONALLY_UNAVAILABLE + : AVAILABLE; + } +} From 4a3af3a735a15743d338b670fb8c6760d02b68ef Mon Sep 17 00:00:00 2001 From: Matthew DeVore Date: Tue, 26 Nov 2024 00:31:22 +0000 Subject: [PATCH 3/9] Show built-in display if topology is visible The topology in the External Displays list will include the built-in display. For consistency, also show the built-in display along with the connected displays, so there is a 1:1 correspondence between blocks in the topology pane and display preference items. Test: launch external display fragment with zero or one external display, verify built-in display item appears and opens Display settings if tapped Flag: com.android.settings.flags.display_topology_pane_in_display_list Bug: b/352648432 Change-Id: Id067034f6af5d0d6fe32f4a8091bc77d1ed75698 --- res/values/strings.xml | 2 + .../ExternalDisplayPreferenceFragment.java | 66 +++++++++++++++++-- ...ExternalDisplayPreferenceFragmentTest.java | 28 +++++++- 3 files changed, 86 insertions(+), 10 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 4d51512d29f..099056e0fa1 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2005,6 +2005,8 @@ Off External Display + + Built-in display Use external display diff --git a/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java b/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java index 047ffd41da2..de1363d24cd 100644 --- a/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java +++ b/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java @@ -16,7 +16,6 @@ package com.android.settings.connecteddevice.display; - import static android.view.Display.INVALID_DISPLAY; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_HELP_URL; @@ -46,6 +45,7 @@ import androidx.preference.PreferenceScreen; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragmentBase; +import com.android.settings.accessibility.TextReadingPreferenceFragment; import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DisplayListener; import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.Injector; import com.android.settings.core.SubSettingLauncher; @@ -64,6 +64,7 @@ import java.util.List; public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmentBase { static final int EXTERNAL_DISPLAY_SETTINGS_RESOURCE = R.xml.external_display_settings; static final String DISPLAYS_LIST_PREFERENCE_KEY = "displays_list_preference"; + static final String BUILTIN_DISPLAY_LIST_PREFERENCE_KEY = "builtin_display_list_preference"; static final String EXTERNAL_DISPLAY_USE_PREFERENCE_KEY = "external_display_use_preference"; static final String EXTERNAL_DISPLAY_ROTATION_KEY = "external_display_rotation"; static final String EXTERNAL_DISPLAY_RESOLUTION_PREFERENCE_KEY = "external_display_resolution"; @@ -83,6 +84,8 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen R.string.external_display_rotation; static final int EXTERNAL_DISPLAY_RESOLUTION_TITLE_RESOURCE = R.string.external_display_resolution_settings_title; + static final int BUILTIN_DISPLAY_SETTINGS_CATEGORY_RESOURCE = + R.string.builtin_display_settings_category; @VisibleForTesting static final String PREVIOUSLY_SHOWN_LIST_KEY = "mPreviouslyShownListOfDisplays"; private boolean mStarted; @@ -101,6 +104,8 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen @Nullable private PreferenceCategory mDisplaysPreference; @Nullable + private PreferenceCategory mBuiltinDisplayPreference; + @Nullable private Injector mInjector; @Nullable private String[] mRotationEntries; @@ -200,7 +205,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen } @VisibleForTesting - protected void launchDisplaySettings(final int displayId) { + protected void launchExternalDisplaySettings(final int displayId) { final Bundle args = new Bundle(); var context = getPrefContext(); args.putInt(DISPLAY_ID_ARG, displayId); @@ -210,6 +215,16 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen .setSourceMetricsCategory(getMetricsCategory()).launch(); } + @VisibleForTesting + protected void launchBuiltinDisplaySettings() { + final Bundle args = new Bundle(); + var context = getPrefContext(); + new SubSettingLauncher(context) + .setDestination(TextReadingPreferenceFragment.class.getName()) + .setArguments(args) + .setSourceMetricsCategory(getMetricsCategory()).launch(); + } + /** * Returns the preference for the footer. */ @@ -281,6 +296,15 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen return mDisplaysPreference; } + @NonNull + private PreferenceCategory getBuiltinDisplayListPreference(@NonNull Context context) { + if (mBuiltinDisplayPreference == null) { + mBuiltinDisplayPreference = new PreferenceCategory(context); + mBuiltinDisplayPreference.setPersistent(false); + } + return mBuiltinDisplayPreference; + } + @NonNull Preference getDisplayTopologyPreference(@NonNull Context context) { if (mDisplayTopologyPreference == null) { mDisplayTopologyPreference = new DisplayTopologyPreference(context); @@ -310,7 +334,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen @NonNull final PreferenceScreen screen, @NonNull Context context) { final boolean forceShowList = displayId == INVALID_DISPLAY && mInjector != null && forceShowDisplayList(mInjector.getFlags()); - final var displaysToShow = getDisplaysToShow(displayId); + final var displaysToShow = externalDisplaysToShow(displayId); if (!forceShowList && displaysToShow.isEmpty() && displayId == INVALID_DISPLAY) { showTextWhenNoDisplaysToShow(screen, context); @@ -373,9 +397,18 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen private void showDisplaysList(@NonNull List displaysToShow, @NonNull PreferenceScreen screen, @NonNull Context context) { - if (mInjector != null - && mInjector.getFlags().displayTopologyPaneInDisplayList()) { + if (mInjector != null && mInjector.getFlags().displayTopologyPaneInDisplayList()) { screen.addPreference(getDisplayTopologyPreference(context)); + + // If topology is shown, we also show a preference for the built-in display for + // consistency with the topology. + var builtinCategory = getBuiltinDisplayListPreference(context); + builtinCategory.setKey(BUILTIN_DISPLAY_LIST_PREFERENCE_KEY); + builtinCategory.setTitle(BUILTIN_DISPLAY_SETTINGS_CATEGORY_RESOURCE); + builtinCategory.removeAll(); + screen.addPreference(builtinCategory); + + builtinCategory.addPreference(new BuiltinDisplaySizeAndTextPreference(context)); } var pref = getDisplaysListPreference(context); @@ -389,7 +422,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen } } - private List getDisplaysToShow(int displayIdToShow) { + private List externalDisplaysToShow(int displayIdToShow) { if (mInjector == null) { return List.of(); } @@ -530,6 +563,24 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen mInjector.getHandler().removeCallbacks(mUpdateRunnable); } + private class BuiltinDisplaySizeAndTextPreference extends Preference + implements Preference.OnPreferenceClickListener { + BuiltinDisplaySizeAndTextPreference(@NonNull final Context context) { + super(context); + + setPersistent(false); + setKey("builtin_display_size_and_text"); + setTitle(R.string.accessibility_text_reading_options_title); + setOnPreferenceClickListener(this); + } + + @Override + public boolean onPreferenceClick(@NonNull Preference preference) { + launchBuiltinDisplaySettings(); + return true; + } + } + @VisibleForTesting class DisplayPreference extends TwoTargetPreference implements Preference.OnPreferenceClickListener { @@ -538,6 +589,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen DisplayPreference(@NonNull final Context context, @NonNull final Display display) { super(context); mDisplayId = display.getDisplayId(); + setPersistent(false); setKey("display_id_" + mDisplayId); setTitle(display.getName()); @@ -548,7 +600,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen @Override public boolean onPreferenceClick(@NonNull Preference preference) { - launchDisplaySettings(mDisplayId); + launchExternalDisplaySettings(mDisplayId); writePreferenceClickMetric(preference); return true; } diff --git a/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java b/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java index 63652260296..93ba97b27f5 100644 --- a/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java +++ b/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java @@ -71,6 +71,7 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa private ExternalDisplayPreferenceFragment mFragment; private int mPreferenceIdFromResource; private int mDisplayIdArg = INVALID_DISPLAY; + private boolean mLaunchedBuiltinSettings; private int mResolutionSelectorDisplayId = INVALID_DISPLAY; @Mock private MetricsLogger mMockedMetricsLogger; @@ -106,6 +107,10 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa pref = mPreferenceScreen.findPreference(DisplayTopologyKt.PREFERENCE_KEY); assertThat(pref).isNull(); + + pref = mPreferenceScreen.findPreference( + ExternalDisplayPreferenceFragment.BUILTIN_DISPLAY_LIST_PREFERENCE_KEY); + assertThat(pref).isNull(); } @Test @@ -124,6 +129,11 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa mPreferenceScreen.findPreference(DISPLAYS_LIST_PREFERENCE_KEY); assertThat(listPref).isNotNull(); assertThat(listPref.getPreferenceCount()).isEqualTo(1); + + listPref = mPreferenceScreen.findPreference( + ExternalDisplayPreferenceFragment.BUILTIN_DISPLAY_LIST_PREFERENCE_KEY); + assertThat(listPref).isNotNull(); + assertThat(listPref.getPreferenceCount()).isEqualTo(1); } @Test @@ -138,11 +148,18 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa var pref = mPreferenceScreen.findPreference(DisplayTopologyKt.PREFERENCE_KEY); assertThat(pref).isNotNull(); - // TODO: add the built-in display to the list, which will cause this preference to not be - // null. PreferenceCategory listPref = mPreferenceScreen.findPreference(DISPLAYS_LIST_PREFERENCE_KEY); assertThat(listPref).isNull(); + + listPref = mPreferenceScreen.findPreference( + ExternalDisplayPreferenceFragment.BUILTIN_DISPLAY_LIST_PREFERENCE_KEY); + assertThat(listPref).isNotNull(); + assertThat(listPref.getPreferenceCount()).isEqualTo(1); + var builtinPref = listPref.getPreference(0); + assertThat(builtinPref.getOnPreferenceClickListener().onPreferenceClick(builtinPref)) + .isTrue(); + assertThat(mLaunchedBuiltinSettings).isTrue(); } @Test @@ -428,10 +445,15 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa } @Override - protected void launchDisplaySettings(final int displayId) { + protected void launchExternalDisplaySettings(final int displayId) { mDisplayIdArg = displayId; } + @Override + protected void launchBuiltinDisplaySettings() { + mLaunchedBuiltinSettings = true; + } + @Override protected void writePreferenceClickMetric(Preference preference) { mLogger.writePreferenceClickMetric(preference); From cc663236138fae0af854a5a59f273634f91fc50a Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Fri, 25 Oct 2024 22:18:55 +0000 Subject: [PATCH 4/9] Revert "Turn off voice access in 16KB mode" This reverts commit 6de4093876dd102803ac029766869592cf92489b. Reason for revert: b/335443194 is fixed now Change-Id: Id2c4584835766e9620234233b6594c0dd59b68e9 --- .../settings/accessibility/AccessibilitySettings.java | 8 -------- .../accessibility/RestrictedPreferenceHelper.java | 9 --------- 2 files changed, 17 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index 34badfc626f..39ce081f606 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -43,7 +43,6 @@ import com.android.internal.content.PackageMonitor; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityUtil.AccessibilityServiceFragmentType; import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.development.Enable16kUtils; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.RestrictedPreference; @@ -96,8 +95,6 @@ public class AccessibilitySettings extends DashboardFragment implements static final String EXTRA_TIME_FOR_LOGGING = "start_time_to_log_a11y_tool"; static final String EXTRA_METRICS_CATEGORY = "metrics_category"; - public static final String VOICE_ACCESS_SERVICE = "android.apps.accessibility.voiceaccess"; - // Timeout before we update the services if packages are added/removed // since the AccessibilityManagerService has to do that processing first // to generate the AccessibilityServiceInfo we need for proper @@ -503,11 +500,6 @@ public class AccessibilitySettings extends DashboardFragment implements String[] services = getResources().getStringArray(key); PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey); for (int i = 0; i < services.length; i++) { - // TODO(b/335443194) Voice access is not available in 16kB mode. - if (services[i].contains(VOICE_ACCESS_SERVICE) - && Enable16kUtils.isPageAgnosticModeOn(getContext())) { - continue; - } ComponentName component = ComponentName.unflattenFromString(services[i]); mPreBundledServiceComponentToCategoryMap.put(component, category); } diff --git a/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java b/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java index 82aa0984a0b..d97895ac85b 100644 --- a/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java +++ b/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java @@ -16,8 +16,6 @@ package com.android.settings.accessibility; -import static com.android.settings.accessibility.AccessibilitySettings.VOICE_ACCESS_SERVICE; - import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityShortcutInfo; import android.app.AppOpsManager; @@ -31,7 +29,6 @@ import android.os.UserHandle; import android.text.TextUtils; import com.android.settings.R; -import com.android.settings.development.Enable16kUtils; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedPreference; @@ -81,12 +78,6 @@ public class RestrictedPreferenceHelper { final AccessibilityServiceInfo info = installedServices.get(i); final ResolveInfo resolveInfo = info.getResolveInfo(); final String packageName = resolveInfo.serviceInfo.packageName; - // TODO(b/335443194) Voice access is not available in 16kB mode. - if (packageName.contains(VOICE_ACCESS_SERVICE) - && Enable16kUtils.isPageAgnosticModeOn(mContext)) { - continue; - } - final ComponentName componentName = new ComponentName(packageName, resolveInfo.serviceInfo.name); final boolean serviceEnabled = enabledServices.contains(componentName); From 5da12934944553508365e562bed60eaefa7dc299 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Fri, 25 Oct 2024 22:09:52 +0000 Subject: [PATCH 5/9] Revert "Turn off voice access in 16KB mode" This reverts commit 6de4093876dd102803ac029766869592cf92489b. Test: m Settigns Bug: 335443194 Bug: 340231742 Change-Id: I6b3ab5ba9626dd17c1e6383d8b390fb7c91c9efc Merged-In: Id2c4584835766e9620234233b6594c0dd59b68e9 --- .../settings/accessibility/AccessibilitySettings.java | 8 -------- .../accessibility/RestrictedPreferenceHelper.java | 8 -------- 2 files changed, 16 deletions(-) diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java index 8441c2acaa5..c52da5ebe1d 100644 --- a/src/com/android/settings/accessibility/AccessibilitySettings.java +++ b/src/com/android/settings/accessibility/AccessibilitySettings.java @@ -44,7 +44,6 @@ import com.android.internal.content.PackageMonitor; import com.android.settings.R; import com.android.settings.accessibility.AccessibilityUtil.AccessibilityServiceFragmentType; import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.development.Enable16kUtils; import com.android.settings.inputmethod.PhysicalKeyboardFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; @@ -101,8 +100,6 @@ public class AccessibilitySettings extends DashboardFragment implements static final String EXTRA_TIME_FOR_LOGGING = "start_time_to_log_a11y_tool"; static final String EXTRA_METRICS_CATEGORY = "metrics_category"; - public static final String VOICE_ACCESS_SERVICE = "android.apps.accessibility.voiceaccess"; - // Timeout before we update the services if packages are added/removed // since the AccessibilityManagerService has to do that processing first // to generate the AccessibilityServiceInfo we need for proper @@ -496,11 +493,6 @@ public class AccessibilitySettings extends DashboardFragment implements String[] services = getResources().getStringArray(key); PreferenceCategory category = mCategoryToPrefCategoryMap.get(categoryKey); for (int i = 0; i < services.length; i++) { - // TODO(b/335443194) Voice access is not available in 16kB mode. - if (services[i].contains(VOICE_ACCESS_SERVICE) - && Enable16kUtils.isPageAgnosticModeOn(getContext())) { - continue; - } ComponentName component = ComponentName.unflattenFromString(services[i]); mPreBundledServiceComponentToCategoryMap.put(component, category); } diff --git a/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java b/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java index 2cabc76eab0..5d94d8c5b8f 100644 --- a/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java +++ b/src/com/android/settings/accessibility/RestrictedPreferenceHelper.java @@ -16,8 +16,6 @@ package com.android.settings.accessibility; -import static com.android.settings.accessibility.AccessibilitySettings.VOICE_ACCESS_SERVICE; - import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.AccessibilityShortcutInfo; import android.app.AppOpsManager; @@ -31,7 +29,6 @@ import android.os.UserHandle; import android.text.TextUtils; import com.android.settings.R; -import com.android.settings.development.Enable16kUtils; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtilsInternal; import com.android.settingslib.RestrictedPreference; @@ -81,11 +78,6 @@ public class RestrictedPreferenceHelper { final AccessibilityServiceInfo info = installedServices.get(i); final ResolveInfo resolveInfo = info.getResolveInfo(); final String packageName = resolveInfo.serviceInfo.packageName; - // TODO(b/335443194) Voice access is not available in 16kB mode. - if (packageName.contains(VOICE_ACCESS_SERVICE) - && Enable16kUtils.isPageAgnosticModeOn(mContext)) { - continue; - } final ComponentName componentName = new ComponentName(packageName, resolveInfo.serviceInfo.name); From 22370a8a4aa7c80ef5338f8ba41508c7b2c6e2cc Mon Sep 17 00:00:00 2001 From: tomhsu Date: Mon, 25 Nov 2024 15:09:56 +0000 Subject: [PATCH 6/9] Make Satellite messageing dynamically change wording by network type Flag: com.android.settings.flags.satellite_oem_settings_ux_migration Fix: b/378410271 Test: atest pass Change-Id: I6d2d2ba656a6e2eb26ae103f8af84a1ce5fd49c8 --- res/values/strings.xml | 17 +- res/xml/satellite_setting.xml | 8 +- .../network/telephony/SatelliteSetting.java | 109 ++++++++--- .../SatelliteSettingPreferenceController.java | 82 +++++++- ...eSettingsPreferenceCategoryController.java | 11 +- ...tingsPreferenceCategoryControllerTest.java | 2 +- ...lliteSettingsPreferenceControllerTest.java | 179 ++++++++++++++++++ 7 files changed, 364 insertions(+), 44 deletions(-) create mode 100644 tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 6ba28533355..aec0fa669ef 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12275,13 +12275,13 @@ Satellite messaging - About satellite messaging + About %1$s You can send and receive text messages by satellite as part of an eligible %1$s account Your %1$s plan - Satellite messaging is included with your account + Messaging is included with your account Satellite messaging isn\u2019t included with your account @@ -12297,9 +12297,9 @@ You can text anyone, including emergency services. Your phone will reconnect to a mobile network when available. - Satellite messaging may take longer and is available only in some areas. Weather and certain structures may affect your satellite connection. Calling by satellite isn\u2019t available. Emergency calls may still connect.\n\nIt may take some time for account changes to show in Settings. Contact your carrier for details. + %1$s may take longer and is available only in some areas. Weather and certain structures may affect your satellite connection. Calling by satellite isn\u2019t available. Emergency calls may still connect.\n\nIt may take some time for account changes to show in Settings. Contact %1$s for details. - More about satellite messaging + More about %1$s Can’t turn on %1$s @@ -12307,7 +12307,14 @@ Satellite connectivity - Satellite connectivity + Satellite connectivity + + satellite connectivity + + satellite messaging + + Use of data is included with your account + diff --git a/res/xml/satellite_setting.xml b/res/xml/satellite_setting.xml index 09fbbd66171..60fe5bfb335 100644 --- a/res/xml/satellite_setting.xml +++ b/res/xml/satellite_setting.xml @@ -22,7 +22,7 @@ settings:keywords="@string/keywords_satellite_setting"> + android:key="key_category_about_satellite"> @@ -35,6 +35,12 @@ + + + { + messagingPreference.setOnPreferenceClickListener(pref -> { String url = readSatelliteMoreInfoString(mSubId); if (!url.isEmpty()) { Uri uri = Uri.parse(url); @@ -173,11 +199,13 @@ public class SatelliteSetting extends RestrictedDashboardFragment { } return true; }); - icon = getResources().getDrawable(R.drawable.ic_block_24px); + icon = getResources().getDrawable(R.drawable.ic_block_24px, null); } icon.setTintList(Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary)); - preference.setIcon(icon); + messagingPreference.setIcon(icon); + } + private void updateHowItWorksContent(boolean isSatelliteEligible) { /* Composes "How it works" section, which guides how users can use satellite messaging, when satellite messaging is included in user's mobile plan, or it'll will be grey out. */ if (!isSatelliteEligible) { @@ -185,13 +213,15 @@ public class SatelliteSetting extends RestrictedDashboardFragment { category.setEnabled(false); category.setShouldDisableView(true); } + } + private void updateFooterContent() { // More about satellite messaging FooterPreference footerPreference = findPreference(KEY_FOOTER_PREFERENCE); if (footerPreference != null) { footerPreference.setSummary( getResources().getString(R.string.satellite_setting_summary_more_information, - operatorName)); + getSubjectString(), mSimOperatorName)); final String[] link = new String[1]; link[0] = readSatelliteMoreInfoString(mSubId); @@ -205,8 +235,9 @@ public class SatelliteSetting extends RestrictedDashboardFragment { } } }); + footerPreference.setLearnMoreText( - getResources().getString(R.string.more_about_satellite_messaging)); + getString(R.string.more_about_satellite_messaging, getDescriptionString())); } } } @@ -245,6 +276,32 @@ public class SatelliteSetting extends RestrictedDashboardFragment { return bundle.getBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false); } + // This is for a word which first letter is uppercase. e.g. Satellite messaging. + private String getSubjectString() { + int result; + if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) { + result = mIsServiceDataType + ? R.string.title_satellite_setting_connectivity + : R.string.satellite_setting_title; + } else { + result = R.string.satellite_setting_title; + } + return getString(result); + } + + // This is for a word without uppercase letter. e.g. satellite messaging. + private String getDescriptionString() { + int result; + if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) { + result = mIsServiceDataType + ? R.string.description_satellite_setting_connectivity + : R.string.description_satellite_setting_messaging; + } else { + result = R.string.satellite_setting_title; + } + return getString(result); + } + private static void loge(String message) { Log.e(TAG, message); } diff --git a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java index efdd9cb9ca5..f13ea354ff5 100644 --- a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java +++ b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java @@ -16,16 +16,25 @@ package com.android.settings.network.telephony; +import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_DATA; +import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_SMS; + import android.content.Context; import android.content.Intent; import android.os.PersistableBundle; import android.provider.Settings; import android.telephony.CarrierConfigManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.telephony.satellite.NtnSignalStrength; import android.telephony.satellite.SatelliteManager; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; @@ -33,28 +42,33 @@ import com.android.internal.telephony.flags.Flags; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.network.CarrierConfigCache; -import com.android.settingslib.core.lifecycle.LifecycleObserver; -import com.android.settingslib.core.lifecycle.events.OnStart; -import com.android.settingslib.core.lifecycle.events.OnStop; +import java.util.List; import java.util.Set; /** * Preference controller for "Satellite Setting" */ public class SatelliteSettingPreferenceController extends - TelephonyBasePreferenceController implements LifecycleObserver, OnStart, OnStop { - + TelephonyBasePreferenceController implements DefaultLifecycleObserver { private static final String TAG = "SatelliteSettingPreferenceController"; CarrierConfigCache mCarrierConfigCache; SatelliteManager mSatelliteManager; - @Nullable private Boolean mIsSatelliteEligible = null; + private TelephonyManager mTelephonyManager = null; + @VisibleForTesting + final CarrierRoamingNtnModeCallback mCarrierRoamingNtnModeCallback = + new CarrierRoamingNtnModeCallback(); + + @Nullable + private Boolean mIsSatelliteEligible = null; + private boolean mIsServiceDataType = false; public SatelliteSettingPreferenceController(@NonNull Context context, @NonNull String key) { super(context, key); mCarrierConfigCache = CarrierConfigCache.getInstance(context); mSatelliteManager = context.getSystemService(SatelliteManager.class); + mTelephonyManager = context.getSystemService(TelephonyManager.class); } @Override @@ -76,11 +90,18 @@ public class SatelliteSettingPreferenceController extends } @Override - public void onStart() { + public void onResume(@NonNull LifecycleOwner owner) { + if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) { + mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(), + mCarrierRoamingNtnModeCallback); + } } @Override - public void onStop() { + public void onPause(@NonNull LifecycleOwner owner) { + if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) { + mTelephonyManager.unregisterTelephonyCallback(mCarrierRoamingNtnModeCallback); + } } @Override @@ -93,6 +114,7 @@ public class SatelliteSettingPreferenceController extends public void updateState(@Nullable Preference preference) { super.updateState(preference); if (preference != null) { + mCarrierRoamingNtnModeCallback.mPref = preference; updateSummary(preference); } } @@ -106,6 +128,7 @@ public class SatelliteSettingPreferenceController extends // This will setup the Home and Search affordance intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SUBSETTING, true); intent.putExtra(SatelliteSetting.SUB_ID, mSubId); + intent.putExtra(SatelliteSetting.EXTRA_IS_SERVICE_DATA_TYPE, mIsServiceDataType); mContext.startActivity(intent); return true; } @@ -115,11 +138,13 @@ public class SatelliteSettingPreferenceController extends /** * Set subId for Satellite Settings page. + * * @param subId subscription ID. */ public void init(int subId) { logd("init(), subId=" + subId); mSubId = subId; + mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId); } private void updateSummary(Preference preference) { @@ -148,4 +173,45 @@ public class SatelliteSettingPreferenceController extends private static void loge(String message) { Log.e(TAG, message); } + + @VisibleForTesting + class CarrierRoamingNtnModeCallback extends TelephonyCallback implements + TelephonyCallback.CarrierRoamingNtnModeListener { + Preference mPref = null; + + @Override + public void onCarrierRoamingNtnAvailableServicesChanged(List availableServices) { + CarrierRoamingNtnModeListener.super.onCarrierRoamingNtnAvailableServicesChanged( + availableServices); + boolean isSmsAvailable = availableServices.contains(SERVICE_TYPE_SMS); + boolean isDataAvailable = availableServices.contains(SERVICE_TYPE_DATA); + logd("isSmsAvailable : " + isSmsAvailable + + " / isDataAvailable " + isDataAvailable); + if (mPref == null) { + logd("Satellite preference is not initialized yet"); + return; + } + if (isDataAvailable) { + mIsServiceDataType = true; + mPref.setTitle(R.string.title_satellite_setting_connectivity); + } else if (isSmsAvailable) { + mPref.setTitle(R.string.satellite_setting_title); + } + } + + @Override + public void onCarrierRoamingNtnEligibleStateChanged(boolean eligible) { + // Do nothing + } + + @Override + public void onCarrierRoamingNtnModeChanged(boolean active) { + // Do nothing + } + + @Override + public void onCarrierRoamingNtnSignalStrengthChanged(NtnSignalStrength ntnSignalStrength) { + // Do nothing + } + } } diff --git a/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java b/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java index ae3262f78ab..c1820595219 100644 --- a/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java +++ b/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryController.java @@ -33,6 +33,7 @@ import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.flags.Flags; import java.util.Arrays; import java.util.List; @@ -87,13 +88,17 @@ public class SatelliteSettingsPreferenceCategoryController @Override public void onResume(@NonNull LifecycleOwner owner) { - mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(), - mCarrierRoamingNtnModeCallback); + if (Flags.satelliteOemSettingsUxMigration()) { + mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(), + mCarrierRoamingNtnModeCallback); + } } @Override public void onPause(@NonNull LifecycleOwner owner) { - mTelephonyManager.unregisterTelephonyCallback(mCarrierRoamingNtnModeCallback); + if (Flags.satelliteOemSettingsUxMigration()) { + mTelephonyManager.unregisterTelephonyCallback(mCarrierRoamingNtnModeCallback); + } } @VisibleForTesting diff --git a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java index bd06a646137..299ea133536 100644 --- a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceCategoryControllerTest.java @@ -114,7 +114,7 @@ public class SatelliteSettingsPreferenceCategoryControllerTest { new int[]{SERVICE_TYPE_DATA}); assertThat(preferenceCategory.getTitle()).isEqualTo( - mContext.getString(R.string.satellite_setting_connectivity)); + mContext.getString(R.string.title_satellite_setting_connectivity)); } diff --git a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java new file mode 100644 index 00000000000..b15c6608080 --- /dev/null +++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 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.network.telephony; + +import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_DATA; +import static android.telephony.NetworkRegistrationInfo.SERVICE_TYPE_SMS; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.Looper; +import android.os.PersistableBundle; +import android.platform.test.annotations.EnableFlags; +import android.telephony.CarrierConfigManager; +import android.telephony.TelephonyManager; +import android.telephony.satellite.SatelliteManager; + +import androidx.preference.Preference; +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; +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 java.util.List; + +@RunWith(AndroidJUnit4.class) +public class SatelliteSettingsPreferenceControllerTest { + private static final String KEY = "key"; + private static final int TEST_SUB_ID = 0; + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + @Mock + private CarrierConfigCache mCarrierConfigCache; + @Mock + private TelephonyManager mTelephonyManager; + + private Context mContext = null; + private SatelliteManager mSatelliteManager; + private SatelliteSettingPreferenceController mController = null; + private PersistableBundle mCarrierConfig = new PersistableBundle(); + + @Before + public void setUp() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + mContext = spy(ApplicationProvider.getApplicationContext()); + mSatelliteManager = new SatelliteManager(mContext); + CarrierConfigCache.setTestInstance(mContext, mCarrierConfigCache); + when(mContext.getSystemService(SatelliteManager.class)).thenReturn(mSatelliteManager); + when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); + when(mTelephonyManager.createForSubscriptionId(TEST_SUB_ID)).thenReturn(mTelephonyManager); + mController = spy(new SatelliteSettingPreferenceController(mContext, KEY)); + } + + @Test + @EnableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) + public void getAvailabilityStatus_noSatellite_returnUnsupport() { + when(mContext.getSystemService(SatelliteManager.class)).thenReturn(null); + mController = new SatelliteSettingPreferenceController(mContext, KEY); + + int result = mController.getAvailabilityStatus(TEST_SUB_ID); + + assertThat(result).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + @EnableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) + public void getAvailabilityStatus_carrierIsNotSupport_returnUnavailable() { + when(mContext.getSystemService(SatelliteManager.class)).thenReturn(null); + mCarrierConfig.putBoolean( + CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, + false); + when(mCarrierConfigCache.getConfigForSubId(TEST_SUB_ID)).thenReturn(mCarrierConfig); + + int result = mController.getAvailabilityStatus(TEST_SUB_ID); + + assertThat(result).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + @EnableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG) + public void getAvailabilityStatus_carrierIsSupport_returnAvailable() { + when(mContext.getSystemService(SatelliteManager.class)).thenReturn(null); + mCarrierConfig.putBoolean( + CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, + true); + when(mCarrierConfigCache.getConfigForSubId(TEST_SUB_ID)).thenReturn(mCarrierConfig); + + int result = mController.getAvailabilityStatus(TEST_SUB_ID); + + assertThat(result).isEqualTo(AVAILABLE); + } + + @Test + @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + public void getAvailabilityStatus_registerTelephonyCallback_success() { + mController.init(TEST_SUB_ID); + mController.onResume(null); + + verify(mTelephonyManager).registerTelephonyCallback(any(), any()); + } + + @Test + @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + public void getAvailabilityStatus_unregisterTelephonyCallback_success() { + mController.init(TEST_SUB_ID); + mController.onPause(null); + + verify(mTelephonyManager).unregisterTelephonyCallback(any()); + } + + @Test + @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + public void getAvailabilityStatus_hasServiceDataType_showDataUi() { + mController.init(TEST_SUB_ID); + Preference preference = new Preference(mContext); + preference.setKey(KEY); + preference.setTitle("test title"); + mController.updateState(preference); + + mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged( + List.of(SERVICE_TYPE_SMS, SERVICE_TYPE_DATA)); + + assertThat(preference.getTitle()).isEqualTo( + mContext.getString(R.string.title_satellite_setting_connectivity)); + } + + @Test + @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + public void getAvailabilityStatus_hasServiceDataType_showSmsUi() { + mController.init(TEST_SUB_ID); + Preference preference = new Preference(mContext); + preference.setKey(KEY); + preference.setTitle("test title"); + mController.updateState(preference); + + mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged( + List.of(SERVICE_TYPE_SMS)); + + assertThat(preference.getTitle()).isEqualTo( + mContext.getString(R.string.satellite_setting_title)); + } +} From ad74d1f1fb674cb6e32ec6d454e274cb982ea12d Mon Sep 17 00:00:00 2001 From: tomhsu Date: Thu, 28 Nov 2024 03:45:08 +0000 Subject: [PATCH 7/9] Modification for Satellite API change. Input parameter changed from List to Int[] Flag: com.android.settings.flags.satellite_oem_settings_ux_migration Fix: b/378410271 Test: atest pass Test: make pass Change-Id: I1df1354fa5ceea960d41d33ab34da0a415d5fc82 --- .../telephony/SatelliteSettingPreferenceController.java | 8 +++++--- .../SatelliteSettingsPreferenceControllerTest.java | 8 +++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java index f13ea354ff5..1b5e056a021 100644 --- a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java +++ b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java @@ -43,6 +43,7 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.network.CarrierConfigCache; +import java.util.Arrays; import java.util.List; import java.util.Set; @@ -180,11 +181,12 @@ public class SatelliteSettingPreferenceController extends Preference mPref = null; @Override - public void onCarrierRoamingNtnAvailableServicesChanged(List availableServices) { + public void onCarrierRoamingNtnAvailableServicesChanged(int[] availableServices) { CarrierRoamingNtnModeListener.super.onCarrierRoamingNtnAvailableServicesChanged( availableServices); - boolean isSmsAvailable = availableServices.contains(SERVICE_TYPE_SMS); - boolean isDataAvailable = availableServices.contains(SERVICE_TYPE_DATA); + List availableServicesList = Arrays.stream(availableServices).boxed().toList(); + boolean isSmsAvailable = availableServicesList.contains(SERVICE_TYPE_SMS); + boolean isDataAvailable = availableServicesList.contains(SERVICE_TYPE_DATA); logd("isSmsAvailable : " + isSmsAvailable + " / isDataAvailable " + isDataAvailable); if (mPref == null) { 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 b15c6608080..6aa48e3b4ca 100644 --- a/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteSettingsPreferenceControllerTest.java @@ -54,8 +54,6 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import java.util.List; - @RunWith(AndroidJUnit4.class) public class SatelliteSettingsPreferenceControllerTest { private static final String KEY = "key"; @@ -155,7 +153,7 @@ public class SatelliteSettingsPreferenceControllerTest { mController.updateState(preference); mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged( - List.of(SERVICE_TYPE_SMS, SERVICE_TYPE_DATA)); + new int[]{SERVICE_TYPE_SMS, SERVICE_TYPE_DATA}); assertThat(preference.getTitle()).isEqualTo( mContext.getString(R.string.title_satellite_setting_connectivity)); @@ -163,7 +161,7 @@ public class SatelliteSettingsPreferenceControllerTest { @Test @EnableFlags(com.android.settings.flags.Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) - public void getAvailabilityStatus_hasServiceDataType_showSmsUi() { + public void getAvailabilityStatus_onlyHasServiceSmsType_showSmsUi() { mController.init(TEST_SUB_ID); Preference preference = new Preference(mContext); preference.setKey(KEY); @@ -171,7 +169,7 @@ public class SatelliteSettingsPreferenceControllerTest { mController.updateState(preference); mController.mCarrierRoamingNtnModeCallback.onCarrierRoamingNtnAvailableServicesChanged( - List.of(SERVICE_TYPE_SMS)); + new int[]{SERVICE_TYPE_SMS}); assertThat(preference.getTitle()).isEqualTo( mContext.getString(R.string.satellite_setting_title)); From 55de3bf24b46b6cc06a5dc4ac805cca3c43120f7 Mon Sep 17 00:00:00 2001 From: tomhsu Date: Thu, 28 Nov 2024 04:32:26 +0000 Subject: [PATCH 8/9] Fix crash due to no SatelliteManager Flag: EXEMPT bug fix fix: 381212236 Test: make pass Change-Id: Ic10ad27c1e84ac29c5c1ccf81c073d6f216ed32e --- .../telephony/SatelliteSettingPreferenceController.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java index f13ea354ff5..c474d6389ac 100644 --- a/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java +++ b/src/com/android/settings/network/telephony/SatelliteSettingPreferenceController.java @@ -148,6 +148,10 @@ public class SatelliteSettingPreferenceController extends } private void updateSummary(Preference preference) { + if (mSatelliteManager == null) { + logd("updateSummary - no SatelliteManager"); + return; + } try { Set restrictionReason = mSatelliteManager.getAttachRestrictionReasonsForCarrier(mSubId); From 9ca8709173124b5f7f2bd9cc785b650b1e9a80f2 Mon Sep 17 00:00:00 2001 From: tomhsu Date: Wed, 20 Nov 2024 13:55:05 +0000 Subject: [PATCH 9/9] Disabled Settings preference in case Satellite's conditions. Conditions - Satellite session started - Current subscription for Satellite is carrier based. Target preference UI in android settings - preferred network type - Automatically select network Flag: com.android.settings.flags.satellite_oem_settings_ux_migration Fix: b/378409439 Fix: b/378409428 Test: atest pass Test: Manual test pass Change-Id: I7aa04b818c8866bf5c891c28372a249c964b066f --- ...nabledNetworkModePreferenceController.java | 95 +++++++++++++++--- ...ferredNetworkModePreferenceController.java | 97 ++++++++++++++++++- .../gsm/AutoSelectPreferenceController.kt | 73 ++++++++++++-- .../gsm/AutoSelectPreferenceControllerTest.kt | 61 +++++++++++- ...edNetworkModePreferenceControllerTest.java | 49 ++++++++++ ...edNetworkModePreferenceControllerTest.java | 50 ++++++++++ 6 files changed, 401 insertions(+), 24 deletions(-) diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java index 1b1eb9e7e9f..8051711ddd4 100644 --- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java @@ -16,9 +16,6 @@ package com.android.settings.network.telephony; -import static androidx.lifecycle.Lifecycle.Event.ON_START; -import static androidx.lifecycle.Lifecycle.Event.ON_STOP; - import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.getNetworkModePreferenceType; import static com.android.settings.network.telephony.EnabledNetworkModePreferenceControllerHelperKt.setAllowedNetworkTypes; import static com.android.settings.network.telephony.mode.NetworkModes.addNrToLteNetworkMode; @@ -33,15 +30,17 @@ import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; +import android.telephony.satellite.SatelliteManager; +import android.telephony.satellite.SatelliteModemStateCallback; +import android.telephony.satellite.SelectedNbIotSatelliteSubscriptionCallback; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; -import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; -import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.ListPreference; import androidx.preference.ListPreferenceDialogFragmentCompat; import androidx.preference.Preference; @@ -67,7 +66,7 @@ import java.util.stream.Stream; */ public class EnabledNetworkModePreferenceController extends BasePreferenceController implements - ListPreference.OnPreferenceChangeListener, LifecycleObserver, + ListPreference.OnPreferenceChangeListener, DefaultLifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient { private static final String LOG_TAG = "EnabledNetworkMode"; @@ -83,6 +82,43 @@ public class EnabledNetworkModePreferenceController extends private PhoneCallStateTelephonyCallback mTelephonyCallback; private FragmentManager mFragmentManager; private LifecycleOwner mViewLifecycleOwner; + private SatelliteManager mSatelliteManager; + private boolean mIsSatelliteSessionStarted = false; + private boolean mIsCurrentSubscriptionForSatellite = false; + + @VisibleForTesting + final SelectedNbIotSatelliteSubscriptionCallback mSelectedNbIotSatelliteSubscriptionCallback = + new SelectedNbIotSatelliteSubscriptionCallback() { + @Override + public void onSelectedNbIotSatelliteSubscriptionChanged(int selectedSubId) { + mIsCurrentSubscriptionForSatellite = selectedSubId == mSubId; + updatePreference(); + } + }; + + @VisibleForTesting + final SatelliteModemStateCallback mSatelliteModemStateCallback = + new SatelliteModemStateCallback() { + @Override + public void onSatelliteModemStateChanged(int state) { + switch (state) { + case SatelliteManager.SATELLITE_MODEM_STATE_OFF: + case SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE: + case SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN: + if (mIsSatelliteSessionStarted) { + mIsSatelliteSessionStarted = false; + updatePreference(); + } + break; + default: + if (!mIsSatelliteSessionStarted) { + mIsSatelliteSessionStarted = true; + updatePreference(); + } + break; + } + } + }; public EnabledNetworkModePreferenceController(Context context, String key) { super(context, key); @@ -90,6 +126,7 @@ public class EnabledNetworkModePreferenceController extends if (mTelephonyCallback == null) { mTelephonyCallback = new PhoneCallStateTelephonyCallback(); } + mSatelliteManager = context.getSystemService(SatelliteManager.class); } @Override @@ -103,8 +140,22 @@ public class EnabledNetworkModePreferenceController extends return mCallState == TelephonyManager.CALL_STATE_IDLE; } - @OnLifecycleEvent(ON_START) - public void onStart() { + @Override + public void onStart(@NonNull LifecycleOwner owner) { + if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) { + if (mSatelliteManager != null) { + try { + mSatelliteManager.registerForModemStateChanged( + mContext.getMainExecutor(), mSatelliteModemStateCallback); + mSatelliteManager.registerForSelectedNbIotSatelliteSubscriptionChanged( + mContext.getMainExecutor(), + mSelectedNbIotSatelliteSubscriptionCallback); + } catch (IllegalStateException e) { + Log.w(LOG_TAG, "IllegalStateException : " + e); + } + } + } + mSubscriptionsListener.start(); if (mAllowedNetworkTypesListener == null || mTelephonyCallback == null) { return; @@ -113,9 +164,21 @@ public class EnabledNetworkModePreferenceController extends mTelephonyCallback.register(mTelephonyManager, mSubId); } - @OnLifecycleEvent(ON_STOP) - public void onStop() { + @Override + public void onStop(@NonNull LifecycleOwner owner) { mSubscriptionsListener.stop(); + if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) { + if (mSatelliteManager != null) { + try { + mSatelliteManager.unregisterForModemStateChanged(mSatelliteModemStateCallback); + mSatelliteManager.unregisterForSelectedNbIotSatelliteSubscriptionChanged( + mSelectedNbIotSatelliteSubscriptionCallback); + } catch (IllegalStateException e) { + Log.w(LOG_TAG, "IllegalStateException : " + e); + } + } + } + if (mAllowedNetworkTypesListener == null || mTelephonyCallback == null) { return; } @@ -147,7 +210,7 @@ public class EnabledNetworkModePreferenceController extends listPreference.setEntryValues(mBuilder.getEntryValues()); listPreference.setValue(Integer.toString(mBuilder.getSelectedEntryValue())); listPreference.setSummary(mBuilder.getSummary()); - boolean listPreferenceEnabled = isCallStateIdle(); + boolean listPreferenceEnabled = isPreferenceShallEnabled(); listPreference.setEnabled(listPreferenceEnabled); if (!listPreferenceEnabled) { // If dialog is already opened when ListPreference disabled, dismiss them. @@ -203,6 +266,14 @@ public class EnabledNetworkModePreferenceController extends } } + private boolean isPreferenceShallEnabled() { + Log.d(LOG_TAG, "isPreferenceShallEnabled, mIsSatelliteSessionStarted : " + + mIsSatelliteSessionStarted + " / mIsCurrentSubscriptionForSatellite : " + + mIsCurrentSubscriptionForSatellite); + return isCallStateIdle() + && !(mIsSatelliteSessionStarted && mIsCurrentSubscriptionForSatellite); + } + private final class PreferenceEntriesBuilder { private CarrierConfigCache mCarrierConfigCache; private Context mContext; @@ -254,7 +325,7 @@ public class EnabledNetworkModePreferenceController extends if (flagHidePrefer3gItem) { mDisplay3gOptions = carrierConfig.getBoolean( - CarrierConfigManager.KEY_PREFER_3G_VISIBILITY_BOOL); + CarrierConfigManager.KEY_PREFER_3G_VISIBILITY_BOOL); } else { mDisplay3gOptions = getResourcesForSubId().getBoolean( R.bool.config_display_network_mode_3g_option); diff --git a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java index d855069c26f..44091884f13 100644 --- a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java @@ -24,10 +24,18 @@ import android.telephony.CarrierConfigManager; import android.telephony.RadioAccessFamily; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.satellite.SatelliteManager; +import android.telephony.satellite.SatelliteModemStateCallback; +import android.telephony.satellite.SelectedNbIotSatelliteSubscriptionCallback; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import androidx.lifecycle.DefaultLifecycleObserver; +import androidx.lifecycle.LifecycleOwner; import androidx.preference.ListPreference; import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; @@ -38,17 +46,56 @@ import com.android.settings.network.telephony.mode.NetworkModes; * Preference controller for "Preferred network mode" */ public class PreferredNetworkModePreferenceController extends BasePreferenceController - implements ListPreference.OnPreferenceChangeListener { + implements ListPreference.OnPreferenceChangeListener, DefaultLifecycleObserver { private static final String TAG = "PrefNetworkModeCtrl"; private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private CarrierConfigCache mCarrierConfigCache; private TelephonyManager mTelephonyManager; private boolean mIsGlobalCdma; + private SatelliteManager mSatelliteManager; + private Preference mPreference; + private boolean mIsSatelliteSessionStarted = false; + private boolean mIsCurrentSubscriptionForSatellite = false; + + @VisibleForTesting + final SelectedNbIotSatelliteSubscriptionCallback mSelectedNbIotSatelliteSubscriptionCallback = + new SelectedNbIotSatelliteSubscriptionCallback() { + @Override + public void onSelectedNbIotSatelliteSubscriptionChanged(int selectedSubId) { + mIsCurrentSubscriptionForSatellite = selectedSubId == mSubId; + updateState(mPreference); + } + }; + + @VisibleForTesting + final SatelliteModemStateCallback mSatelliteModemStateCallback = + new SatelliteModemStateCallback() { + @Override + public void onSatelliteModemStateChanged(int state) { + switch (state) { + case SatelliteManager.SATELLITE_MODEM_STATE_OFF: + case SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE: + case SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN: + if (mIsSatelliteSessionStarted) { + mIsSatelliteSessionStarted = false; + updateState(mPreference); + } + break; + default: + if (!mIsSatelliteSessionStarted) { + mIsSatelliteSessionStarted = true; + updateState(mPreference); + } + break; + } + } + }; public PreferredNetworkModePreferenceController(Context context, String key) { super(context, key); mCarrierConfigCache = CarrierConfigCache.getInstance(context); + mSatelliteManager = context.getSystemService(SatelliteManager.class); } @Override @@ -58,9 +105,19 @@ public class PreferredNetworkModePreferenceController extends BasePreferenceCont ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + } + @Override public void updateState(Preference preference) { + if (preference == null) { + return; + } super.updateState(preference); + preference.setEnabled(!(mIsCurrentSubscriptionForSatellite && mIsSatelliteSessionStarted)); final ListPreference listPreference = (ListPreference) preference; final int networkMode = getPreferredNetworkMode(); listPreference.setValue(Integer.toString(networkMode)); @@ -75,9 +132,9 @@ public class PreferredNetworkModePreferenceController extends BasePreferenceCont TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, RadioAccessFamily.getRafFromNetworkType(newPreferredNetworkMode)); - final ListPreference listPreference = (ListPreference) preference; - listPreference.setSummary(getPreferredNetworkModeSummaryResId(newPreferredNetworkMode)); - return true; + final ListPreference listPreference = (ListPreference) preference; + listPreference.setSummary(getPreferredNetworkModeSummaryResId(newPreferredNetworkMode)); + return true; } public void init(int subId) { @@ -90,6 +147,38 @@ public class PreferredNetworkModePreferenceController extends BasePreferenceCont && carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_CDMA_CHOICES_BOOL); } + @Override + public void onStart(@NonNull LifecycleOwner owner) { + if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) { + if (mSatelliteManager != null) { + try { + mSatelliteManager.registerForModemStateChanged( + mContext.getMainExecutor(), mSatelliteModemStateCallback); + mSatelliteManager.registerForSelectedNbIotSatelliteSubscriptionChanged( + mContext.getMainExecutor(), + mSelectedNbIotSatelliteSubscriptionCallback); + } catch (IllegalStateException e) { + Log.w(TAG, "IllegalStateException : " + e); + } + } + } + } + + @Override + public void onStop(@NonNull LifecycleOwner owner) { + if (com.android.settings.flags.Flags.satelliteOemSettingsUxMigration()) { + if (mSatelliteManager != null) { + try { + mSatelliteManager.unregisterForModemStateChanged(mSatelliteModemStateCallback); + mSatelliteManager.unregisterForSelectedNbIotSatelliteSubscriptionChanged( + mSelectedNbIotSatelliteSubscriptionCallback); + } catch (IllegalStateException e) { + Log.w(TAG, "IllegalStateException : " + e); + } + } + } + } + private int getPreferredNetworkMode() { if (mTelephonyManager == null) { Log.w(TAG, "TelephonyManager is null"); diff --git a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt index 67a23563727..4bd91b2b5e6 100644 --- a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt +++ b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.kt @@ -25,18 +25,22 @@ import android.telephony.CarrierConfigManager import android.telephony.ServiceState import android.telephony.SubscriptionManager import android.telephony.TelephonyManager +import android.telephony.satellite.SatelliteManager +import android.telephony.satellite.SatelliteModemStateCallback +import android.telephony.satellite.SelectedNbIotSatelliteSubscriptionCallback +import android.util.Log import androidx.annotation.VisibleForTesting import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.res.stringResource +import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.preference.Preference -import androidx.preference.PreferenceScreen import com.android.settings.R import com.android.settings.Settings.NetworkSelectActivity +import com.android.settings.flags.Flags import com.android.settings.network.CarrierConfigCache import com.android.settings.network.telephony.MobileNetworkUtils import com.android.settings.network.telephony.allowedNetworkTypesFlow @@ -46,8 +50,6 @@ import com.android.settingslib.spa.framework.compose.OverridableFlow import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spa.widget.preference.SwitchPreference import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel -import kotlin.properties.Delegates.notNull -import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.delay @@ -59,6 +61,7 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlin.time.Duration.Companion.seconds /** * Preference controller for "Auto Select Network" @@ -73,9 +76,13 @@ class AutoSelectPreferenceController @JvmOverloads constructor( private val getConfigForSubId: (subId: Int) -> PersistableBundle = { subId -> CarrierConfigCache.getInstance(context).getConfigForSubId(subId) }, -) : ComposePreferenceController(context, key) { +) : ComposePreferenceController(context, key), DefaultLifecycleObserver { + + private var isSatelliteSessionStarted = false + private var isSelectedSubIdForSatellite = false private lateinit var telephonyManager: TelephonyManager + private lateinit var satelliteManager: SatelliteManager private val listeners = mutableListOf() @VisibleForTesting @@ -83,6 +90,21 @@ class AutoSelectPreferenceController @JvmOverloads constructor( private var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID + val satelliteModemStateCallback = SatelliteModemStateCallback { state -> + isSatelliteSessionStarted = when (state) { + SatelliteManager.SATELLITE_MODEM_STATE_OFF, + SatelliteManager.SATELLITE_MODEM_STATE_UNAVAILABLE, + SatelliteManager.SATELLITE_MODEM_STATE_UNKNOWN -> false + + else -> true + } + } + + val selectedNbIotSatelliteSubscriptionCallback = + SelectedNbIotSatelliteSubscriptionCallback { selectedSubId -> + isSelectedSubIdForSatellite = selectedSubId == subId + } + /** * Initialization based on given subscription id. */ @@ -90,7 +112,7 @@ class AutoSelectPreferenceController @JvmOverloads constructor( this.subId = subId telephonyManager = mContext.getSystemService(TelephonyManager::class.java)!! .createForSubscriptionId(subId) - + satelliteManager = mContext.getSystemService(SatelliteManager::class.java)!! return this } @@ -117,7 +139,10 @@ class AutoSelectPreferenceController @JvmOverloads constructor( SwitchPreference(object : SwitchPreferenceModel { override val title = stringResource(R.string.select_automatically) override val summary = { disallowedSummary } - override val changeable = { disallowedSummary.isEmpty() } + override val changeable = { + disallowedSummary.isEmpty() + && !(isSatelliteSessionStarted && isSelectedSubIdForSatellite) + } override val checked = { isAuto } override val onCheckedChange: (Boolean) -> Unit = { newChecked -> if (newChecked) { @@ -132,6 +157,38 @@ class AutoSelectPreferenceController @JvmOverloads constructor( }) } + override fun onStart(owner: LifecycleOwner) { + if (Flags.satelliteOemSettingsUxMigration()) { + if (satelliteManager != null) { + try { + satelliteManager.registerForModemStateChanged( + mContext.mainExecutor, satelliteModemStateCallback + ) + satelliteManager.registerForSelectedNbIotSatelliteSubscriptionChanged( + mContext.mainExecutor, selectedNbIotSatelliteSubscriptionCallback + ) + } catch (e: IllegalStateException) { + Log.w(TAG, "IllegalStateException $e") + } + } + } + } + + override fun onStop(owner: LifecycleOwner) { + if (Flags.satelliteOemSettingsUxMigration()) { + if (satelliteManager != null) { + try { + satelliteManager.unregisterForModemStateChanged(satelliteModemStateCallback) + satelliteManager.unregisterForSelectedNbIotSatelliteSubscriptionChanged( + selectedNbIotSatelliteSubscriptionCallback + ) + } catch (e: IllegalStateException) { + Log.w(TAG, "IllegalStateException $e") + } + } + } + } + private suspend fun getDisallowedSummary(serviceState: ServiceState): String = withContext(Dispatchers.Default) { if (!serviceState.roaming && onlyAutoSelectInHome()) { @@ -213,6 +270,8 @@ class AutoSelectPreferenceController @JvmOverloads constructor( } companion object { + private const val TAG = "AutoSelectPreferenceController" + private val MINIMUM_DIALOG_TIME = 1.seconds } } diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt index f821e1a76fd..641866d7862 100644 --- a/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.kt @@ -18,10 +18,12 @@ package com.android.settings.network.telephony.gsm import android.content.Context import android.content.Intent +import android.platform.test.annotations.EnableFlags import android.provider.Settings import android.telephony.CarrierConfigManager import android.telephony.ServiceState import android.telephony.TelephonyManager +import android.telephony.satellite.SatelliteManager import androidx.compose.ui.test.assertIsEnabled import androidx.compose.ui.test.assertIsNotEnabled import androidx.compose.ui.test.assertIsOff @@ -36,6 +38,7 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settings.R import com.android.settings.Settings.NetworkSelectActivity +import com.android.settings.flags.Flags import com.android.settings.spa.preference.ComposePreference import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.delay @@ -46,6 +49,8 @@ import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito.`when` +import org.mockito.junit.MockitoJUnit import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.doNothing @@ -57,6 +62,9 @@ import org.mockito.kotlin.whenever @RunWith(AndroidJUnit4::class) class AutoSelectPreferenceControllerTest { + @get:Rule + val mockito = MockitoJUnit.rule() + @get:Rule val composeTestRule = createComposeRule() @@ -65,8 +73,12 @@ class AutoSelectPreferenceControllerTest { on { simOperatorName } doReturn OPERATOR_NAME } + private val mockSatelliteManager = mock { + } + private val context: Context = spy(ApplicationProvider.getApplicationContext()) { on { getSystemService(TelephonyManager::class.java) } doReturn mockTelephonyManager + on { getSystemService(SatelliteManager::class.java) } doReturn mockSatelliteManager doNothing().whenever(mock).startActivity(any()) } @@ -115,7 +127,6 @@ class AutoSelectPreferenceControllerTest { .assertIsOff() } - @Test fun isEnabled_isRoaming_enabled() { serviceState.roaming = true @@ -158,6 +169,54 @@ class AutoSelectPreferenceControllerTest { .assertIsNotEnabled() } + @Test + @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + fun isEnabled_isSatelliteSessionStartedAndSelectedSubForSatellite_disabled() { + controller.selectedNbIotSatelliteSubscriptionCallback + .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID) + controller.satelliteModemStateCallback + .onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED) + + composeTestRule.setContent { + controller.Content() + } + + composeTestRule.onNodeWithText(context.getString(R.string.select_automatically)) + .assertIsNotEnabled() + } + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + fun isEnabled_isSatelliteSessionNotStartedButIsSelectedSubForSatellite_enabled() { + controller.selectedNbIotSatelliteSubscriptionCallback + .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID) + controller.satelliteModemStateCallback + .onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_OFF) + + composeTestRule.setContent { + controller.Content() + } + + composeTestRule.onNodeWithText(context.getString(R.string.select_automatically)) + .assertIsEnabled() + } + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + fun isEnabled_isSatelliteSessionStartedButNotSelectedSubForSatellite_enabled() { + controller.selectedNbIotSatelliteSubscriptionCallback + .onSelectedNbIotSatelliteSubscriptionChanged(0) + controller.satelliteModemStateCallback + .onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED) + + composeTestRule.setContent { + controller.Content() + } + + composeTestRule.onNodeWithText(context.getString(R.string.select_automatically)) + .assertIsEnabled() + } + @Test fun onClick_turnOff_startNetworkSelectActivity() { serviceState.isManualSelection = false diff --git a/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java index 54b78c7a5d8..95ae1d1557e 100644 --- a/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java @@ -16,6 +16,9 @@ package com.android.settings.network.telephony; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF; + import static androidx.lifecycle.Lifecycle.Event.ON_START; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.CDMA; @@ -29,12 +32,15 @@ import static com.android.settings.network.telephony.TelephonyConstants.RadioAcc import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; import android.os.PersistableBundle; +import android.platform.test.annotations.EnableFlags; import android.telephony.CarrierConfigManager; import android.telephony.RadioAccessFamily; import android.telephony.ServiceState; @@ -51,6 +57,7 @@ import androidx.test.annotation.UiThreadTest; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.settings.flags.Flags; import com.android.settings.network.CarrierConfigCache; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -294,6 +301,48 @@ public class EnabledNetworkModePreferenceControllerTest { String.valueOf(TelephonyManager.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA)); } + @UiThreadTest + @Test + @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + public void updateState_satelliteIsStartedAndSelectedSubForSatellite_disablePreference() { + mController.mSatelliteModemStateCallback + .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_CONNECTED); + mController.mSelectedNbIotSatelliteSubscriptionCallback + .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID); + + mController.updateState(mPreference); + + assertFalse(mPreference.isEnabled()); + } + + @UiThreadTest + @Test + @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + public void updateState_satelliteIsIdle_enablePreference() { + mController.mSatelliteModemStateCallback + .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_OFF); + mController.mSelectedNbIotSatelliteSubscriptionCallback + .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID); + + mController.updateState(mPreference); + + assertTrue(mPreference.isEnabled()); + } + + @UiThreadTest + @Test + @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + public void updateState_notSelectedSubForSatellite_enablePreference() { + mController.mSatelliteModemStateCallback + .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_CONNECTED); + mController.mSelectedNbIotSatelliteSubscriptionCallback + .onSelectedNbIotSatelliteSubscriptionChanged(0); + + mController.updateState(mPreference); + + assertTrue(mPreference.isEnabled()); + } + @UiThreadTest @Test public void onPreferenceChange_updateSuccess() { diff --git a/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java index d3972919009..e0a5c180f27 100644 --- a/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java @@ -16,12 +16,17 @@ package com.android.settings.network.telephony; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED; +import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_OFF; + import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.GSM; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.RAF_TD_SCDMA; import static com.android.settings.network.telephony.TelephonyConstants.RadioAccessFamily.WCDMA; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -30,15 +35,18 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.os.PersistableBundle; +import android.platform.test.annotations.EnableFlags; import android.telephony.RadioAccessFamily; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import androidx.preference.ListPreference; +import androidx.test.annotation.UiThreadTest; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; +import com.android.settings.flags.Flags; import com.android.settings.network.CarrierConfigCache; import com.android.settings.testutils.ResourcesUtils; @@ -104,6 +112,48 @@ public class PreferredNetworkModePreferenceControllerTest { "preferred_network_mode_tdscdma_gsm_wcdma_summary")); } + @Test + @UiThreadTest + @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + public void updateState_satelliteIsStartedAndSelectedSubForSatellite_disablePreference() { + mController.mSatelliteModemStateCallback + .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_CONNECTED); + mController.mSelectedNbIotSatelliteSubscriptionCallback + .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID); + + mController.updateState(mPreference); + + assertFalse(mPreference.isEnabled()); + } + + @Test + @UiThreadTest + @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + public void updateState_satelliteIsIdle_enablePreference() { + mController.mSatelliteModemStateCallback + .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_OFF); + mController.mSelectedNbIotSatelliteSubscriptionCallback + .onSelectedNbIotSatelliteSubscriptionChanged(SUB_ID); + + mController.updateState(mPreference); + + assertTrue(mPreference.isEnabled()); + } + + @Test + @UiThreadTest + @EnableFlags(Flags.FLAG_SATELLITE_OEM_SETTINGS_UX_MIGRATION) + public void updateState_notSelectedSubForSatellite_enablePreference() { + mController.mSatelliteModemStateCallback + .onSatelliteModemStateChanged(SATELLITE_MODEM_STATE_CONNECTED); + mController.mSelectedNbIotSatelliteSubscriptionCallback + .onSelectedNbIotSatelliteSubscriptionChanged(0); + + mController.updateState(mPreference); + + assertTrue(mPreference.isEnabled()); + } + @Test public void onPreferenceChange_updateNetworkMode() { mController.onPreferenceChange(mPreference,