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

Commit 57d9bb44 authored by Pengquan Meng's avatar Pengquan Meng Committed by Gerrit Code Review
Browse files

Merge "Refactor CDNR"

parents efb39577 7005169e
Loading
Loading
Loading
Loading
+0 −323
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.internal.telephony;

import android.annotation.NonNull;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.SparseArray;

import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.IccRecords.CarrierNameDisplayConditionBitmask;
import com.android.internal.telephony.uicc.IccRecords.OperatorPlmnInfo;
import com.android.internal.telephony.uicc.IccRecords.PlmnNetworkName;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Use EF filed from various source according to the priority to resolve the service provider name
 * and PLMN network name.
 */
public class CarrierDisplayNameResolverImpl implements CarrierDisplayNameResolver {
    private static final boolean DBG = true;
    private static final String TAG = "CDNRImpl";

    /**
     * Only display SPN in home network, and PLMN network name in roaming network.
     */
    @CarrierNameDisplayConditionBitmask
    private static final int DEFAULT_CARRIER_NAME_DISPLAY_CONDITION_BITMASK = 0;

    private final SparseArray<String> mServiceProviderNames = new SparseArray<>();
    private final SparseArray<List<String>> mSpdi = new SparseArray<>();
    private final SparseArray<CarrierDisplayNameConditionRule> mCarrierNameDisplayConditionRules =
            new SparseArray<>();
    private final SparseArray<List<PlmnNetworkName>> mPlmnNetworkNames = new SparseArray<>();
    private final SparseArray<List<OperatorPlmnInfo>> mOperatorPlmns = new SparseArray<>();
    private final SparseArray<List<String>> mEhplmns = new SparseArray<>();
    private final LocalLog mLocalLog;

    private ServiceState mServiceState;
    private boolean mShouldShowServiceProviderName;
    private boolean mShouldShowPlmnNetworkName;
    private String mServiceProviderName;
    private String mPlmnNetworkName;
    private String mHomePlmn;

    /** {@code True} if any item is changed after the previous carrier name resolved. */
    private boolean mItemChanged;

    /**
     * The priority of ef source. Lower index means higher priority.
     *
     * {@link CarrierDisplayNameResolver#EF_SOURCE_DEFAULT} should always be the lowest priority
     * source.
     */
    private static final List<Integer> EF_SOURCE_PRIORITY =
            Arrays.asList(
                    EF_SOURCE_CARRIER_API,
                    EF_SOURCE_CARRIER_CONFIG,
                    EF_SOURCE_ERI,
                    EF_SOURCE_USIM,
                    EF_SOURCE_SIM,
                    EF_SOURCE_CSIM,
                    EF_SOURCE_RUIM,
                    EF_SOURCE_VOICE_OPERATOR_SIGNALLING,
                    EF_SOURCE_DATA_OPERATOR_SIGNALLING,
                    EF_SOURCE_MODEM_CONFIG,
                    EF_SOURCE_DEFAULT);

    public CarrierDisplayNameResolverImpl(LocalLog localLog) {
        mLocalLog = localLog;
        int key = getSourcePriority(EF_SOURCE_DEFAULT);
        mServiceProviderNames.put(key, "");
        mSpdi.put(key, Collections.EMPTY_LIST);
        mCarrierNameDisplayConditionRules.put(key,
                new CarrierDisplayNameConditionRule(
                        DEFAULT_CARRIER_NAME_DISPLAY_CONDITION_BITMASK));
        mPlmnNetworkNames.put(key, Collections.EMPTY_LIST);
        mOperatorPlmns.put(key, Collections.EMPTY_LIST);
        mEhplmns.put(key, Collections.EMPTY_LIST);
    }

    @Override
    public void updateServiceProviderName(@EFSource int source, String spn) {
        if (TextUtils.isEmpty(spn)) return;
        mServiceProviderNames.put(getSourcePriority(source), spn);
        mItemChanged = true;
    }

    @Override
    public void updateServiceProviderDisplayInformation(
            @EFSource int source, @NonNull List<String> spdi) {
        if (ArrayUtils.isEmpty(spdi)) return;
        mSpdi.put(getSourcePriority(source), spdi);
        mItemChanged = true;
    }

    @Override
    public void updateServiceProviderNameDisplayCondition(
            @EFSource int source, @CarrierNameDisplayConditionBitmask int condition) {
        if (condition == IccRecords.INVALID_CARRIER_NAME_DISPLAY_CONDITION_BITMASK) return;
        mCarrierNameDisplayConditionRules.put(getSourcePriority(source),
                new CarrierDisplayNameConditionRule(condition));
        mItemChanged = true;
    }

    @Override
    public void updatePlmnNetworkNameList(
            @EFSource int source, @NonNull List<PlmnNetworkName> pnnList) {
        if (ArrayUtils.isEmpty(pnnList)) return;
        mPlmnNetworkNames.put(getSourcePriority(source), pnnList);
        mItemChanged = true;
    }

    @Override
    public void updateEhplmnList(@EFSource int source, @NonNull List<String> ehplmns) {
        if (ArrayUtils.isEmpty(ehplmns)) return;
        mEhplmns.put(getSourcePriority(source), ehplmns);
        mItemChanged = true;
    }

    @Override
    public void updateServiceState(@NonNull ServiceState serviceState) {
        mServiceState = serviceState;
        mItemChanged = true;
    }

    @Override
    public void updateOperatorPlmnList(@EFSource int source, @NonNull List<OperatorPlmnInfo> opl) {
        if (ArrayUtils.isEmpty(opl)) return;
        mOperatorPlmns.put(getSourcePriority(source), opl);
        mItemChanged = true;
    }

    @Override
    public void updateHomePlmnNumeric(@NonNull String homePlmnNumeric) {
        mHomePlmn = homePlmnNumeric;
        mItemChanged = true;
    }

    @Override
    public boolean shouldShowPlmnNetworkName() {
        if (mItemChanged) resolveCarrierDisplayName();
        return mShouldShowPlmnNetworkName;
    }

    @Override
    public boolean shouldShowServiceProviderName() {
        if (mItemChanged) resolveCarrierDisplayName();
        return mShouldShowServiceProviderName;
    }

    @Override
    public String getPlmnNetworkName() {
        if (mItemChanged) resolveCarrierDisplayName();
        return mPlmnNetworkName;
    }

    @Override
    public String getServiceProviderName() {
        if (mItemChanged) resolveCarrierDisplayName();
        return mServiceProviderName;
    }

    private void resolveCarrierDisplayName() {
        if (mServiceState == null) return;

        CarrierDisplayNameConditionRule displayRule =
                mCarrierNameDisplayConditionRules.valueAt(0);

        String registeredPlmnNumeric = mServiceState.getOperatorNumeric();
        List<String> efSpdi = mSpdi.valueAt(0);

        // Currently use the roaming state from ServiceState.
        // EF_SPDI is only used when determine the service provider name and PLMN network name
        // display condition rule.
        // All the PLMNs will be considered HOME PLMNs if there is a brand override.
        boolean isRoaming = mServiceState.getRoaming() && !efSpdi.contains(registeredPlmnNumeric);
        mShouldShowServiceProviderName = displayRule.shouldShowSpn(isRoaming);
        mShouldShowPlmnNetworkName = displayRule.shouldShowPnn(isRoaming);

        mServiceProviderName = mServiceProviderNames.valueAt(0);

        // Resolve the PLMN network name
        mPlmnNetworkName = "";
        List<OperatorPlmnInfo> efOpl = mOperatorPlmns.valueAt(0);
        List<PlmnNetworkName> efPnn = mPlmnNetworkNames.valueAt(0);

        if (efOpl.isEmpty()) {
            // If the EF_OPL is not present, then the first record in EF_PNN is used for the
            // default network name when registered in the HPLMN or an EHPLMN(if the EHPLMN list
            // is present).
            mPlmnNetworkName = efPnn.isEmpty() ? "" : getPlmnNetworkName(efPnn.get(0));
        } else {
            // TODO: Check the TAC/LAC & registered PLMN numeric in OPL list to determine which
            // PLMN name should be used to override the current one.
        }

        // If no PLMN override is present, then the PLMN should be displayed numerically.
        if (mPlmnNetworkName.isEmpty()) {
            mPlmnNetworkName = registeredPlmnNumeric;
        }

        String logInfo = "isRoaming = " + isRoaming
                + " ,registeredPLMN = " + registeredPlmnNumeric
                + " ,displayRule = " + displayRule
                + " ,shouldShowPlmn = " + mShouldShowPlmnNetworkName
                + " ,plmn = " + mPlmnNetworkName
                + " ,shouldShowSpn = " + mShouldShowServiceProviderName
                + " ,spn = " + mServiceProviderName;
        if (DBG) Rlog.d(TAG, logInfo);
        mLocalLog.log(logInfo);

        mItemChanged = false;
    }

    @Override
    public String toString() {
        Boolean roamingFromSS = mServiceState != null ? mServiceState.getRoaming() : null;
        String registeredPLMN = mServiceState != null ? mServiceState.getOperatorNumeric() : null;
        return " { spnDisplayCondition = " + mCarrierNameDisplayConditionRules
                + " ,roamingFromSS = " + roamingFromSS
                + " ,registeredPLMN = " + registeredPLMN
                + " ,homePLMN = " + mHomePlmn
                + " ,spnList = " + mServiceProviderNames
                + " ,spnCondition " + mCarrierNameDisplayConditionRules
                + " ,spdiList = " + mSpdi
                + " ,pnnList = " + mPlmnNetworkNames
                + " ,oplList = " + mOperatorPlmns
                + " ,ehplmn = " + mEhplmns
                + " }";
    }

    /**
     * Dumps information for carrier display name resolver.
     * @param pw information printer.
     */
    public void dump(IndentingPrintWriter pw) {
        pw.println("CDNRImpl");
        pw.increaseIndent();
        pw.println("fields = " + toString());
        pw.println("shouldShowPlmn = " + mShouldShowPlmnNetworkName);
        pw.println("plmn= " + mPlmnNetworkName);
        pw.println("showShowSpn = " + mShouldShowServiceProviderName);
        pw.println("spn = " + mServiceProviderName);
        pw.decreaseIndent();
    }

    /**
     * Get the PLMN network name from the {@link PlmnNetworkName} object.
     * @param name the {@link PlmnNetworkName} object may contain the full and short version of PLMN
     * network name.
     * @return full/short version PLMN network name if one of those is existed, otherwise return an
     * empty string.
     */
    private static String getPlmnNetworkName(PlmnNetworkName name) {
        if (name == null) return "";
        if (!TextUtils.isEmpty(name.fullName)) return name.fullName;
        if (!TextUtils.isEmpty(name.shortName)) return name.shortName;
        return "";
    }

    /**
     * Get the priority of the source of ef object. If {@code source} is not in the priority list,
     * return {@link Integer#MAX_VALUE}.
     * @param source source of ef object.
     * @return the priority of the source of ef object.
     */
    private static int getSourcePriority(@EFSource int source) {
        int priority = EF_SOURCE_PRIORITY.indexOf(source);
        if (priority == -1) priority = Integer.MAX_VALUE;
        return priority;
    }

    private static final class CarrierDisplayNameConditionRule {
        private int mDisplayConditionBitmask;

        CarrierDisplayNameConditionRule(int carrierDisplayConditionBitmask) {
            mDisplayConditionBitmask = carrierDisplayConditionBitmask;
        }

        boolean shouldShowSpn(boolean isRoaming) {
            return !isRoaming || ((mDisplayConditionBitmask
                    & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN)
                    == IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN);
        }

        boolean shouldShowPnn(boolean isRoaming) {
            return isRoaming || ((mDisplayConditionBitmask
                    & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN)
                    == IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN);
        }

        @Override
        public String toString() {
            return String.format("{ SPN_bit = %d, PLMN_bit = %d }",
                    mDisplayConditionBitmask
                            & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN,
                    mDisplayConditionBitmask
                            & IccRecords.CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN);
        }
    }
}
+85 −363

File changed.

Preview size limit exceeded, changes collapsed.

+48 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.internal.telephony.cdnr;

import java.util.Arrays;
import java.util.List;

/** EF data from brand override. */
public final class BrandOverrideEfData implements EfData {
    private final String mSpn;
    private final String mRegisteredPlmn;

    public BrandOverrideEfData(String operatorName, String registeredPlmn) {
        mSpn = operatorName;
        mRegisteredPlmn = registeredPlmn;
    }

    @Override
    public String getServiceProviderName() {
        return mSpn;
    }

    @Override
    public int getServiceProviderNameDisplayCondition() {
        // No SPN in roaming network, no PLMN in home network
        return 0;
    }

    @Override
    public List<String> getServiceProviderDisplayInformation() {
        // Registered PLMN should be regarded as HOME PLMN
        return Arrays.asList(mRegisteredPlmn);
    }
}
+115 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.internal.telephony.cdnr;

import android.annotation.NonNull;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.text.TextUtils;

import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.IccRecords.OperatorPlmnInfo;
import com.android.internal.telephony.uicc.IccRecords.PlmnNetworkName;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/** Ef data from carrier config. */
public final class CarrierConfigEfData implements EfData {
    private static final String TAG = "CarrierConfigEfData";
    private final PersistableBundle mConfig;

    public CarrierConfigEfData(@NonNull PersistableBundle config) {
        mConfig = config;
    }

    @Override
    public String getServiceProviderName() {
        String spn = mConfig.getString(CarrierConfigManager.KEY_CARRIER_NAME_STRING);
        if (TextUtils.isEmpty(spn)) return null;
        return spn;
    }

    @Override
    public int getServiceProviderNameDisplayCondition() {
        int condition = mConfig.getInt(
                CarrierConfigManager.KEY_SPN_DISPLAY_CONDITION_OVERRIDE_INT,
                IccRecords.INVALID_CARRIER_NAME_DISPLAY_CONDITION_BITMASK);
        return condition;
    }

    @Override
    public List<String> getServiceProviderDisplayInformation() {
        String[] spdi = mConfig.getStringArray(
                CarrierConfigManager.KEY_SPDI_OVERRIDE_STRING_ARRAY);
        return spdi != null ? Arrays.asList(spdi) : null;
    }

    @Override
    public List<String> getEhplmnList() {
        String[] ehplmn = mConfig.getStringArray(
                CarrierConfigManager.KEY_EHPLMN_OVERRIDE_STRING_ARRAY);
        return ehplmn != null ? Arrays.asList(ehplmn) : null;
    }

    @Override
    public List<PlmnNetworkName> getPlmnNetworkNameList() {
        String[] pnn = mConfig.getStringArray(
                CarrierConfigManager.KEY_PNN_OVERRIDE_STRING_ARRAY);
        List<PlmnNetworkName> pnnList = null;
        if (pnn != null) {
            pnnList = new ArrayList<>(pnn.length);
            for (String pnnStr : pnn) {
                try {
                    String[] names = pnnStr.split("\\s*,\\s*");
                    String alphal = names[0];
                    String alphas = names.length > 1 ? names[1] : "";
                    pnnList.add(new PlmnNetworkName(alphal, alphas));
                } catch (Exception ex) {
                    Rlog.e(TAG, "CarrierConfig wrong pnn format, pnnStr = " + pnnStr);
                }
            }
        }
        return pnnList;
    }

    @Override
    public List<OperatorPlmnInfo> getOperatorPlmnList() {
        // OPL
        String[] opl = mConfig.getStringArray(
                CarrierConfigManager.KEY_OPL_OVERRIDE_STRING_ARRAY);
        List<OperatorPlmnInfo> oplList = null;
        if (opl != null) {
            oplList = new ArrayList<>(opl.length);
            for (String oplStr : opl) {
                try {
                    String[] info = oplStr.split("\\s*,\\s*");
                    oplList.add(new OperatorPlmnInfo(
                            info[0] /* plmn */,
                            Integer.parseInt(info[1]) /* lactac_start */,
                            Integer.parseInt(info[2]) /* lactac_end */,
                            Integer.parseInt(info[3]) /* pnn index */));
                } catch (Exception ex) {
                    Rlog.e(TAG, "CarrierConfig wrong opl format, oplStr = " + oplStr);
                }
            }
        }
        return oplList;
    }
}
+201 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.internal.telephony.cdnr;

import android.os.Parcel;
import android.os.Parcelable;

import java.util.Objects;

/**
 * A container of carrier display name.
 */
public class CarrierDisplayNameData implements Parcelable {
    /** Service provider name. */
    private final String mSpn;

    /** Data service provider name. */
    private final String mDataSpn;

    /** PLMN network name */
    private final String mPlmn;

    /** {@code True} if display service provider name is required. */
    private final boolean mShowSpn;

    /** {@code True} if display PLMN network name is required. */
    private final boolean mShowPlmn;

    private CarrierDisplayNameData(String spn, String dataSpn, boolean showSpn, String plmn,
            boolean showPlmn) {
        this.mSpn = spn;
        this.mDataSpn = dataSpn;
        this.mShowSpn = showSpn;
        this.mPlmn = plmn;
        this.mShowPlmn = showPlmn;
    }

    /**
     * Get the service provider name.
     * @return service provider name.
     */
    public String getSpn() {
        return mSpn;
    }

    /**
     * Get the service provider name of data provider.
     * @return service provider name of data provider.
     */
    public String getDataSpn() {
        return mDataSpn;
    }

    /**
     * Get the PLMN network name.
     * @return PLMN network name.
     */
    public String getPlmn() {
        return mPlmn;
    }

    /**
     * Whether the spn should be displayed.
     * @return
     */
    public boolean shouldShowSpn() {
        return mShowSpn;
    }

    /**
     * Whether the PLMN should be displayed.
     * @return
     */
    public boolean shouldShowPlmn() {
        return mShowPlmn;
    }

    @Override
    public String toString() {
        return String.format("{ spn = %s, dataSpn = %s, showSpn = %b, plmn = %s, showPlmn = %b",
                mSpn, mDataSpn, mShowSpn, mPlmn, mShowPlmn);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(mSpn);
        dest.writeString(mDataSpn);
        dest.writeString(mPlmn);
        dest.writeBoolean(mShowSpn);
        dest.writeBoolean(mShowPlmn);
    }

    private CarrierDisplayNameData(Parcel source) {
        mSpn = source.readString();
        mDataSpn = source.readString();
        mPlmn = source.readString();
        mShowSpn = source.readBoolean();
        mShowPlmn = source.readBoolean();
    }

    public static final Parcelable.Creator<CarrierDisplayNameData> CREATOR =
            new Creator<CarrierDisplayNameData>() {
                @Override
                public CarrierDisplayNameData createFromParcel(Parcel source) {
                    return new CarrierDisplayNameData(source);
                }

                @Override
                public CarrierDisplayNameData[] newArray(int size) {
                    return new CarrierDisplayNameData[size];
                }
            };

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CarrierDisplayNameData that = (CarrierDisplayNameData) o;
        return mShowSpn == that.mShowSpn
                && mShowPlmn == that.mShowPlmn
                && Objects.equals(mSpn, that.mSpn)
                && Objects.equals(mDataSpn, that.mDataSpn)
                && Objects.equals(mPlmn, that.mPlmn);
    }

    @Override
    public int hashCode() {
        return Objects.hash(mSpn, mDataSpn, mPlmn, mShowSpn, mShowPlmn);
    }

    /** Builder class for {@link com.android.internal.telephony.cdnr.CarrierDisplayNameData}. */
    public static final class Builder {
        private String mSpn;
        private String mDataSpn;
        private String mPlmn;
        private boolean mShowSpn;
        private boolean mShowPlmn;

        public Builder() {
            mSpn = null;
            mDataSpn = null;
            mPlmn = null;
            mShowPlmn = false;
            mShowSpn = false;
        }

        /** Create a {@link com.android.internal.telephony.cdnr.CarrierDisplayNameData} instance. */
        public CarrierDisplayNameData build() {
            return new CarrierDisplayNameData(mSpn, mDataSpn, mShowSpn, mPlmn, mShowPlmn);
        }

        /** Set service provider name. */
        public Builder setSpn(String spn) {
            mSpn = spn;
            return this;
        }

        /** Set data service provider name. */
        public Builder setDataSpn(String dataSpn) {
            mDataSpn = dataSpn;
            return this;
        }

        /** Set PLMN network name. */
        public Builder setPlmn(String plmn) {
            mPlmn = plmn;
            return this;
        }

        /** Set whether the service provider name should be displayed. */
        public Builder setShowSpn(boolean showSpn) {
            mShowSpn = showSpn;
            return this;
        }

        /** Set whether the PLMN network name should be displayed. */
        public Builder setShowPlmn(boolean showPlmn) {
            mShowPlmn = showPlmn;
            return this;
        }
    }
}
Loading