Android GMS项目预设电话簿

[QUESTION]

遇到客户要求在gms项目中预设紧急联系人,但是电话簿和电话应用都替换为谷歌应用,无法通过在应用中直接修改,那么只能用其他方式去实现。

[RESOLVENT]

方案一:

查看应用后,发现系统会在开机后创建电话簿数据库,即contacts2.db,那么就可以通过替换该数据库来达到目的(没办法,权限高就是这么任性=_=!)。

1、编译打包:

将数据库文件放到编译目录中,在编译的时候保证数据库会编译并打包到img文件中,如下
device/mediatek/vendor/common/device.mk

ifeq ($(strip $(REPLACE_CONTACTS_DB)), yes)
PRODUCT_COPY_FILES += $(LOCAL_PATH)/contacts2.db:$/system/etc/init/contacts2.db
endif
2、开机后将数据库拷贝到指定目录下,即/data/data/com.android.providers.contacts/databases/下,该路径下的数据库则为联系人的数据库:

/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

@@ -9284,6 +9286,26 @@ public class PackageManagerService extends IPackageManager.Stub
     public void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
             long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
         Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
+        if (scanDir.getAbsolutePath().contains("data")) {
+			//遍历文件找到应用的/data/目录
+            SharedPreferences mSp =mContext.getSharedPreferences("Copy_Contacts",Context.MODE_PRIVATE);
+            boolean mFirstBoot = mSp.getBoolean(FIRST_BOOT, true);
+            SharedPreferences.Editor editor = mSp.edit();
+            if(mFirstBoot){
+                new Thread(() ->
+                {
+                    try {
+                        if (new File("/system/etc/init/contacts2.db").exists()) {
+                            copyFile("/system/etc/init/contacts2.db", "/data/data/com.android.providers.contacts/databases/contacts2.db");
+                            editor.putBoolean(FIRST_BOOT, false); //赋值false,拷贝成功后标记
+                            editor.commit();
+                        }
+                        Thread.sleep(3000);
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                });
+            }
+        }
         try {
             scanDirLI(scanDir, parseFlags, scanFlags, currentTime, packageParser, executorService);
         } finally {
@@ -9291,6 +9313,37 @@ public class PackageManagerService extends IPackageManager.Stub
         }
     }
 
+
+    public void copyFile(String oldPath, String newPath) {
+        try {
+            int bytesum = 0;
+            int byteread = 0;
+            File oldfile = new File(oldPath);
+            File newfile = new File(newPath);
+            if (oldfile.exists() && newfile.exists() ) { //文件存在时
+                InputStream inStream = new FileInputStream(oldPath); //读入原文件
+                FileOutputStream fs = new FileOutputStream(newPath);
+                byte[] buffer = new byte[1444];
+                int length;
+                while ( (byteread = inStream.read(buffer)) != -1) {
+                    bytesum += byteread; //字节数 文件大小
+                    System.out.println(bytesum);
+                    fs.write(buffer, 0, byteread);
+                }
+                inStream.close();
+                Log.d("seven", "PackageManagerService.java-->>copyFile: 复制完成!");
+            }
+            else
+            {
+                Log.d("seven", "PackageManagerService.java-->>copyFile: 文件已存在!");
+            }
+        }
+        catch (Exception e) {
+            Log.d("seven", "PackageManagerService.java-->>copyFile: 文件复制失败!");
+            e.printStackTrace();
+
+        }
+    }

方案二:

该方案通过监听开机广播,启动服务,再调用数据库创建数据的方式来达到预置联系人的目的。

1、监听开机广播&&启动服务
public class BootCmpReceiver extends BroadcastReceiver {
    private static final String TAG = "seven";
    private static final int ERROR_SUB_ID = -1000;
    private static final String FIRST_BOOT = "first_boot";
    private SharedPreferences mSp;
    public void onReceive(Context context, Intent intent) {
        final String action = intent.getAction();

        mSp = context.getSharedPreferences("SimProcessor",Context.MODE_PRIVATE);
        // add for multi-user ALPS01964765, whether the current user is running.
        // if not , will do nothing.
        UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
        boolean isRunning = userManager.isUserRunning(new UserHandle(UserHandle.myUserId()));
        Log.d(TAG, "[onReceive] action=" + action + " isRunning: " + isRunning
                + "isUserUnlocked() = " + userManager.isUserUnlocked());
        if (!isRunning) {
            return;
        }

        /// M: Not support SIM Contacts in guest mode.
        if (UserHandle.myUserId() != UserHandle.USER_OWNER) {
            Log.i(TAG, "[onReceive], The current user isn't owner !");
            return;
        }
		 if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
            if (!isPhbReady()) {
                processBootComplete(context);
            } else {
                processDupSimContacts(context);
            }
            android.util.Log.d("seven", "BootCmpReceiver.java-->>onReceive: 1111111111111111");
            //add by fenghuan for import contact
            if(context.getResources().getBoolean(R.bool.hct_preload_contacts)) {
                boolean mFirstBoot = mSp.getBoolean(FIRST_BOOT, true);
                SharedPreferences.Editor editor = mSp.edit();
                if(mFirstBoot){
                    presetServiceNumber(context);
                }
                editor.putBoolean(FIRST_BOOT, false); //赋值false,表示下次开机不用再拷贝了
                editor.commit();
            }
            //end
        } else if (TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED.equals(action)) {
            processMultiSimConfigChanged(context);
        }
    }

    private void startSimService(Context context, int subId, int workType) {
        Intent intent = null;
        intent = new Intent(context, SimProcessorService.class);
        intent.putExtra(SimServiceUtils.SERVICE_SUBSCRIPTION_KEY, subId);
        intent.putExtra(SimServiceUtils.SERVICE_WORK_TYPE, workType);
        Log.d(TAG, "[startSimService]subId:" + subId + "|workType:" + workType);
        SimProcessorService.setServiceIsStarting(true);
        context.startService(intent);
    }

}

2、创建数据
public class SimProcessorService extends Service {
    private final static String TAG = "SimProcessorService";
    private SimProcessorManager mProcessorManager;

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "[onCreate]...");
        GlobalEnv.setApplicationContext(getApplicationContext());
        mProcessorManager = new SimProcessorManager(this, mListener); 
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int id) {
        super.onStartCommand(intent, flags, id);
        processIntent(intent);
        IS_SERVICE_STARTING = false;
        return START_REDELIVER_INTENT;
    }

    private void processIntent(Intent intent) {
        if (intent == null) {
            Log.w(TAG, "[processIntent] intent is null.");
            return;
        }
        int subId = intent.getIntExtra(SimServiceUtils.SERVICE_SUBSCRIPTION_KEY, 0);
        int workType = intent.getIntExtra(SimServiceUtils.SERVICE_WORK_TYPE, -1);

        mProcessorManager.handleProcessor(getApplicationContext(), subId, workType, intent);
    }

    private SimProcessorManager.ProcessorManagerListener mListener =
            new ProcessorManagerListener() {
        @Override
        public void addProcessor(long scheduleTime, ProcessorBase processor) {
            if (processor != null) {
                try {
                    mExecutorService.execute(processor);
                    Settings.System.putString(getContentResolver(), IMPORT_REMOVE_RUNNING, "true");
                    sIsSimProcessorRunning = true;
                } catch (RejectedExecutionException e) {
                    Log.e(TAG, "[addProcessor] RejectedExecutionException: " + e.toString());
                }
            }
        }
}
    
public class PresetContactsImportProcessor extends SimProcessorBase {
    private static final String TAG = "PresetContactsImportProcessor";
    private static boolean sIsRunningNumberCheck = false;
    private static final int INSERT_PRESET_NUMBER_COUNT = 2; //预置联系人的个数
    private String[] INSERT_PRESET_NAME ={"110","118","119"}; //= {R.string.preloader_contacts_name1, R.string.preloader_contacts_name2}; //各预置联系人的姓名
    private String[] INSERT_PRESET_NUMBER ={"110","118","119"};// = {R.string.preloader_contacts_name1, R.string.preloader_contacts_name1}; //各预置联系人的号码

    private int mSubId;
    private Context mContext;

    public PresetContactsImportProcessor(Context context, int subId, Intent intent, ProcessorCompleteListener listener) {
        super(intent, listener);
        mContext = context;
        mSubId = subId;
        INSERT_PRESET_NAME = mContext.getResources().getStringArray(R.array.preloader_contacts_names);
        INSERT_PRESET_NUMBER = mContext.getResources().getStringArray(R.array.preloader_contacts_nums);
    }

    @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.length; 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(MtkContactsContract.RawContactsColumns.INDICATE_PHONE_SIM, MtkContactsContract.RawContacts.INDICATE_PHONE);
                    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]);
                    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]);
                    builder.withValue(Data.IS_PRIMARY, 1);
                    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;
        }
    }
}

小结:

方法一只做参考,该方法弊端太大了,且不容易维护,在复制文件时容易出现问题,但是还是有可取之处的,预置文件是可以用该方法的,不过需要完善;
方法二除了用来预置联系人,还可以用来执行开机以后需要完成的任务,且可维护性强,后续有需求可完善该方式。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值