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

Commit db7d612c authored by Masaho Nishikawa's avatar Masaho Nishikawa Committed by Amit Mahajan
Browse files

Data connection for carrier specific APN

Implement the following features to support carrier network connection.

1. Sets default preferred APN
   Customize a preferred APN which is used on the first boot. Because
   some operators specify the APN to use by default if the preferred
   APN is not set. So, make it possible that specify the default
   preferred APN by CarrierConfig.

2. Does not use dun apn in roaming network
   Some operators does not use dun apn for the tethering data
   connection in roaming networks. So, make it possible that to not
   use dun apn in roaming network.

3. Uses only preferred APN set
   Some operators does not want to use anything other than preferred
   APN automatically even if the connection fails to access network.
   So, make it possible that to use only APNs with the same set id as
   preferred APN.

Test: Manual
Bug: 147969062
Merged-in: I062e650f9a906f07356c51c3042fe2ffcc34ba61
Change-Id: I062e650f9a906f07356c51c3042fe2ffcc34ba61
(cherry picked from commit 249adbcc)
parent 203e00cd
Loading
Loading
Loading
Loading
+140 −23
Original line number Diff line number Diff line
@@ -1776,29 +1776,109 @@ public class DcTracker extends Handler {
        if (DBG) log(str + " apnContext=" + apnContext + " dc=" + apnContext.getDataConnection());
    }

    private Cursor getPreferredApnCursor(int subId) {
        Cursor cursor = null;
        if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
            cursor = mPhone.getContext().getContentResolver().query(
                    Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID,
                            String.valueOf(subId)), null, null, null,
                    Telephony.Carriers.DEFAULT_SORT_ORDER);
        }
        return cursor;
    }

    private ApnSetting getPreferredApnFromDB() {
        ApnSetting preferredApn = null;
        Cursor cursor = getPreferredApnCursor(mPhone.getSubId());
        if (cursor != null) {
            if (cursor.getCount() > 0) {
                cursor.moveToFirst();
                preferredApn = ApnSetting.makeApnSetting(cursor);
            }
            cursor.close();
        }
        if (VDBG) log("getPreferredApnFromDB: preferredApn=" + preferredApn);
        return preferredApn;
    }

    private void setDefaultPreferredApnIfNeeded() {
        ApnSetting defaultPreferredApn = null;
        PersistableBundle bundle = getCarrierConfig();
        String defaultPreferredApnName = bundle.getString(CarrierConfigManager
                .KEY_DEFAULT_PREFERRED_APN_NAME_STRING);

        if (TextUtils.isEmpty(defaultPreferredApnName) || getPreferredApnFromDB() != null) {
            return;
        }

        String selection = Telephony.Carriers.APN + " = \"" + defaultPreferredApnName + "\" AND "
                + Telephony.Carriers.EDITED_STATUS + " = " + Telephony.Carriers.UNEDITED;
        Cursor cursor = mPhone.getContext().getContentResolver().query(
                Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI,
                        "filtered/subId/" + mPhone.getSubId()),
                null, selection, null, Telephony.Carriers._ID);

        if (cursor != null) {
            if (cursor.getCount() > 0) {
                if (cursor.moveToFirst()) {
                    defaultPreferredApn = ApnSetting.makeApnSetting(cursor);
                }
            }
            cursor.close();
        }

        if (defaultPreferredApn != null
                && defaultPreferredApn.canHandleType(mRequestedApnType)) {
            log("setDefaultPreferredApnIfNeeded: For APN type "
                    + ApnSetting.getApnTypeString(mRequestedApnType)
                    + " found default apnSetting "
                    + defaultPreferredApn);

            setPreferredApn(defaultPreferredApn.getId(), true);
        }

        return;
    }

    /**
     * Check if preferred apn is allowed to edit by user.
     * @return {@code true} if it is allowed to edit.
     */
    @VisibleForTesting
    public boolean isPreferredApnUserEdited() {
        boolean isUserEdited = false;
        Cursor cursor = getPreferredApnCursor(mPhone.getSubId());
        if (cursor != null) {
            if (cursor.getCount() > 0) {
                if (cursor.moveToFirst()) {
                    isUserEdited = cursor.getInt(
                            cursor.getColumnIndexOrThrow(Telephony.Carriers.EDITED_STATUS))
                            == Telephony.Carriers.USER_EDITED;
                }
            }
            cursor.close();
        }
        if (VDBG) log("isPreferredApnUserEdited: isUserEdited=" + isUserEdited);
        return isUserEdited;
    }

    /**
     * Fetch the DUN apns
     * @return a list of DUN ApnSetting objects
     */
    @VisibleForTesting
    public @NonNull ArrayList<ApnSetting> fetchDunApns() {
        if (mPhone.getServiceState().getRoaming() && !isPreferredApnUserEdited()
                && getCarrierConfig().getBoolean(CarrierConfigManager
                .KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL)) {
            if (VDBG) log("fetchDunApns: Dun apn is not used in roaming network");
            return new ArrayList<ApnSetting>(0);
        }

        int bearer = getDataRat();
        ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
        ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();

        if (mPhone.getServiceState().getRoaming()) {
            CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
                    .getSystemService(Context.CARRIER_CONFIG_SERVICE);
            if (configManager != null) {
                PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId());
                if (b != null) {
                    if (b.getBoolean(CarrierConfigManager.KEY_DISABLE_DUN_APN_WHILE_ROAMING)) {
                        return new ArrayList<>();
                    }
                }
            }
        }

        // Places to look for tether APN in order: TETHER_DUN_APN setting (to be deprecated soon),
        // APN database
        String apnData = Settings.Global.getString(mResolver, Settings.Global.TETHER_DUN_APN);
@@ -1818,12 +1898,11 @@ public class DcTracker extends Handler {
            }
        }

        int preferredApnSetId = getPreferredApnSetId();
        for (ApnSetting dunSetting : dunCandidates) {
            if (dunSetting.canSupportNetworkType(
                    ServiceState.rilRadioTechnologyToNetworkType(bearer))) {
                int preferredApnSetId = getPreferredApnSetId();
                if (preferredApnSetId == Telephony.Carriers.NO_APN_SET_ID
                        || preferredApnSetId == dunSetting.getApnSetId()) {
                if (preferredApnSetId == dunSetting.getApnSetId()) {
                    retDunSettings.add(dunSetting);
                }
            }
@@ -2046,7 +2125,15 @@ public class DcTracker extends Handler {
              iaApnSetting = mPreferredApn;
        } else if (!mAllApnSettings.isEmpty()) {
            // Search for Initial APN setting and the first apn that can handle default
            int preferredApnSetId = getPreferredApnSetId();
            for (ApnSetting apn : mAllApnSettings) {
                if (preferredApnSetId != apn.getApnSetId()) {
                    if (VDBG) {
                        log("setInitialApn: APN set id " + apn.getApnSetId()
                                + " does not match the preferred set id " + preferredApnSetId);
                    }
                    continue;
                }
                if (firstNonEmergencyApnSetting == null
                        && !apn.isEmergencyApn()) {
                    firstNonEmergencyApnSetting = apn;
@@ -2121,6 +2208,7 @@ public class DcTracker extends Handler {
        // TODO: It'd be nice to only do this if the changed entrie(s)
        // match the current operator.
        if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections");
        setDefaultPreferredApnIfNeeded();
        createAllApnList();
        setDataProfilesAsNeeded();
        setInitialAttachApn();
@@ -2267,6 +2355,7 @@ public class DcTracker extends Handler {

        mAutoAttachEnabled.set(false);
        setDefaultDataRoamingEnabled();
        setDefaultPreferredApnIfNeeded();
        read5GConfiguration();
        registerSettingsObserver();
        mConfigReady = true;
@@ -3164,11 +3253,20 @@ public class DcTracker extends Handler {

        ArrayList<DataProfile> dataProfileList = new ArrayList<>();

        int preferredApnSetId = getPreferredApnSetId();
        for (ApnSetting apn : mAllApnSettings) {
            if (apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID
                    || preferredApnSetId == apn.getApnSetId()) {
                DataProfile dp = createDataProfile(apn, apn.equals(getPreferredApn()));
                if (!dataProfileList.contains(dp)) {
                    dataProfileList.add(dp);
                }
            } else {
                if (VDBG) {
                    log("setDataProfilesAsNeeded: APN set id " + apn.getApnSetId()
                            + " does not match the preferred set id " + preferredApnSetId);
                }
            }
        }

        // Check if the data profiles we are sending are same as we did last time. We don't want to
@@ -3376,13 +3474,12 @@ public class DcTracker extends Handler {
        }

        if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings);
        int preferredApnSetId = getPreferredApnSetId();
        for (ApnSetting apn : mAllApnSettings) {
            if (apn.canHandleType(requestedApnTypeBitmask)) {
                if (apn.canSupportNetworkType(
                        ServiceState.rilRadioTechnologyToNetworkType(radioTech))) {
                    int preferredApnSetId = getPreferredApnSetId();
                    if (apn.isEmergencyApn()
                            || preferredApnSetId == Telephony.Carriers.NO_APN_SET_ID
                    if (apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID
                            || preferredApnSetId == apn.getApnSetId()) {
                        if (VDBG) log("buildWaitingApns: adding apn=" + apn);
                        apnList.add(apn);
@@ -3419,7 +3516,11 @@ public class DcTracker extends Handler {
    }

    private void setPreferredApn(int pos) {
        if (!mCanSetPreferApn) {
        setPreferredApn(pos, false);
    }

    private void setPreferredApn(int pos, boolean force) {
        if (!force && !mCanSetPreferApn) {
            log("setPreferredApn: X !canSEtPreferApn");
            return;
        }
@@ -4328,6 +4429,7 @@ public class DcTracker extends Handler {
                | TelephonyManager.NETWORK_TYPE_BITMASK_IWLAN))
                .setApnName("sos")
                .setApnTypeBitmask(ApnSetting.TYPE_EMERGENCY)
                .setApnSetId(Telephony.Carriers.MATCH_ALL_APN_SET_ID)
                .build();
    }

@@ -5134,4 +5236,19 @@ public class DcTracker extends Handler {
        return apnSetting1.equals(apnSetting2,
                mPhone.getServiceState().getDataRoamingFromRegistration());
    }

    @NonNull
    private PersistableBundle getCarrierConfig() {
        CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
                .getSystemService(Context.CARRIER_CONFIG_SERVICE);
        if (configManager != null) {
            // If an invalid subId is used, this bundle will contain default values.
            PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId());
            if (config != null) {
                return config;
            }
        }
        // Return static default defined in CarrierConfigManager.
        return CarrierConfigManager.getDefaultConfig();
    }
}
+21 −2
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -473,6 +474,16 @@ public class DcTrackerTest extends TelephonyTest {
            mPreferredApnSet = values.getAsInteger(Telephony.Carriers.APN_SET_ID);
            return 1;
        }

        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            return 0;
        }

        @Override
        public Uri insert(Uri uri, ContentValues values) {
            return null;
        }
    }

    @Before
@@ -1409,7 +1420,8 @@ public class DcTrackerTest extends TelephonyTest {
    @SmallTest
    public void testFetchDunApnWhileRoaming() {
        doReturn(true).when(mServiceState).getRoaming();
        mBundle.putBoolean(CarrierConfigManager.KEY_DISABLE_DUN_APN_WHILE_ROAMING, true);
        mBundle.putBoolean(CarrierConfigManager
                .KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL, true);

        sendInitializationEvents();

@@ -1418,8 +1430,15 @@ public class DcTrackerTest extends TelephonyTest {

        Settings.Global.putString(mContext.getContentResolver(),
                Settings.Global.TETHER_DUN_APN, dunApnString);

        DcTracker spyDct = spy(mDct);
        doReturn(true).when(spyDct).isPreferredApnUserEdited();
        // Expect non-empty DUN APN list
        assertEquals(1, spyDct.fetchDunApns().size());

        doReturn(false).when(spyDct).isPreferredApnUserEdited();
        // Expect empty DUN APN list
        assertEquals(0, mDct.fetchDunApns().size());
        assertEquals(0, spyDct.fetchDunApns().size());

        Settings.Global.putString(mContext.getContentResolver(),
                Settings.Global.TETHER_DUN_APN, null);