2009-12-26

[Android] Turn on/off data connectivity by APN

I am working on a small plugin for my new application. This plugin is used to turn on/off data connectivity at a specific time. I flipped through API documentation and found nothing about how to turn on/off data connectivity but how to listen to its state change.

Fortunately, Android is an open-source platform. I can find the answer for myself. I checked out the source code of platform/packages/apps/Settings.git in Android source tree and dug into ApnSettings.java.

Now, I am wondering if changing APN names will do the tricks? Let's find out!

Two content URIs defined as constants in the file,
public static final String RESTORE_CARRIERS_URI = "content://telephony/carriers/restore";
public static final String PREFERRED_APN_URI = "content://telephony/carriers/preferapn";
and the "content://telephony/carriers" is hinting me that it should store all carriers your phone predefined or has searched. I wrote a small piece of code to dump the contents of this URI.
private List getApnInfoList(Context context) {
    List retList = new ArrayList();
    ContentResolver contentResolver = context.getContentResolver();
    Cursor apnCursor =
        contentResolver.query(CARRIERS_URI,
                              new String[]{COLUMN_NAME_ID,
                                           COLUMN_NAME_APN,
                                           COLUMN_NAME_TYPES},
                              null, null, null);
    if (apnCursor.moveToFirst()) {
        do {
            ApnInfo apnInfo = new ApnInfo();
            apnInfo.id = apnCursor.getInt(COLUMN_INDEX_ID);
            apnInfo.apn = apnCursor.getString(COLUMN_INDEX_APN);
            apnInfo.types = apnCursor.getString(COLUMN_INDEX_TYPES);
            retList.add(apnInfo);
        } while (apnCursor.moveToNext());
    }
    apnCursor.close();
    return retList;
}

This function gave me a list of carriers and their types in the emulator.
IdAPNTypes
1epc.tmobile.comnull
2epc.tmobile.comnull
3epc.tmobile.comnull
4epc.tmobile.comnull
5epc.tmobile.comnull
6epc.tmobile.comnull
7epc.tmobile.comnull
8epc.tmobile.comnull
9epc.tmobile.comnull
10epc.tmobile.comnull
11epc.tmobile.comnull
12epc.tmobile.comnull
13epc.tmobile.comnull
14epc.tmobile.comnull
15general.t-mobile.uknull
16internet.t-mobilenull
17gprsinternetdefault
18gprsmmsmms
19internet.t-mobile.czdefault
20mms.t-mobile.czmms
21internetdefault
22mmsmms
23wap.cingularnull
24wap.cingularnull
25proxynull
26internet.comnull
27internetnull
28internetnull
29internetnull
30internetnull
31portalnmmsnull
32wapsfrdefault
33mmssfrmms
34orangedefault
35orange.actemms
36mmsbouygtel.comnull
37internetnull
38internetnull
39internetgnull
40internetnull
41internetnull
42gprs.swisscom.chnull
43erainternetnull
44cmwapnull
45internetnull
46internetnull
47internetdefault
48mmsmms
49internetnull

Now, it's time to see whether or not changing APN of a carrier will do the trick. I appended all the APNs with a fixed suffix. For example, orange becomes "orange haha". Guess what, the logcat shows these messages to make me think I am doing the right thing.
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: epc.tmobile.com reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
D/TelephonyProvider(  620): Setting numeric '310260' to be the current operator
D/dalvikvm(  577): GREF has increased to 301
D/GpsLocationProvider(  577): state: DISCONNECTED apnName: null reason: apnChanged
...
And I went to open a URL link in Browser and it can't receive any data from internet.

Next, I'm gonna to test it on my Magic. :)