这样一个需求,手机第一次启动的时候,需要内置一个群组,并且里面有给定的联系人信息,

本来打算写双进程守护的,结果昨天接到一个这样的任务,就先把它做了,发现里面有些操作数据库的东西还是值得看一下。

首先接到这样一个需求第一眼就是懵逼,然后还是得硬着头皮搞,接下来分析下这个需求需要怎么搞:

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 内置群组,联系人的更多相关文章

  1. 写一个android内置android程序

    当我们编译完毕android源代码之后,就须要对他做点什么事情,我如今正在看老罗的"Android源代码情景分析"一书.在这里主要是记录一些书中没有说清楚的地方. 相同.我们创建一 ...

  2. Android内置和外置SD卡的位置获取

    public class StorageUtils { private static String TAG="123"; // 获取主存储卡路径 内置内存卡路径 public st ...

  3. android 内置视频目录

    在做引导界面的时候有一个视频文件, 把它放在res/raw目录下面. 引用方法 如下: videoView = (VideoView) findViewById(R.id.video_view); v ...

  4. Android之Socket群组聊天

    在这只做了一个简单的例子,没有用到数据库,思路就是客户端发送信息到服务器端,服务器端转发所有数据到客户端,校验服务器端发来消息是否是自己发出的,如果是自己发出的,则不显示自己的消息 贴一下Androi ...

  5. Android内置下拉刷新组件SwipeRefreshLayout

    也许下拉刷新之前,你可能会使用一些第三方的开源库,例如PullToRefresh, ActionBar-PullToRefresh等待,但现在有的正式组成部分---SwipeRefreshLayout ...

  6. 【Android】16.5 Android内置的系统服务

    分类:C#.Android.VS2015: 创建日期:2016-03-01 一.简介 实际上,在Android.Content.Context类中,Android已经提供了多种类型的系统服务,这些服务 ...

  7. 【Android】18.1 利用安卓内置的定位服务实现位置跟踪

    分类:C#.Android.VS2015: 创建日期:2016-03-04 一.安卓内置的定位服务简介 通常将各种不同的定位技术称为位置服务或定位服务.这种服务是通过电信运营商的无线电通信网络(如GS ...

  8. 【Android】9.2 内置行视图的分类和呈现效果

    分类:C#.Android.VS2015: 创建日期:2016-02-18 一.简介 Android内置了很多行视图模板,在应用程序中可直接使用这些内置的视图来呈现列表项. 要在ListView中使用 ...

  9. adb将Apk内置到系统中(system/priv-app)

    https://blog.csdn.net/starhosea/article/details/78697007 so文件的处理是目前遇到过的问题.文章中解释了. 正文: 有时候我们在Android ...

随机推荐

  1. U盘分区后合并

    1.首先把你的U盘插在电脑上,点击开始→所有程序→附件→命令提示符(前面这步骤也可以直接用Win+R组合键打开"运行",之后输入cmd也可打开命令提示符). 2.然后在命令提示窗口 ...

  2. 开源协议瞎扯淡,什么是 MIT 协议?[转]

    图片来源:http://ruby-china.org/topics/15979

  3. LeakCanary检测内存泄漏.md

    一使用步骤 添加依赖 // 内存泄漏检测 debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4' releaseCompile ...

  4. 设计APP时我们该怎么做

    不得不承认,手机APP已经渗透到我们的生活中,根据数据统计,人们每天平均有3.9个小时是花费在手机APP的使用上的,可以预见,手机APP正在改变我们的生活.手机APP受到人们的欢迎,很多商家也看到了其 ...

  5. mysql用limit时offset越大时间越长

    首先说明一下MySQL的版本:mysql> select version();+-----------+| version() |+-----------+| 5.7.17    |+----- ...

  6. python内置方法

    1. 简介 本指南归纳于我的几个月的博客,主题是 魔法方法 . 什么是魔法方法呢?它们在面向对象的Python的处处皆是.它们是一些可以让你对类添加"魔法"的特殊方法. 它们经常是 ...

  7. python 随笔

    python 学习笔记 运算符重载 PYTHON-进阶-魔术方法小结(方法运算符重载) python有着像C++相似的运算符重载,只需要在类中重写__add__.sub 等方法,就可以直接对对象进行 ...

  8. 参考用bat文件

    @echo off rem *************** start of 'main' set DEBUG= " (set TRACE=echo) else (set TRACE=rem ...

  9. [Luogu 1410]子序列

    Description 给定一个长度为N(N为偶数)的序列,问能否将其划分为两个长度为N/2的严格递增子序列, Input 若干行,每行表示一组数据.对于每组数据,首先输入一个整数N,表示序列的长度. ...

  10. STL rope

    rope的部分简单操作 函数 功能 push_back(x) 在末尾添加x insert(pos,x) 在pos插入x erase(pos,x) 从pos开始删除x个 replace(pos,x) 从 ...