Merge "Enable network type icon overlays by carrier Id" into tm-qpr-dev

This commit is contained in:
Evan Laird
2022-11-10 20:01:23 +00:00
committed by Android (Google) Code Review
18 changed files with 865 additions and 153 deletions

View File

@@ -0,0 +1,33 @@
<!--
Copyright (C) 2022 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="22"
android:viewportHeight="17"
android:width="22dp"
android:height="17dp">
<group>
<group>
<path android:fillColor="#FF000000"
android:pathData="M1.03 8.47l0.43-4.96h4.33v1.17H2.48L2.25 7.39C2.66 7.1 3.1 6.96 3.57 6.96c0.77 0 1.38 0.3 1.83 0.9 s0.66 1.41 0.66 2.43c0 1.03-0.24 1.84-0.72 2.43S4.2 13.6 3.36 13.6c-0.75 0-1.36-0.24-1.83-0.73s-0.74-1.16-0.81-2.02h1.13 c0.07 0.57 0.23 1 0.49 1.29s0.59 0.43 1.01 0.43c0.47 0 0.84-0.2 1.1-0.61c0.26-0.41 0.4-0.96 0.4-1.65 c0-0.65-0.14-1.18-0.43-1.59S3.76 8.09 3.28 8.09c-0.4 0-0.72 0.1-0.96 0.31L1.99 8.73L1.03 8.47z"/>
</group>
<group>
<path android:fillColor="#FF000000"
android:pathData="M 18.93,5.74 L 18.93,3.39 L 17.63,3.39 L 17.63,5.74 L 15.28,5.74 L 15.28,7.04 L 17.63,7.04 L 17.63,9.39 L 18.93,9.39 L 18.93,7.04 L 21.28,7.04 L 21.28,5.74 z"/>
</group>
<path android:fillColor="#FF000000"
android:pathData="M13.78 12.24l-0.22 0.27c-0.63 0.73-1.55 1.1-2.76 1.1c-1.08 0-1.92-0.36-2.53-1.07s-0.93-1.72-0.94-3.02V7.56 c0-1.39 0.28-2.44 0.84-3.13s1.39-1.04 2.51-1.04c0.95 0 1.69 0.26 2.23 0.79s0.83 1.28 0.89 2.26h-1.25 c-0.05-0.62-0.22-1.1-0.52-1.45s-0.74-0.52-1.34-0.52c-0.72 0-1.24 0.23-1.57 0.7S8.6 6.37 8.59 7.4v2.03c0 1 0.19 1.77 0.57 2.31 c0.38 0.54 0.93 0.8 1.65 0.8c0.67 0 1.19-0.16 1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z"/>
</group>
</vector>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 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.
-->
<!--
~ This resource file exists to enumerate all network type icon overrides on a
~ per-carrierId basis
-->
<resources>
<!--
Network type (RAT) icon overrides can be configured here on a per-carrierId basis.
1. Add a new TypedArray here, using the naming scheme below
2. The entries are (NetworkType, drawable ID) pairs
3. Add this array's ID to the MAPPING field of MobileIconCarrierIdOverrides.kt
-->
<array name="carrierId_2032_iconOverrides">
<item>5G_PLUS</item>
<item>@drawable/ic_5g_plus_mobiledata_default</item>
</array>
</resources>

View File

@@ -0,0 +1,142 @@
/*
* Copyright (C) 2022 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.settingslib.mobile
import android.annotation.DrawableRes
import android.content.res.Resources
import android.content.res.TypedArray
import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.settingslib.R
import com.android.settingslib.SignalIcon.MobileIconGroup
/**
* This class defines a network type (3G, 4G, etc.) override mechanism on a per-carrierId basis.
*
* Traditionally, carrier-customized network type iconography was achieved using the `MCC/MNC`
* resource qualifiers, and swapping out the drawable resource by name. It would look like this:
*
* res/
* drawable/
* 3g_mobiledata_icon.xml
* drawable-MCC-MNC/
* 3g_mobiledata_icon.xml
*
* This would mean that, provided a context created with this MCC/MNC configuration set, loading
* the network type icon through [MobileIconGroup] would provide a carrier-defined network type
* icon rather than the AOSP-defined default.
*
* The MCC/MNC mechanism no longer can fully define carrier-specific network type icons, because
* there is no longer a 1:1 mapping between MCC/MNC and carrier. With the advent of MVNOs, multiple
* carriers can have the same MCC/MNC value, but wish to differentiate based on their carrier ID.
* CarrierId is a newer concept than MCC/MNC, and provides more granularity when it comes to
* determining the carrier (e.g. MVNOs can share MCC/MNC values with the network owner), therefore
* it can fit all of the same use cases currently handled by `MCC/MNC`, without the need to apply a
* configuration context in order to get the proper UI for a given SIM icon.
*
* NOTE: CarrierId icon overrides will always take precedence over those defined using `MCC/MNC`
* resource qualifiers.
*
* [MAPPING] encodes the relationship between CarrierId and the corresponding override array
* that exists in the config.xml. An alternative approach could be to generate the resource name
* by string concatenation at run-time:
*
* val resName = "carrierId_$carrierId_iconOverrides"
* val override = resources.getResourceIdentifier(resName)
*
* However, that's going to be far less efficient until MAPPING grows to a sufficient size. For now,
* given a relatively small number of entries, we should just maintain the mapping here.
*/
interface MobileIconCarrierIdOverrides {
@DrawableRes
fun getOverrideFor(carrierId: Int, networkType: String, resources: Resources): Int
fun carrierIdEntryExists(carrierId: Int): Boolean
}
class MobileIconCarrierIdOverridesImpl : MobileIconCarrierIdOverrides {
@DrawableRes
override fun getOverrideFor(carrierId: Int, networkType: String, resources: Resources): Int {
val resId = MAPPING[carrierId] ?: return 0
val ta = resources.obtainTypedArray(resId)
val map = parseNetworkIconOverrideTypedArray(ta)
ta.recycle()
return map[networkType] ?: 0
}
override fun carrierIdEntryExists(carrierId: Int) =
overrideExists(carrierId, MAPPING)
companion object {
private const val TAG = "MobileIconOverrides"
/**
* This map maintains the lookup from the canonical carrier ID (see below link) to the
* corresponding overlay resource. New overrides should add an entry below in order to
* change the network type icon resources based on carrier ID
*
* Refer to the link below for the canonical mapping maintained in AOSP:
* https://android.googlesource.com/platform/packages/providers/TelephonyProvider/+/master/assets/latest_carrier_id/carrier_list.textpb
*/
private val MAPPING = mapOf(
// 2032 == Xfinity Mobile
2032 to R.array.carrierId_2032_iconOverrides,
)
/**
* Parse `carrierId_XXXX_iconOverrides` for a particular network type. The resource file
* "carrierid_icon_overrides.xml" defines a TypedArray format for overriding specific
* network type icons (a.k.a. RAT icons) for a particular carrier ID. The format is defined
* as an array of (network type name, drawable) pairs:
* <array name="carrierId_XXXX_iconOverrides>
* <item>NET_TYPE_1</item>
* <item>@drawable/net_type_1_override</item>
* <item>NET_TYPE_2</item>
* <item>@drawable/net_type_2_override</item>
* </array>
*
* @param ta the [TypedArray] defined in carrierid_icon_overrides.xml
* @return the overridden drawable resource ID if it exists, or 0 if it does not
*/
@VisibleForTesting
@JvmStatic
fun parseNetworkIconOverrideTypedArray(ta: TypedArray): Map<String, Int> {
if (ta.length() % 2 != 0) {
Log.w(TAG,
"override must contain an even number of (key, value) entries. skipping")
return mapOf()
}
val result = mutableMapOf<String, Int>()
// The array is defined as Pair(String, resourceId), so walk by 2
for (i in 0 until ta.length() step 2) {
val key = ta.getString(i)
val override = ta.getResourceId(i + 1, 0)
if (key == null || override == 0) {
Log.w(TAG, "Invalid override found. Skipping")
continue
}
result[key] = override
}
return result
}
@JvmStatic
private fun overrideExists(carrierId: Int, mapping: Map<Int, Int>): Boolean =
mapping.containsKey(carrierId)
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright (C) 2022 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.settingslib.mobile;
import static com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl.parseNetworkIconOverrideTypedArray;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.res.TypedArray;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.Map;
@RunWith(RobolectricTestRunner.class)
public final class MobileIconCarrierIdOverridesTest {
private static final String OVERRIDE_ICON_1_NAME = "name_1";
private static final int OVERRIDE_ICON_1_RES = 1;
private static final String OVERRIDE_ICON_2_NAME = "name_2";
private static final int OVERRIDE_ICON_2_RES = 2;
NetworkOverrideTypedArrayMock mResourceMock;
@Before
public void setUp() {
mResourceMock = new NetworkOverrideTypedArrayMock(
new String[] { OVERRIDE_ICON_1_NAME, OVERRIDE_ICON_2_NAME },
new int[] { OVERRIDE_ICON_1_RES, OVERRIDE_ICON_2_RES }
);
}
@Test
public void testParse_singleOverride() {
mResourceMock.setOverrides(
new String[] { OVERRIDE_ICON_1_NAME },
new int[] { OVERRIDE_ICON_1_RES }
);
Map<String, Integer> parsed = parseNetworkIconOverrideTypedArray(mResourceMock.getMock());
assertThat(parsed.get(OVERRIDE_ICON_1_NAME)).isEqualTo(OVERRIDE_ICON_1_RES);
}
@Test
public void testParse_multipleOverrides() {
mResourceMock.setOverrides(
new String[] { OVERRIDE_ICON_1_NAME, OVERRIDE_ICON_2_NAME },
new int[] { OVERRIDE_ICON_1_RES, OVERRIDE_ICON_2_RES }
);
Map<String, Integer> parsed = parseNetworkIconOverrideTypedArray(mResourceMock.getMock());
assertThat(parsed.get(OVERRIDE_ICON_2_NAME)).isEqualTo(OVERRIDE_ICON_2_RES);
assertThat(parsed.get(OVERRIDE_ICON_1_NAME)).isEqualTo(OVERRIDE_ICON_1_RES);
}
@Test
public void testParse_nonexistentKey_isNull() {
mResourceMock.setOverrides(
new String[] { OVERRIDE_ICON_1_NAME },
new int[] { OVERRIDE_ICON_1_RES }
);
Map<String, Integer> parsed = parseNetworkIconOverrideTypedArray(mResourceMock.getMock());
assertThat(parsed.get(OVERRIDE_ICON_2_NAME)).isNull();
}
static class NetworkOverrideTypedArrayMock {
private Object[] mInterleaved;
private final TypedArray mMockTypedArray = mock(TypedArray.class);
NetworkOverrideTypedArrayMock(
String[] networkTypes,
int[] iconOverrides) {
mInterleaved = interleaveTypes(networkTypes, iconOverrides);
doAnswer(invocation -> {
return mInterleaved[(int) invocation.getArgument(0)];
}).when(mMockTypedArray).getString(/* index */ anyInt());
doAnswer(invocation -> {
return mInterleaved[(int) invocation.getArgument(0)];
}).when(mMockTypedArray).getResourceId(/* index */ anyInt(), /* default */ anyInt());
when(mMockTypedArray.length()).thenAnswer(invocation -> {
return mInterleaved.length;
});
}
TypedArray getMock() {
return mMockTypedArray;
}
void setOverrides(String[] types, int[] resIds) {
mInterleaved = interleaveTypes(types, resIds);
}
private Object[] interleaveTypes(String[] strs, int[] ints) {
assertThat(strs.length).isEqualTo(ints.length);
Object[] ret = new Object[strs.length * 2];
// Keep track of where we are in the interleaved array, but iterate the overrides
int interleavedIndex = 0;
for (int i = 0; i < strs.length; i++) {
ret[interleavedIndex] = strs[i];
interleavedIndex += 1;
ret[interleavedIndex] = ints[i];
interleavedIndex += 1;
}
return ret;
}
}
}

View File

@@ -15,9 +15,7 @@
*/
package com.android.systemui.statusbar.connectivity;
import static com.android.settingslib.mobile.MobileMappings.getDefaultIcons;
import static com.android.settingslib.mobile.MobileMappings.getIconKey;
import static com.android.settingslib.mobile.MobileMappings.mapIconSets;
import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID;
import android.content.Context;
import android.content.Intent;
@@ -46,6 +44,7 @@ import com.android.settingslib.mobile.MobileStatusTracker.SubscriptionDefaults;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.SignalStrengthUtil;
import com.android.systemui.R;
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy;
import com.android.systemui.util.CarrierConfigTracker;
import java.io.PrintWriter;
@@ -63,6 +62,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
private final TelephonyManager mPhone;
private final CarrierConfigTracker mCarrierConfigTracker;
private final SubscriptionDefaults mDefaults;
private final MobileMappingsProxy mMobileMappingsProxy;
private final String mNetworkNameDefault;
private final String mNetworkNameSeparator;
private final ContentObserver mObserver;
@@ -121,6 +121,7 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
TelephonyManager phone,
CallbackHandler callbackHandler,
NetworkControllerImpl networkController,
MobileMappingsProxy mobileMappingsProxy,
SubscriptionInfo info,
SubscriptionDefaults defaults,
Looper receiverLooper,
@@ -135,13 +136,14 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
mPhone = phone;
mDefaults = defaults;
mSubscriptionInfo = info;
mMobileMappingsProxy = mobileMappingsProxy;
mNetworkNameSeparator = getTextIfExists(
R.string.status_bar_network_name_separator).toString();
mNetworkNameDefault = getTextIfExists(
com.android.internal.R.string.lockscreen_carrier_default).toString();
mNetworkToIconLookup = mapIconSets(mConfig);
mDefaultIcons = getDefaultIcons(mConfig);
mNetworkToIconLookup = mMobileMappingsProxy.mapIconSets(mConfig);
mDefaultIcons = mMobileMappingsProxy.getDefaultIcons(mConfig);
String networkName = info.getCarrierName() != null ? info.getCarrierName().toString()
: mNetworkNameDefault;
@@ -161,8 +163,8 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
void setConfiguration(Config config) {
mConfig = config;
updateInflateSignalStrength();
mNetworkToIconLookup = mapIconSets(mConfig);
mDefaultIcons = getDefaultIcons(mConfig);
mNetworkToIconLookup = mMobileMappingsProxy.mapIconSets(mConfig);
mDefaultIcons = mMobileMappingsProxy.getDefaultIcons(mConfig);
updateTelephony();
}
@@ -271,8 +273,9 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
dataContentDescription = mContext.getString(R.string.data_connection_no_internet);
}
final QsInfo qsInfo = getQsInfo(contentDescription, icons.dataType);
final SbInfo sbInfo = getSbInfo(contentDescription, icons.dataType);
int iconId = mCurrentState.getNetworkTypeIcon(mContext);
final QsInfo qsInfo = getQsInfo(contentDescription, iconId);
final SbInfo sbInfo = getSbInfo(contentDescription, iconId);
MobileDataIndicators mobileDataIndicators = new MobileDataIndicators(
sbInfo.icon,
@@ -373,6 +376,10 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
} else if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
updateDataSim();
notifyListenersIfNecessary();
} else if (action.equals(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED)) {
int carrierId = intent.getIntExtra(
TelephonyManager.EXTRA_CARRIER_ID, UNKNOWN_CARRIER_ID);
mCurrentState.setCarrierId(carrierId);
}
}
@@ -477,7 +484,8 @@ public class MobileSignalController extends SignalController<MobileState, Mobile
mCurrentState.level = getSignalLevel(mCurrentState.signalStrength);
}
String iconKey = getIconKey(mCurrentState.telephonyDisplayInfo);
mCurrentState.setCarrierId(mPhone.getSimCarrierId());
String iconKey = mMobileMappingsProxy.getIconKey(mCurrentState.telephonyDisplayInfo);
if (mNetworkToIconLookup.get(iconKey) != null) {
mCurrentState.iconGroup = mNetworkToIconLookup.get(iconKey);
} else {

View File

@@ -22,6 +22,7 @@ import android.telephony.TelephonyManager
import com.android.settingslib.mobile.MobileMappings
import com.android.settingslib.mobile.MobileStatusTracker
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
import com.android.systemui.util.CarrierConfigTracker
import javax.inject.Inject
@@ -33,6 +34,7 @@ internal class MobileSignalControllerFactory @Inject constructor(
val context: Context,
val callbackHandler: CallbackHandler,
val carrierConfigTracker: CarrierConfigTracker,
val mobileMappings: MobileMappingsProxy,
) {
fun createMobileSignalController(
config: MobileMappings.Config,
@@ -56,6 +58,7 @@ internal class MobileSignalControllerFactory @Inject constructor(
phone,
callbackHandler,
networkController,
mobileMappings,
subscriptionInfo,
subscriptionDefaults,
receiverLooper,

View File

@@ -16,10 +16,14 @@
package com.android.systemui.statusbar.connectivity
import android.annotation.DrawableRes
import android.content.Context
import android.telephony.ServiceState
import android.telephony.SignalStrength
import android.telephony.TelephonyDisplayInfo
import android.telephony.TelephonyManager
import com.android.internal.annotations.VisibleForTesting
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.Utils
import com.android.settingslib.mobile.MobileStatusTracker.MobileStatus
import com.android.settingslib.mobile.TelephonyIcons
@@ -41,7 +45,7 @@ internal class MobileState(
@JvmField var roaming: Boolean = false,
@JvmField var dataState: Int = TelephonyManager.DATA_DISCONNECTED,
// Tracks the on/off state of the defaultDataSubscription
@JvmField var defaultDataOff: Boolean = false
@JvmField var defaultDataOff: Boolean = false,
) : ConnectivityState() {
@JvmField var telephonyDisplayInfo = TelephonyDisplayInfo(TelephonyManager.NETWORK_TYPE_UNKNOWN,
@@ -49,6 +53,11 @@ internal class MobileState(
@JvmField var serviceState: ServiceState? = null
@JvmField var signalStrength: SignalStrength? = null
var carrierId = TelephonyManager.UNKNOWN_CARRIER_ID
@VisibleForTesting
var networkTypeResIdCache: NetworkTypeResIdCache = NetworkTypeResIdCache()
/** @return true if this state is disabled or not default data */
val isDataDisabledOrNotDefault: Boolean
get() = (iconGroup === TelephonyIcons.DATA_DISABLED ||
@@ -125,6 +134,21 @@ internal class MobileState(
return serviceState != null && serviceState!!.roaming
}
/**
*
* Load the (potentially customized) icon resource id for the current network type. Note that
* this operation caches the result. Note that reading the [MobileIconGroup.dataType] field
* directly will not yield correct results in cases where the carrierId has an associated
* override. This is the preferred method for getting the network type indicator.
*
* @return a drawable res id appropriate for the current (carrierId, networkType) pair
*/
@DrawableRes
fun getNetworkTypeIcon(context: Context): Int {
val icon = (iconGroup as MobileIconGroup)
return networkTypeResIdCache.get(icon, carrierId, context)
}
fun setFromMobileStatus(mobileStatus: MobileStatus) {
activityIn = mobileStatus.activityIn
activityOut = mobileStatus.activityOut
@@ -140,6 +164,7 @@ internal class MobileState(
super.toString(builder)
builder.append(',')
builder.append("dataSim=$dataSim,")
builder.append("carrierId=$carrierId")
builder.append("networkName=$networkName,")
builder.append("networkNameData=$networkNameData,")
builder.append("dataConnected=$dataConnected,")
@@ -157,6 +182,8 @@ internal class MobileState(
builder.append("voiceServiceState=${getVoiceServiceState()},")
builder.append("isInService=${isInService()},")
builder.append("networkTypeIconCache=$networkTypeResIdCache")
builder.append("serviceState=${serviceState?.minLog() ?: "(null)"},")
builder.append("signalStrength=${signalStrength?.minLog() ?: "(null)"},")
builder.append("displayInfo=$telephonyDisplayInfo")
@@ -164,6 +191,7 @@ internal class MobileState(
override fun tableColumns(): List<String> {
val columns = listOf("dataSim",
"carrierId",
"networkName",
"networkNameData",
"dataConnected",
@@ -178,6 +206,7 @@ internal class MobileState(
"showQuickSettingsRatIcon",
"voiceServiceState",
"isInService",
"networkTypeIconCache",
"serviceState",
"signalStrength",
"displayInfo")
@@ -187,6 +216,7 @@ internal class MobileState(
override fun tableData(): List<String> {
val columns = listOf(dataSim,
carrierId,
networkName,
networkNameData,
dataConnected,
@@ -201,6 +231,7 @@ internal class MobileState(
showQuickSettingsRatIcon(),
getVoiceServiceState(),
isInService(),
networkTypeResIdCache,
serviceState?.minLog() ?: "(null)",
signalStrength?.minLog() ?: "(null)",
telephonyDisplayInfo).map { it.toString() }
@@ -217,6 +248,7 @@ internal class MobileState(
if (networkName != other.networkName) return false
if (networkNameData != other.networkNameData) return false
if (carrierId != other.carrierId) return false
if (dataSim != other.dataSim) return false
if (dataConnected != other.dataConnected) return false
if (isEmergency != other.isEmergency) return false
@@ -238,6 +270,7 @@ internal class MobileState(
var result = super.hashCode()
result = 31 * result + (networkName?.hashCode() ?: 0)
result = 31 * result + (networkNameData?.hashCode() ?: 0)
result = 31 * result + (carrierId.hashCode())
result = 31 * result + dataSim.hashCode()
result = 31 * result + dataConnected.hashCode()
result = 31 * result + isEmergency.hashCode()

View File

@@ -22,6 +22,7 @@ import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN
import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_INOUT;
import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE;
import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT;
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -139,7 +140,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
private final MobileSignalControllerFactory mMobileFactory;
private TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private int mActiveMobileDataSubscription = INVALID_SUBSCRIPTION_ID;
// Subcontrollers.
@VisibleForTesting
@@ -503,6 +504,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
filter.addAction(TelephonyManager.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED);
filter.addAction(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED);
filter.addAction(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED);
filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mReceiverHandler);
mListening = true;
@@ -793,6 +795,20 @@ public class NetworkControllerImpl extends BroadcastReceiver
mConfig = Config.readConfig(mContext);
mReceiverHandler.post(this::handleConfigurationChanged);
break;
case TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED: {
// Notify the relevant MobileSignalController of the change
int subId = intent.getIntExtra(
TelephonyManager.EXTRA_SUBSCRIPTION_ID,
INVALID_SUBSCRIPTION_ID
);
if (SubscriptionManager.isValidSubscriptionId(subId)) {
if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
mMobileSignalControllers.get(subId).handleBroadcast(intent);
}
}
}
break;
case Intent.ACTION_SIM_STATE_CHANGED:
// Avoid rebroadcast because SysUI is direct boot aware.
if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
@@ -820,7 +836,7 @@ public class NetworkControllerImpl extends BroadcastReceiver
break;
default:
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
INVALID_SUBSCRIPTION_ID);
if (SubscriptionManager.isValidSubscriptionId(subId)) {
if (mMobileSignalControllers.indexOfKey(subId) >= 0) {
mMobileSignalControllers.get(subId).handleBroadcast(intent);
@@ -1336,6 +1352,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
String slotString = args.getString("slot");
int slot = TextUtils.isEmpty(slotString) ? 0 : Integer.parseInt(slotString);
slot = MathUtils.constrain(slot, 0, 8);
String carrierIdString = args.getString("carrierid");
int carrierId = TextUtils.isEmpty(carrierIdString) ? 0
: Integer.parseInt(carrierIdString);
// Ensure we have enough sim slots
List<SubscriptionInfo> subs = new ArrayList<>();
while (mMobileSignalControllers.size() <= slot) {
@@ -1347,6 +1366,9 @@ public class NetworkControllerImpl extends BroadcastReceiver
}
// Hack to index linearly for easy use.
MobileSignalController controller = mMobileSignalControllers.valueAt(slot);
if (carrierId != 0) {
controller.getState().setCarrierId(carrierId);
}
controller.getState().dataSim = datatype != null;
controller.getState().isDefault = datatype != null;
controller.getState().dataConnected = datatype != null;

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2022 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.systemui.statusbar.connectivity
import android.annotation.DrawableRes
import android.content.Context
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl
/**
* Cache for network type resource IDs.
*
* The default framework behavior is to have a statically defined icon per network type. See
* [MobileIconGroup] for the standard mapping.
*
* For the case of carrierId-defined overrides, we want to check [MobileIconCarrierIdOverrides] for
* an existing icon override, and cache the result of the operation
*/
class NetworkTypeResIdCache(
private val overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl()
) {
@DrawableRes private var cachedResId: Int = 0
private var lastCarrierId: Int? = null
private var lastIconGroup: MobileIconGroup? = null
private var isOverridden: Boolean = false
@DrawableRes
fun get(iconGroup: MobileIconGroup, carrierId: Int, context: Context): Int {
if (lastCarrierId != carrierId || lastIconGroup != iconGroup) {
lastCarrierId = carrierId
lastIconGroup = iconGroup
val maybeOverride = calculateOverriddenIcon(iconGroup, carrierId, context)
if (maybeOverride > 0) {
cachedResId = maybeOverride
isOverridden = true
} else {
cachedResId = iconGroup.dataType
isOverridden = false
}
}
return cachedResId
}
override fun toString(): String {
return "networkTypeResIdCache={id=$cachedResId, isOverridden=$isOverridden}"
}
@DrawableRes
private fun calculateOverriddenIcon(
iconGroup: MobileIconGroup,
carrierId: Int,
context: Context,
): Int {
val name = iconGroup.name
if (!overrides.carrierIdEntryExists(carrierId)) {
return 0
}
return overrides.getOverrideFor(carrierId, name, context.resources)
}
}

View File

@@ -37,6 +37,13 @@ import javax.inject.Inject
* own [Configuration] and track resources based on the full set of available mcc-mnc combinations.
*
* (for future reference: b/240555502 is the initiating bug for this)
*
* NOTE: MCC/MNC qualifiers are not sufficient to fully describe a network type icon qualified by
* network type + carrier ID. This class exists to keep the legacy behavior of using the MCC/MNC
* resource qualifiers working, but if a carrier-specific icon is requested, then the override
* provided by [MobileIconCarrierIdOverrides] will take precedence.
*
* TODO(b/258503704): consider removing this class in favor of the `carrierId` overrides
*/
@SysUISingleton
class MobileContextProvider

View File

@@ -32,6 +32,7 @@ import javax.inject.Inject
interface MobileMappingsProxy {
fun mapIconSets(config: Config): Map<String, MobileIconGroup>
fun getDefaultIcons(config: Config): MobileIconGroup
fun getIconKey(displayInfo: TelephonyDisplayInfo): String
fun toIconKey(@NetworkType networkType: Int): String
fun toIconKeyOverride(@NetworkType networkType: Int): String
}
@@ -44,6 +45,9 @@ class MobileMappingsProxyImpl @Inject constructor() : MobileMappingsProxy {
override fun getDefaultIcons(config: Config): MobileIconGroup =
MobileMappings.getDefaultIcons(config)
override fun getIconKey(displayInfo: TelephonyDisplayInfo): String =
MobileMappings.getIconKey(displayInfo)
override fun toIconKey(@NetworkType networkType: Int): String =
MobileMappings.toIconKey(networkType)

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2022 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.systemui.statusbar.connectivity
import android.content.res.Resources
import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
typealias CarrierId = Int
typealias NetworkType = String
typealias ResId = Int
class MobileIconCarrierIdOverridesFake : MobileIconCarrierIdOverrides {
/** Backing for [carrierIdEntryExists] */
var overriddenIds = mutableSetOf<Int>()
/** Backing for [getOverrideFor]. Map should be Map< CarrierId < NetworkType, ResId>> */
var overridesByCarrierId = mutableMapOf<CarrierId, Map<NetworkType, ResId>>()
override fun getOverrideFor(
carrierId: CarrierId,
networkType: NetworkType,
resources: Resources
): ResId {
if (!overriddenIds.contains(carrierId)) return 0
return overridesByCarrierId[carrierId]?.get(networkType) ?: 0
}
override fun carrierIdEntryExists(carrierId: Int): Boolean {
return overriddenIds.contains(carrierId)
}
}

View File

@@ -1,137 +0,0 @@
/*
* 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.systemui.statusbar.connectivity;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class MobileStateTest extends SysuiTestCase {
private final MobileState mState = new MobileState();
@Before
public void setUp() {
}
@Test
public void testIsDataDisabledOrNotDefault_dataDisabled() {
mState.iconGroup = TelephonyIcons.DATA_DISABLED;
mState.userSetup = true;
assertTrue(mState.isDataDisabledOrNotDefault());
}
@Test
public void testIsDataDisabledOrNotDefault_notDefaultData() {
mState.iconGroup = TelephonyIcons.NOT_DEFAULT_DATA;
mState.userSetup = true;
assertTrue(mState.isDataDisabledOrNotDefault());
}
@Test
public void testIsDataDisabledOrNotDefault_notDisabled() {
mState.iconGroup = TelephonyIcons.G;
mState.userSetup = true;
assertFalse(mState.isDataDisabledOrNotDefault());
}
@Test
public void testHasActivityIn_noData_noActivity() {
mState.dataConnected = false;
mState.carrierNetworkChangeMode = false;
mState.activityIn = false;
assertFalse(mState.hasActivityIn());
}
@Test
public void testHasActivityIn_noData_activityIn() {
mState.dataConnected = false;
mState.carrierNetworkChangeMode = false;
mState.activityIn = true;
assertFalse(mState.hasActivityIn());
}
@Test
public void testHasActivityIn_dataConnected_activityIn() {
mState.dataConnected = true;
mState.carrierNetworkChangeMode = false;
mState.activityIn = true;
assertTrue(mState.hasActivityIn());
}
@Test
public void testHasActivityIn_carrierNetworkChange() {
mState.dataConnected = true;
mState.carrierNetworkChangeMode = true;
mState.activityIn = true;
assertFalse(mState.hasActivityIn());
}
@Test
public void testHasActivityOut_noData_noActivity() {
mState.dataConnected = false;
mState.carrierNetworkChangeMode = false;
mState.activityOut = false;
assertFalse(mState.hasActivityOut());
}
@Test
public void testHasActivityOut_noData_activityOut() {
mState.dataConnected = false;
mState.carrierNetworkChangeMode = false;
mState.activityOut = true;
assertFalse(mState.hasActivityOut());
}
@Test
public void testHasActivityOut_dataConnected_activityOut() {
mState.dataConnected = true;
mState.carrierNetworkChangeMode = false;
mState.activityOut = true;
assertTrue(mState.hasActivityOut());
}
@Test
public void testHasActivityOut_carrierNetworkChange() {
mState.dataConnected = true;
mState.carrierNetworkChangeMode = true;
mState.activityOut = true;
assertFalse(mState.hasActivityOut());
}
}

View File

@@ -0,0 +1,119 @@
/*
* 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.systemui.statusbar.connectivity
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import com.android.settingslib.mobile.TelephonyIcons
import com.android.systemui.SysuiTestCase
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidTestingRunner::class)
class MobileStateTest : SysuiTestCase() {
private val state = MobileState()
@Before fun setUp() {}
@Test
fun testIsDataDisabledOrNotDefault_dataDisabled() {
state.iconGroup = TelephonyIcons.DATA_DISABLED
state.userSetup = true
assertTrue(state.isDataDisabledOrNotDefault)
}
@Test
fun testIsDataDisabledOrNotDefault_notDefaultData() {
state.iconGroup = TelephonyIcons.NOT_DEFAULT_DATA
state.userSetup = true
assertTrue(state.isDataDisabledOrNotDefault)
}
@Test
fun testIsDataDisabledOrNotDefault_notDisabled() {
state.iconGroup = TelephonyIcons.G
state.userSetup = true
assertFalse(state.isDataDisabledOrNotDefault)
}
@Test
fun testHasActivityIn_noData_noActivity() {
state.dataConnected = false
state.carrierNetworkChangeMode = false
state.activityIn = false
assertFalse(state.hasActivityIn())
}
@Test
fun testHasActivityIn_noData_activityIn() {
state.dataConnected = false
state.carrierNetworkChangeMode = false
state.activityIn = true
assertFalse(state.hasActivityIn())
}
@Test
fun testHasActivityIn_dataConnected_activityIn() {
state.dataConnected = true
state.carrierNetworkChangeMode = false
state.activityIn = true
assertTrue(state.hasActivityIn())
}
@Test
fun testHasActivityIn_carrierNetworkChange() {
state.dataConnected = true
state.carrierNetworkChangeMode = true
state.activityIn = true
assertFalse(state.hasActivityIn())
}
@Test
fun testHasActivityOut_noData_noActivity() {
state.dataConnected = false
state.carrierNetworkChangeMode = false
state.activityOut = false
assertFalse(state.hasActivityOut())
}
@Test
fun testHasActivityOut_noData_activityOut() {
state.dataConnected = false
state.carrierNetworkChangeMode = false
state.activityOut = true
assertFalse(state.hasActivityOut())
}
@Test
fun testHasActivityOut_dataConnected_activityOut() {
state.dataConnected = true
state.carrierNetworkChangeMode = false
state.activityOut = true
assertTrue(state.hasActivityOut())
}
@Test
fun testHasActivityOut_carrierNetworkChange() {
state.dataConnected = true
state.carrierNetworkChangeMode = true
state.activityOut = true
assertFalse(state.hasActivityOut())
}
}

View File

@@ -71,6 +71,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.demomode.DemoModeController;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.plugins.log.LogBuffer;
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.telephony.TelephonyListenerManager;
@@ -125,6 +126,8 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
protected CarrierConfigTracker mCarrierConfigTracker;
protected FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
protected Handler mMainHandler;
// Use a real mobile mappings object since lots of tests rely on it
protected FakeMobileMappingsProxy mMobileMappingsProxy = new FakeMobileMappingsProxy();
protected WifiStatusTrackerFactory mWifiStatusTrackerFactory;
protected MobileSignalControllerFactory mMobileFactory;
@@ -219,10 +222,13 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
mWifiStatusTrackerFactory = new WifiStatusTrackerFactory(
mContext, mMockWm, mMockNsm, mMockCm, mMainHandler);
// Most of these tests rely on the actual MobileMappings behavior
mMobileMappingsProxy.setUseRealImpl(true);
mMobileFactory = new MobileSignalControllerFactory(
mContext,
mCallbackHandler,
mCarrierConfigTracker
mCarrierConfigTracker,
mMobileMappingsProxy
);
mNetworkController = new NetworkControllerImpl(mContext,

View File

@@ -18,12 +18,21 @@ package com.android.systemui.statusbar.connectivity;
import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN;
import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS;
import static android.telephony.TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED;
import static android.telephony.TelephonyManager.EXTRA_CARRIER_ID;
import static android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID;
import static com.android.settingslib.mobile.TelephonyIcons.NR_5G_PLUS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.content.Intent;
import android.net.NetworkCapabilities;
import android.os.Handler;
import android.os.Looper;
@@ -35,6 +44,7 @@ import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
import com.android.settingslib.SignalIcon.MobileIconGroup;
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.dump.DumpManager;
@@ -45,6 +55,8 @@ import com.android.systemui.util.CarrierConfigTracker;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.HashMap;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
@@ -329,6 +341,57 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest {
assertFalse(mNetworkController.isMobileDataNetworkInService());
}
@Test
public void mobileSignalController_getsCarrierId() {
when(mMockTm.getSimCarrierId()).thenReturn(1);
setupDefaultSignal();
assertEquals(1, mMobileSignalController.getState().getCarrierId());
}
@Test
public void mobileSignalController_updatesCarrierId_onChange() {
when(mMockTm.getSimCarrierId()).thenReturn(1);
setupDefaultSignal();
// Updates are sent down through this broadcast, we can send the intent directly
Intent intent = new Intent(ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED);
intent.putExtra(EXTRA_SUBSCRIPTION_ID, mSubId);
intent.putExtra(EXTRA_CARRIER_ID, 2);
mMobileSignalController.handleBroadcast(intent);
assertEquals(2, mMobileSignalController.getState().getCarrierId());
}
@Test
public void networkTypeIcon_hasCarrierIdOverride() {
int fakeCarrier = 1;
int fakeIconOverride = 12345;
int testDataNetType = 100;
String testDataString = "100";
HashMap<String, MobileIconGroup> testMap = new HashMap<>();
testMap.put(testDataString, NR_5G_PLUS);
// Pretend that there is an override for this icon, and this carrier ID
NetworkTypeResIdCache mockCache = mock(NetworkTypeResIdCache.class);
when(mockCache.get(eq(NR_5G_PLUS), eq(fakeCarrier), any())).thenReturn(fakeIconOverride);
// Turn off the default mobile mapping, so we can override
mMobileMappingsProxy.setUseRealImpl(false);
mMobileMappingsProxy.setIconMap(testMap);
// Use the mocked cache
mMobileSignalController.mCurrentState.setNetworkTypeResIdCache(mockCache);
// Rebuild the network map
mMobileSignalController.setConfiguration(mConfig);
when(mMockTm.getSimCarrierId()).thenReturn(fakeCarrier);
setupDefaultSignal();
updateDataConnectionState(TelephonyManager.DATA_CONNECTED, testDataNetType);
verifyDataIndicators(fakeIconOverride);
}
private void testDataActivity(int direction, boolean in, boolean out) {
updateDataActivity(direction);

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2022 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.systemui.statusbar.connectivity
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidTestingRunner::class)
class NetworkTypeResIdCacheTest : SysuiTestCase() {
private lateinit var cache: NetworkTypeResIdCache
private var overrides = MobileIconCarrierIdOverridesFake()
@Before
fun setUp() {
cache = NetworkTypeResIdCache(overrides)
}
@Test
fun carrier1_noOverride_usesDefault() {
assertThat(cache.get(group1, CARRIER_1, context)).isEqualTo(iconDefault1)
}
@Test
fun carrier1_overridden_usesOverride() {
overrides.overriddenIds.add(CARRIER_1)
overrides.overridesByCarrierId[CARRIER_1] = mapOf(NET_TYPE_1 to iconOverride1)
assertThat(cache.get(group1, CARRIER_1, context)).isEqualTo(iconOverride1)
}
@Test
fun carrier1_override_carrier2UsesDefault() {
overrides.overriddenIds.add(CARRIER_1)
overrides.overridesByCarrierId[CARRIER_1] = mapOf(NET_TYPE_1 to iconOverride1)
assertThat(cache.get(group1, CARRIER_2, context)).isEqualTo(iconDefault1)
}
@Test
fun carrier1_overrideType1_type2UsesDefault() {
overrides.overriddenIds.add(CARRIER_1)
overrides.overridesByCarrierId[CARRIER_1] = mapOf(NET_TYPE_1 to iconOverride1)
assertThat(cache.get(group2, CARRIER_1, context)).isEqualTo(iconDefault2)
}
companion object {
// Simplified icon overrides here
const val CARRIER_1 = 1
const val CARRIER_2 = 2
const val NET_TYPE_1 = "one"
const val iconDefault1 = 123
const val iconOverride1 = 321
val group1 = MobileIconGroup(NET_TYPE_1, /* dataContentDesc */ 0, iconDefault1)
const val NET_TYPE_2 = "two"
const val iconDefault2 = 234
val group2 = MobileIconGroup(NET_TYPE_2, /* dataContentDesc*/ 0, iconDefault2)
}
}

View File

@@ -16,31 +16,59 @@
package com.android.systemui.statusbar.pipeline.mobile.util
import android.telephony.TelephonyDisplayInfo
import com.android.settingslib.SignalIcon.MobileIconGroup
import com.android.settingslib.mobile.MobileMappings.Config
import com.android.settingslib.mobile.TelephonyIcons
class FakeMobileMappingsProxy : MobileMappingsProxy {
// The old [NetworkControllerDataTest] infra requires us to be able to use the real
// impl sometimes
var useRealImpl = false
private var realImpl = MobileMappingsProxyImpl()
private var iconMap = mapOf<String, MobileIconGroup>()
private var defaultIcons = TelephonyIcons.THREE_G
fun setIconMap(map: Map<String, MobileIconGroup>) {
iconMap = map
}
override fun mapIconSets(config: Config): Map<String, MobileIconGroup> = iconMap
override fun mapIconSets(config: Config): Map<String, MobileIconGroup> {
if (useRealImpl) {
return realImpl.mapIconSets(config)
}
return iconMap
}
fun getIconMap() = iconMap
fun setDefaultIcons(group: MobileIconGroup) {
defaultIcons = group
}
override fun getDefaultIcons(config: Config): MobileIconGroup = defaultIcons
override fun getDefaultIcons(config: Config): MobileIconGroup {
if (useRealImpl) {
return realImpl.getDefaultIcons(config)
}
return defaultIcons
}
/** This is only used in the old pipeline, use the real impl always */
override fun getIconKey(displayInfo: TelephonyDisplayInfo): String {
return realImpl.getIconKey(displayInfo)
}
fun getDefaultIcons(): MobileIconGroup = defaultIcons
override fun toIconKey(networkType: Int): String {
if (useRealImpl) {
return realImpl.toIconKeyOverride(networkType)
}
return networkType.toString()
}
override fun toIconKeyOverride(networkType: Int): String {
if (useRealImpl) {
return realImpl.toIconKeyOverride(networkType)
}
return toIconKey(networkType) + "_override"
}
}