contacts 账户同步

来源:互联网 发布:360软件助手 编辑:程序博客网 时间:2024/06/12 02:40

本流程图基于MTK平台 Android 7.0,本流程只作为沟通学习使用

工作中遇到一个问题,手机登陆Google账户并同步账户里面的contacts后,本地保存的联系人数据被无缘无故的删除了,甚是奇怪,通过对比前后的数据库我们发现,同步后直接把我们的本地账户给删除了,所以导致属于这个账户的所有联系人都不见了,那么无缘无故为什么会删除本地账户呢?我们先抛出问题,等我们看完整个流程再回来看看真是什么。前提,我们的手机是被客制化过,不是android原生系统。

整体流程图

这里写图片描述

部分流程说明

我们重点看看updateAccountsInBackground这个方法

后台更新账户,判断账户是否合法,不合法就删除合法就保存

private boolean updateAccountsInBackground(Account[] systemAccounts) {        if (!haveAccountsChanged(systemAccounts)) { //判断当前账户是否有改变            return false;        }.....        Log.i(TAG, "Accounts changed");        invalidateFastScrollingIndexCache();        final ContactsDatabaseHelper dbHelper = mDbHelper.get();        final SQLiteDatabase db = dbHelper.getWritableDatabase();.....        try {            // First, remove stale rows from raw_contacts, groups, and related tables.            // All accounts that are used in raw_contacts and/or groups.            final Set<AccountWithDataSet> knownAccountsWithDataSets                    = dbHelper.getAllAccountsWithDataSets();            // Find the accounts that have been removed.            final List<AccountWithDataSet> accountsWithDataSetsToDelete = Lists.newArrayList();            for (AccountWithDataSet knownAccountWithDataSet : knownAccountsWithDataSets) {                if (knownAccountWithDataSet.isLocalAccount()                        || !canDeleteAccount(knownAccountWithDataSet)                        || knownAccountWithDataSet.inSystemAccounts(systemAccounts, mSkipRemoval)) {                    continue;                }                accountsWithDataSetsToDelete.add(knownAccountWithDataSet);//保存需要删除的账户,后面如果这个list不为空就删除里面账户的相关信息            }            if (!accountsWithDataSetsToDelete.isEmpty()) {                for (AccountWithDataSet accountWithDataSet : accountsWithDataSetsToDelete) {.....做一些数据库删除操作,把这个账户相关的数据都删除              }            }            // Second, remove stale rows from Tables.SETTINGS and Tables.DIRECTORIES            removeStaleAccountRows(                    Tables.SETTINGS, Settings.ACCOUNT_NAME, Settings.ACCOUNT_TYPE, systemAccounts);            removeStaleAccountRows(Tables.DIRECTORIES, Directory.ACCOUNT_NAME,                    Directory.ACCOUNT_TYPE, systemAccounts);.....一些删除操作            /// @}            // Third, remaining tasks that must be done in a transaction.            // TODO: Should sync state take data set into consideration?            dbHelper.getSyncState().onAccountsChanged(db, systemAccounts);            saveAccounts(systemAccounts);//保存新加的账户            db.setTransactionSuccessful();        } finally {.....        mAccountWritability.clear();        updateContactsAccountCount(systemAccounts);        updateProviderStatus();        return true;    }

haveAccountsChanged

查看账户是否有变更

    @VisibleForTesting    boolean haveAccountsChanged(Account[] currentSystemAccounts) {        final ContactsDatabaseHelper dbHelper = mDbHelper.get();        final Set<Account> knownAccountSet;        try {            knownAccountSet =                    stringToAccounts(dbHelper.getProperty(DbProperties.KNOWN_ACCOUNTS, ""));        } catch (IllegalArgumentException e) {            // Failed to get the last known accounts for an unknown reason.  Let's just            // treat as if accounts have changed.            return true;        }        final Set<Account> currentAccounts = Sets.newHashSet(currentSystemAccounts);        return !knownAccountSet.equals(currentAccounts);    }

isLocalAccount

通过账户类型判断当前账户是否是本地账户

    public static final String ACCOUNT_TYPE_LOCAL_PHONE = "Local Phone Account";    private static final String ACCOUNT_TYPE_SIM = "SIM Account";    private static final String ACCOUNT_TYPE_USIM = "USIM Account";    private static final String ACCOUNT_TYPE_RUIM = "RUIM Account";    private static final String ACCOUNT_TYPE_CSIM = "CSIM Account";    private static final String LOCAL_ACCOUNT_TYPES = "('" +            ACCOUNT_TYPE_LOCAL_PHONE + "' , '" +            ACCOUNT_TYPE_SIM + "' , '" +            ACCOUNT_TYPE_USIM + "' , '" +            ACCOUNT_TYPE_RUIM + "' , '" +            ACCOUNT_TYPE_CSIM + "')";    /**     * Check if the account is local account     */    public static boolean isLocalAccount(String accountType, String accountName) {        return (accountType == null && accountName == null)                || (accountType != null && LOCAL_ACCOUNT_TYPES.contains(accountType));    }

inSystemAccounts

判断当前账户是不是系统合法账户

    public boolean inSystemAccounts(Account[] systemAccounts, boolean skip) {        // Note we don't want to create a new Account object from this instance, as it may contain        // null account name/type, which Account wouldn't accept.  So we need to compare field by        // field.        for (Account systemAccount : systemAccounts) {            if (Objects.equal(systemAccount.name, getAccountName())//通过获取账户名和账户类型来判断                    && Objects.equal(systemAccount.type, getAccountType())) {                return true;            }        }        return false;    }

saveAccounts

将合法账户保存下来并更新一些值

    @VisibleForTesting    void saveAccounts(Account[] systemAccounts) {        final ContactsDatabaseHelper dbHelper = mDbHelper.get();        dbHelper.setProperty(                DbProperties.KNOWN_ACCOUNTS, accountsToString(Sets.newHashSet(systemAccounts)));    }

问题解决

回顾我们的问题,我们是发现登陆账户同步联系人后,本地账户被删除了,然而我们本地账户是被客制化了的,根据上面的流程我们可以知道,添加账户后会检查已存在的账户和加入的账户是否是本地账户,并检查账户是否合法,那么我们就有怀疑点了,是否是我们的本地账户类型不合法呢?所以我们就有了解决办法。
1.把我们预置的本地账户类型改成代码中本地账户合法的类型
2.把我们预置的本地账户类型添加到LOCAL_ACCOUNT_TYPES 中,让其成为一个合法的本地账户类型

原创粉丝点击