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

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

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

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. [LeetCode] Array Nesting 数组嵌套

    A zero-indexed array A consisting of N different integers is given. The array contains all integers ...

  2. EventBus InMemory 的实践基于eShopOnContainers (二)

    前言 最近在工作中遇到了一个需求,会用到EventBus,正好看到eShopOnContainers上有相关的实例,去研究了研究.下面来分享一下用EventBus 来改造一下我们上篇Event发布与实 ...

  3. 洛谷P3209 [HNOI2010]PLANAR

    首先用一波神奇的操作,平面图边数m<=3*n-6,直接把m降到n, 然后对于冲突的边一条环内,一条环外,可以用并查集或者2Sat做, 当然并查集是无向的,2Sat是有向的,显然用并查集比较好 复 ...

  4. 【HNOI2017】大佬

    题目描述 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语. 你作为一个 OIER,面对这样的事情非常不开心,于 ...

  5. poj3580 splay树 REVOVLE循环

    SuperMemo Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 12795   Accepted: 3989 Case T ...

  6. javascript 手势(swipeLeft,swipeRight)滑动中使用css3动画卡顿,开启硬件加速

    今天,在做一个移动端项目,遇到了css3动画卡顿的现象. 例图: 在手势滑动中(swipeLeft,swipeRight)遇到了动画卡顿的现象,最后使用了css3动画-webkit-transform ...

  7. Windows2003无法连接远程桌面问题 解决方法!

    按照以下步骤来一一排除问题吧!  步骤1.遇到这样的情况,通常情况下我们都是先检查远程有没有开启,就是右击我的电脑查看属性里的远程前面的框框有没有勾上,勾上后即可远程,metsc 127.0.0.1 ...

  8. ionic3-ng4学习见闻--(自定义ion-tab图标)

    学习混合开发语言,目的就是为了快速开发一个适用于多平台的app. app基本都会有footer,也就是tabbar,用来快速导航不同的页面. ionic也有这个组件,ion-tab. 常用方法如下: ...

  9. 使用foreach需要判空。

    今天写代码的时候,需要遍历一个作为参数传递进来的容器, 当时顺手就加上了判空条件: if(null==list)return; 后来就像,不知道遍历(foreach)有没有帮我做这个工作: 下面看实验 ...

  10. 四柱加强版汉诺塔HanoiTower----是甜蜜还是烦恼

    我想很多人第一次学习递归的时候,老师或者书本上可能会举汉诺塔的例子. 但是今天,我们讨论的重点不是简单的汉诺塔算法,而是三柱汉诺塔的延伸.先来看看经典的三柱汉诺塔. 一.三柱汉诺塔(Hanoi_Thr ...