Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce84bfbc authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Refactor CellInfoUtil" into main

parents 6bdfac7c e3b527a2
Loading
Loading
Loading
Loading
+0 −219
Original line number Diff line number Diff line
/*
 * 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<CellInfo> 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;
    }
}
+113 −0
Original line number Diff line number Diff line
/*
 * 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<CellInfo>): 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
    }
}
+9 −40
Original line number Diff line number Diff line
@@ -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) {
+2 −4
Original line number Diff line number Diff line
@@ -365,14 +365,12 @@ public class NetworkSelectSettings extends DashboardFragment {
        }
        ArrayList<CellInfo> 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<CellInfo> 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();
+173 −0
Original line number Diff line number Diff line
/*
 * 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,
        )
    }
}