预置联系人

一:[Contacts Data]在手机中预置联系人/Service Number

[DESCRIPTION]

预置联系人/Service Number

此方法比较适合预置联系人的数目不是特别多的情况

联系人比较多的情况,请参考:FAQ12935 预置联系人之Vcard预置联系人

 

 

[SOLUTION]

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

代码分为两部分:

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

Part Two 保证预置联系人只读,无法被编辑删

(在三个地方屏蔽对预置联系人进行编辑处理:联系人详情界面、联系人多选界面、新建联系人选择合并联系人时)。

【注意】

如果您不需要限制预置联系人的删除/编辑操作,加入Part One部分代码即可,并去掉第一步importDefaultReadonlyContact() 中的语句:contactvalues.put(RawContacts.IS_SDN_CONTACT, -2);

 

Part One

1.新建PresetContactsImportProcessor.java

Before Android N:

 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 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 {
             // 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();
             }
         } //END for
         Log.i(TAG, "isRunningNumberCheck insert: " + sIsRunningNumberCheck);
         sIsRunningNumberCheck = false;
      }
    }
}

Android N:

 Path: alps\packages\apps\Contacts\SimProcessor\src\com\mediatek\SimProcessor

package com.mediatek.simprocessor;

import android.content.Context;
import android.content.Intent;
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.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.RawContacts;
import android.os.RemoteException;
import java.util.ArrayList;
import com.mediatek.simprocessor.SimProcessorManager.ProcessorCompleteListener;
import com.mediatek.simprocessor.SimServiceUtils;
import com.mediatek.simprocessor.Log;
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[] = {"xxxx","xxxx", ...}; //各预置联系人的号码

    private int mSubId;
    private Context mContext;
    
    public PresetContactsImportProcessor(Context context, int subId, Intent intent, ProcessorCompleteListener listener) {
        super(intent, listener);
        mContext = context;
        mSubId = subId;
    }

    @Override
    public int getType() {
        return SimServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS;
    }

    @Override
    public void doWork() {
        if (isCancelled()) {
            Log.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 operationList = new ArrayList();
                    ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
                    ContentValues contactvalues = new ContentValues();
                    contactvalues.put(RawContacts.ACCOUNT_NAME, "Phone");
                    contactvalues.put(RawContacts.ACCOUNT_TYPE, "Local Phone Account");
                    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();
                }
            }
            Log.i(TAG, "isRunningNumberCheck insert: " + sIsRunningNumberCheck);
            sIsRunningNumberCheck = false;
        }
    }
}

 

2.

Before Android N:
  修改SIMServiceUtils.java
  Path: alps\packages\apps\ContactsCommon\src\com\mediatek\contacts\simservice

Android N:
  修改SimServiceUtils.java
  Path: alps\packages\apps\Contacts\SimProcessor\src\com\mediatek\SimProcessor

添加

public static final int SERVICE_WORK_IMPORT_PRESET_CONTACTS = 5;

 

3.

Before Android N:
  修改SIMProcessorManager.java
  Path: alps\packages\apps\Contacts\src\com\mediatek\contacts\simservice
  在createProcessor函数里添加

else if (workType == SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS) {
    processor = new PresetContactsImportProcessor(context, subId, intent, listener);
}

Android N:
  修改SimProcessorManager.java
  Path: alps\packages\apps\Contacts\SimProcessor\src\com\mediatek\SimProcessor
  在createProcessor函数里添加

else if (workType == SimServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS) {
    processor = new PresetContactsImportProcessor(context, subId, intent, listener);
}

 

4.修改BootCmpReceiver.java

Before Android N:
  Path: alps\packages\apps\Contacts\src\com\mediatek\contacts\simservice
  添加如下方法:

 /**
 * when boot complete,preset the service number directly.
 */
 private void presetServiceNumber(Context context) {
     Log.d(TAG, "presetServiceNumber");
     startSimService(context, -1, SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS);
 }

Android N:
  Path: alps\packages\apps\Contacts\SimProcessor\src\com\mediatek\SimProcessor
  添加如下方法:

 /**
 * when boot complete,preset the service number directly.
 */
 private void presetServiceNumber(Context context) {
     Log.d(TAG, "presetServiceNumber");
     startSimService(context, -1, SimServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS);
 }

 

5. 修改BootCmpReceiver.java

Before Android N:
  Path: alps\packages\apps\Contacts\src\com\mediatek\contacts\simservice
  在onReceive()方法

 public void onReceive(Context context, Intent intent) {
     ... ...
     } 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);
         }
     }
     ... ...
 }

修改为:

 public void onReceive(Context context, Intent intent) {
     ... ...
     } 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]
     }
     ... ...
 }

Android N:

  Path: alps\packages\apps\Contacts\SimProcessor\src\com\mediatek\SimProcessor

  在onReceive()方法

 public void onReceive(Context context, Intent intent) {
     ... ...
     } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
         if (!isPhbReady()) {
             processBootComplete(context);
         } else {
             processDupSimContacts(context);
         }
     }
     ... ...
 }

  修改为:

 public void onReceive(Context context, Intent intent) {
     ... ...
     } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
         if (!isPhbReady()) {
             processBootComplete(context);
         } else {
             processDupSimContacts(context);
         }

         // [START] add for Preset service number
         presetServiceNumber(context);
         // [END]
     }
     ... ...
 }

 

Part Two

  1.  

Before Android N:

 File:DefaultContactListAdapter.java

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

Android N:

 File:ContactsCommonListUtils.java

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

configureOnlyShowPhoneContactsSelection函数中如下语句:

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

selectionArgs.add("-1");

之后增加下面的代码

selection.append(" AND " + RawContacts.IS_SDN_CONTACT + " > -2");
  •  
  1. File:Contact.java 
  1. alps\packages\apps\ContactsCommon\src\com\android\contacts\common\model 

增加如下函数:

//add for Preset Contacts
public boolean isReadOnlyContact() {
    return mIsSdnContact == -2;
}
  •  
  1.  
  1. Android N: 
  •  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.isInternationalDialNumber(); // before
    return mContactData != null && !mContactData.isDirectoryEntry() && !mContactData.isSdnContacts() && !mContactData.isInternationalDialNumber() && !mContactData.isReadOnlyContact() ; // after
}

 Android N:

 File:QuickContactActivity.java

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

将isContactEditable函数修改为:

 private boolean isContactEditable() {
  // return mContactData != null && !mContactData.isDirectoryEntry() && !mContactData.isSdnContacts() ; // before
     return mContactData != null && !mContactData.isDirectoryEntry() && !mContactData.isSdnContacts() && !mContactData.isReadOnlyContact() ; // after
}

 

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);
mAdapter.configureLoader(loader, directoryId);
  •  
  1.  
  1. Android M:
  •  File: ContactsMultiDeletionFragment.java

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

添加代码:

protected boolean isInstanceOfContactsMultiDeletionFragment(){
    return true;
}

[ Android M:

C  File: packages/apps/ContactsCommon/src/com/android/contacts/common/list/ContactEntryListAdapter.java

public boolean isSdnNumber(int position) {
    boolean isSdnNumber = false;
    int partition = getPartitionForPosition(position);
    if (partition >= 0) {
        // Save the old cursor position - the call to getItem() may modify the cursor
        // position.
        int offset = getCursor(partition).getPosition();
        Cursor cursor = (Cursor) getItem(position);
        if (cursor != null) {
            // [START]
            // Before
            // isSdnNumber = cursor.getInt(ContactQuery.IS_SDN_CONTACT) == 1;
            // After
            final long isSdn = cursor.getInt(ContactQuery.IS_SDN_CONTACT);
            if (isSdn == 1 || isSdn == -2) {
               isSdnNumber = true;
            }
            Log.d(TAG, "[isSdnNumber] isSdn = " + isSdn + ",isSdnNumber = " + isSdnNumber); //add log 
            // [END]

            // Restore the old cursor position.
            cursor.moveToPosition(offset);
        }
    }
    return isSdnNumber;
}

 Android N:

C  File: packages/apps/ContactsCommon/src/com/android/contacts/common/list/ContactEntryListAdapter.java

 public boolean isSdnNumber(int position) {
     boolean isSdnNumber = false;
     int partition = getPartitionForPosition(position);
     if (partition >= 0) {
         // Save the old cursor position - the call to getItem() may modify the cursor
         // position.
         int offset = getCursor(partition).getPosition();
         Cursor cursor = (Cursor) getItem(position);
         if (cursor != null) {
              // [START]
              // Before
              // isSdnNumber = cursor.getInt(cursor.getColumnIndex(Contacts.IS_SDN_CONTACT)) == 1;
              // After
              final long isSdn = cursor.getInt(cursor.getColumnIndex(Contacts.IS_SDN_CONTACT));
              if (isSdn == 1 || isSdn == -2) {
                  isSdnNumber = true;
              }
              Log.d(TAG, "[isSdnNumber] isSdn = " + isSdn + ",isSdnNumber = " + isSdnNumber); //add log 
              // [END]

             // Restore the old cursor position.
             cursor.moveToPosition(offset);
         }
     }
     return isSdnNumber;
}

 7.

 Before Android M:

  File:MultiContactsBasePickerAdapter.java

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

 After Android M:

  File:MultiBasePickerAdapter.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");
}

loader.setSelection(selection.toString());

 

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)

Before Android N:

 将:

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");

Android N:
 将:

 if (ContactsPortableUtils.MTK_PHONE_BOOK_SUPPORT) {
     loader.setSelection(Contacts._ID + "!=?" + " AND " + Contacts.INDICATE_PHONE_SIM
             + "=-1");
 } else {
     loader.setSelection(Contacts._ID + "!=?");
 }

 修改为:

 if (ContactsPortableUtils.MTK_PHONE_BOOK_SUPPORT) {
     loader.setSelection(Contacts._ID + "!=?" + " AND " + Contacts.INDICATE_PHONE_SIM
             + "=-1" + " AND " + Contacts.IS_SDN_CONTACT + "!=-2");
 } else {
     loader.setSelection(Contacts._ID + "!=?" + " AND " + Contacts.IS_SDN_CONTACT + "!=-2");
 }


10.

Android N:
 File: MultiSelectEntryContactListAdapter
 Path: packages\apps\contacts\src\com\android\contacts\list
 语句:

 if (ContactsPortableUtils.MTK_PHONE_BOOK_SUPPORT
         && cursor.getInt(
                 cursor.getColumnIndex(ContactsContract.Contacts.IS_SDN_CONTACT)) == 1) {
     view.setClickable(false);
     view.hideCheckBox();
     return;
 }

 修改为:

 if ((ContactsPortableUtils.MTK_PHONE_BOOK_SUPPORT
         && cursor.getInt(cursor.getColumnIndex(
                 ContactsContract.Contacts.IS_SDN_CONTACT)) == 1)
         || cursor.getInt(cursor.getColumnIndex(
                 ContactsContract.Contacts.IS_SDN_CONTACT)) == -2) {
     view.setClickable(false);
     view.hideCheckBox();
     return;
 }

//End for Test

 

二:【Contacts Data】预置联系人之Vcard预置联系人

[DESCRIPTION]

 

通过Vcard文件方式预置联系人,支持几乎所有联系人信息种类,包括联系人Name、Phone、Email、Avatar、Postal、Note、Website、Organization等。

 

[SOLUTION]

 

 

Part1:准备预置联系人VCard文件

1.  在手机编辑需要预置的联系人,以VCard方式导出,重命名为preset_contacts.vcf

2.  将preset_contacts.vcf文件放置到路径:alps\packages\apps\Contacts\assets

 

注意:默认从手机中导出的Vcard文件,若联系人有头像,其清晰度会降低。若需要保证联系人头像的清晰度,需要使用工具JPEG2VcardAvatar,下载链接:http://online.mediatek.inc/_layouts/15/mol/tool/ext/TOLProps.aspx?toolid=1a6482b6-3e3b-4f4f-bafa-67f50d827160

 

因JB与KK上Contacts结构不相同,以下部分分两个软件版本

 

KK / L / M 版本

Part2:导入预置联系人VCard文件

 

1. 修改SIMServiceUtils.java

Pathalps\packages\apps\ContactsCommon\src\com\mediatek\contacts\simservice  

添加

public static final int SERVICE_WORK_IMPORT_PRESET_CONTACTS = 5;

2. 修改SIMProcessorManager.java

Pathalps\packages\apps\Contacts\src\com\mediatek\contacts\simservice

在SIMProcessorManager.java中createProcessor函数里添加

else if (workType == SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS) {

            processor = new ImportPresetContactProcessor(context, ImportPresetContactProcessor.PRESET_CONTACT_VCARD, 0);        }

4. 修改BootCmpReceiver.java

Pathalps\packages\apps\Contacts\src\com\mediatek\contacts\simcontact

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

startSimService(-1, SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS);

 

5. 新建ImportPresetContactProcessor.java

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

 

package com.mediatek.contacts.vcard;

import android.content.Context;

import android.accounts.Account;

import android.content.ContentResolver;

import android.net.Uri;

// The following lines are provided and maintained by Mediatek Inc.

import android.os.PowerManager;

import android.os.Process;

// The previous lines are provided and maintained by Mediatek Inc.

import android.util.Log;

 

import com.mediatek.contacts.ext.ContactPluginDefault;

import com.android.vcard.VCardEntryCounter;

import com.android.vcard.VCardSourceDetector;

import com.android.vcard.VCardEntry;

import com.android.vcard.VCardEntryCommitter;

import com.android.vcard.VCardEntryConstructor;

import com.android.vcard.VCardEntryHandler;

import com.android.vcard.VCardInterpreter;

import com.android.vcard.VCardParser;

import com.android.vcard.VCardParser_V21;

import com.android.vcard.VCardParser_V30;

import com.android.vcard.exception.VCardException;

import com.android.vcard.exception.VCardNestedException;

import com.android.vcard.exception.VCardNotSupportedException;

import com.android.vcard.exception.VCardVersionException;

import com.mediatek.contacts.ExtensionManager;

import com.android.contacts.common.vcard.ImportRequest;

 

import java.io.ByteArrayInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.util.ArrayList;

import java.util.List;

//add by MTK for importing preset contact START

import com.mediatek.contacts.simservice.SIMServiceUtils;

import com.mediatek.contacts.simservice.SIMProcessorBase;

 

//add by MTK for importing preset contact END

 

/**

 * Class for processing one import request from a user. Dropped after importing requested Uri(s).

 * {@link VCardService} will create another object when there is another import request.

 */

public class ImportPresetContactProcessor extends SIMProcessorBase implements VCardEntryHandler {

 

            /* package */ static final String VCARD_URI_ARRAY = "vcard_uri";

    /* package */ static final String ESTIMATED_VCARD_TYPE_ARRAY = "estimated_vcard_type";

    /* package */ static final String ESTIMATED_CHARSET_ARRAY = "estimated_charset";

    /* package */ static final String VCARD_VERSION_ARRAY = "vcard_version";

    /* package */ static final String ENTRY_COUNT_ARRAY = "entry_count";

 

    /* package */ final static int VCARD_VERSION_AUTO_DETECT = 0;

    /* package */ final static int VCARD_VERSION_V21 = 1;

    /* package */ final static int VCARD_VERSION_V30 = 2;

            private static final String LOG_TAG = "VCardImportPresetContact";

 

            public static final String PRESET_CONTACT_VCARD =

"file:///android_asset/preset_contacts.vcf";

    private static final boolean DEBUG = false;

 

    private final Context mContext;

    private final ContentResolver mResolver;

    private final Uri mUri;

            private final String mDisplayName;

    private final int mJobId;

 

    // TODO: remove and show appropriate message instead.

    private final List<Uri> mFailedUris = new ArrayList<Uri>();

 

    private VCardParser mVCardParser;

 

    private volatile boolean mCanceled;

    private volatile boolean mDone;

 

    /*

     * Change Feature by Mediatek Begin.

     *   Descriptions: handle cancel in the cancel function

     */

    private volatile boolean mIsRunning = false;

    /*

     * Change Feature by Mediatek End.

     */

 

    private int mCurrentCount = 0;

    private int mTotalCount = 0;

    /*

     * New Feature by Mediatek Begin.

     *   Descriptions: All of process should not be stopped by PM.

     */

    private PowerManager.WakeLock mWakeLock;

    /*

     * New Feature by Mediatek End.

     */

 

    public ImportPresetContactProcessor(final Context context,

            final String vcardFilePath, final int jobId) {

                                   super(null, null);

        mContext = context;

        mResolver = mContext.getContentResolver();

        mJobId = jobId;

                       mUri = Uri.parse(vcardFilePath);

                       mDisplayName = mUri.getLastPathSegment();

                       Log.d(LOG_TAG, "vCard Uri = " + mUri.getPath() + ", vCard DisplayName = " + mDisplayName);

        /*

         * New Feature by Mediatek Begin.

         *   Descriptions: All of process should not be stopped by PM.

         */

        final PowerManager powerManager = (PowerManager) mContext.getApplicationContext()

                .getSystemService("power");

        mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK

                | PowerManager.ON_AFTER_RELEASE, LOG_TAG);

        /*

         * New Feature by Mediatek End.

         */

        Log.d(LOG_TAG, "ImportProcessor() ");

    }

 

    @Override

    public void onStart() {

        // do nothing

    }

 

    @Override

    public void onEnd() {

        Log.d(LOG_TAG, "onEnd() ");

        // do nothing

    }

 

    @Override

    public void onEntryCreated(VCardEntry entry) {

        mCurrentCount++;

 

    }

 

    @Override

    public final int getType() {

                       //add by MTK for importing preset contact START

                       //return VCardService.TYPE_IMPORT;

        return SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS;

                       //add by MTK for importing preset contact END

    }

 

            //add by MTK for importing preset contact START

    public void doWork() {

        Log.d(LOG_TAG,"ImportPresetContactProcessor, run()");

            //add by MTK for importing preset contact END

 

        /*

         * Change Feature by Mediatek Begin.

         *   Descriptions: handle cancel in the cancel function

         */

        mIsRunning = true;

        /*

         * Change Feature by Mediatek End.

         */

        /*

         * New Feature by Mediatek Begin.

         *   Descriptions: All of process should not be stopped by PM.

         */

        mWakeLock.acquire();

        /*

         * New Feature by Mediatek End.

         */

        // ExecutorService ignores RuntimeException, so we need to show it here.

        try {

            /*

             * Bug Fix by Mediatek Begin.

             *   CR ID: ALPS00115856

             *   Descriptions: Set the thread priority to lowest

             *     and give up the change for Query

             */

            Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);

            /*

             * Bug Fix by Mediatek End.

             */

            runInternal();

 

        } catch (OutOfMemoryError e) {

            Log.e(LOG_TAG, "OutOfMemoryError thrown during import", e);

            throw e;

        } catch (RuntimeException e) {

            Log.e(LOG_TAG, "RuntimeException thrown during import", e);

            throw e;

        } finally {

            synchronized (this) {

                mDone = true;

            }

            /*

             * New Feature by Mediatek Begin.

             *   Descriptions: All of process should not be stopped by PM.

             */

            if (mWakeLock != null && mWakeLock.isHeld()) {

                mWakeLock.release();

            }

            /*

             * New Feature by Mediatek End.

             */

        }

    }

 

    private void runInternal() {

int count = context.getContentResolver().delete( RawContacts.CONTENT_URI.buildUpon().build(), RawContacts.IS_SDN_CONTACT + " = -2", null);
LogUtils.d(TAG,"[deletePresetContacts]count:" + count);

                      

        Log.i(LOG_TAG, String.format("vCard import (id: %d) has started.", mJobId));

        final ImportRequest request = getImportRequest(mUri, mDisplayName);

        if (isCancelled()) {

            Log.i(LOG_TAG, "Canceled before actually handling parameter (" + request.uri + ")");

            return;

        }

        final int[] possibleVCardVersions;

        if (request.vcardVersion == VCARD_VERSION_AUTO_DETECT) {

            /**

             * Note: this code assumes that a given Uri is able to be opened more than once,

             * which may not be true in certain conditions.

             */

            possibleVCardVersions = new int[] {

                    VCARD_VERSION_V21,

                    VCARD_VERSION_V30

            };

        } else {

            possibleVCardVersions = new int[] {

                    request.vcardVersion

            };

        }

 

        final Uri uri = request.uri;

        final Account account = request.account;

        final int estimatedVCardType = request.estimatedVCardType;

        final String estimatedCharset = request.estimatedCharset;

        final int entryCount = request.entryCount;

        mTotalCount += entryCount;

 

        /**

         * add for import/export group infomations feature . start

         * original code:

         *        final VCardEntryConstructor constructor =

         *        new VCardEntryConstructor(estimatedVCardType, account, estimatedCharset);

         */

        final VCardEntryConstructor constructor = new VCardEntryConstructorForPresetContact(

                        estimatedVCardType, account, estimatedCharset);

        /**

         * add for import/export group infomations feature . end

         */

 

                       final VCardEntryCommitter committer = new VCardEntryCommitter(mResolver);

 

        constructor.addEntryHandler(committer);

        constructor.addEntryHandler(this);

 

        InputStream is = null;

        boolean successful = false;

        try {

            if (uri != null) {

                Log.i(LOG_TAG, "start importing one vCard (Uri: " + uri + ")");

                                               is = mContext.getAssets().open(uri.getLastPathSegment());

                //is = mResolver.openInputStream(uri);

            } else if (request.data != null){

                Log.i(LOG_TAG, "start importing one vCard (byte[])");

                is = new ByteArrayInputStream(request.data);

            }

 

            if (is != null) {

                successful = readOneVCard(is, estimatedVCardType, estimatedCharset, constructor,

                        possibleVCardVersions);

            }

        } catch (IOException e) {

            successful = false;

        } finally {

            if (is != null) {

                try {

                    is.close();

                } catch (Exception e) {

                    // ignore

                }

            }

        }

 

        if (successful) {

            // TODO: successful becomes true even when cancelled. Should return more appropriate

            // value

            if (isCancelled()) {

                Log.i(LOG_TAG, "vCard import has been canceled (uri: " + uri + ")");

                // Cancel notification will be done outside this method.

            } else {

                Log.i(LOG_TAG, "Successfully finished importing one vCard file: " + uri);

                List<Uri> uris = committer.getCreatedUris();

 

            }

        } else {

            Log.w(LOG_TAG, "Failed to read one vCard file: " + uri);

            mFailedUris.add(uri);

        }

    }

 

    private boolean readOneVCard(InputStream is, int vcardType, String charset,

            final VCardInterpreter interpreter,

            final int[] possibleVCardVersions) {

        boolean successful = false;

        final int length = possibleVCardVersions.length;

        for (int i = 0; i < length; i++) {

            final int vcardVersion = possibleVCardVersions[i];

            try {

                if (i > 0 && (interpreter instanceof VCardEntryConstructor)) {

                    // Let the object clean up internal temporary objects,

                    ((VCardEntryConstructor) interpreter).clear();

                }

 

                // We need synchronized block here,

                // since we need to handle mCanceled and mVCardParser at once.

                // In the worst case, a user may call cancel() just before creating

                // mVCardParser.

                synchronized (this) {

                    mVCardParser = (vcardVersion == VCARD_VERSION_V30 ?

                            new VCardParser_V30(vcardType) :

                                new VCardParser_V21(vcardType));

                    if (isCancelled()) {

                        Log.i(LOG_TAG, "ImportProcessor already recieves cancel request, so " +

                                "send cancel request to vCard parser too.");

                        mVCardParser.cancel();

                    }

                }

                mVCardParser.parse(is, interpreter);

 

                successful = true;

                break;

            } catch (IOException e) {

                Log.e(LOG_TAG, "IOException was emitted: " + e.getMessage());

            } catch (VCardNestedException e) {

                // This exception should not be thrown here. We should instead handle it

                // in the preprocessing session in ImportVCardActivity, as we don't try

                // to detect the type of given vCard here.

                //

                // TODO: Handle this case appropriately, which should mean we have to have

                // code trying to auto-detect the type of given vCard twice (both in

                // ImportVCardActivity and ImportVCardService).

                Log.e(LOG_TAG, "Nested Exception is found.");

            } catch (VCardNotSupportedException e) {

                Log.e(LOG_TAG, e.toString());

            } catch (VCardVersionException e) {

                if (i == length - 1) {

                    Log.e(LOG_TAG, "Appropriate version for this vCard is not found.");

                } else {

                    // We'll try the other (v30) version.

                }

            } catch (VCardException e) {

                Log.e(LOG_TAG, e.toString());

            } finally {

                if (is != null) {

                    try {

                        is.close();

                    } catch (IOException e) {

                    }

                }

            }

        }

 

        return successful;

    }

 

    @Override

    public synchronized boolean cancel(boolean mayInterruptIfRunning) {

        if (DEBUG) Log.d(LOG_TAG, "ImportProcessor received cancel request");

        if (mDone || mCanceled) {

            return false;

        }

        mCanceled = true;

 

        synchronized (this) {

            if (mVCardParser != null) {

                mVCardParser.cancel();

            }

        }

        return true;

    }

 

    @Override

    public synchronized boolean isCancelled() {

        return mCanceled;

    }

 

 

    @Override

    public synchronized boolean isDone() {

        return mDone;

    }

           

            private ImportRequest getImportRequest(final Uri localDataUri, final String displayName){

            final ImportRequest request;

                                   try {

                                               request = constructImportRequest(null, localDataUri, displayName);

                                   } catch (VCardException e) {

                                               Log.e(LOG_TAG, "Maybe the file is in wrong format", e);

                                               ///fixed cr ALPS00598462

                                               return null;

                                               /*

                                                * Bug Fix by Mediatek Begin. CR ID: ALPS00318987

                                                */

                                   } catch (IllegalArgumentException e) {

                                               Log.e(LOG_TAG, "Maybe the file is in wrong format", e);

                                               ///fixed cr ALPS00598462

                                               return null;

                                   /*

                                    * Bug Fix by Mediatek End.

                                    */

                                   } catch (IOException e) {

                                               Log.e(LOG_TAG, "Unexpected IOException", e);

                                               ///fixed cr ALPS00598462

 

                                               return null;

                                   }

                                   return request;

            }

           

            private ImportRequest constructImportRequest(final byte[] data,

                final Uri localDataUri, final String displayName)

                throws IOException, VCardException {

            final ContentResolver resolver = mContext.getApplicationContext().getContentResolver();

            VCardEntryCounter counter = null;

            VCardSourceDetector detector = null;

            int vcardVersion = VCARD_VERSION_V21;

            try {

                boolean shouldUseV30 = false;

                InputStream is;

                if (data != null) {

                    is = new ByteArrayInputStream(data);

                } else {

                                                          is = mContext.getAssets().open(localDataUri.getLastPathSegment());

                    //is = resolver.openInputStream(localDataUri);

                }

                mVCardParser = new VCardParser_V21();

                try {

                    counter = new VCardEntryCounter();

                    detector = new VCardSourceDetector();

                    mVCardParser.addInterpreter(counter);

                    mVCardParser.addInterpreter(detector);

                    mVCardParser.parse(is);

                } catch (VCardVersionException e1) {

                    try {

                        is.close();

                    } catch (IOException e) {

                    }

 

                    shouldUseV30 = true;

                    if (data != null) {

                        is = new ByteArrayInputStream(data);

                    } else {

                                                                      is = mContext.getAssets().open(localDataUri.getLastPathSegment());

                        //is = resolver.openInputStream(localDataUri);

                    }

                    mVCardParser = new VCardParser_V30();

                    try {

                        counter = new VCardEntryCounter();

                        detector = new VCardSourceDetector();

                        mVCardParser.addInterpreter(counter);

                        mVCardParser.addInterpreter(detector);

                        mVCardParser.parse(is);

                    } catch (VCardVersionException e2) {

                        throw new VCardException("vCard with unspported version.");

                    }

                } finally {

                    if (is != null) {

                        try {

                            is.close();

                        } catch (IOException e) {

                        }

                    }

                }

 

                vcardVersion = shouldUseV30 ? VCARD_VERSION_V30 : VCARD_VERSION_V21;

            } catch (VCardNestedException e) {

                Log.w(LOG_TAG, "Nested Exception is found (it may be false-positive).");

                // Go through without throwing the Exception, as we may be able to detect the

                // version before it

            }

            return new ImportRequest(null,

                    data, localDataUri, displayName,

                    detector.getEstimatedType(),

                    detector.getEstimatedCharset(),

                    vcardVersion, counter.getCount());

        }

}

 

6. 新建VCardEntryConstructorForPresetContact.java

path: alps\packages\apps\ContactsCommon\src\com\mediatek\contacts\vcard

 

package com.mediatek.contacts.vcard;

 

import android.accounts.Account;

import com.android.vcard.VCardConfig;

import com.android.vcard.VCardEntryConstructor;

import com.android.vcard.VCardEntry;

 

public class VCardEntryConstructorForPresetContact extends VCardEntryConstructor {

    private final int mVCardType;

    private final Account mAccount;

 

    public VCardEntryConstructorForPresetContact() {

        this(VCardConfig.VCARD_TYPE_V21_GENERIC, null, null);

    }

 

    public VCardEntryConstructorForPresetContact(final int vcardType) {

        this(vcardType, null, null);

    }

 

    public VCardEntryConstructorForPresetContact(final int vcardType, final Account account) {

        this(vcardType, account, null);

    }

 

    /**

     * @deprecated targetCharset is not used anymore.

     * Use {@link #VCardEntryConstructor(int, Account)}

     */

    @Deprecated

    public VCardEntryConstructorForPresetContact(final int vcardType, final Account account,

            String targetCharset) {

        mVCardType = vcardType;

        mAccount = account;

    }

    protected VCardEntry getVCardEntry() {

        return new VCardEntryForPresetContact(mVCardType, mAccount);

    }

}

 

7.      新建VCardEntryForPresetContact.java 

path: alps\packages\apps\ContactsCommon\src\com\mediatek\contacts\vcard

 

package com.mediatek.contacts.vcard;

 

import com.android.vcard.VCardEntry;

import android.accounts.Account;

import android.content.ContentProviderOperation;

import android.content.ContentResolver;

import android.provider.ContactsContract.RawContacts;

 

import java.util.ArrayList;

import java.util.List;

 

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

 

public class VCardEntryForPresetContact extends VCardEntry{

 

             public VCardEntryForPresetContact(int vcardType, Account account){

                       super(vcardType, account);

             }

            @Override

    public ArrayList<ContentProviderOperation> constructInsertOperations(ContentResolver resolver,

            ArrayList<ContentProviderOperation> operationList) {

        if (operationList == null) {

            operationList = new ArrayList<ContentProviderOperation>();

        }

 

        if (isIgnorable()) {

            return operationList;

        }

 

        final int backReferenceIndex = operationList.size();

 

        // After applying the batch the first result's Uri is returned so it is important that

        // the RawContact is the first operation that gets inserted into the list.

        ContentProviderOperation.Builder builder = ContentProviderOperation

                .newInsert(RawContacts.CONTENT_URI);

 

        builder.withValue(RawContacts.ACCOUNT_NAME, AccountType.ACCOUNT_NAME_LOCAL_PHONE);

        builder.withValue(RawContacts.ACCOUNT_TYPE, AccountType.ACCOUNT_TYPE_LOCAL_PHONE);

        builder.withValue(RawContacts.INDICATE_PHONE_SIM, RawContacts.INDICATE_PHONE);

                       builder.withValue(RawContacts.IS_SDN_CONTACT, -2);

        operationList.add(builder.build());

 

        int start = operationList.size();

        iterateAllData(new InsertOperationConstrutor(operationList, backReferenceIndex));

        int end = operationList.size();

 

        return operationList;

    }

 

private class InsertOperationConstrutor implements EntryElementIterator {

        private final List<ContentProviderOperation> mOperationList;

 

        private final int mBackReferenceIndex;

 

        public InsertOperationConstrutor(List<ContentProviderOperation> operationList,

                int backReferenceIndex) {

            mOperationList = operationList;

            mBackReferenceIndex = backReferenceIndex;

        }

 

        @Override

        public void onIterationStarted() {

        }

 

        @Override

        public void onIterationEnded() {

        }

 

        @Override

        public void onElementGroupStarted(EntryLabel label) {

        }

 

        @Override

        public void onElementGroupEnded() {

        }

 

        @Override

        public boolean onElement(EntryElement elem) {

            if (!elem.isEmpty()) {

                elem.constructInsertOperation(mOperationList, mBackReferenceIndex);

            }

            return true;

        }

    }

}

 

displayName = sourceUri.getLastPathSegment();

 

private ImportRequest constructImportRequest(final byte[] data,

                final Uri localDataUri, final String displayName)

                throws IOException, VCardException {

            final ContentResolver resolver = ImportVCardActivity.this.getContentResolver();

            VCardEntryCounter counter = null;

            VCardSourceDetector detector = null;

            int vcardVersion = VCARD_VERSION_V21;

            try {

                boolean shouldUseV30 = false;

                InputStream is;

                if (data != null) {

                    is = new ByteArrayInputStream(data);

                } else {

                    is = resolver.openInputStream(localDataUri);

                }

                mVCardParser = new VCardParser_V21();

                try {

                    counter = new VCardEntryCounter();

                    detector = new VCardSourceDetector();

                    mVCardParser.addInterpreter(counter);

                    mVCardParser.addInterpreter(detector);

                    mVCardParser.parse(is);

                } catch (VCardVersionException e1) {

                    try {

                        is.close();

                    } catch (IOException e) {

                    }

 

                    shouldUseV30 = true;

                    if (data != null) {

                        is = new ByteArrayInputStream(data);

                    } else {

                        is = resolver.openInputStream(localDataUri);

                    }

                    mVCardParser = new VCardParser_V30();

                    try {

                        counter = new VCardEntryCounter();

                        detector = new VCardSourceDetector();

                        mVCardParser.addInterpreter(counter);

                        mVCardParser.addInterpreter(detector);

                        mVCardParser.parse(is);

                    } catch (VCardVersionException e2) {

                        throw new VCardException("vCard with unspported version.");

                    }

                } finally {

                    if (is != null) {

                        try {

                            is.close();

                        } catch (IOException e) {

                        }

                    }

                }

 

                vcardVersion = shouldUseV30 ? VCARD_VERSION_V30 : VCARD_VERSION_V21;

            } catch (VCardNestedException e) {

                Log.w(LOG_TAG, "Nested Exception is found (it may be false-positive).");

                // Go through without throwing the Exception, as we may be able to detect the

                // version before it

            }

            return new ImportRequest(mAccount,

                    data, localDataUri, displayName,

                    detector.getEstimatedType(),

                    detector.getEstimatedCharset(),

                    vcardVersion, counter.getCount());

        }

 

Part3:保证预置联系人不可编辑

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 + " < 0");

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");

10.File: ContactDetailPhotoSetter.java

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

将onClick()函数修改为

@Override

public void onClick(View v) {

if(mContactData!= null && !mContactData.isContactEditable()){

            // Assemble the intent.

            RawContactDeltaList delta = mContactData.createRawContactDeltaList();

 

            // Find location and bounds of target view, adjusting based on the

            // assumed local density.

            final float appScale =

                    mContext.getResources().getCompatibilityInfo().applicationScale;

            final int[] pos = new int[2];

            v.getLocationOnScreen(pos);

 

            // rect is the bounds (in pixels) of the photo view in screen coordinates

            final Rect rect = new Rect();

            rect.left = (int) (pos[0] * appScale + 0.5f);

            rect.top = (int) (pos[1] * appScale + 0.5f);

            rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);

            rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);

 

            Uri photoUri = null;

            if (mContactData.getPhotoUri() != null) {

                photoUri = Uri.parse(mContactData.getPhotoUri());

            }

            Intent photoSelectionIntent = PhotoSelectionActivity.buildIntent(mContext,

                    photoUri, mPhotoBitmap, mPhotoBytes, rect, delta, mContactData.isUserProfile(),

                    mContactData.isDirectoryEntry(), mExpandPhotoOnClick);

            // Cache the bitmap directly, so the activity can pull it from the

            // photo manager.

            if (mPhotoBitmap != null) {

                ContactPhotoManager.getInstance(mContext).cacheBitmap(

                        photoUri, mPhotoBitmap, mPhotoBytes);

            }

            mContext.startActivity(photoSelectionIntent);

}

}

 

JB7、JB9版本

 

Part2:导入预置联系人VCard文件

 

1. 修改SIMServiceUtils.java

Pathalps\packages\apps\Contacts\src\com\mediatek\contacts\simservice  

添加

public static final int SERVICE_WORK_IMPORT_PRESET_CONTACTS = 5;

2. 修改SIMProcessorManager.java

Pathalps\packages\apps\Contacts\src\com\mediatek\contacts\simservice

在SIMProcessorManager.java中createProcessor函数里添加

else if (workType == SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS) {

            processor = new ImportPresetContactProcessor(context, ImportPresetContactProcessor.PRESET_CONTACT_VCARD, 0);        }

4. 修改BootCmpReceiver.java

Pathalps\packages\apps\Contacts\src\com\mediatek\contacts\simcontact

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

startSimService(-1, SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS);

 

5. 新建ImportPresetContactProcessor.java

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

 

package com.mediatek.contacts.vcard;

import android.content.Context;

import android.accounts.Account;

import android.content.ContentResolver;

import android.net.Uri;

// The following lines are provided and maintained by Mediatek Inc.

import android.os.PowerManager;

import android.os.Process;

// The previous lines are provided and maintained by Mediatek Inc.

import android.util.Log;

 

import com.mediatek.contacts.ext.ContactPluginDefault;

import com.android.vcard.VCardEntryCounter;

import com.android.vcard.VCardSourceDetector;

import com.android.vcard.VCardEntry;

import com.android.vcard.VCardEntryCommitter;

import com.android.vcard.VCardEntryConstructor;

import com.android.vcard.VCardEntryHandler;

import com.android.vcard.VCardInterpreter;

import com.android.vcard.VCardParser;

import com.android.vcard.VCardParser_V21;

import com.android.vcard.VCardParser_V30;

import com.android.vcard.exception.VCardException;

import com.android.vcard.exception.VCardNestedException;

import com.android.vcard.exception.VCardNotSupportedException;

import com.android.vcard.exception.VCardVersionException;

import com.mediatek.contacts.ExtensionManager;

import com.android.contacts.common.vcard.ImportRequest;

 

import java.io.ByteArrayInputStream;

import java.io.IOException;

import java.io.InputStream;

import java.util.ArrayList;

import java.util.List;

//add by MTK for importing preset contact START

import com.mediatek.contacts.simservice.SIMServiceUtils;

import com.mediatek.contacts.simservice.SIMProcessorBase;

 

//add by MTK for importing preset contact END

 

/**

 * Class for processing one import request from a user. Dropped after importing requested Uri(s).

 * {@link VCardService} will create another object when there is another import request.

 */

public class ImportPresetContactProcessor extends SIMProcessorBase implements VCardEntryHandler {

 

            /* package */ static final String VCARD_URI_ARRAY = "vcard_uri";

    /* package */ static final String ESTIMATED_VCARD_TYPE_ARRAY = "estimated_vcard_type";

    /* package */ static final String ESTIMATED_CHARSET_ARRAY = "estimated_charset";

    /* package */ static final String VCARD_VERSION_ARRAY = "vcard_version";

    /* package */ static final String ENTRY_COUNT_ARRAY = "entry_count";

 

    /* package */ final static int VCARD_VERSION_AUTO_DETECT = 0;

    /* package */ final static int VCARD_VERSION_V21 = 1;

    /* package */ final static int VCARD_VERSION_V30 = 2;

            private static final String LOG_TAG = "VCardImportPresetContact";

 

            public static final String PRESET_CONTACT_VCARD =

"file:///android_asset/preset_contacts.vcf";

    private static final boolean DEBUG = false;

 

    private final Context mContext;

    private final ContentResolver mResolver;

    private final Uri mUri;

            private final String mDisplayName;

    private final int mJobId;

 

    // TODO: remove and show appropriate message instead.

    private final List<Uri> mFailedUris = new ArrayList<Uri>();

 

    private VCardParser mVCardParser;

 

    private volatile boolean mCanceled;

    private volatile boolean mDone;

 

    /*

     * Change Feature by Mediatek Begin.

     *   Descriptions: handle cancel in the cancel function

     */

    private volatile boolean mIsRunning = false;

    /*

     * Change Feature by Mediatek End.

     */

 

    private int mCurrentCount = 0;

    private int mTotalCount = 0;

    /*

     * New Feature by Mediatek Begin.

     *   Descriptions: All of process should not be stopped by PM.

     */

    private PowerManager.WakeLock mWakeLock;

    /*

     * New Feature by Mediatek End.

     */

 

    public ImportPresetContactProcessor(final Context context,

            final String vcardFilePath, final int jobId) {

                                   super(null, null);

        mContext = context;

        mResolver = mContext.getContentResolver();

        mJobId = jobId;

                       mUri = Uri.parse(vcardFilePath);

                       mDisplayName = mUri.getLastPathSegment();

                       Log.d(LOG_TAG, "vCard Uri = " + mUri.getPath() + ", vCard DisplayName = " + mDisplayName);

        /*

         * New Feature by Mediatek Begin.

         *   Descriptions: All of process should not be stopped by PM.

         */

        final PowerManager powerManager = (PowerManager) mContext.getApplicationContext()

                .getSystemService("power");

        mWakeLock = powerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK

                | PowerManager.ON_AFTER_RELEASE, LOG_TAG);

        /*

         * New Feature by Mediatek End.

         */

        Log.d(LOG_TAG, "ImportProcessor() ");

    }

 

    @Override

    public void onStart() {

        // do nothing

    }

 

    @Override

    public void onEnd() {

        Log.d(LOG_TAG, "onEnd() ");

        // do nothing

    }

 

    @Override

    public void onEntryCreated(VCardEntry entry) {

        mCurrentCount++;

 

    }

 

    @Override

    public final int getType() {

                       //add by MTK for importing preset contact START

                       //return VCardService.TYPE_IMPORT;

        return SIMServiceUtils.SERVICE_WORK_IMPORT_PRESET_CONTACTS;

                       //add by MTK for importing preset contact END

    }

 

            //add by MTK for importing preset contact START

    public void doWork() {

        Log.d(LOG_TAG,"ImportPresetContactProcessor, run()");

            //add by MTK for importing preset contact END

 

        /*

         * Change Feature by Mediatek Begin.

         *   Descriptions: handle cancel in the cancel function

         */

        mIsRunning = true;

        /*

         * Change Feature by Mediatek End.

         */

        /*

         * New Feature by Mediatek Begin.

         *   Descriptions: All of process should not be stopped by PM.

         */

        mWakeLock.acquire();

        /*

         * New Feature by Mediatek End.

         */

        // ExecutorService ignores RuntimeException, so we need to show it here.

        try {

            /*

             * Bug Fix by Mediatek Begin.

             *   CR ID: ALPS00115856

             *   Descriptions: Set the thread priority to lowest

             *     and give up the change for Query

             */

            Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST);

            /*

             * Bug Fix by Mediatek End.

             */

            runInternal();

 

        } catch (OutOfMemoryError e) {

            Log.e(LOG_TAG, "OutOfMemoryError thrown during import", e);

            throw e;

        } catch (RuntimeException e) {

            Log.e(LOG_TAG, "RuntimeException thrown during import", e);

            throw e;

        } finally {

            synchronized (this) {

                mDone = true;

            }

            /*

             * New Feature by Mediatek Begin.

             *   Descriptions: All of process should not be stopped by PM.

             */

            if (mWakeLock != null && mWakeLock.isHeld()) {

                mWakeLock.release();

            }

            /*

             * New Feature by Mediatek End.

             */

        }

    }

 

    private void runInternal() {

            int count = context.getContentResolver().delete( RawContacts.CONTENT_URI.buildUpon().build(), RawContacts.IS_SDN_CONTACT + " = -2", null);
            LogUtils.d(TAG,"[deletePresetContacts]count:" + count);

                      

        Log.i(LOG_TAG, String.format("vCard import (id: %d) has started.", mJobId));

        final ImportRequest request = getImportRequest(mUri, mDisplayName);

        if (isCancelled()) {

            Log.i(LOG_TAG, "Canceled before actually handling parameter (" + request.uri + ")");

            return;

        }

        final int[] possibleVCardVersions;

        if (request.vcardVersion == VCARD_VERSION_AUTO_DETECT) {

            /**

             * Note: this code assumes that a given Uri is able to be opened more than once,

             * which may not be true in certain conditions.

             */

            possibleVCardVersions = new int[] {

                    VCARD_VERSION_V21,

                    VCARD_VERSION_V30

            };

        } else {

            possibleVCardVersions = new int[] {

                    request.vcardVersion

            };

        }

 

        final Uri uri = request.uri;

        final Account account = request.account;

        final int estimatedVCardType = request.estimatedVCardType;

        final String estimatedCharset = request.estimatedCharset;

        final int entryCount = request.entryCount;

        mTotalCount += entryCount;

 

        /**

         * add for import/export group infomations feature . start

         * original code:

         *        final VCardEntryConstructor constructor =

         *        new VCardEntryConstructor(estimatedVCardType, account, estimatedCharset);

         */

        final VCardEntryConstructor constructor = new VCardEntryConstructorForPresetContact(

                        estimatedVCardType, account, estimatedCharset);

        /**

         * add for import/export group infomations feature . end

         */

 

                       final VCardEntryCommitter committer = new VCardEntryCommitter(mResolver);

 

        constructor.addEntryHandler(committer);

        constructor.addEntryHandler(this);

 

        InputStream is = null;

        boolean successful = false;

        try {

            if (uri != null) {

                Log.i(LOG_TAG, "start importing one vCard (Uri: " + uri + ")");

                                               is = mContext.getAssets().open(uri.getLastPathSegment());

                //is = mResolver.openInputStream(uri);

            } else if (request.data != null){

                Log.i(LOG_TAG, "start importing one vCard (byte[])");

                is = new ByteArrayInputStream(request.data);

            }

 

            if (is != null) {

                successful = readOneVCard(is, estimatedVCardType, estimatedCharset, constructor,

                        possibleVCardVersions);

            }

        } catch (IOException e) {

            successful = false;

        } finally {

            if (is != null) {

                try {

                    is.close();

                } catch (Exception e) {

                    // ignore

                }

            }

        }

 

        if (successful) {

            // TODO: successful becomes true even when cancelled. Should return more appropriate

            // value

            if (isCancelled()) {

                Log.i(LOG_TAG, "vCard import has been canceled (uri: " + uri + ")");

                // Cancel notification will be done outside this method.

            } else {

                Log.i(LOG_TAG, "Successfully finished importing one vCard file: " + uri);

                List<Uri> uris = committer.getCreatedUris();

 

            }

        } else {

            Log.w(LOG_TAG, "Failed to read one vCard file: " + uri);

            mFailedUris.add(uri);

        }

    }

 

    private boolean readOneVCard(InputStream is, int vcardType, String charset,

            final VCardInterpreter interpreter,

            final int[] possibleVCardVersions) {

        boolean successful = false;

        final int length = possibleVCardVersions.length;

        for (int i = 0; i < length; i++) {

            final int vcardVersion = possibleVCardVersions[i];

            try {

                if (i > 0 && (interpreter instanceof VCardEntryConstructor)) {

                    // Let the object clean up internal temporary objects,

                    ((VCardEntryConstructor) interpreter).clear();

                }

 

                // We need synchronized block here,

                // since we need to handle mCanceled and mVCardParser at once.

                // In the worst case, a user may call cancel() just before creating

                // mVCardParser.

                synchronized (this) {

                    mVCardParser = (vcardVersion == VCARD_VERSION_V30 ?

                            new VCardParser_V30(vcardType) :

                                new VCardParser_V21(vcardType));

                    if (isCancelled()) {

                        Log.i(LOG_TAG, "ImportProcessor already recieves cancel request, so " +

                                "send cancel request to vCard parser too.");

                        mVCardParser.cancel();

                    }

                }

                mVCardParser.parse(is, interpreter);

 

                successful = true;

                break;

            } catch (IOException e) {

                Log.e(LOG_TAG, "IOException was emitted: " + e.getMessage());

            } catch (VCardNestedException e) {

                // This exception should not be thrown here. We should instead handle it

                // in the preprocessing session in ImportVCardActivity, as we don't try

                // to detect the type of given vCard here.

                //

                // TODO: Handle this case appropriately, which should mean we have to have

                // code trying to auto-detect the type of given vCard twice (both in

                // ImportVCardActivity and ImportVCardService).

                Log.e(LOG_TAG, "Nested Exception is found.");

            } catch (VCardNotSupportedException e) {

                Log.e(LOG_TAG, e.toString());

            } catch (VCardVersionException e) {

                if (i == length - 1) {

                    Log.e(LOG_TAG, "Appropriate version for this vCard is not found.");

                } else {

                    // We'll try the other (v30) version.

                }

            } catch (VCardException e) {

                Log.e(LOG_TAG, e.toString());

            } finally {

                if (is != null) {

                    try {

                        is.close();

                    } catch (IOException e) {

                    }

                }

            }

        }

 

        return successful;

    }

 

    @Override

    public synchronized boolean cancel(boolean mayInterruptIfRunning) {

        if (DEBUG) Log.d(LOG_TAG, "ImportProcessor received cancel request");

        if (mDone || mCanceled) {

            return false;

        }

        mCanceled = true;

 

        synchronized (this) {

            if (mVCardParser != null) {

                mVCardParser.cancel();

            }

        }

        return true;

    }

 

    @Override

    public synchronized boolean isCancelled() {

        return mCanceled;

    }

 

 

    @Override

    public synchronized boolean isDone() {

        return mDone;

    }

           

            private ImportRequest getImportRequest(final Uri localDataUri, final String displayName){

            final ImportRequest request;

                                   try {

                                               request = constructImportRequest(null, localDataUri, displayName);

                                   } catch (VCardException e) {

                                               Log.e(LOG_TAG, "Maybe the file is in wrong format", e);

                                               ///fixed cr ALPS00598462

                                               return null;

                                               /*

                                                * Bug Fix by Mediatek Begin. CR ID: ALPS00318987

                                                */

                                   } catch (IllegalArgumentException e) {

                                               Log.e(LOG_TAG, "Maybe the file is in wrong format", e);

                                               ///fixed cr ALPS00598462

                                               return null;

                                   /*

                                    * Bug Fix by Mediatek End.

                                    */

                                   } catch (IOException e) {

                                               Log.e(LOG_TAG, "Unexpected IOException", e);

                                               ///fixed cr ALPS00598462

 

                                               return null;

                                   }

                                   return request;

            }

           

            private ImportRequest constructImportRequest(final byte[] data,

                final Uri localDataUri, final String displayName)

                throws IOException, VCardException {

            final ContentResolver resolver = mContext.getApplicationContext().getContentResolver();

            VCardEntryCounter counter = null;

            VCardSourceDetector detector = null;

            int vcardVersion = VCARD_VERSION_V21;

            try {

                boolean shouldUseV30 = false;

                InputStream is;

                if (data != null) {

                    is = new ByteArrayInputStream(data);

                } else {

                                                          is = mContext.getAssets().open(localDataUri.getLastPathSegment());

                    //is = resolver.openInputStream(localDataUri);

                }

                mVCardParser = new VCardParser_V21();

                try {

                    counter = new VCardEntryCounter();

                    detector = new VCardSourceDetector();

                    mVCardParser.addInterpreter(counter);

                    mVCardParser.addInterpreter(detector);

                    mVCardParser.parse(is);

                } catch (VCardVersionException e1) {

                    try {

                        is.close();

                    } catch (IOException e) {

                    }

 

                    shouldUseV30 = true;

                    if (data != null) {

                        is = new ByteArrayInputStream(data);

                    } else {

                                                                      is = mContext.getAssets().open(localDataUri.getLastPathSegment());

                        //is = resolver.openInputStream(localDataUri);

                    }

                    mVCardParser = new VCardParser_V30();

                    try {

                        counter = new VCardEntryCounter();

                        detector = new VCardSourceDetector();

                        mVCardParser.addInterpreter(counter);

                        mVCardParser.addInterpreter(detector);

                        mVCardParser.parse(is);

                    } catch (VCardVersionException e2) {

                        throw new VCardException("vCard with unspported version.");

                    }

                } finally {

                    if (is != null) {

                        try {

                            is.close();

                        } catch (IOException e) {

                        }

                    }

                }

 

                vcardVersion = shouldUseV30 ? VCARD_VERSION_V30 : VCARD_VERSION_V21;

            } catch (VCardNestedException e) {

                Log.w(LOG_TAG, "Nested Exception is found (it may be false-positive).");

                // Go through without throwing the Exception, as we may be able to detect the

                // version before it

            }

            return new ImportRequest(null,

                    data, localDataUri, displayName,

                    detector.getEstimatedType(),

                    detector.getEstimatedCharset(),

                    vcardVersion, counter.getCount());

        }

}

 

6. 新建VCardEntryConstructorForPresetContact.java

path: alps\packages\apps\Contacts\src\com\mediatek\contacts\vcard

 

package com.mediatek.contacts.vcard;

 

import android.accounts.Account;

import com.android.vcard.VCardConfig;

import com.android.vcard.VCardEntryConstructor;

import com.android.vcard.VCardEntry;

 

public class VCardEntryConstructorForPresetContact extends VCardEntryConstructor {

    private final int mVCardType;

    private final Account mAccount;

 

    public VCardEntryConstructorForPresetContact() {

        this(VCardConfig.VCARD_TYPE_V21_GENERIC, null, null);

    }

 

    public VCardEntryConstructorForPresetContact(final int vcardType) {

        this(vcardType, null, null);

    }

 

    public VCardEntryConstructorForPresetContact(final int vcardType, final Account account) {

        this(vcardType, account, null);

    }

 

    /**

     * @deprecated targetCharset is not used anymore.

     * Use {@link #VCardEntryConstructor(int, Account)}

     */

    @Deprecated

    public VCardEntryConstructorForPresetContact(final int vcardType, final Account account,

            String targetCharset) {

        mVCardType = vcardType;

        mAccount = account;

    }

    protected VCardEntry getVCardEntry() {

        return new VCardEntryForPresetContact(mVCardType, mAccount);

    }

}

 

7.      新建VCardEntryForPresetContact.java 

path: alps\packages\apps\Contacts\src\com\mediatek\contacts\vcard

 

package com.mediatek.contacts.vcard;

 

import com.android.vcard.VCardEntry;

import android.accounts.Account;

import android.content.ContentProviderOperation;

import android.content.ContentResolver;

import android.provider.ContactsContract.RawContacts;

 

import java.util.ArrayList;

import java.util.List;

 

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

 

public class VCardEntryForPresetContact extends VCardEntry{

 

             public VCardEntryForPresetContact(int vcardType, Account account){

                       super(vcardType, account);

             }

            @Override

    public ArrayList<ContentProviderOperation> constructInsertOperations(ContentResolver resolver,

            ArrayList<ContentProviderOperation> operationList) {

        if (operationList == null) {

            operationList = new ArrayList<ContentProviderOperation>();

        }

 

        if (isIgnorable()) {

            return operationList;

        }

 

        final int backReferenceIndex = operationList.size();

 

        // After applying the batch the first result's Uri is returned so it is important that

        // the RawContact is the first operation that gets inserted into the list.

        ContentProviderOperation.Builder builder = ContentProviderOperation

                .newInsert(RawContacts.CONTENT_URI);

 

        builder.withValue(RawContacts.ACCOUNT_NAME, AccountType.ACCOUNT_NAME_LOCAL_PHONE);

        builder.withValue(RawContacts.ACCOUNT_TYPE, AccountType.ACCOUNT_TYPE_LOCAL_PHONE);

        builder.withValue(RawContacts.INDICATE_PHONE_SIM, RawContacts.INDICATE_PHONE);

                       builder.withValue(RawContacts.IS_SDN_CONTACT, -2);

        operationList.add(builder.build());

 

        int start = operationList.size();

        iterateAllData(new InsertOperationConstrutor(operationList, backReferenceIndex));

        int end = operationList.size();

 

        return operationList;

    }

 

private class InsertOperationConstrutor implements EntryElementIterator {

        private final List<ContentProviderOperation> mOperationList;

 

        private final int mBackReferenceIndex;

 

        public InsertOperationConstrutor(List<ContentProviderOperation> operationList,

                int backReferenceIndex) {

            mOperationList = operationList;

            mBackReferenceIndex = backReferenceIndex;

        }

 

        @Override

        public void onIterationStarted() {

        }

 

        @Override

        public void onIterationEnded() {

        }

 

        @Override

        public void onElementGroupStarted(EntryLabel label) {

        }

 

        @Override

        public void onElementGroupEnded() {

        }

 

        @Override

        public boolean onElement(EntryElement elem) {

            if (!elem.isEmpty()) {

                elem.constructInsertOperation(mOperationList, mBackReferenceIndex);

            }

            return true;

        }

    }

}

 

displayName = sourceUri.getLastPathSegment();

 

private ImportRequest constructImportRequest(final byte[] data,

                final Uri localDataUri, final String displayName)

                throws IOException, VCardException {

            final ContentResolver resolver = ImportVCardActivity.this.getContentResolver();

            VCardEntryCounter counter = null;

            VCardSourceDetector detector = null;

            int vcardVersion = VCARD_VERSION_V21;

            try {

                boolean shouldUseV30 = false;

                InputStream is;

                if (data != null) {

                    is = new ByteArrayInputStream(data);

                } else {

                    is = resolver.openInputStream(localDataUri);

                }

                mVCardParser = new VCardParser_V21();

                try {

                    counter = new VCardEntryCounter();

                    detector = new VCardSourceDetector();

                    mVCardParser.addInterpreter(counter);

                    mVCardParser.addInterpreter(detector);

                    mVCardParser.parse(is);

                } catch (VCardVersionException e1) {

                    try {

                        is.close();

                    } catch (IOException e) {

                    }

 

                    shouldUseV30 = true;

                    if (data != null) {

                        is = new ByteArrayInputStream(data);

                    } else {

                        is = resolver.openInputStream(localDataUri);

                    }

                    mVCardParser = new VCardParser_V30();

                    try {

                        counter = new VCardEntryCounter();

                        detector = new VCardSourceDetector();

                        mVCardParser.addInterpreter(counter);

                        mVCardParser.addInterpreter(detector);

                        mVCardParser.parse(is);

                    } catch (VCardVersionException e2) {

                        throw new VCardException("vCard with unspported version.");

                    }

                } finally {

                    if (is != null) {

                        try {

                            is.close();

                        } catch (IOException e) {

                        }

                    }

                }

 

                vcardVersion = shouldUseV30 ? VCARD_VERSION_V30 : VCARD_VERSION_V21;

            } catch (VCardNestedException e) {

                Log.w(LOG_TAG, "Nested Exception is found (it may be false-positive).");

                // Go through without throwing the Exception, as we may be able to detect the

                // version before it

            }

            return new ImportRequest(mAccount,

                    data, localDataUri, displayName,

                    detector.getEstimatedType(),

                    detector.getEstimatedCharset(),

                    vcardVersion, counter.getCount());

        }

 

Part3:保证预置联系人不可编辑

 

1.     File:DefaultContactListAdapter.java 

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

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

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

        selectionArgs.add("-1");

之后增加下面的代码

selection.append(" AND " + RawContacts.IS_SDN_CONTACT + " < 0");

 

2.     File:Contact.java 

Path: alps\packages\apps\Contacts\src\com\android\contacts\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\contacts\src\com\android\contacts\list 

在文件最后增加以下代码:

    public boolean showReadOnlyContact = true;

    public void setShowReadOnlyContact(boolean canDelete) {

        showReadOnlyContact = canDelete;

    }

 

5.   File:ContactEntryListFragment.java 

Path:alps\packages\apps\contacts\src\com\android\contacts\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");

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
测试编号 | 测试步骤 | 测试数据 | 预期结果 | 实际结果 | 预置条件 | 优先级 | 模块 --- | --- | --- | --- | --- | --- | --- | --- REG-001 | 输入手机号 | 12345678901 | 提示手机号格式不正确 | | 无 | 高 | 注册 REG-002 | 输入密码 | 123 | 提示密码长度不够 | | 无 | 高 | 注册 REG-003 | 输入密码 | 123456789012345678 | 提示密码长度超过限制 | | 无 | 高 | 注册 REG-004 | 输入密码 | abcdef | 提示密码必须包含数字 | | 无 | 高 | 注册 REG-005 | 输入验证码 | abcdef | 提示验证码格式不正确 | | 无 | 高 | 注册 REG-006 | 输入手机号、密码、验证码 | 12345678901、abcdef、1234 | 提示验证码不正确 | | 无 | 高 | 注册 REG-007 | 输入正确的手机号、密码、验证码 | 12345678901、abcdef123、1234 | 提示注册成功 | | 无 | 高 | 注册 REG-008 | 输入集团用户信息 | 集团名称、联系人姓名、联系人电话、集团地址、集团图片3张 | 提示信息已提交,请等待审核 | | 无 | 高 | 注册 REG-009 | 输入集团用户信息,但手机号格式不正确 | 集团名称、联系人姓名、联系人电话、集团地址、集团图片3张 | 提示手机号格式不正确 | | 无 | 高 | 注册 REG-010 | 输入集团用户信息,但缺少必填项 | 集团名称、联系人姓名、联系人电话、集团图片3张 | 提示缺少必填项 | | 无 | 高 | 注册 REG-011 | 输入正确的手机号、密码、验证码,但未同意协议 | 12345678901、abcdef123、1234 | 提示请同意协议 | | 无 | 高 | 注册 LOG-001 | 输入未注册的手机号、密码、验证码 | 12345678900、abcdef123、1234 | 提示手机号未注册 | | 无 | 高 | 登录 LOG-002 | 输入已注册的手机号,但密码不正确 | 12345678901、abcdef1234、1234 | 提示密码错误 | | 已注册的手机号 | 高 | 登录 LOG-003 | 输入已注册的手机号、正确的密码、错误的验证码 | 12345678901、abcdef123、5678 | 提示验证码错误 | | 已注册的手机号 | 高 | 登录 LOG-004 | 输入已注册的手机号、正确的密码、正确的验证码 | 12345678901、abcdef123、1234 | 提示登录成功 | | 已注册的手机号 | 高 | 登录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值