diff --git a/src/com/android/settings/network/SubscriptionsPreferenceController.java b/src/com/android/settings/network/SubscriptionsPreferenceController.java index 6e67543a7e0..634581e3bb4 100644 --- a/src/com/android/settings/network/SubscriptionsPreferenceController.java +++ b/src/com/android/settings/network/SubscriptionsPreferenceController.java @@ -20,6 +20,8 @@ import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE; import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; import static com.android.settings.network.telephony.MobileNetworkUtils.NO_CELL_DATA_TYPE_ICON; +import static com.android.settingslib.mobile.MobileMappings.getIconKey; +import static com.android.settingslib.mobile.MobileMappings.mapIconSets; import android.content.BroadcastReceiver; import android.content.Context; @@ -31,6 +33,7 @@ import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.util.ArraySet; @@ -49,9 +52,12 @@ import com.android.settings.network.telephony.DataConnectivityListener; import com.android.settings.network.telephony.MobileNetworkActivity; import com.android.settings.network.telephony.MobileNetworkUtils; import com.android.settings.network.telephony.SignalStrengthListener; +import com.android.settings.network.telephony.TelephonyDisplayInfoListener; import com.android.settings.widget.GearPreference; import com.android.settings.wifi.WifiPickerTrackerHelper; import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.mobile.MobileMappings; +import com.android.settingslib.mobile.MobileMappings.Config; import com.android.settingslib.net.SignalStrengthUtil; import java.util.Collections; @@ -73,7 +79,7 @@ import java.util.Set; public class SubscriptionsPreferenceController extends AbstractPreferenceController implements LifecycleObserver, SubscriptionsChangeListener.SubscriptionsChangeListenerClient, MobileDataEnabledListener.Client, DataConnectivityListener.Client, - SignalStrengthListener.Callback { + SignalStrengthListener.Callback, TelephonyDisplayInfoListener.Callback { private static final String TAG = "SubscriptionsPrefCntrlr"; private UpdateListener mUpdateListener; @@ -85,6 +91,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl private MobileDataEnabledListener mDataEnabledListener; private DataConnectivityListener mConnectivityListener; private SignalStrengthListener mSignalStrengthListener; + private TelephonyDisplayInfoListener mTelephonyDisplayInfoListener; private WifiPickerTrackerHelper mWifiPickerTrackerHelper; @VisibleForTesting @@ -93,6 +100,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) { + mConfig = mSubsPrefCtrlInjector.getConfig(mContext); update(); } } @@ -102,8 +110,12 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl private Map mSubscriptionPreferences; private int mStartOrder; private GearPreference mSubsGearPref; - + private Config mConfig = null; private SubsPrefCtrlInjector mSubsPrefCtrlInjector; + private TelephonyDisplayInfo mTelephonyDisplayInfo = + new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); + /** * This interface lets a parent of this class know that some change happened - this could * either be because overall availability changed, or because we've added/removed/updated some @@ -140,8 +152,10 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl mDataEnabledListener = new MobileDataEnabledListener(context, this); mConnectivityListener = new DataConnectivityListener(context, this); mSignalStrengthListener = new SignalStrengthListener(context, this); + mTelephonyDisplayInfoListener = new TelephonyDisplayInfoListener(context, this); lifecycle.addObserver(this); mSubsPrefCtrlInjector = createSubsPrefCtrlInjector(); + mConfig = mSubsPrefCtrlInjector.getConfig(mContext); } private void registerDataSubscriptionChangedReceiver() { @@ -163,6 +177,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl mDataEnabledListener.start(mSubsPrefCtrlInjector.getDefaultDataSubscriptionId()); mConnectivityListener.start(); mSignalStrengthListener.resume(); + mTelephonyDisplayInfoListener.resume(); registerDataSubscriptionChangedReceiver(); update(); } @@ -173,6 +188,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl mDataEnabledListener.stop(); mConnectivityListener.stop(); mSignalStrengthListener.pause(); + mTelephonyDisplayInfoListener.pause(); unRegisterDataSubscriptionChangedReceiver(); } @@ -196,6 +212,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl mSubscriptionPreferences.clear(); mSignalStrengthListener.updateSubscriptionIds(Collections.emptySet()); + mTelephonyDisplayInfoListener.updateSubscriptionIds(Collections.emptySet()); mUpdateListener.onChildrenUpdated(); return; } @@ -226,22 +243,23 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl mSubsGearPref.setTitle(subInfo.getDisplayName()); mSubsGearPref.setOrder(mStartOrder); - //TODO(b/176141828) Wait for api provided by system ui. - mSubsGearPref.setSummary(getMobilePreferenceSummary()); + mSubsGearPref.setSummary(getMobilePreferenceSummary(subInfo.getSubscriptionId())); mSubsGearPref.setIcon(getIcon(subInfo.getSubscriptionId())); mPreferenceGroup.addPreference(mSubsGearPref); final Set activeDataSubIds = new ArraySet<>(); activeDataSubIds.add(subInfo.getSubscriptionId()); mSignalStrengthListener.updateSubscriptionIds(activeDataSubIds); + mTelephonyDisplayInfoListener.updateSubscriptionIds(activeDataSubIds); mUpdateListener.onChildrenUpdated(); } - private String getMobilePreferenceSummary() { - //TODO(b/176141828) Waiting for the api provided by system UI. - String result = "5G"; - if (MobileNetworkUtils.activeNetworkIsCellular(mContext)) { - result = "Active, " + result; + private String getMobilePreferenceSummary(int subId) { + String result = mSubsPrefCtrlInjector.getNetworkType( + mContext, mConfig, mTelephonyDisplayInfo, subId); + if (!result.isEmpty() && mSubsPrefCtrlInjector.isActiveCellularNetwork(mContext)) { + result = mContext.getString(R.string.preference_summary_default_combination, + mContext.getString(R.string.mobile_data_connection_active), result); } return result; } @@ -462,6 +480,12 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl update(); } + @Override + public void onTelephonyDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) { + mTelephonyDisplayInfo = telephonyDisplayInfo; + update(); + } + @VisibleForTesting boolean canSubscriptionBeDisplayed(Context context, int subId) { return (SubscriptionUtil.getAvailableSubscription(context, @@ -534,6 +558,24 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl return Utils.isProviderModelEnabled(context); } + /** + * Get config for carrier customization. + */ + public Config getConfig(Context context) { + return MobileMappings.Config.readConfig(context); + } + + /** + * Get current mobile network type. + */ + public String getNetworkType(Context context, Config config, + TelephonyDisplayInfo telephonyDisplayInfo, int subId) { + String iconKey = getIconKey(telephonyDisplayInfo); + int resId = mapIconSets(config).get(iconKey).dataContentDescription; + return resId != 0 + ? SubscriptionManager.getResourcesForSubId(context, subId).getString(resId) : ""; + } + /** * Get signal icon with different signal level. */ diff --git a/src/com/android/settings/network/telephony/TelephonyDisplayInfoListener.java b/src/com/android/settings/network/telephony/TelephonyDisplayInfoListener.java new file mode 100644 index 00000000000..334da3c931f --- /dev/null +++ b/src/com/android/settings/network/telephony/TelephonyDisplayInfoListener.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2021 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 android.content.Context; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyDisplayInfo; +import android.telephony.TelephonyManager; +import android.util.ArraySet; + +import com.google.common.collect.Sets; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Help to listen telephony display info change to subscriptions. + * TODO(b/177647571): unit test is needed. + */ +public class TelephonyDisplayInfoListener { + + private TelephonyManager mBaseTelephonyManager; + private Callback mCallback; + private Map mListeners; + + private TelephonyDisplayInfo mTelephonyDisplayInfo = + new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); + /** + * Interface of callback and to use notify TelephonyDisplayInfo change. + */ + public interface Callback { + /** + * Used to notify TelephonyDisplayInfo change. + */ + void onTelephonyDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo); + } + + public TelephonyDisplayInfoListener(Context context, Callback callback) { + mBaseTelephonyManager = context.getSystemService(TelephonyManager.class); + mCallback = callback; + mListeners = new HashMap<>(); + } + /** + * Get TelephonyDisplayInfo. + */ + public TelephonyDisplayInfo getTelephonyDisplayInfo() { + return mTelephonyDisplayInfo; + } + + /** Resumes listening telephony display info changes to the set of ids from the last call to + * {@link #updateSubscriptionIds(Set)} */ + public void resume() { + for (int subId : mListeners.keySet()) { + startListening(subId); + } + } + + /** Pauses listening for telephony display info changes */ + public void pause() { + for (int subId : mListeners.keySet()) { + stopListening(subId); + } + } + + /** Updates the set of ids we want to be listening for, beginning to listen for any new ids and + * stopping listening for any ids not contained in the new set */ + public void updateSubscriptionIds(Set ids) { + Set currentIds = new ArraySet<>(mListeners.keySet()); + for (int idToRemove : Sets.difference(currentIds, ids)) { + stopListening(idToRemove); + mListeners.remove(idToRemove); + } + for (int idToAdd : Sets.difference(ids, currentIds)) { + PhoneStateListener listener = new PhoneStateListener() { + @Override + public void onDisplayInfoChanged(TelephonyDisplayInfo telephonyDisplayInfo) { + mTelephonyDisplayInfo = telephonyDisplayInfo; + mCallback.onTelephonyDisplayInfoChanged(telephonyDisplayInfo); + } + }; + mListeners.put(idToAdd, listener); + startListening(idToAdd); + } + } + + private void startListening(int subId) { + TelephonyManager mgr = mBaseTelephonyManager.createForSubscriptionId(subId); + mgr.listen(mListeners.get(subId), PhoneStateListener.LISTEN_DISPLAY_INFO_CHANGED); + } + + private void stopListening(int subId) { + TelephonyManager mgr = mBaseTelephonyManager.createForSubscriptionId(subId); + mgr.listen(mListeners.get(subId), PhoneStateListener.LISTEN_NONE); + } +} diff --git a/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java index 27dd2aa0795..f3e084c5075 100644 --- a/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/SubscriptionsPreferenceControllerTest.java @@ -45,6 +45,7 @@ import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import androidx.lifecycle.LifecycleOwner; @@ -62,6 +63,7 @@ import com.android.settings.network.SubscriptionsPreferenceController.SubsPrefCt import com.android.settings.testutils.ResourcesUtils; import com.android.settings.wifi.WifiPickerTrackerHelper; import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.mobile.MobileMappings; import org.junit.After; import org.junit.Before; @@ -102,7 +104,6 @@ public class SubscriptionsPreferenceControllerTest { private PreferenceScreen mPreferenceScreen; private PreferenceManager mPreferenceManager; private NetworkCapabilities mNetworkCapabilities; - private FakeSubscriptionsPreferenceController mController; private static SubsPrefCtrlInjector sInjector; @@ -134,6 +135,7 @@ public class SubscriptionsPreferenceControllerTest { mOnChildUpdatedCount = 0; mUpdateListener = () -> mOnChildUpdatedCount++; + sInjector = spy(new SubsPrefCtrlInjector()); initializeMethod(true, 1, 1, 1, false, false); mController = new FakeSubscriptionsPreferenceController(mContext, mLifecycle, @@ -408,6 +410,45 @@ public class SubscriptionsPreferenceControllerTest { assertThat(mPreferenceCategory.getPreference(0).getTitle()).isEqualTo("sub1"); } + @Test + @UiThreadTest + public void displayPreference_providerAndHasMultiSimAndActive_connectedAndRat() { + final String expectedSummary = "Connected / 5G"; + final String networkType = "5G"; + final List sub = setupMockSubscriptions(2); + doReturn(true).when(sInjector).isProviderModelEnabled(mContext); + doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo(); + setupGetIconConditions(sub.get(0).getSubscriptionId(), true, true, + TelephonyManager.DATA_CONNECTED, ServiceState.STATE_IN_SERVICE); + doReturn(mock(MobileMappings.Config.class)).when(sInjector).getConfig(mContext); + doReturn(networkType) + .when(sInjector).getNetworkType(any(), any(), any(), anyInt()); + + mController.onResume(); + mController.displayPreference(mPreferenceScreen); + + assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(expectedSummary); + } + + @Test + @UiThreadTest + public void displayPreference_providerAndHasMultiSimAndNotActive_showRatOnly() { + final String expectedSummary = "5G"; + final String networkType = "5G"; + final List sub = setupMockSubscriptions(2); + doReturn(true).when(sInjector).isProviderModelEnabled(mContext); + doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo(); + setupGetIconConditions(sub.get(0).getSubscriptionId(), false, true, + TelephonyManager.DATA_CONNECTED, ServiceState.STATE_IN_SERVICE); + doReturn(networkType) + .when(sInjector).getNetworkType(any(), any(), any(), anyInt()); + + mController.onResume(); + mController.displayPreference(mPreferenceScreen); + + assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(expectedSummary); + } + @Test @UiThreadTest public void displayPreference_providerAndNoSim_noPreference() { @@ -420,6 +461,54 @@ public class SubscriptionsPreferenceControllerTest { assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(0); } + @Test + @UiThreadTest + public void onTelephonyDisplayInfoChanged_providerAndHasMultiSimAndActive_connectedAndRat() { + final String expectedSummary = "Connected / LTE"; + final String networkType = "LTE"; + final List sub = setupMockSubscriptions(2); + final TelephonyDisplayInfo telephonyDisplayInfo = + new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); + doReturn(true).when(sInjector).isProviderModelEnabled(mContext); + doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo(); + setupGetIconConditions(sub.get(0).getSubscriptionId(), true, true, + TelephonyManager.DATA_CONNECTED, ServiceState.STATE_IN_SERVICE); + doReturn(mock(MobileMappings.Config.class)).when(sInjector).getConfig(mContext); + doReturn(networkType) + .when(sInjector).getNetworkType(any(), any(), any(), anyInt()); + + mController.onResume(); + mController.displayPreference(mPreferenceScreen); + mController.onTelephonyDisplayInfoChanged(telephonyDisplayInfo); + + assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(expectedSummary); + } + + @Test + @UiThreadTest + public void onTelephonyDisplayInfoChanged_providerAndHasMultiSimAndNotActive_showRat() { + final String expectedSummary = "LTE"; + final String networkType = "LTE"; + final List sub = setupMockSubscriptions(2); + final TelephonyDisplayInfo telephonyDisplayInfo = + new TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN, + TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); + doReturn(true).when(sInjector).isProviderModelEnabled(mContext); + doReturn(sub.get(0)).when(mSubscriptionManager).getDefaultDataSubscriptionInfo(); + setupGetIconConditions(sub.get(0).getSubscriptionId(), false, true, + TelephonyManager.DATA_CONNECTED, ServiceState.STATE_IN_SERVICE); + doReturn(mock(MobileMappings.Config.class)).when(sInjector).getConfig(mContext); + doReturn(networkType) + .when(sInjector).getNetworkType(any(), any(), any(), anyInt()); + + mController.onResume(); + mController.displayPreference(mPreferenceScreen); + mController.onTelephonyDisplayInfoChanged(telephonyDisplayInfo); + + assertThat(mPreferenceCategory.getPreference(0).getSummary()).isEqualTo(expectedSummary); + } + @Test @UiThreadTest public void onAirplaneModeChanged_providerAndHasSim_noPreference() {