From e3b527a2bf7d025b56aad38f3eda70c54a259e9c Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Wed, 3 Jan 2024 12:42:30 +0800 Subject: [PATCH] Refactor CellInfoUtil Unify and simplify the logic, and add unit test. Bug: 293845605 Test: manual - on Mobile Settings Test: unit test Change-Id: I5467b92baa8e47fbd400c7a21fd39fd5ec90ed3a --- .../network/telephony/CellInfoUtil.java | 219 ------------------ .../network/telephony/CellInfoUtil.kt | 113 +++++++++ .../telephony/NetworkOperatorPreference.java | 49 +--- .../telephony/NetworkSelectSettings.java | 6 +- .../network/telephony/CellInfoUtilTest.kt | 173 ++++++++++++++ 5 files changed, 297 insertions(+), 263 deletions(-) delete mode 100644 src/com/android/settings/network/telephony/CellInfoUtil.java create mode 100644 src/com/android/settings/network/telephony/CellInfoUtil.kt create mode 100644 tests/unit/src/com/android/settings/network/telephony/CellInfoUtilTest.kt diff --git a/src/com/android/settings/network/telephony/CellInfoUtil.java b/src/com/android/settings/network/telephony/CellInfoUtil.java deleted file mode 100644 index 8889586edd3..00000000000 --- a/src/com/android/settings/network/telephony/CellInfoUtil.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2018 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.telephony.CellIdentity; -import android.telephony.CellIdentityGsm; -import android.telephony.CellIdentityLte; -import android.telephony.CellIdentityNr; -import android.telephony.CellIdentityTdscdma; -import android.telephony.CellIdentityWcdma; -import android.telephony.CellInfo; -import android.telephony.CellInfoCdma; -import android.telephony.CellInfoGsm; -import android.telephony.CellInfoLte; -import android.telephony.CellInfoNr; -import android.telephony.CellInfoTdscdma; -import android.telephony.CellInfoWcdma; -import android.text.BidiFormatter; -import android.text.TextDirectionHeuristics; -import android.text.TextUtils; - -import com.android.internal.telephony.OperatorInfo; - -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - -/** - * Add static Utility functions to get information from the CellInfo object. - * TODO: Modify {@link CellInfo} for simplify those functions - */ -public final class CellInfoUtil { - private static final String TAG = "NetworkSelectSetting"; - - private CellInfoUtil() { - } - - /** - * Returns the title of the network obtained in the manual search. - * - * @param cellId contains the identity of the network. - * @param networkMccMnc contains the MCCMNC string of the network - * @return Long Name if not null/empty, otherwise Short Name if not null/empty, - * else MCCMNC string. - */ - public static String getNetworkTitle(CellIdentity cellId, String networkMccMnc) { - if (cellId != null) { - String title = Objects.toString(cellId.getOperatorAlphaLong(), ""); - if (TextUtils.isEmpty(title)) { - title = Objects.toString(cellId.getOperatorAlphaShort(), ""); - } - if (!TextUtils.isEmpty(title)) { - return title; - } - } - if (TextUtils.isEmpty(networkMccMnc)) { - return ""; - } - final BidiFormatter bidiFormatter = BidiFormatter.getInstance(); - return bidiFormatter.unicodeWrap(networkMccMnc, TextDirectionHeuristics.LTR); - } - - /** - * Returns the CellIdentity from CellInfo - * - * @param cellInfo contains the information of the network. - * @return CellIdentity within CellInfo - */ - public static CellIdentity getCellIdentity(CellInfo cellInfo) { - if (cellInfo == null) { - return null; - } - CellIdentity cellId = null; - if (cellInfo instanceof CellInfoGsm) { - cellId = ((CellInfoGsm) cellInfo).getCellIdentity(); - } else if (cellInfo instanceof CellInfoCdma) { - cellId = ((CellInfoCdma) cellInfo).getCellIdentity(); - } else if (cellInfo instanceof CellInfoWcdma) { - cellId = ((CellInfoWcdma) cellInfo).getCellIdentity(); - } else if (cellInfo instanceof CellInfoTdscdma) { - cellId = ((CellInfoTdscdma) cellInfo).getCellIdentity(); - } else if (cellInfo instanceof CellInfoLte) { - cellId = ((CellInfoLte) cellInfo).getCellIdentity(); - } else if (cellInfo instanceof CellInfoNr) { - cellId = ((CellInfoNr) cellInfo).getCellIdentity(); - } - return cellId; - } - - /** - * Creates a CellInfo object from OperatorInfo. GsmCellInfo is used here only because - * operatorInfo does not contain technology type while CellInfo is an abstract object that - * requires to specify technology type. It doesn't matter which CellInfo type to use here, since - * we only want to wrap the operator info and PLMN to a CellInfo object. - */ - public static CellInfo convertOperatorInfoToCellInfo(OperatorInfo operatorInfo) { - final String operatorNumeric = operatorInfo.getOperatorNumeric(); - String mcc = null; - String mnc = null; - if (operatorNumeric != null && operatorNumeric.matches("^[0-9]{5,6}$")) { - mcc = operatorNumeric.substring(0, 3); - mnc = operatorNumeric.substring(3); - } - final CellIdentityGsm cig = new CellIdentityGsm( - Integer.MAX_VALUE /* lac */, - Integer.MAX_VALUE /* cid */, - Integer.MAX_VALUE /* arfcn */, - Integer.MAX_VALUE /* bsic */, - mcc, - mnc, - operatorInfo.getOperatorAlphaLong(), - operatorInfo.getOperatorAlphaShort(), - Collections.emptyList()); - - final CellInfoGsm ci = new CellInfoGsm(); - ci.setCellIdentity(cig); - return ci; - } - - /** Convert a list of cellInfos to readable string without sensitive info. */ - public static String cellInfoListToString(List cellInfos) { - return cellInfos.stream() - .map(cellInfo -> cellInfoToString(cellInfo)) - .collect(Collectors.joining(", ")); - } - - /** Convert {@code cellInfo} to a readable string without sensitive info. */ - public static String cellInfoToString(CellInfo cellInfo) { - final String cellType = cellInfo.getClass().getSimpleName(); - final CellIdentity cid = getCellIdentity(cellInfo); - String mcc = getCellIdentityMcc(cid); - String mnc = getCellIdentityMnc(cid); - CharSequence alphaLong = null; - CharSequence alphaShort = null; - if (cid != null) { - alphaLong = cid.getOperatorAlphaLong(); - alphaShort = cid.getOperatorAlphaShort(); - } - return String.format( - "{CellType = %s, isRegistered = %b, mcc = %s, mnc = %s, alphaL = %s, alphaS = %s}", - cellType, cellInfo.isRegistered(), mcc, mnc, - alphaLong, alphaShort); - } - - /** - * Returns the MccMnc. - * - * @param cid contains the identity of the network. - * @return MccMnc string. - */ - public static String getCellIdentityMccMnc(CellIdentity cid) { - String mcc = getCellIdentityMcc(cid); - String mnc = getCellIdentityMnc(cid); - return (mcc == null || mnc == null) ? null : mcc + mnc; - } - - /** - * Returns the Mcc. - * - * @param cid contains the identity of the network. - * @return Mcc string. - */ - public static String getCellIdentityMcc(CellIdentity cid) { - String mcc = null; - if (cid != null) { - if (cid instanceof CellIdentityGsm) { - mcc = ((CellIdentityGsm) cid).getMccString(); - } else if (cid instanceof CellIdentityWcdma) { - mcc = ((CellIdentityWcdma) cid).getMccString(); - } else if (cid instanceof CellIdentityTdscdma) { - mcc = ((CellIdentityTdscdma) cid).getMccString(); - } else if (cid instanceof CellIdentityLte) { - mcc = ((CellIdentityLte) cid).getMccString(); - } else if (cid instanceof CellIdentityNr) { - mcc = ((CellIdentityNr) cid).getMccString(); - } - } - return (mcc == null) ? null : mcc; - } - - /** - * Returns the Mnc. - * - * @param cid contains the identity of the network. - * @return Mcc string. - */ - public static String getCellIdentityMnc(CellIdentity cid) { - String mnc = null; - if (cid != null) { - if (cid instanceof CellIdentityGsm) { - mnc = ((CellIdentityGsm) cid).getMncString(); - } else if (cid instanceof CellIdentityWcdma) { - mnc = ((CellIdentityWcdma) cid).getMncString(); - } else if (cid instanceof CellIdentityTdscdma) { - mnc = ((CellIdentityTdscdma) cid).getMncString(); - } else if (cid instanceof CellIdentityLte) { - mnc = ((CellIdentityLte) cid).getMncString(); - } else if (cid instanceof CellIdentityNr) { - mnc = ((CellIdentityNr) cid).getMncString(); - } - } - return (mnc == null) ? null : mnc; - } -} diff --git a/src/com/android/settings/network/telephony/CellInfoUtil.kt b/src/com/android/settings/network/telephony/CellInfoUtil.kt new file mode 100644 index 00000000000..c7b6b24b521 --- /dev/null +++ b/src/com/android/settings/network/telephony/CellInfoUtil.kt @@ -0,0 +1,113 @@ +/* + * 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 android.telephony.CellIdentity +import android.telephony.CellIdentityGsm +import android.telephony.CellInfo +import android.telephony.CellInfoGsm +import android.text.BidiFormatter +import android.text.TextDirectionHeuristics +import com.android.internal.telephony.OperatorInfo + +/** + * Add static Utility functions to get information from the CellInfo object. + * TODO: Modify [CellInfo] for simplify those functions + */ +object CellInfoUtil { + + /** + * Returns the title of the network obtained in the manual search. + * + * By the following order, + * 1. Long Name if not null/empty + * 2. Short Name if not null/empty + * 3. OperatorNumeric (MCCMNC) string + */ + @JvmStatic + fun CellIdentity.getNetworkTitle(): String? { + operatorAlphaLong?.takeIf { it.isNotBlank() }?.let { return it.toString() } + operatorAlphaShort?.takeIf { it.isNotBlank() }?.let { return it.toString() } + val operatorNumeric = getOperatorNumeric() ?: return null + val bidiFormatter = BidiFormatter.getInstance() + return bidiFormatter.unicodeWrap(operatorNumeric, TextDirectionHeuristics.LTR) + } + + /** + * Creates a CellInfo object from OperatorInfo. GsmCellInfo is used here only because + * operatorInfo does not contain technology type while CellInfo is an abstract object that + * requires to specify technology type. It doesn't matter which CellInfo type to use here, since + * we only want to wrap the operator info and PLMN to a CellInfo object. + */ + @JvmStatic + fun convertOperatorInfoToCellInfo(operatorInfo: OperatorInfo): CellInfo { + val operatorNumeric = operatorInfo.operatorNumeric + var mcc: String? = null + var mnc: String? = null + if (operatorNumeric?.matches("^[0-9]{5,6}$".toRegex()) == true) { + mcc = operatorNumeric.substring(0, 3) + mnc = operatorNumeric.substring(3) + } + return CellInfoGsm().apply { + cellIdentity = CellIdentityGsm( + /* lac = */ Int.MAX_VALUE, + /* cid = */ Int.MAX_VALUE, + /* arfcn = */ Int.MAX_VALUE, + /* bsic = */ Int.MAX_VALUE, + /* mccStr = */ mcc, + /* mncStr = */ mnc, + /* alphal = */ operatorInfo.operatorAlphaLong, + /* alphas = */ operatorInfo.operatorAlphaShort, + /* additionalPlmns = */ emptyList(), + ) + } + } + + /** + * Convert a list of cellInfos to readable string without sensitive info. + */ + @JvmStatic + fun cellInfoListToString(cellInfos: List): String = + cellInfos.joinToString { cellInfo -> cellInfo.readableString() } + + /** + * Convert [CellInfo] to a readable string without sensitive info. + */ + private fun CellInfo.readableString(): String = buildString { + append("{CellType = ${this@readableString::class.simpleName}, ") + append("isRegistered = $isRegistered, ") + append(cellIdentity.readableString()) + append("}") + } + + private fun CellIdentity.readableString(): String = buildString { + append("mcc = $mccString, ") + append("mnc = $mncString, ") + append("alphaL = $operatorAlphaLong, ") + append("alphaS = $operatorAlphaShort") + } + + /** + * Returns the MccMnc. + */ + @JvmStatic + fun CellIdentity.getOperatorNumeric(): String? { + val mcc = mccString + val mnc = mncString + return if (mcc == null || mnc == null) null else mcc + mnc + } +} diff --git a/src/com/android/settings/network/telephony/NetworkOperatorPreference.java b/src/com/android/settings/network/telephony/NetworkOperatorPreference.java index 7404aa47353..7a584330425 100644 --- a/src/com/android/settings/network/telephony/NetworkOperatorPreference.java +++ b/src/com/android/settings/network/telephony/NetworkOperatorPreference.java @@ -18,14 +18,11 @@ package com.android.settings.network.telephony; import static android.telephony.SignalStrength.NUM_SIGNAL_STRENGTH_BINS; +import static com.android.settings.network.telephony.CellInfoUtil.getOperatorNumeric; + import android.content.Context; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CellIdentity; -import android.telephony.CellIdentityGsm; -import android.telephony.CellIdentityLte; -import android.telephony.CellIdentityNr; -import android.telephony.CellIdentityTdscdma; -import android.telephony.CellIdentityWcdma; import android.telephony.CellInfo; import android.telephony.CellInfoCdma; import android.telephony.CellInfoGsm; @@ -36,6 +33,7 @@ import android.telephony.CellInfoWcdma; import android.telephony.CellSignalStrength; import android.util.Log; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -87,7 +85,7 @@ public class NetworkOperatorPreference extends Preference { * Change cell information */ public void updateCell(CellInfo cellinfo) { - updateCell(cellinfo, CellInfoUtil.getCellIdentity(cellinfo)); + updateCell(cellinfo, cellinfo.getCellIdentity()); } @VisibleForTesting @@ -104,14 +102,14 @@ public class NetworkOperatorPreference extends Preference { if (cellinfo == null) { return false; } - return mCellId.equals(CellInfoUtil.getCellIdentity(cellinfo)); + return mCellId.equals(cellinfo.getCellIdentity()); } /** * Return true when this preference is for forbidden network */ public boolean isForbiddenNetwork() { - return ((mForbiddenPlmns != null) && mForbiddenPlmns.contains(getOperatorNumeric())); + return ((mForbiddenPlmns != null) && mForbiddenPlmns.contains(getOperatorNumeric(mCellId))); } /** @@ -147,41 +145,12 @@ public class NetworkOperatorPreference extends Preference { updateIcon(level); } - /** - * Operator numeric of this cell - */ - public String getOperatorNumeric() { - final CellIdentity cellId = mCellId; - if (cellId == null) { - return null; - } - if (cellId instanceof CellIdentityGsm) { - return ((CellIdentityGsm) cellId).getMobileNetworkOperator(); - } - if (cellId instanceof CellIdentityWcdma) { - return ((CellIdentityWcdma) cellId).getMobileNetworkOperator(); - } - if (cellId instanceof CellIdentityTdscdma) { - return ((CellIdentityTdscdma) cellId).getMobileNetworkOperator(); - } - if (cellId instanceof CellIdentityLte) { - return ((CellIdentityLte) cellId).getMobileNetworkOperator(); - } - if (cellId instanceof CellIdentityNr) { - final String mcc = ((CellIdentityNr) cellId).getMccString(); - if (mcc == null) { - return null; - } - return mcc.concat(((CellIdentityNr) cellId).getMncString()); - } - return null; - } - /** * Operator name of this cell */ + @Nullable public String getOperatorName() { - return CellInfoUtil.getNetworkTitle(mCellId, getOperatorNumeric()); + return CellInfoUtil.getNetworkTitle(mCellId); } /** @@ -190,7 +159,7 @@ public class NetworkOperatorPreference extends Preference { public OperatorInfo getOperatorInfo() { return new OperatorInfo(Objects.toString(mCellId.getOperatorAlphaLong(), ""), Objects.toString(mCellId.getOperatorAlphaShort(), ""), - getOperatorNumeric(), getAccessNetworkTypeFromCellInfo(mCellInfo)); + getOperatorNumeric(mCellId), getAccessNetworkTypeFromCellInfo(mCellInfo)); } private int getIconIdForCell(CellInfo ci) { diff --git a/src/com/android/settings/network/telephony/NetworkSelectSettings.java b/src/com/android/settings/network/telephony/NetworkSelectSettings.java index 1cfa043ce6e..243b629ecb1 100644 --- a/src/com/android/settings/network/telephony/NetworkSelectSettings.java +++ b/src/com/android/settings/network/telephony/NetworkSelectSettings.java @@ -365,14 +365,12 @@ public class NetworkSelectSettings extends DashboardFragment { } ArrayList aggregatedList = new ArrayList<>(); for (CellInfo cellInfo : cellInfoListInput) { - String plmn = CellInfoUtil.getNetworkTitle(cellInfo.getCellIdentity(), - CellInfoUtil.getCellIdentityMccMnc(cellInfo.getCellIdentity())); + String plmn = CellInfoUtil.getNetworkTitle(cellInfo.getCellIdentity()); Class className = cellInfo.getClass(); Optional itemInTheList = aggregatedList.stream().filter( item -> { - String itemPlmn = CellInfoUtil.getNetworkTitle(item.getCellIdentity(), - CellInfoUtil.getCellIdentityMccMnc(item.getCellIdentity())); + String itemPlmn = CellInfoUtil.getNetworkTitle(item.getCellIdentity()); return itemPlmn.equals(plmn) && item.getClass().equals(className); }) .findFirst(); diff --git a/tests/unit/src/com/android/settings/network/telephony/CellInfoUtilTest.kt b/tests/unit/src/com/android/settings/network/telephony/CellInfoUtilTest.kt new file mode 100644 index 00000000000..c3c61888d9b --- /dev/null +++ b/tests/unit/src/com/android/settings/network/telephony/CellInfoUtilTest.kt @@ -0,0 +1,173 @@ +/* + * 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 android.telephony.CellIdentityCdma +import android.telephony.CellIdentityGsm +import android.telephony.CellInfoCdma +import android.telephony.CellInfoGsm +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.internal.telephony.OperatorInfo +import com.android.settings.network.telephony.CellInfoUtil.getNetworkTitle +import com.android.settings.network.telephony.CellInfoUtil.getOperatorNumeric +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +class CellInfoUtilTest { + + @Test + fun getNetworkTitle_alphaLong() { + val networkTitle = CELL_IDENTITY_GSM.getNetworkTitle() + + assertThat(networkTitle).isEqualTo(LONG) + } + + @Test + fun getNetworkTitle_alphaShort() { + val cellIdentity = CellIdentityGsm( + /* lac = */ 1, + /* cid = */ 2, + /* arfcn = */ 3, + /* bsic = */ 4, + /* mccStr = */ "123", + /* mncStr = */ "01", + /* alphal = */ "", + /* alphas = */ SHORT, + /* additionalPlmns = */ emptyList(), + ) + + val networkTitle = cellIdentity.getNetworkTitle() + + assertThat(networkTitle).isEqualTo(SHORT) + } + + @Test + fun getNetworkTitle_operatorNumeric() { + val cellIdentity = CellIdentityGsm( + /* lac = */ 1, + /* cid = */ 2, + /* arfcn = */ 3, + /* bsic = */ 4, + /* mccStr = */ "123", + /* mncStr = */ "01", + /* alphal = */ "", + /* alphas = */ "", + /* additionalPlmns = */ emptyList(), + ) + + val networkTitle = cellIdentity.getNetworkTitle() + + assertThat(networkTitle).isEqualTo("12301") + } + + @Test + fun getNetworkTitle_null() { + val cellIdentity = CellIdentityGsm( + /* lac = */ 1, + /* cid = */ 2, + /* arfcn = */ 3, + /* bsic = */ 4, + /* mccStr = */ null, + /* mncStr = */ null, + /* alphal = */ null, + /* alphas = */ null, + /* additionalPlmns = */ emptyList(), + ) + + val networkTitle = cellIdentity.getNetworkTitle() + + assertThat(networkTitle).isNull() + } + + @Test + fun convertOperatorInfoToCellInfo() { + val operatorInfo = OperatorInfo(LONG, SHORT, "12301") + + val cellInfo = CellInfoUtil.convertOperatorInfoToCellInfo(operatorInfo) + + assertThat(cellInfo.cellIdentity.mccString).isEqualTo("123") + assertThat(cellInfo.cellIdentity.mncString).isEqualTo("01") + assertThat(cellInfo.cellIdentity.operatorAlphaLong).isEqualTo(LONG) + assertThat(cellInfo.cellIdentity.operatorAlphaShort).isEqualTo(SHORT) + } + + @Test + fun cellInfoListToString() { + val cellInfoList = + listOf( + CellInfoCdma().apply { + cellIdentity = CELL_IDENTITY_CDMA + }, + CellInfoGsm().apply { + isRegistered = true + cellIdentity = CELL_IDENTITY_GSM + }, + ) + + val string = CellInfoUtil.cellInfoListToString(cellInfoList) + + assertThat(string).isEqualTo( + "{CellType = CellInfoCdma, isRegistered = false, " + + "mcc = null, mnc = null, alphaL = Long, alphaS = Short}, " + + "{CellType = CellInfoGsm, isRegistered = true, " + + "mcc = 123, mnc = 01, alphaL = Long, alphaS = Short}" + ) + } + + @Test + fun getOperatorNumeric_cdma() { + val operatorNumeric = CELL_IDENTITY_CDMA.getOperatorNumeric() + + assertThat(operatorNumeric).isNull() + } + + @Test + fun getOperatorNumeric_gsm() { + val operatorNumeric = CELL_IDENTITY_GSM.getOperatorNumeric() + + assertThat(operatorNumeric).isEqualTo("12301") + } + + private companion object { + const val LONG = "Long" + const val SHORT = "Short" + + val CELL_IDENTITY_GSM = CellIdentityGsm( + /* lac = */ 1, + /* cid = */ 2, + /* arfcn = */ 3, + /* bsic = */ 4, + /* mccStr = */ "123", + /* mncStr = */ "01", + /* alphal = */ LONG, + /* alphas = */ SHORT, + /* additionalPlmns = */ emptyList(), + ) + + val CELL_IDENTITY_CDMA = CellIdentityCdma( + /* nid = */ 1, + /* sid = */ 2, + /* bid = */ 3, + /* lon = */ 4, + /* lat = */ 5, + /* alphal = */ LONG, + /* alphas = */ SHORT, + ) + } +}