代码分为两部分:

Part One 将预置的联系人插入到数据库中;

Part Two 保证预置联系人仅仅读,无法被编辑删除(在三个地方屏蔽对预置联系人进行编辑处理:联系人详情界面、联系人多选界面、新建联系人选择合并联系人时)。

【注意】假设您不须要限制预置联系人的删除/编辑操作,增加Part One部分代码就可以,并去掉第三步”新增函数“  中的语句:contactvalues.put(RawContacts.IS_SDN_CONTACT, -1);

 

Part One:

File:AbstractStartSIMService.java

Path: alps\packages\apps\Contacts\src\com\mediatek\contacts\simcontact

 

1.引入包

import android.provider.ContactsContract.PhoneLookup;

 

2.添加变量

private static boolean sIsRunningNumberCheck = false;

private static final int INSERT_PRESET_NUMBER_COUNT = xxx;           //预置联系人的个数

private static final String  INSERT_PRESET_NAME[]    = {"xxx1","xxx2",...};  //各预置联系人的姓名 

private static final String  INSERT_PRESET_NUMBER[] = {"xxx1","xxx2",...};  //各预置联系人的号码

 

3.添加函数(将预置联系人信息写入数据库中):

  private void importDefaultReadonlyContact() {

      new Thread(new Runnable() {

 

          @Override

          public void run() {

              Log.i(TAG, "isRunningNumberCheck before: " + sIsRunningNumberCheck);

              if (sIsRunningNumberCheck) {

                   return;

              }

              sIsRunningNumberCheck = true;

              for(int i = 0;i < INSERT_PRESET_NUMBER_COUNT; i++)

              {

                Log.i(TAG, "isRunningNumberCheck after: " + sIsRunningNumberCheck);

                Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri

                        .encode(INSERT_PRESET_NUMBER[i]));

                Log.i(TAG, "getContactInfoByPhoneNumbers(), uri = " + uri);

 

                Cursor contactCursor = 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<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();

                        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, -1);

                        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 {

                            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 {

                    // when this service start,but the contactsprovider has not been started yet.

                    // the contactCursor perhaps null, but not always.(first load will weekup the provider)

                    // so add null block to avoid nullpointerexception

                    if (contactCursor != null) {

                        contactCursor.close();

                    }

                }

              }//for

              Log.i(TAG, "isRunningNumberCheck insert: " + sIsRunningNumberCheck);

              sIsRunningNumberCheck = false;

          }

      }).start();

 

  }

   

4.onStart中调用这个函数:

 

    public void onStart(Intent intent, int startId) {

        .....           

        //add by MTK---Preset Contacts

        importDefaultReadonlyContact();

           

        log("[onStart]" + intent + ", startId " + startId);

        if (intent == null) {

            return;

        }

        .....

}

 

Part Two

1.File:DefaultContactListAdapter.java  Path:alps\packages\apps\contacts\src\com\android\contacts\list

(1)configureSelection函数中有五处 RawContacts.IS_SDN_CONTACT + " = 0",都改为:RawContacts.IS_SDN_CONTACT + " < 1"

 

(2)configureOnlyShowPhoneContactsSelection函数中例如以下语句:

selection.append(Contacts.INDICATE_PHONE_SIM + "= ?");

        selectionArgs.add("-1");

之后添加以下的代码

selection.append(" AND " + RawContacts.IS_SDN_CONTACT + " > -1");

 

 

2.File:ProfileAndContactsLoader.java  Path:alps\packages\apps\contacts\src\com\android\contacts\list 

loadSDN函数中有两处 RawContacts.IS_SDN_CONTACT + " = 0",都改为:RawContacts.IS_SDN_CONTACT + " < 1"

 

3. File:Contact.java  Path:alps\packages\apps\contacts\src\com\android\contacts\model 

添加例如以下函数:

    //add by MTK---Preset Contacts

    public boolean isReadOnlyContact() {

             return mIsSdnContact == -1;

     }

 

4. File:ContactLoaderFragment.java Path:alps\packages\apps\contacts\src\com\android\contacts\detail 

将isContactEditable函数改动为:

   public boolean isContactEditable() {

        return mContactData != null && !mContactData.isDirectoryEntry()

                && !mContactData.isSdnContacts() &&  !mContactData.isReadOnlyContact() ;

    }

 

5. File:ContactEntryListAdapter.java Path:alps\packages\apps\contacts\src\com\android\contacts\list  

在文件最后添加下面代码:

    public boolean showReadOnlyContact = true;

    public void setShowReadOnlyContact(boolean canDelete) {

        showReadOnlyContact = canDelete;

    }

 

6. File:ContactEntryListFragment.java  Path:alps\packages\apps\contacts\src\com\android\contacts\list

引入例如以下包:

import com.mediatek.contacts.list.ContactsMultiDeletionFragment;

 

在onCreateLoader函数中。倒数第二句mAdapter.configureLoader(loader, directoryId);之前添加语句:   

            mAdapter.setShowReadOnlyContact((this instanceof ContactsMultiDeletionFragment) ?

false : true);

 

8 7.File:MultiContactsBasePickerAdapter.java Path:alps\packages\apps\contacts\src\com\mediatek\contacts\list  在configureSelection函数最后的语句 loader.setSelection(selection.toString());之前添加语句:

        if (!showReadOnlyContact ) {

            selection.append(" AND " + Contacts.IS_SDN_CONTACT + "=0");

        }

      

 

8.File:AggregationSuggestionEngine.java Path:alps\packages\apps\contacts\src\com\android\contacts\editor

在configureSelection函数最后的语句 

在语句:   sb.append(" AND " + Contacts.INDICATE_PHONE_SIM + "=-1");

之后加入: sb.append(" AND " + Contacts.IS_SDN_CONTACT + "!=-1");

9.File:JoinContactListAdapter.java

Path:packages\apps\contacts\src\com\android\contacts\list   

函数:public void configureLoader(CursorLoader cursorLoader, long directoryId) 

将: loader.setSelection(Contacts._ID + "!=?"+" AND " + Contacts.INDICATE_PHONE_SIM + "=-1");‘

改动为:

    loader.setSelection(Contacts._ID + "!=?"+" AND " + Contacts.INDICATE_PHONE_SIM + "=-1" + " AND " + Contacts.IS_SDN_CONTACT + "!=-1");

 

【After JB5】

实现预置联系人(包括姓名、号码信息)至手机中;并保证该联系人是仅仅读的。无法被删除/编辑。

代码分为两部分:

Part One 将预置的联系人插入到数据库中;

Part Two 保证预置联系人仅仅读,无法被编辑删除(在三个地方屏蔽对预置联系人进行编辑处理:联系人详情界面、联系人多选界面、新建联系人选择合并联系人时)。

【注意】假设您不须要限制预置联系人的删除/编辑操作,增加Part One部分代码就可以。并去掉第一步”新增函数“  中的语句:contactvalues.put(RawContacts.IS_SDN_CONTACT, -2);

 

Part One:

1.新建PresetContactsImportProcessor.java

Path: alps\packages\apps\Contacts\src\com\mediatek\contacts\simservice

package com.mediatek.contacts.simservice;

 

import com.mediatek.contacts.simservice.SIMProcessorManager.ProcessorCompleteListener;

 

import android.content.Context;

import android.content.Intent;

import android.util.Log;

import android.content.ContentProviderOperation;

import android.content.ContentValues;

import android.content.OperationApplicationException;

import android.database.Cursor;

import android.net.Uri;

 

import android.provider.ContactsContract;

import android.provider.ContactsContract.CommonDataKinds.Email;//for usim

import android.provider.ContactsContract.CommonDataKinds.GroupMembership;

import android.provider.ContactsContract.CommonDataKinds.Phone;

import android.provider.ContactsContract.CommonDataKinds.StructuredName;

import android.provider.ContactsContract.Data;

import android.provider.ContactsContract.Groups;

import android.provider.ContactsContract.RawContacts;

 

 

import com.android.contacts.common.model.account.AccountType;

import android.os.RemoteException;

 

import java.util.ArrayList;

import com.mediatek.contacts.simservice.SIMProcessorManager.ProcessorCompleteListener;

import com.mediatek.contacts.simservice.SIMServiceUtils;

import com.mediatek.contacts.simservice.SIMServiceUtils.ServiceWorkData;

import com.mediatek.contacts.simcontact.SimCardUtils;

import com.mediatek.contacts.util.LogUtils;

import android.provider.ContactsContract.PhoneLookup;

 

public class PresetContactsImportProcessor extends SIMProcessorBase {

    private static final String TAG = "PresetContactsImportProcessor";

   

    private static boolean sIsRunningNumberCheck = false;

    private static final int INSERT_PRESET_NUMBER_COUNT = xxx;           //预置联系人的个数

    private static final String  INSERT_PRESET_NAME[]    = {"xxx1","xxx2",...};  //各预置联系人的姓名

    private static final String  INSERT_PRESET_NUMBER[] = {"xxx1","xxx2",...};  //各预置联系人的号码

   

    private int mSlotId;

    private Context mContext;

 

    public PresetContactsImportProcessor(Context context, int slotId, Intent intent,

            ProcessorCompleteListener listener) {

        super(intent, listener);

        mContext = context;

        mSlotId = slotId;

    }

 

    @Override

    public int getType() {

        return SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS;

    }

 

    @Override

    public void doWork() {

        if (isCancelled()) {

            LogUtils.d(TAG, "[doWork]cancel import preset contacts work. Thread id=" + Thread.currentThread().getId());

            return;

        }

        importDefaultReadonlyContact();

    }

   

    private void importDefaultReadonlyContact(){

         Log.i(TAG, "isRunningNumberCheck before: " + sIsRunningNumberCheck);

         if (sIsRunningNumberCheck) {

            return;

         }

         sIsRunningNumberCheck = true;

         for(int i = 0;i < INSERT_PRESET_NUMBER_COUNT; i++)

         {

             Log.i(TAG, "isRunningNumberCheck after: " + sIsRunningNumberCheck);

             Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri

                      .encode(INSERT_PRESET_NUMBER[i]));

             Log.i(TAG, "getContactInfoByPhoneNumbers(), uri = " + uri);

 

             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<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();

                  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 {

             // when this service start,but the contactsprovider has not been started yet.

             // the contactCursor perhaps null, but not always.(first load will weekup the provider)

             // so add null block to avoid nullpointerexception

             if (contactCursor != null) {

                  contactCursor.close();

             }

         }//for

         Log.i(TAG, "isRunningNumberCheck insert: " + sIsRunningNumberCheck);

         sIsRunningNumberCheck = false;

         }

    }

}

 

2. 改动SIMServiceUtils.java

Path:alps\packages\apps\ContactsCommon\src\com\mediatek\contacts\simservice  

加入

public static final int SERVICE_WORK_IMPORT_PRESET_CONTACTS = 5;

3. 改动SIMProcessorManager.java

Path:alps\packages\apps\Contacts\src\com\mediatek\contacts\simservice

在SIMProcessorManager.java中createProcessor函数里加入

else if (workType == SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS) {

            processor = new PresetContactsImportProcessor(context, slotId, intent, listener);

        }

4. 改动BootCmpReceiver.java

Path:alps\packages\apps\Contacts\src\com\mediatek\contacts\simcontact

在BootCmpReceiver.java中processBootComplete()方法最后加入代码

startSimService(-1, SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS);

Part Two

1.  File:DefaultContactListAdapter.java 

Path: alps\packages\apps\ContactsCommon\src\com\android\contacts\common\list

(1)configureOnlyShowPhoneContactsSelection函数中例如以下语句:

selection.append(Contacts.INDICATE_PHONE_SIM + "= ?

");

        selectionArgs.add("-1");

之后添加以下的代码

selection.append(" AND " + RawContacts.IS_SDN_CONTACT + " > -2");

2.  File:Contact.java 

Path: alps\packages\apps\ContactsCommon\src\com\android\contacts\common\model 

添加例如以下函数:

    //add by MTK---Preset Contacts

    public boolean isReadOnlyContact() {

             return mIsSdnContact == -2;

     }

3.  File:ContactLoaderFragment.java

Path:alps\packages\apps\contacts\src\com\android\contacts\detail 

将isContactEditable函数改动为:

   public boolean isContactEditable() {

        return mContactData != null && !mContactData.isDirectoryEntry()&& !mContactData.isSdnContacts()&&  !mContactData.is InternationalDialNumber()&&  !mContactData.isReadOnlyContact() ;

    }

 

4.  File:ContactEntryListAdapter.java 

Path:alps\packages\apps\contactscommon\src\com\android\contacts\common\list  

在文件最后添加下面代码:

    public boolean showReadOnlyContact = true;

    public void setShowReadOnlyContact(boolean canDelete) {

        showReadOnlyContact = canDelete;

    }

 

5.  File:ContactEntryListFragment.java  

Path:alps\packages\apps\contactscommon\src\com\android\contacts\common\list

加入代码:

    protected boolean isInstanceOfContactsMultiDeletionFragment(){

    return false;

    }

在onCreateLoader函数中,倒数第二句mAdapter.configureLoader(loader, directoryId);之前添加语句:   

            mAdapter.setShowReadOnlyContact(isInstanceOfContactsMultiDeletionFragment() ? false : true);

6.  File: ContactsMultiDeletionFragment.java

Path:alps\packages\apps\Contacts\src\com\mediatek\contacts\list

加入代码:

    protected boolean isInstanceOfContactsMultiDeletionFragment(){

    return true;

    }

7.File:MultiContactsBasePickerAdapter.java

Path:alps\packages\apps\contacts\src\com\mediatek\contacts\list 

在configureSelection函数最后的语句 loader.setSelection(selection.toString());之前添加语句:

        if (!showReadOnlyContact ) {

            selection.append(" AND " + Contacts.IS_SDN_CONTACT + "=0");

}

8.File:AggregationSuggestionEngine.java

Path:alps\packages\apps\contacts\src\com\android\contacts\editor

在loadAggregationSuggestions函数最后的语句 

在语句:   sb.append(" AND " + Contacts.INDICATE_PHONE_SIM + "=-1");

之后加入: sb.append(" AND " + Contacts.IS_SDN_CONTACT + "!=-2");

9.File:JoinContactListAdapter.java

Path:packages\apps\contacts\src\com\android\contacts\list   

函数:public void configureLoader(CursorLoader cursorLoader, long directoryId) 

将: loader.setSelection(Contacts._ID + "!=?

"+" AND " + Contacts.INDICATE_PHONE_SIM + "=-1");

改动为:

    loader.setSelection(Contacts._ID + "!=?"+" AND " + Contacts.INDICATE_PHONE_SIM + "=-1" + " AND " + Contacts.IS_SDN_CONTACT + "!=-2");

在手机中预置联系人/Service Number的更多相关文章

  1. 读取手机中的联系人信息(android.provider.ContactsContract)

    本篇开始讲如何从Android中得到本机联系人的信息.由于Android较快的版本升级,部分API已经发生了变化.本篇探究的通过ContentProvider机制获取联系人的API从Android2. ...

  2. Android向手机通讯录中的所有的联系人(包括SIM卡),向手机通讯录中插入联系人

    package com.example.myapi.phonepersion; import java.util.ArrayList; import java.util.List; import an ...

  3. Android-->发送短信页面实现(短信发送以及群发和从电话本中选择联系人)-----------》2

    分析下怎么写 首先,我们需要一个输入框,可以手动的输入手机号码, 其次,很少有人愿意手动输入,那么我们需要提供一个按钮来给我们的用户选择自己电话本中的联系人(一次可以选择多个即群发) 然后,我们需要一 ...

  4. [UWP]UWP中获取联系人/邮件发送/SMS消息发送操作

    这篇博客将介绍如何在UWP程序中获取联系人/邮件发送/SMS发送的基础操作. 1. 获取联系人 UWP中联系人获取需要引入Windows.ApplicationModel.Contacts名称空间. ...

  5. 【转】Android 增,删,改,查 通讯录中的联系人

    一.权限 操作通讯录必须在AndroidManifest.xml中先添加2个权限, <uses-permission android:name="android.permission. ...

  6. 微软BI 之SSIS 系列 - 在 SSIS 中使用 Web Service 以及 XML 解析

    开篇介绍 Web Service 的用途非常广几乎无处不在,像各大门户网站上的天气预报使用到的第三方 Web Service API,像手机客户端和服务器端的交互等都可以通过事先设计好的 Web Se ...

  7. Android 增,删,改,查 通讯录中的联系人

    一.权限 操作通讯录必须在AndroidManifest.xml中先添加2个权限, <uses-permission android:name="android.permission. ...

  8. 从Android手机中取出已安装的app包,导出apk

    从Android手机中取出已安装的app包,导出apk TAG:Android,提取,apk,adb,pm,root,导出apk 假设有这样一个场景,A君看到你手机上一个实用APP,想要安装到自己手机 ...

  9. 【Java EE 学习 24 下】【注解在数据库开发中的使用】【反射+注解+动态代理在事务中的应用service层】

    一.使用注解可以解决JavaBean和数据库中表名不一致.字段名不一致.字段数量不一致的问题. 1.Sun公司给jdbc提供的注解 @Table.@Column.@Id.@OneToMany.@One ...

随机推荐

  1. 22.IntelliJ IDEA 切换 project

    转自:https://blog.csdn.net/qwdafedv/article/details/73838628?utm_source=blogxgwz0 1.file->open 2.选择 ...

  2. Unity(IoC)

    一.什么是IoC? IoC(Inversion of Control,控制反转)又称“依赖注入”(Dependence Injection,DI). 控制反转就是创建对象的权利由开发人员控制,转为由容 ...

  3. powerdesigner导出sql

    http://jingyan.baidu.com/article/7082dc1c48960ee40a89bd38.html 生成注释 http://wangjingyi.iteye.com/blog ...

  4. jquery中prop()方法和attr()方法

    接着上一篇笔记的疑惑,找了下prop()方法和attr()方法的区别. 原来query1.6中新加了一个方法prop(),一直没用过它,官方解释只有一句话:获取在匹配的元素集中的第一个元素的属性值. ...

  5. PHP获取随机字符串的两种方法

    <?php /** * 随机返回字符串 * @param number 返回字符串长度 * @param string 从哪些字符串中随机返回,已设置默认字符串,可空 * @return str ...

  6. GridView单元格取值显示为&nbsp;

    在通过GridView取一个单元格(cell)的值时,数据库中为NULL,而页面上显示为空格.发现通过gridview.cell[i].text取出来的值为 ,导致获取数据出现问题. 解决方法: 一. ...

  7. react入门安装

    react的入门安装 1.react的适用方法有两种,其一是依赖在线的cdn地址: https://reactjs.org/docs/cdn-links.html 官方给的cdn地址如下 <sc ...

  8. iOS 的组件化开发

    在一个APP开发过程中,如果项目较小且团队人数较少,使用最基本的MVC.MVVM开发就已经足够了,因为维护成本比较低. 但是当一个项目开发团队人数较多时,因为每个人都会负责相应组件的开发,常规开发模式 ...

  9. Linux学习总结(5)——CentOS常用的目录文件操作命令

    CentOS常用的目录文件操作命令 一.路径操作的CentOS常用命令  cd pwd  NO1. 显示当前路径  [root@rehat root]# pwd  NO2. 返回用户主目录  [roo ...

  10. 洛谷 P2171 Hz吐泡泡

    P2171 Hz吐泡泡 题目背景 Hz大大是一种可爱的动物(神).他很喜欢吐泡泡(更喜欢写作业). 题目描述 这天,Hz大大心血来潮,吐了n个不同的泡泡玩(保证没有重复的泡泡).因为他还要写作业,所以 ...