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

Commit 9b4dfab5 authored by lucaslin's avatar lucaslin
Browse files

Use location mcc to load the resource

Provide a way for OEM to provide their customization when
device doesn't have a sim card inserted.

Bug: 141406258
Test: 1. Build pass
      2. atest NetworkStackTests

Change-Id: Iad8340e643580f8efa536884d22f0ea0a97cd9a5
parent 4336b91f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
         permissions added would cause crashes on startup unless they are also added to the
         privileged permissions whitelist for that package. -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+3 −0
Original line number Diff line number Diff line
@@ -43,4 +43,7 @@
    <!-- Customized default DNS Servers address. -->
    <string-array name="config_default_dns_servers" translatable="false">
    </string-array>
    <!-- Set to true if NetworkMonitor needs to load the resource by neighbor mcc when device
         doesn't have a SIM card inserted. -->
    <bool name="config_no_sim_card_uses_neighbor_mcc">false</bool>
</resources>
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
            <item type="string" name="config_captive_portal_http_url"/>
            <item type="string" name="config_captive_portal_https_url"/>
            <item type="array" name="config_captive_portal_fallback_urls"/>
            <item type="bool" name="config_no_sim_card_uses_neighbor_mcc"/>
            <!-- Configuration value for DhcpResults -->
            <item type="array" name="config_default_dns_servers"/>
        </policy>
+97 −2
Original line number Diff line number Diff line
@@ -76,6 +76,8 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.DnsResolver;
@@ -101,11 +103,19 @@ import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.AccessNetworkConstants;
import android.telephony.CellIdentityNr;
import android.telephony.CellInfo;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoNr;
import android.telephony.CellInfoTdscdma;
import android.telephony.CellInfoWcdma;
import android.telephony.CellSignalStrength;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
@@ -116,6 +126,7 @@ import android.util.Log;
import android.util.Pair;

import androidx.annotation.ArrayRes;
import androidx.annotation.BoolRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
@@ -141,8 +152,10 @@ import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
@@ -1315,8 +1328,78 @@ public class NetworkMonitor extends StateMachine {
                CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
    }

    @Nullable
    private String getMccFromCellInfo(final CellInfo cell) {
        if (cell instanceof CellInfoGsm) {
            return ((CellInfoGsm) cell).getCellIdentity().getMccString();
        } else if (cell instanceof CellInfoLte) {
            return ((CellInfoLte) cell).getCellIdentity().getMccString();
        } else if (cell instanceof CellInfoWcdma) {
            return ((CellInfoWcdma) cell).getCellIdentity().getMccString();
        } else if (cell instanceof CellInfoTdscdma) {
            return ((CellInfoTdscdma) cell).getCellIdentity().getMccString();
        } else if (cell instanceof CellInfoNr) {
            return ((CellIdentityNr) ((CellInfoNr) cell).getCellIdentity()).getMccString();
        } else {
            return null;
        }
    }

    /**
     * Return location mcc.
     */
    @VisibleForTesting
    @Nullable
    protected String getLocationMcc() {
        // Adding this check is because the new permission won't be granted by mainline update,
        // the new permission only be granted by OTA for current design. Tracking: b/145774617.
        if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
                Process.myPid(), Process.myUid())
                == PackageManager.PERMISSION_DENIED) {
            log("getLocationMcc : NetworkStack does not hold ACCESS_FINE_LOCATION");
            return null;
        }
        try {
            final List<CellInfo> cells = mTelephonyManager.getAllCellInfo();
            final Map<String, Integer> countryCodeMap = new HashMap<>();
            int maxCount = 0;
            for (final CellInfo cell : cells) {
                final String mcc = getMccFromCellInfo(cell);
                if (mcc != null) {
                    final int count = countryCodeMap.getOrDefault(mcc, 0) + 1;
                    countryCodeMap.put(mcc, count);
                }
            }
            // Return the MCC which occurs most.
            if (countryCodeMap.size() <= 0) return null;
            return Collections.max(countryCodeMap.entrySet(),
                    (e1, e2) -> e1.getValue().compareTo(e2.getValue())).getKey();
        } catch (SecurityException e) {
            log("Permission is not granted:" + e);
            return null;
        }
    }

    @VisibleForTesting
    protected Context getContextByMccIfNoSimCardOrDefault() {
        final boolean useNeighborResource =
                getResBooleanConfig(mContext, R.bool.config_no_sim_card_uses_neighbor_mcc);
        if (!useNeighborResource
                || TelephonyManager.SIM_STATE_READY == mTelephonyManager.getSimState()) {
            return mContext;
        }
        final String mcc = getLocationMcc();
        if (TextUtils.isEmpty(mcc)) {
            return mContext;
        }
        final Configuration config = mContext.getResources().getConfiguration();
        config.mcc = Integer.parseInt(mcc);
        return mContext.createConfigurationContext(config);
    }

    private String getCaptivePortalServerHttpsUrl() {
        return getSettingFromResource(mContext, R.string.config_captive_portal_https_url,
        final Context targetContext = getContextByMccIfNoSimCardOrDefault();
        return getSettingFromResource(targetContext, R.string.config_captive_portal_https_url,
                R.string.default_captive_portal_https_url, CAPTIVE_PORTAL_HTTPS_URL);
    }

@@ -1347,6 +1430,17 @@ public class NetworkMonitor extends StateMachine {
        }
    }

    @VisibleForTesting
    protected boolean getResBooleanConfig(@NonNull final Context context,
            @BoolRes int configResource) {
        final Resources res = context.getResources();
        try {
            return res.getBoolean(configResource);
        } catch (Resources.NotFoundException e) {
            return false;
        }
    }

    /**
     * Get the captive portal server HTTP URL that is configured on the device.
     *
@@ -1355,7 +1449,8 @@ public class NetworkMonitor extends StateMachine {
     * on one URL that can be used, while NetworkMonitor may implement more complex logic.
     */
    public String getCaptivePortalServerHttpUrl() {
        return getSettingFromResource(mContext, R.string.config_captive_portal_http_url,
        final Context targetContext = getContextByMccIfNoSimCardOrDefault();
        return getSettingFromResource(targetContext, R.string.config_captive_portal_http_url,
                R.string.default_captive_portal_http_url, CAPTIVE_PORTAL_HTTP_URL);
    }

+52 −0
Original line number Diff line number Diff line
@@ -64,7 +64,10 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.DnsResolver;
@@ -87,6 +90,11 @@ import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
import android.telephony.CellInfo;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellSignalStrength;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
@@ -133,6 +141,7 @@ public class NetworkMonitorTest {
    private static final String LOCATION_HEADER = "location";

    private @Mock Context mContext;
    private @Mock Configuration mConfiguration;
    private @Mock Resources mResources;
    private @Mock IpConnectivityLog mLogger;
    private @Mock SharedLog mValidationLogger;
@@ -484,6 +493,10 @@ public class NetworkMonitorTest {
            assertTrue("NetworkMonitor did not quit after " + HANDLER_TIMEOUT_MS + "ms",
                    mQuitCv.block(HANDLER_TIMEOUT_MS));
        }

        protected Context getContext() {
            return mContext;
        }
    }

    private WrappedNetworkMonitor makeMonitor(NetworkCapabilities nc) {
@@ -512,6 +525,45 @@ public class NetworkMonitorTest {
        HandlerUtilsKt.waitForIdle(nm.getHandler(), HANDLER_TIMEOUT_MS);
    }

    @Test
    public void testGetLocationMcc() throws Exception {
        final WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
        doReturn(PackageManager.PERMISSION_DENIED).when(mContext).checkPermission(
                eq(android.Manifest.permission.ACCESS_FINE_LOCATION),  anyInt(), anyInt());
        assertNull(wnm.getLocationMcc());
        doReturn(PackageManager.PERMISSION_GRANTED).when(mContext).checkPermission(
                eq(android.Manifest.permission.ACCESS_FINE_LOCATION),  anyInt(), anyInt());
        doReturn(new ContextWrapper(mContext)).when(mContext).createConfigurationContext(any());
        // Prepare CellInfo and check if the vote mechanism is working or not.
        final CellInfoGsm cellInfoGsm1 = new CellInfoGsm();
        final CellInfoGsm cellInfoGsm2 = new CellInfoGsm();
        final CellInfoLte cellInfoLte = new CellInfoLte();
        final CellIdentityGsm cellIdentityGsm =
                new CellIdentityGsm(0, 0, 0, 0, "460", "01", "", "");
        final CellIdentityLte cellIdentityLte =
                new CellIdentityLte(0, 0, 0, 0, 0, "466", "01", "", "");
        cellInfoGsm1.setCellIdentity(cellIdentityGsm);
        cellInfoGsm2.setCellIdentity(cellIdentityGsm);
        cellInfoLte.setCellIdentity(cellIdentityLte);
        final List<CellInfo> cellList = new ArrayList<CellInfo>();
        cellList.add(cellInfoGsm1);
        cellList.add(cellInfoGsm2);
        cellList.add(cellInfoLte);
        doReturn(cellList).when(mTelephony).getAllCellInfo();
        // The count of 460 is 2 and the count of 466 is 1, so the getLocationMcc() should return
        // 460.
        assertEquals("460", wnm.getLocationMcc());
        // getContextByMccIfNoSimCardOrDefault() shouldn't return mContext when using neighbor mcc
        // is enabled and the sim is not ready.
        doReturn(true).when(mResources).getBoolean(R.bool.config_no_sim_card_uses_neighbor_mcc);
        doReturn(TelephonyManager.SIM_STATE_ABSENT).when(mTelephony).getSimState();
        doReturn(mConfiguration).when(mResources).getConfiguration();
        assertEquals(460,
                wnm.getContextByMccIfNoSimCardOrDefault().getResources().getConfiguration().mcc);
        doReturn(false).when(mResources).getBoolean(R.bool.config_no_sim_card_uses_neighbor_mcc);
        assertEquals(wnm.getContext(), wnm.getContextByMccIfNoSimCardOrDefault());
    }

    @Test
    public void testGetIntSetting() throws Exception {
        WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();