代码分为两部分:

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. Spring-MVC:应用上下文webApplicationContext

    一.先说ServletContext javaee标准规定了,servlet容器需要在应用项目启动时,给应用项目初始化一个ServletContext作为公共环境容器存放公共信息.ServletCon ...

  2. 关于Javascript的forEach 和 map

    本篇博客转载自 https://blog.fundebug.com/2018/02/05/map_vs_foreach/ 如果你已经有使用JavaScript的经验,你可能已经知道这两个看似相同的方法 ...

  3. POJ 3181完全背包(+高精)

    思路: f[i]表示还剩i空间的方案数 套个高精 (网上有人把它拆成了两个long long) 其实这道题的高精并不难写-.. //By SiriusRen #include <cstdio&g ...

  4. hbase启动报错:Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=128m; support was removed in 8.0

    输入HBASE_MASTER_OPTS只是为了快速寻找这个选项而已,如果你手工找也可以 刚才那个命令回车后直接跳到这 前面加#就好了 修改后保存.重新启动hbase就好了. 注意:各个节点都要修改哦. ...

  5. spring 中国下载点

    http://repo.spring.io/libs-release-local/org/springframework/spring/ spring 中国下载点

  6. 学习TF:《TensorFlow技术解析与实战》PDF+代码

    TensorFlow 是谷歌公司开发的深度学习框架,也是目前深度学习的主流框架之一.<TensorFlow技术解析与实战>从深度学习的基础讲起,深入TensorFlow框架原理.模型构建. ...

  7. SpringMVC框架的多表查询和增删查改

    必须声明本文章==>http://www.cnblogs.com/zhu520/p/7883268.html 一: 1):我的运行环境 我使用myeclipse(你也可以使用eclipse),t ...

  8. 【ios开发学习 - 第二课】iOS项目文件夹结构

    文件夹结构 AppDelegate Models Macro General Helpers Vendors Sections Resources   一个合理的文件夹结构首先应该是清晰的.让人一眼看 ...

  9. 【LeetCode-面试算法经典-Java实现】【05-Longest Palindromic Substring(最大回文字符串)】

    背景 近期開始研究算法,于是在leetcode上做算法题,第五题Longest Palindromic Substring便是关于回文子串的. 什么是回文字串 回文字符串是指将该字符串前后颠倒之后和该 ...

  10. 61.node.js开发错误——Error: Connection strategy not found

    转自:https://blog.csdn.net/fd214333890/article/details/53457145