【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方法:
在查询preferredapn的过程中,先从preferred-apn.xml中读取出键值,该键值存储的是preferredapn的id号。然后在将id号作为where条件,从数据库的carriers表中读取出符合要求的对象,然后返回。
preferred-apn.xml文件的默认路径为:/data/data/com.android.providers.telephony/shared_prefs/
该xml文件的内容为:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201707/b564c32aed64d062536a7dc32b5f8a04)
上面的是从模拟器中导出来的,因为是单卡,所以不带id。
delete方法:
delete方法是将preferred-apn.xml中的键值修改为-1,-1肯定不是数据库中的id。
insert方法
同样也是调用setPreferredApnId方法,将键值修改为指定的id。
在DcTracker.java中,
在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给这个处理加了一个很好的封装。
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给这个处理加了一个很好的封装。
相关文章推荐
- android源码分析--MMS data 数据模型及业务逻辑transaction
- android_launcher的源码详细分析和壁纸修改
- Android Launcher分析和修改4——初始化加载数据
- 函数数据Android(2.3+)源码分析MediaPlayer之RTSP
- Android恢复出厂设置流程分析【Android源码解析十】
- android smack源码分析——接收消息以及如何解析消息
- android_launcher的源码详细分析和壁纸修改
- [Android源码解析]蓝牙扫描结果反馈的分析
- Android源码分析之---View.MeasureSpec 解析
- Android恢复出厂设置流程分析【Android源码解析十】
- Android恢复出厂设置流程分析【Android源码解析十】
- android 系统上做GC双模的---数据业务的处理分析
- android源码解析------Media多媒体framework层分析
- Android恢复出厂设置流程分析【Android源码解析十】
- android smack源码分析——接收消息以及如何解析消息
- android smack源码分析——接收消息以及如何解析消息【3】
- [Android源码分析]蓝牙文件传输过程解析之UI实现
- Discuz源码分析--数据库各数据表解析&各字段的用途
- android 系统上做GC双模的---数据业务的处理分析
- Hadoop源码分析HDFS Client向HDFS写入数据的过程解析