Android Emulator Tips -- Simulate Mobile Carrier

Background

I'm not an Android developer, but I do work with Android applications which means I have to work with Android Studio and Android emulator quite often. Recently, I encountered a quite interesting problem which prompt me to write this post and hopefully can help someone in the future.

Why?

Because I need to identify where the user of the mobile app is located and provide different content to the user based on their location.

How?

There are definitely several ways to do so, one obvious way is to use the IP address. However, with the growing use of VPN, this is definitely not the most reliable option.

The other option that comes up is to identify through the mobile carrier. If you are not familiar with telco or mobile networks, I will provide a brief background next.

MCCs and MNCs
Each mobile network operator (or carrier) can be uniquely identified by using a combination of MCC (mobile country code) and MNC(mobile network code). More information on this on Wikipedia. What this means is that, you can usually reliably identify where the user is from by looking at their mobile carrier's MCC code.

Usually, you would have to translate the MCC code to a country code on your own but it turns out in Android you don't have to do the translation yourself. Instead, you can directly use this API which will give you an ISO country code in 2 letters. You can then do whatever you want with this country code, pass this through a header to a server or the likes.

Once you have implemented this using getNetworkCountryIso, you will realize it is almost impossible to test or verify if this functionality will actually work as expected. One of the easiest way is to provide a debug menu within the app (in debug mode) and then mock different countries, this is the obviously the most efficient and cost effective way.

If in reality, a debug menu to mock countries is not something you can achieve, then you will have to use the emulator. This is what the rest of this post will be about, and hopefully this post can help you with your solution.

The problem to solve is to "change" the carrier in the Android emulator.

Solution

The solution I came up with involves changing one of Android system image, only one file change is strictly necessary.

In Linux and/or MacOS systems, the file to change sits under $ANDROID_SDK_ROOT/system-images/android-33/google_apis/x86_64/data/misc/modem_simulator/etc/modem_simulator/files/numeric_operator.xml

What you would need to do is to add the MCC and MNC combo to the file and give it whatever name you want.

In Linux, system image location:
$ANDROID_SDK_ROOT/system-images/android-$sdk_version/google_apis/x86_64

File to change or copy?

  • $ANDROID_SDK_ROOT/system-images/android-33/google_apis/x86_64/data/misc/modem_simulator/iccprofile_for_sim0.xml Line 79, CIMI, replace first three digit with MCC you want.
  • $ANDROID_SDK_ROOT/system-images/android-33/google_apis/x86_64/data/misc/modem_simulator/etc/modem_simulator/files/numeric_operator.xml, add the newly added MCC to this file, give it a name

Verify:

1
2
3
4
5
6
adb shell getprop|grep gsm
emulator @$(emulator -list-avds|head) \
-logcat '*:silent' \
-no-snapshot \
-writable-system \
-no-boot-anim

Once the emulator has started, you can check the carrier has changed to the one you have chosen.

Another way

Android emulator allow you to pass the iccprofile at boot time as well, so you can copy the iccprofile_for_sim0 to the location you want and start the emulator as follows:

1
2
3
4
5
6
7
adb shell getprop|grep gsm
emulator @$(emulator -list-avds|head) \
-logcat '*:silent' \
-no-snapshot \
-writable-system \
-iccprofile LOCATION_TO_YOUR_ICC_PROFILE
-no-boot-anim