您的位置:首页 > 移动开发 > Android开发

【Android 数据业务解析】PreferredApn修改的源码分析

2017-07-16 12:23 459 查看
DcTracker中需要去获取preferredapn的id以及修改preferredapn的id,涉及到两个方法的使用,如下:

getPreferredApn方法
// 得到preferredapn的方法
private ApnSetting getPreferredApn() {
if (mAllApnSettings == null || mAllApnSettings.isEmpty()) { // 为空判断
log("getPreferredApn: mAllApnSettings is " + ((mAllApnSettings == null)?"null":"empty"));
return null;
}

String subId = Long.toString(mPhone.getSubId());
Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId);
// 从数据库中读取preferredapn
Cursor cursor = mPhone.getContext().getContentResolver().query(
uri, new String[] { "_id", "name", "apn" },
null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);

if (cursor != null) {
mCanSetPreferApn = true;
} else {
mCanSetPreferApn = false;
}
// mRequestedApnType就是PhoneConstants.APN_TYPE_DEFAULT
log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor
+ " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0));

if (mCanSetPreferApn && cursor.getCount() > 0) {
int pos;
cursor.moveToFirst();
// 获取preferredapn在数据库中的id号
pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
for(ApnSetting p : mAllApnSettings) {
log("getPreferredApn: apnSetting=" + p);
// 遍历apn集合,存在id相同,并且apn type符合preferredapn的要求时,则返回给preferredapn
if (p.id == pos && p.canHandleType(mRequestedApnType)) {
log("getPreferredApn: X found apnSetting" + p);
cursor.close();
return p;
}
}
}

if (cursor != null) {
cursor.close();
}

log("getPreferredApn: X not found");
return null;
}
setPreferredApn方法

// 更新数据库中保存的preferredapn的id
private void setPreferredApn(int pos) {
if (!mCanSetPreferApn) {
log("setPreferredApn: X !canSEtPreferApn");
return;
}

// 由于id只有一个,所以首先要删除过去的id
String subId = Long.toString(mPhone.getSubId());
// 注意PREFERAPN_NO_UPDATE_URI_USING_SUBID中包含了NO_UPDATE,说明此修改无需将数据库的变化通知相应的监听器
Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId);
log("setPreferredApn: delete");
ContentResolver resolver = mPhone.getContext().getContentResolver();
// 删除数据库中的数据
resolver.delete(uri, null, null);

if (pos >= 0) {
// 如果pos为-1,则不执行插入,否则插入新的preferredapn,pos即为id
log("setPreferredApn: insert");
ContentValues values = new ContentValues();
values.put(APN_ID, pos); // APN_ID = "apn_id"
resolver.insert(uri, values);
}
}

涉及到ContentProvider的query、delete和insert方法。而该ContentProvider对应的是TelephonyProvider。
因而query、delete和insert方法最终会调用到TelephonyProvider这个类的对应方法。

下面来看下TelephonyProvider这个类。
query方法:
@Override
public synchronized Cursor query(Uri url, String[] projectionIn, String selection,
String[] selectionArgs, String sort) {
if (VDBG) log("query: url=" + url + ", projectionIn=" + projectionIn + ", selection="
+ selection + "selectionArgs=" + selectionArgs + ", sort=" + sort);
TelephonyManager mTelephonyManager =
(TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE);
int subId = SubscriptionManager.getDefaultSubId();
String subIdString;
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
qb.setStrict(true); // a little protection from injection attacks
qb.setTables(CARRIERS_TABLE);

// 匹配URI
int match = s_urlMatcher.match(url);
switch (match) {
... ...

// preferredapn的处理
case URL_PREFERAPN_USING_SUBID:
case URL_PREFERAPN_NO_UPDATE_USING_SUBID: {
// 获取subid
subIdString = url.getLastPathSegment();
try {
subId = Integer.parseInt(subIdString);
} catch (NumberFormatException e) {
loge("NumberFormatException" + e);
return null;
}
if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
}
//intentional fall through from above case
case URL_PREFERAPN:
case URL_PREFERAPN_NO_UPDATE: {
qb.appendWhere("_id = " + getPreferredApnId(subId));
break;
}
... ...

default: {
return null;
}
}

if (match != URL_SIMINFO) {
if (projectionIn != null) {
for (String column : projectionIn) {
if (Telephony.Carriers.TYPE.equals(column) ||
Telephony.Carriers.MMSC.equals(column) ||
Telephony.Carriers.MMSPROXY.equals(column) ||
Telephony.Carriers.MMSPORT.equals(column) ||
Telephony.Carriers.APN.equals(column)) {
// noop
} else {
checkPermission();
break;
}
}
} else {
// null returns all columns, so need permission check
checkPermission();
}
}

// 获取操作数据库的对象
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor ret = null;
try {
// Exclude entries marked deleted
if (CARRIERS_TABLE.equals(qb.getTables())) {
if (TextUtils.isEmpty(selection)) {
selection = "";
} else {
selection += " and ";
}
selection += "edited!=" + Telephony.Carriers.USER_DELETED + " and edited!="
+ Telephony.Carriers.USER_DELETED_BUT_PRESENT_IN_XML + " and edited!="
+ Telephony.Carriers.CARRIER_DELETED + " and edited!="
+ Telephony.Carriers.CARRIER_DELETED_BUT_PRESENT_IN_XML;
if (VDBG) log("query: selection modified to " + selection);
}
// 从数据库中查询_id = getPreferredApnId(subId)的对象
ret = qb.query(db, projectionIn, selection, selectionArgs, null, null, sort);
} catch (SQLException e) {
loge("got exception when querying: " + e);
}
if (ret != null)
ret.setNotificationUri(getContext().getContentResolver(), url);
return ret;
}

// 从preferred-apn.xml中读取出键"apn_id"+subId的值
private long getPreferredApnId(int subId) {
SharedPreferences sp = getContext().getSharedPreferences(
PREF_FILE, Context.MODE_PRIVATE);
return sp.getLong(COLUMN_APN_ID + subId, -1);
}

在查询preferredapn的过程中,先从preferred-apn.xml中读取出键值,该键值存储的是preferredapn的id号。然后在将id号作为where条件,从数据库的carriers表中读取出符合要求的对象,然后返回。

preferred-apn.xml文件的默认路径为:/data/data/com.android.providers.telephony/shared_prefs/
该xml文件的内容为:



上面的是从模拟器中导出来的,因为是单卡,所以不带id。

delete方法:
@Override
public synchronized int delete(Uri url, String where, String[] whereArgs)
{
// 复位,用于告知监听器数据库发生了变化
int count = 0;
// 获取卡的id
int subId = SubscriptionManager.getDefaultSubId();
String userOrCarrierEdited = ") and (" +
Telephony.Carriers.EDITED + "=" + Telephony.Carriers.USER_EDITED +  " or " +
Telephony.Carriers.EDITED + "=" + Telephony.Carriers.CARRIER_EDITED + ")";
String notUserOrCarrierEdited = ") and (" +
Telephony.Carriers.EDITED + "!=" + Telephony.Carriers.USER_EDITED +  " and " +
Telephony.Carriers.EDITED + "!=" + Telephony.Carriers.CARRIER_EDITED + ")";
ContentValues cv = new ContentValues();
cv.put(Telephony.Carriers.EDITED, Telephony.Carriers.USER_DELETED);

checkPermission();

SQLiteDatabase db = mOpenHelper.getWritableDatabase();
// 匹配URI
int match = s_urlMatcher.match(url);
switch (match)
{
... ...

// preferredapn的操作在此处
case URL_PREFERAPN_USING_SUBID:
case URL_PREFERAPN_NO_UPDATE_USING_SUBID: {
// 获取subid
String subIdString = url.getLastPathSegment();
try {
subId = Integer.parseInt(subIdString);
} catch (NumberFormatException e) {
loge("NumberFormatException" + e);
throw new IllegalArgumentException("Invalid subId " + url);
}
if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
}
//intentional fall through from above case
// 中间无break,继续执行
case URL_PREFERAPN:
case URL_PREFERAPN_NO_UPDATE:
{
// 将xml文件中preferredapn的id置为-1
setPreferredApnId((long)-1, subId);
// 如果url匹配到的是URL_PREFERAPN或者URL_PREFERAPN_USING_SUBID时,说明需要通知相应的监听器,数据库发生了变化
if ((match == U
a94e
RL_PREFERAPN) || (match == URL_PREFERAPN_USING_SUBID)) count = 1;
break;
}

... ...

default: {
throw new UnsupportedOperationException("Cannot delete that URL: " + url);
}
}

// 通知相应的监听器,数据库发生变化
if (count > 0) {
getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null,
true, UserHandle.USER_ALL);
}

return count;
}

// 将preferred-apn.xml中的preferredapn的id置为id
private void setPreferredApnId(Long id, int subId) {
SharedPreferences sp = getContext().getSharedPreferences(
PREF_FILE, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
// COLUMN_APN_ID = "apn_id"
editor.putLong(COLUMN_APN_ID + subId, id != null ? id.longValue() : -1);
editor.apply();
}

delete方法是将preferred-apn.xml中的键值修改为-1,-1肯定不是数据库中的id。

insert方法
@Override
public synchronized Uri insert(Uri url, ContentValues initialValues)
{
Uri result = null;
int subId = SubscriptionManager.getDefaultSubId();

checkPermission();

SQLiteDatabase db = mOpenHelper.getWritableDatabase();
// 匹配URI
int match = s_urlMatcher.match(url);
boolean notify = false;
switch (match)
{
... ...

// preferredapn的操作
case URL_PREFERAPN_USING_SUBID:
case URL_PREFERAPN_NO_UPDATE_USING_SUBID:
{
// 获取subid
String subIdString = url.getLastPathSegment();
try {
subId = Integer.parseInt(subIdString);
} catch (NumberFormatException e) {
loge("NumberFormatException" + e);
return result;
}
if (DBG) log("subIdString = " + subIdString + " subId = " + subId);
}
//intentional fall through from above case

case URL_PREFERAPN:
case URL_PREFERAPN_NO_UPDATE:
{
if (initialValues != null) {
// 查看ContentValues中是否包含"apn_id"的键
if(initialValues.containsKey(COLUMN_APN_ID)) {
// 将preferredapn的id更新到数据库中
setPreferredApnId(initialValues.getAsLong(COLUMN_APN_ID), subId);
}
}
break;
}

... ...
}

if (notify) {
getContext().getContentResolver().notifyChange(Telephony.Carriers.CONTENT_URI, null,
true, UserHandle.USER_ALL);
}

return result;
}

同样也是调用setPreferredApnId方法,将键值修改为指定的id。

在DcTracker.java中,
static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID =
Uri.parse("content://telephony/carriers/preferapn_no_update/subId/");

在TelephonyProvider.java中,

s_urlMatcher.addURI("telephony", "carriers/preferapn", URL_PREFERAPN);
s_urlMatcher.addURI("telephony", "carriers/preferapn_no_update", URL_PREFERAPN_NO_UPDATE);
s_urlMatcher.addURI("telephony", "carriers/preferapn/subId/*", URL_PREFERAPN_USING_SUBID);
s_urlMatcher.addURI("telephony", "carriers/preferapn_no_update/subId/*", URL_PREFERAPN_NO_UPDATE_USING_SUBID);
总结:
在获取和修改preferredapn时,最终都是通过处理preferred-apn.xml中的键值来做到的,Google给这个处理加了一个很好的封装。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: