Android 内置群组,联系人
这样一个需求,手机第一次启动的时候,需要内置一个群组,并且里面有给定的联系人信息,
本来打算写双进程守护的,结果昨天接到一个这样的任务,就先把它做了,发现里面有些操作数据库的东西还是值得看一下。
首先接到这样一个需求第一眼就是懵逼,然后还是得硬着头皮搞,接下来分析下这个需求需要怎么搞:
1、首先第一次启动 Android 有一个开机启动的广播;
2、启动后去内置一个群组;
3、内置客户给的联系人;
4、把联系人加到群组里面。
根据这四个步骤我们来一步一步搞定(透漏一下这篇文章的精华所在 就是最后一步把联系人加到群组里面 这个网上找了好久都没找到)
1、开机启动广播
由于我是基于源码开发的即在android原生的contacts进行修改
android源码中应用层关于contacts的代码位于
packages\apps\Contacts
packages\apps\ContactsCommon
这两个地方
基于源码开发一般先要看看源码中有没有我们需要的开机广播有的话我们就不需要重新去写这些代码了,一方面省事,另一方面既然源码里面已经有
了,我们在去重新写 会显得代码比较混乱。
通过搜索发现有这样一个类BootCmpReceiver.java
中有接受开机广播的地方
else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
// fix ALPS01003520,when boot complete,remove the contacts if the
// card of a slot has been removed
if (!isPhbReady()) {
processBootComplete(context);
}
// [START] add for Preset service number
presetServiceNumber(context);
// [END]
}
private void presetServiceNumber(Context context) {
SIMProcessorBase processor = null;
LogUtils.d(TAG, "presetServiceNumber");
// processor = new PresetContactsImportProcessor(context, -1, null, null);
startSimService(context, -1, SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS);
}
private void startSimService(Context context, int subId, int workType) {
Intent intent = null;
intent = new Intent(context, SIMProcessorService.class);
intent.putExtra(SIMServiceUtils.SERVICE_SUBSCRIPTION_KEY, subId);
intent.putExtra(SIMServiceUtils.SERVICE_WORK_TYPE, workType);
LogUtils.d(TAG, "[startSimService]subId:" + subId + "|workType:" + workType);
context.startService(intent);
}
所以我在其中加了这几段启动服务的代码 看这代码结构也许跟google原生的不一样这是我们公司修修改改后的结果 我们主要分析原理
首先找到开机广播 在里面加入我们的函数presetServiceNumber(context) 然后开启服务去执行我们的内置群组、联系人的操作
2、 内置群组
private void addDefaultGroups() {
Uri uri = Groups.CONTENT_URI;
StringBuilder selection = new StringBuilder();
selection.append(Groups.DELETED + "=0");
selection.append(" AND " + Groups.TITLE + "='" + "ROAMING" + "'");
Cursor groupCursor = mContext.getContentResolver().query(uri,
new String[] { Groups._ID, Groups.TITLE }, selection.toString(), null, null);
try {
if (groupCursor != null && groupCursor.getCount() > 0) {
return;
} else {
String defaultGroups[] = "ROAMING";
final ArrayList operationList = new ArrayList();
ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(uri);
ContentValues groupValues = new ContentValues();
groupValues.put(Groups.ACCOUNT_NAME,AccountType.ACCOUNT_NAME_LOCAL_PHONE);
groupValues.put(Groups.ACCOUNT_TYPE,AccountType.ACCOUNT_TYPE_LOCAL_PHONE);
groupValues.put(Groups.TITLE, defaultGroups);
groupValues.put(Groups.GROUP_IS_READ_ONLY, 1);
builder.withValues(groupValues);
operationList.add(builder.build());
try {
mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
groupValues.clear();
operationList.clear();
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
}
}
} finally {
if (groupCursor != null) {
groupCursor.close();
}
}
}
去掉不相关的代码这就是我们内置群组的核心代码,
看上面代码 首先我们去查询群组名为“ROAMING”的群组是否存在。
当Groups.DELETED=0的时候, 是 查询没有被删除的联系人分组
当Groups.DELETED=1的时候,是查询删除的分组
如果存在就return了,不存在我们就是新建,新建群组的大部分都都相似主要是
groupValues.put(Groups.TITLE, defaultGroups); //群组的TITLE
groupValues.put(Groups.GROUP_IS_READ_ONLY, 1); //是否只读
3、内置联系人
private void importDefaultReadonlyContact(){
for(int i = 0;i < INSERT_PRESET_NAME.length; i++) {
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(INSERT_PRESET_NUMBER[i]));
Cursor contactCursor = mContext.getContentResolver().query(uri,
new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup.PHOTO_ID}, null, null, null);
try {
if (contactCursor != null && contactCursor.getCount() > 0) {
return;
} else {
final ArrayList operationList = new ArrayList();
ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
ContentValues contactvalues = new ContentValues();
contactvalues.put(RawContacts.ACCOUNT_NAME, AccountType.ACCOUNT_NAME_LOCAL_PHONE);
contactvalues.put(RawContacts.ACCOUNT_TYPE, AccountType.ACCOUNT_TYPE_LOCAL_PHONE);
contactvalues.put(RawContacts.INDICATE_PHONE_SIM, ContactsContract.RawContacts.INDICATE_PHONE);
contactvalues.put(RawContacts.IS_SDN_CONTACT, -2);
builder.withValues(contactvalues);
builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
operationList.add(builder.build());
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
builder.withValue(Phone.TYPE, Phone.TYPE_MOBILE);
builder.withValue(Phone.NUMBER, INSERT_PRESET_NUMBER[i]);
builder.withValue(Data.IS_PRIMARY, 1);
operationList.add(builder.build());
builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
builder.withValue(StructuredName.DISPLAY_NAME, INSERT_PRESET_NAME[i]);
operationList.add(builder.build());
try {
mContext.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operationList);
} catch (RemoteException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
} catch (OperationApplicationException e) {
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
}
}
} finally {
if (contactCursor != null) {
contactCursor.close();
}
}
}
}
去掉不相关的代码这就是我们内置联系人的核心代码 其中INSERT_PRESET_NUMBER是我们的联系人号码数组可以写 如{“185…..”,”158…..”,”137….”}等
INSERT_PRESET_NAME是联系人姓名数组可以写 如{“张三”,“李四”,“王五”}等
首先也是查询数据库看看我们的联系人号码是否存在,存在的话就 return
不存在的话就去创建
联系人的操作大部分也都是一样的
主要是
builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE); //MIME类型
builder.withValue(Phone.TYPE, Phone.TYPE_MOBILE);//phone类型可以是 号码 姓名之类的
builder.withValue(Phone.NUMBER, INSERT_PRESET_NUMBER[i]);//号码
builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE); //MIME类型
builder.withValue(StructuredName.DISPLAY_NAME, INSERT_PRESET_NAME[i]);//姓名
还可以加入邮箱之类的,
builder.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE); //MIME类型
builder.withValue(Email.TYPE, Email.TYPE_MOBILE);//Email类型
builder.withValue(Email.DATA, email);//EMail
4、把联系人加到群组里面。
怎么把联系人加入到群组呢
有两种方法 第一种是内置联系人是 在联系人中加入群组标示;
第二中是内置群组后,把联系人批量导入群组
我们今天用第一种方式实现:
首先看联系人的操作
builder.withValue(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);//MIME类型
builder.withValue(GroupMembership.GROUP_ROW_ID, grpId);//群组
我们可以通过这样把联系人加如群组标签
所以这里我们关键的操作就是找到grpId即我们要加入群组ID
Uri urigroup = Groups.CONTENT_URI;
StringBuilder selection = new StringBuilder();
selection.append(Groups.DELETED + "=0");
selection.append(" AND " + Groups.TITLE + "='" + "ROAMING CUSTOMER CARE" + "'");
Cursor groupCursor = mContext.getContentResolver().query(urigroup,
new String[] { Groups._ID, Groups.TITLE }, selection.toString(), null, null);
try {
if(groupCursor!=null && groupCursor.getCount()>0 ){
while (groupCursor.moveToNext()) {
grpId = groupCursor.getLong(groupCursor.getColumnIndex(Groups._ID));
}
}else{
addDefaultGroups();
}
}finally {
if (groupCursor != null) {
groupCursor.close();
}
}
跟内置群组操作差不多一样但是这么我们如果查询到的话就取出这个群组的id如果不存在就是内置群组,
经过上面这四步我们就能顺利的吧联系人内置到群组里面了。
Android 内置群组,联系人的更多相关文章
- 写一个android内置android程序
当我们编译完毕android源代码之后,就须要对他做点什么事情,我如今正在看老罗的"Android源代码情景分析"一书.在这里主要是记录一些书中没有说清楚的地方. 相同.我们创建一 ...
- Android内置和外置SD卡的位置获取
public class StorageUtils { private static String TAG="123"; // 获取主存储卡路径 内置内存卡路径 public st ...
- android 内置视频目录
在做引导界面的时候有一个视频文件, 把它放在res/raw目录下面. 引用方法 如下: videoView = (VideoView) findViewById(R.id.video_view); v ...
- Android之Socket群组聊天
在这只做了一个简单的例子,没有用到数据库,思路就是客户端发送信息到服务器端,服务器端转发所有数据到客户端,校验服务器端发来消息是否是自己发出的,如果是自己发出的,则不显示自己的消息 贴一下Androi ...
- Android内置下拉刷新组件SwipeRefreshLayout
也许下拉刷新之前,你可能会使用一些第三方的开源库,例如PullToRefresh, ActionBar-PullToRefresh等待,但现在有的正式组成部分---SwipeRefreshLayout ...
- 【Android】16.5 Android内置的系统服务
分类:C#.Android.VS2015: 创建日期:2016-03-01 一.简介 实际上,在Android.Content.Context类中,Android已经提供了多种类型的系统服务,这些服务 ...
- 【Android】18.1 利用安卓内置的定位服务实现位置跟踪
分类:C#.Android.VS2015: 创建日期:2016-03-04 一.安卓内置的定位服务简介 通常将各种不同的定位技术称为位置服务或定位服务.这种服务是通过电信运营商的无线电通信网络(如GS ...
- 【Android】9.2 内置行视图的分类和呈现效果
分类:C#.Android.VS2015: 创建日期:2016-02-18 一.简介 Android内置了很多行视图模板,在应用程序中可直接使用这些内置的视图来呈现列表项. 要在ListView中使用 ...
- adb将Apk内置到系统中(system/priv-app)
https://blog.csdn.net/starhosea/article/details/78697007 so文件的处理是目前遇到过的问题.文章中解释了. 正文: 有时候我们在Android ...
随机推荐
- Ubuntu Sublime 配置
p { margin-bottom: 0.25cm; line-height: 120% } a:link { } 2018.4.14 Ubuntu Sublime 配置 承 Ubuntu Apach ...
- es6第一章 continue
块级作用域 ES6内允许块级作用域任意嵌套 {{{{let insane = 'Hello World'}}}} 这段代码使用了一个五层的作用域. {{{{ {let c = ''hello worl ...
- javaIO流--Writer,Reader
Writer /** *<li> Writer中定义的一个重要的方法: * public void writer(String str)throws IOException; */ pac ...
- 第一章 搭建一个通用的.net core项目框架
项目目标部署环境:CentOS 7+ 项目技术点:.netcore2.0 + Autofac +webAPI + NHibernate5.1 + mysql5.6 + nginx 开源地址:https ...
- Oracle RAC环境下定位并杀掉最终阻塞的会话-续
之前在<Oracle RAC环境下定位并杀掉最终阻塞的会话>中,最终使用一个SQL查询出RAC实例之间的所有阻塞关系.但是实际在某些极端的生产环境,是不允许执行复杂的SQL语句,即使允许执 ...
- ●洛谷P3687 [ZJOI2017]仙人掌
题链: https://www.luogu.org/problemnew/show/P3687题解: 计数DP,树形DP. (首先对于这个图来说,如果初始就不是仙人掌,那么就直接输出0) 然后由于本来 ...
- Codeforces Round #411 (Div. 1) D. Expected diameter of a tree
题目大意:给出一个森林,每次询问给出u,v,问从u所在连通块中随机选出一个点与v所在连通块中随机选出一个点相连,连出的树的直径期望(不是树输出-1).(n,q<=10^5) 解法:预处理出各连通 ...
- codeforces round #419 C. Karen and Game
C. Karen and Game time limit per test 2 seconds memory limit per test 512 megabytes input standard i ...
- ●BZOJ 4710 [Jsoi2011]分特产
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4710 题解: 容斥,组合先看看这个方案数的计算:把 M 个相同的东西分给 N 个人,每个人可 ...
- hdu 3016 dp+线段树
Man Down Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...