【Android 数据业务解析】PreferredApn修改的源码分析
来源:互联网 发布:男包品牌 知乎 编辑:程序博客网 时间:2024/05/27 20:04
DcTracker中需要去获取preferredapn的id以及修改preferredapn的id,涉及到两个方法的使用,如下:
在TelephonyProvider.java中,
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的idprivate 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方法:
@Overridepublic 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方法:
@Overridepublic 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 == URL_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置为idprivate 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方法
@Overridepublic 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给这个处理加了一个很好的封装。
阅读全文
0 0
- 【Android 数据业务解析】PreferredApn修改的源码分析
- 【Android 数据业务解析】nwTypeChanged引发的原因
- Android 数据业务框架分析<一>
- Android 数据业务框架分析<三>
- 【Android 数据业务解析】APN参数创建
- android 系统数据业务---模式切换分析(上)
- android 系统数据业务---模式切换分析(下)
- 谈数据业务的漫游时解析 APN
- android 系统上做GC双模的---数据业务的处理分析
- android 系统上做GC双模的---数据业务的处理分析
- 四、 Android 数据业务APN参数的创建
- Android 5.0源码解析 ---Activity源码分析
- [Android源码解析]Eventloop在jni层的分析
- [Android源码解析]蓝牙扫描结果反馈的分析
- Android源码解析之Dalvik虚拟机的启动过程分析
- Android数据业务发起流程
- Android N数据业务总结
- android 系统数据业务---打开
- 怎样花两年时间去面试一个人
- onTouch事件的传递机制
- 代理模式
- Qt中插入图片
- windows搭建基于nginx的本地web前后端开发环境
- 【Android 数据业务解析】PreferredApn修改的源码分析
- caffe学习资料整理
- Latex写作的入门使用
- HTML 2017.7.16
- nodejs密码加密中生成随机数
- Dating with girls(2) HDU
- 问题
- Spring Data Redis(Pipeling)
- Android BLE控制端