TelephonyProvider.java
package com.android.providers.telephony;
import android.content.*;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.Environment;
import android.provider.Telephony;
import android.util.Config;
import android.util.Log;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class TelephonyProvider extends ContentProvider
{
private static final String DATABASE_NAME = "telephony.db";
// DATABASE_VERSION needs to be in-sync with version in apns.xml.
private static final int DATABASE_VERSION = 4 << 16;
private static final int URL_TELEPHONY = 1;
private static final int URL_CURRENT = 2;
private static final int URL_ID = 3;
private static final String TAG = "TelephonyProvider";
private static final String CARRIERS_TABLE = "carriers";
private static final String PARTNER_APNS_PATH = "etc/apns-conf.xml";
private static final UriMatcher s_urlMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final ContentValues s_currentNullMap;
private static final ContentValues s_currentSetMap;
static {
s_urlMatcher.addURI("telephony", "carriers", URL_TELEPHONY);
s_urlMatcher.addURI("telephony", "carriers/current", URL_CURRENT);
s_urlMatcher.addURI("telephony", "carriers/#", URL_ID);
s_currentNullMap = new ContentValues(1);
s_currentNullMap.put("current", (Long) null);
s_currentSetMap = new ContentValues(1);
s_currentSetMap.put("current", "1");
}
private static class DatabaseHelper extends SQLiteOpenHelper {
// Context to access resources with
private Context mContext;
/**
* DatabaseHelper helper class for loading apns into a database.
*
* @param parser the system-default parser for apns.xml
* @param confidential an optional parser for confidential APNS (stored separately)
*/
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, getVersion(context));
mContext = context;
}
private static int getVersion(Context context) {
// Get the database version, combining a static schema version and the XML version
Resources r = context.getResources();
XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
try {
XmlUtils.beginDocument(parser, "apns");
int publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
return DATABASE_VERSION | publicversion;
} catch (Exception e) {
Log.e(TAG, "Can't get version of APN database", e);
return DATABASE_VERSION;
} finally {
parser.close();
}
}
@Override
public void onCreate(SQLiteDatabase db) {
// Set up the database schema
db.execSQL("CREATE TABLE " + CARRIERS_TABLE +
"(_id INTEGER PRIMARY KEY," +
"name TEXT," +
"numeric TEXT," +
"mcc TEXT," +
"mnc TEXT," +
"apn TEXT," +
"user TEXT," +
"server TEXT," +
"password TEXT," +
"proxy TEXT," +
"port TEXT," +
"mmsproxy TEXT," +
"mmsport TEXT," +
"mmsc TEXT," +
"type TEXT," +
"current INTEGER);");
// Read internal APNS data
Resources r = mContext.getResources();
XmlResourceParser parser = r.getXml(com.android.internal.R.xml.apns);
int publicversion = -1;
try {
XmlUtils.beginDocument(parser, "apns");
publicversion = Integer.parseInt(parser.getAttributeValue(null, "version"));
loadApns(db, parser);
} catch (Exception e) {
Log.e(TAG, "Got execption while loading APN database.", e);
} finally {
parser.close();
}
// Read external APNS data (partner-provided)
XmlPullParser confparser = null;
// Environment.getRootDirectory() is a fancy way of saying ANDROID_ROOT or "/system".
File confFile = new File(Environment.getRootDirectory(), PARTNER_APNS_PATH);
FileReader confreader = null;
try {
confreader = new FileReader(confFile);
confparser = Xml.newPullParser();
confparser.setInput(confreader);
XmlUtils.beginDocument(confparser, "apns");
// Sanity check. Force internal version and confidential versions to agree
int confversion = Integer.parseInt(confparser.getAttributeValue(null, "version"));
if (publicversion != confversion) {
throw new IllegalStateException("Internal APNS file version doesn't match "
+ confFile.getAbsolutePath());
}
loadApns(db, confparser);
} catch (FileNotFoundException e) {
// It's ok if the file isn't found. It means there isn't a confidential file
// Log.e(TAG, "File not found: '" + confFile.getAbsolutePath() + "'");
} catch (Exception e) {
Log.e(TAG, "Exception while parsing '" + confFile.getAbsolutePath() + "'", e);
} finally {
try { if (confreader != null) confreader.close(); } catch (IOException e) { }
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + CARRIERS_TABLE + ";");
onCreate(db);
}
/**
* Gets the next row of apn values.
*
* @param parser the parser
* @return the row or null if it's not an apn
*/
private ContentValues getRow(XmlPullParser parser) {
if (!"apn".equals(parser.getName())) {
return null;
}
ContentValues map = new ContentValues();
String mcc = parser.getAttributeValue(null, "mcc");
String mnc = parser.getAttributeValue(null, "mnc");
String numeric = mcc + mnc;
map.put(Telephony.Carriers.NUMERIC,numeric);
map.put(Telephony.Carriers.MCC, mcc);
map.put(Telephony.Carriers.MNC, mnc);
map.put(Telephony.Carriers.NAME, parser.getAttributeValue(null, "carrier"));
map.put(Telephony.Carriers.APN, parser.getAttributeValue(null, "apn"));
map.put(Telephony.Carriers.USER, parser.getAttributeValue(null, "user"));
map.put(Telephony.Carriers.SERVER, parser.getAttributeValue(null, "server"));
map.put(Telephony.Carriers.PASSWORD, parser.getAttributeValue(null, "password"));
// do not add NULL to the map so that insert() will set the default value
String proxy = parser.getAttributeValue(null, "proxy");
if (proxy != null) {
map.put(Telephony.Carriers.PROXY, proxy);
}
String port = parser.getAttributeValue(null, "port");
if (port != null) {
map.put(Telephony.Carriers.PORT, port);
}
String mmsproxy = parser.getAttributeValue(null, "mmsproxy");
if (mmsproxy != null) {
map.put(Telephony.Carriers.MMSPROXY, mmsproxy);
}
String mmsport = parser.getAttributeValue(null, "mmsport");
if (mmsport != null) {
map.put(Telephony.Carriers.MMSPORT, mmsport);
}
map.put(Telephony.Carriers.MMSC, parser.getAttributeValue(null, "mmsc"));
String type = parser.getAttributeValue(null, "type");
if (type != null) {
map.put(Telephony.Carriers.TYPE, type);
}
return map;
}
/*
* Loads apns from xml file into the database
*
* @param db the sqlite database to write to
* @param parser the xml parser
*
*/
private void loadApns(SQLiteDatabase db, XmlPullParser parser) {
if (parser != null) {
try {
while (true) {
XmlUtils.nextElement(parser);
ContentValues row = getRow(parser);
if (row != null) {
db.insert(CARRIERS_TABLE, null, row);
} else {
break; // do we really want to skip the rest of the file?
}
}
} catch (XmlPullParserException e) {
Log.e(TAG, "Got execption while getting perferred time zone.", e);
} catch (IOException e) {
Log.e(TAG, "Got execption while getting perferred time zone.", e);
}
}
}
}
@Override
public boolean onCreate() {
mOpenHelper = new DatabaseHelper(getContext());
return true;
}
@Override
public Cursor query(Uri url, String[] projectionIn, String selection,
String[] selectionArgs, String sort) {
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setTables("carriers");
int match = s_urlMatcher.match(url);
switch (match) {
// do nothing
case URL_TELEPHONY: {
break;
}
case URL_CURRENT: {
qb.appendWhere("current IS NOT NULL");
// ignore the selection
selection = null;
break;
}
case URL_ID: {
qb.appendWhere("_id = " + url.getPathSegments().get(1));
break;
}
default: {
return null;
}
}
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort);
ret.setNotificationUri(getContext().getContentResolver(), url);
return ret;
}
@Override
public String getType(Uri url)
{
switch (s_urlMatcher.match(url)) {
case URL_TELEPHONY:
return "vnd.android.cursor.dir/telephony-carrier";
case URL_ID:
return "vnd.android.cursor.item/telephony-carrier";
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
}
@Override
public Uri insert(Uri url, ContentValues initialValues)
{
Uri result = null;
checkPermission();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int match = s_urlMatcher.match(url);
boolean notify = false;
switch (match)
{
case URL_TELEPHONY:
{
ContentValues values;
if (initialValues != null) {
values = new ContentValues(initialValues);
} else {
values = new ContentValues();
}
// TODO Review this. This code should probably not bet here.
// It is valid for the database to return a null string.
if (values.containsKey(Telephony.Carriers.NAME) == false) {
values.put(Telephony.Carriers.NAME, "");
}
if (values.containsKey(Telephony.Carriers.APN) == false) {
values.put(Telephony.Carriers.APN, "");
}
if (values.containsKey(Telephony.Carriers.PORT) == false) {
values.put(Telephony.Carriers.PORT, "");
}
if (values.containsKey(Telephony.Carriers.PROXY) == false) {
values.put(Telephony.Carriers.PROXY, "");
}
if (values.containsKey(Telephony.Carriers.USER) == false) {
values.put(Telephony.Carriers.USER, "");
}
if (values.containsKey(Telephony.Carriers.SERVER) == false) {
values.put(Telephony.Carriers.SERVER, "");
}
if (values.containsKey(Telephony.Carriers.PASSWORD) == false) {
values.put(Telephony.Carriers.PASSWORD, "");
}
if (values.containsKey(Telephony.Carriers.MMSPORT) == false) {
values.put(Telephony.Carriers.MMSPORT, "");
}
if (values.containsKey(Telephony.Carriers.MMSPROXY) == false) {
values.put(Telephony.Carriers.MMSPROXY, "");
}
long rowID = db.insert(CARRIERS_TABLE, null, values);
if (rowID > 0)
{
result = ContentUris.withAppendedId(Telephony.Carriers.CONTENT_URI, rowID);
notify = true;
}
if (Config.LOGD) Log.d(TAG, "inserted " + values.toString() + " rowID = " + rowID);
break;
}
case URL_CURRENT:
{
// null out the previous operator
db.update("carriers", s_currentNullMap, "current IS NOT NULL", null);
String numeric = initialValues.getAsString("numeric");
int updated = db.update("carriers", s_currentSetMap,
"numeric = '" + numeric + "'", null);
if (updated > 0)
{
if (Config.LOGD) {
Log.d(TAG, "Setting numeric '" + numeric + "' to be the current operator");
}
}
else
{
Log.e(TAG, "Failed setting numeric '" + numeric + "' to the current operator");
}
break;
}
}
if (notify) {
getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null);
}
return result;
}
@Override
public int delete(Uri url, String where, String[] whereArgs)
{
int count;
checkPermission();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int match = s_urlMatcher.match(url);
switch (match)
{
case URL_TELEPHONY:
{
count = db.delete(CARRIERS_TABLE, where, whereArgs);
break;
}
case URL_CURRENT:
{
count = db.delete(CARRIERS_TABLE, where, whereArgs);
break;
}
case URL_ID:
{
count = db.delete(CARRIERS_TABLE, Telephony.Carriers._ID + "=?",
new String[] { url.getLastPathSegment() });
break;
}
default: {
throw new UnsupportedOperationException("Cannot delete that URL: " + url);
}
}
if (count > 0) {
getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null);
}
return count;
}
@Override
public int update(Uri url, ContentValues values, String where, String[] whereArgs)
{
int count;
checkPermission();
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
int match = s_urlMatcher.match(url);
switch (match)
{
case URL_TELEPHONY:
{
count = db.update(CARRIERS_TABLE, values, where, whereArgs);
break;
}
case URL_CURRENT:
{
count = db.update(CARRIERS_TABLE, values, where, whereArgs);
break;
}
case URL_ID:
{
if (where != null || whereArgs != null) {
throw new UnsupportedOperationException(
"Cannot update URL " + url + " with a where clause");
}
count = db.update(CARRIERS_TABLE, values, Telephony.Carriers._ID + "=?",
new String[] { url.getLastPathSegment() });
break;
}
default: {
throw new UnsupportedOperationException("Cannot update that URL: " + url);
}
}
if (count > 0) {
getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null);
}
return count;
}
private void checkPermission() {
// Check the permissions
getContext().enforceCallingOrSelfPermission("android.permission.WRITE_APN_SETTINGS",
"No permission to write APN settings");
}
private SQLiteOpenHelper mOpenHelper;
}
以上是TelephonyProvider的源代码
其实TelephonyProvider是一个工具类,封装了对数据库的操作,负责添加删除查询carriers 的信息。
com.android.providers.telephony.TelephonyProvider
com.android.providers.telephony.TelephonyProvider.delete(Uri, String, String[])
com.android.providers.telephony.TelephonyProvider.getType(Uri)
com.android.providers.telephony.TelephonyProvider.insert(Uri, ContentValues)
com.android.providers.telephony.TelephonyProvider.onCreate()
com.android.providers.telephony.TelephonyProvider.query(Uri, String[], String, String[], String)
com.android.providers.telephony.TelephonyProvider.update(Uri, ContentValues, String, String[])
现在就要找到调用情况,clone一个TelephonyProvider出来完成对phone2 相同的操作。