Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 159e85fe authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Detect empty device accounts." into ub-contactsdialer-g-dev

parents 32876909 bc510849
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -1490,7 +1490,8 @@ public class PeopleActivity extends ContactsDrawerActivity implements


        if (getSupportActionBar() != null) {
        if (getSupportActionBar() != null) {
            String actionBarTitle;
            String actionBarTitle;
            if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS) {
            if (filter.filterType == ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS &&
                    filter.accountName == null) {
                actionBarTitle = getString(R.string.account_phone);
                actionBarTitle = getString(R.string.account_phone);
            } else if (!TextUtils.isEmpty(filter.accountName)) {
            } else if (!TextUtils.isEmpty(filter.accountName)) {
                actionBarTitle = getActionBarTitleForAccount(filter);
                actionBarTitle = getActionBarTitleForAccount(filter);
+7 −3
Original line number Original line Diff line number Diff line
@@ -93,6 +93,12 @@ public final class ContactListFilter implements Comparable<ContactListFilter>, P
                /* accountType= */ null, /* accountName= */ null, /* dataSet= */ null, icon);
                /* accountType= */ null, /* accountName= */ null, /* dataSet= */ null, icon);
    }
    }


    public static ContactListFilter createDeviceContactsFilter(Drawable icon,
            AccountWithDataSet account) {
        return new ContactListFilter(ContactListFilter.FILTER_TYPE_DEVICE_CONTACTS,
                account.type, account.name, account.dataSet, icon);
    }

    /**
    /**
     * Whether the given {@link ContactListFilter} has a filter type that should be displayed as
     * Whether the given {@link ContactListFilter} has a filter type that should be displayed as
     * the default contacts list view.
     * the default contacts list view.
@@ -333,10 +339,8 @@ public final class ContactListFilter implements Comparable<ContactListFilter>, P
    }
    }


    public AccountWithDataSet toAccountWithDataSet() {
    public AccountWithDataSet toAccountWithDataSet() {
        if (filterType == FILTER_TYPE_ACCOUNT) {
        if (filterType == FILTER_TYPE_ACCOUNT || filterType == FILTER_TYPE_DEVICE_CONTACTS) {
            return new AccountWithDataSet(accountName, accountType, dataSet);
            return new AccountWithDataSet(accountName, accountType, dataSet);
        } else if (filterType == FILTER_TYPE_DEVICE_CONTACTS) {
            return AccountWithDataSet.getLocalAccount();
        } else {
        } else {
            throw new IllegalStateException("Cannot create Account from filter type " +
            throw new IllegalStateException("Cannot create Account from filter type " +
                    filterTypeToString(filterType));
                    filterTypeToString(filterType));
+64 −29
Original line number Original line Diff line number Diff line
@@ -18,10 +18,10 @@ package com.android.contacts.common.model;
import android.accounts.AccountManager;
import android.accounts.AccountManager;
import android.content.ContentResolver;
import android.content.ContentResolver;
import android.database.Cursor;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.VisibleForTesting;


import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.util.DeviceLocalAccountTypeFactory;
import com.android.contacts.common.util.DeviceLocalAccountTypeFactory;


@@ -39,6 +39,9 @@ import java.util.Set;
 */
 */
public class DeviceLocalAccountLocator {
public class DeviceLocalAccountLocator {


    // Note this class is assuming ACCOUNT_NAME and ACCOUNT_TYPE have same values in
    // RawContacts, Groups, and Settings. This assumption simplifies the code somewhat and it
    // is true right now and unlikely to ever change.
    @VisibleForTesting
    @VisibleForTesting
    static String[] PROJECTION = new String[] {
    static String[] PROJECTION = new String[] {
            ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE,
            ContactsContract.RawContacts.ACCOUNT_NAME, ContactsContract.RawContacts.ACCOUNT_TYPE,
@@ -49,30 +52,59 @@ public class DeviceLocalAccountLocator {
    private static final int COL_TYPE = 1;
    private static final int COL_TYPE = 1;
    private static final int COL_DATA_SET = 2;
    private static final int COL_DATA_SET = 2;



    private final ContentResolver mResolver;
    private final ContentResolver mResolver;
    private final DeviceLocalAccountTypeFactory mAccountTypeFactory;
    private final DeviceLocalAccountTypeFactory mAccountTypeFactory;
    private final Set<String> mKnownAccountTypes;


    private final String mSelection;
    private final String[] mSelectionArgs;


    public DeviceLocalAccountLocator(ContentResolver contentResolver,
    public DeviceLocalAccountLocator(ContentResolver contentResolver,
            DeviceLocalAccountTypeFactory factory,
            DeviceLocalAccountTypeFactory factory,
            List<AccountWithDataSet> knownAccounts) {
            List<AccountWithDataSet> knownAccounts) {
        mResolver = contentResolver;
        mResolver = contentResolver;
        mAccountTypeFactory = factory;
        mAccountTypeFactory = factory;
        mKnownAccountTypes = new HashSet<>();

        final Set<String> knownAccountTypes = new HashSet<>();
        for (AccountWithDataSet account : knownAccounts) {
        for (AccountWithDataSet account : knownAccounts) {
            mKnownAccountTypes.add(account.type);
            knownAccountTypes.add(account.type);
        }
        }
        mSelection = getSelection(knownAccountTypes);
        mSelectionArgs = getSelectionArgs(knownAccountTypes);
    }
    }


    public List<AccountWithDataSet> getDeviceLocalAccounts() {
    public List<AccountWithDataSet> getDeviceLocalAccounts() {
        final String[] selectionArgs = getSelectionArgs();
        final Cursor cursor = mResolver.query(ContactsContract.RawContacts.CONTENT_URI, PROJECTION,
                getSelection(), selectionArgs, null);


        final Set<AccountWithDataSet> localAccounts = new HashSet<>();
        final Set<AccountWithDataSet> localAccounts = new HashSet<>();

        // Many device accounts have default groups associated with them.
        addAccountsFromQuery(ContactsContract.Groups.CONTENT_URI, localAccounts);

        addAccountsFromQuery(ContactsContract.Settings.CONTENT_URI, localAccounts);

        if (localAccounts.isEmpty()) {
            // It's probably safe to assume that if one of the earlier queries found a "device"
            // account then this query isn't going to find any different device accounts.
            // We skip this query because it probably is kind of expensive (relative to the other
            // queries).
            addAccountsFromQuery(ContactsContract.RawContacts.CONTENT_URI, localAccounts);
        }

        return new ArrayList<>(localAccounts);
    }

    private void addAccountsFromQuery(Uri uri, Set<AccountWithDataSet> accounts) {
        final Cursor cursor = mResolver.query(uri, PROJECTION, mSelection, mSelectionArgs, null);

        if (cursor == null) return;

        try {
        try {
            addAccountsFromCursor(cursor, accounts);
        } finally {
            cursor.close();
        }
    }

    private void addAccountsFromCursor(Cursor cursor, Set<AccountWithDataSet> accounts) {
        while (cursor.moveToNext()) {
        while (cursor.moveToNext()) {
            final String name = cursor.getString(COL_NAME);
            final String name = cursor.getString(COL_NAME);
            final String type = cursor.getString(COL_TYPE);
            final String type = cursor.getString(COL_TYPE);
@@ -80,36 +112,39 @@ public class DeviceLocalAccountLocator {


            if (DeviceLocalAccountTypeFactory.Util.isLocalAccountType(
            if (DeviceLocalAccountTypeFactory.Util.isLocalAccountType(
                    mAccountTypeFactory, type)) {
                    mAccountTypeFactory, type)) {
                    localAccounts.add(new AccountWithDataSet(name, type, dataSet));
                accounts.add(new AccountWithDataSet(name, type, dataSet));
            }
            }
        }
        }
        } finally {
            cursor.close();
    }
    }


        return new ArrayList<>(localAccounts);
    @VisibleForTesting
    public String getSelection() {
        return mSelection;
    }
    }


    @VisibleForTesting
    @VisibleForTesting
    public String getSelection() {
    public String[] getSelectionArgs() {
        final StringBuilder sb = new StringBuilder();
        return mSelectionArgs;
        sb.append(ContactsContract.RawContacts.DELETED).append(" =0 AND (")
    }

    private static String getSelection(Set<String> knownAccountTypes) {
        final StringBuilder sb = new StringBuilder()
                .append(ContactsContract.RawContacts.ACCOUNT_TYPE).append(" IS NULL");
                .append(ContactsContract.RawContacts.ACCOUNT_TYPE).append(" IS NULL");
        if (mKnownAccountTypes.isEmpty()) {
        if (knownAccountTypes.isEmpty()) {
            return sb.append(')').toString();
            return sb.toString();
        }
        }
        sb.append(" OR ").append(ContactsContract.RawContacts.ACCOUNT_TYPE).append(" NOT IN (");
        sb.append(" OR ").append(ContactsContract.RawContacts.ACCOUNT_TYPE).append(" NOT IN (");
        for (String ignored : mKnownAccountTypes) {
        for (String ignored : knownAccountTypes) {
            sb.append("?,");
            sb.append("?,");
        }
        }
        // Remove trailing ','
        // Remove trailing ','
        sb.deleteCharAt(sb.length() - 1).append(')').append(')');
        sb.deleteCharAt(sb.length() - 1).append(')');

        return sb.toString();
        return sb.toString();
    }
    }


    @VisibleForTesting
    private static String[] getSelectionArgs(Set<String> knownAccountTypes) {
    public String[] getSelectionArgs() {
        if (knownAccountTypes.isEmpty()) return null;
        return mKnownAccountTypes.toArray(new String[mKnownAccountTypes.size()]);

        return knownAccountTypes.toArray(new String[knownAccountTypes.size()]);
    }
    }
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -139,6 +139,7 @@ public class AccountWithDataSet implements Parcelable {
                args = new String[] {type, name, dataSet};
                args = new String[] {type, name, dataSet};
            }
            }
        }
        }
        selection += " AND " + RawContacts.DELETED + "=0";


        final Cursor c = context.getContentResolver().query(RAW_CONTACTS_URI_LIMIT_1,
        final Cursor c = context.getContentResolver().query(RAW_CONTACTS_URI_LIMIT_1,
                ID_PROJECTION, selection, args, null);
                ID_PROJECTION, selection, args, null);
+15 −6
Original line number Original line Diff line number Diff line
@@ -22,7 +22,9 @@ import android.content.AsyncTaskLoader;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Drawable;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.text.TextUtils;
import android.util.Log;
import android.util.Log;


@@ -31,8 +33,10 @@ import com.android.contacts.common.list.AccountFilterActivity;
import com.android.contacts.common.list.ContactListFilter;
import com.android.contacts.common.list.ContactListFilter;
import com.android.contacts.common.list.ContactListFilterController;
import com.android.contacts.common.list.ContactListFilterController;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.RawContact;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contactsbind.ObjectFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Lists;


import java.util.ArrayList;
import java.util.ArrayList;
@@ -90,15 +94,17 @@ public class AccountFilterUtil {
     */
     */
    public static class FilterLoader extends AsyncTaskLoader<List<ContactListFilter>> {
    public static class FilterLoader extends AsyncTaskLoader<List<ContactListFilter>> {
        private Context mContext;
        private Context mContext;
        private DeviceLocalAccountTypeFactory mDeviceLocalFactory;


        public FilterLoader(Context context) {
        public FilterLoader(Context context) {
            super(context);
            super(context);
            mContext = context;
            mContext = context;
            mDeviceLocalFactory = ObjectFactory.getDeviceLocalAccountTypeFactory(context);
        }
        }


        @Override
        @Override
        public List<ContactListFilter> loadInBackground() {
        public List<ContactListFilter> loadInBackground() {
            return loadAccountFilters(mContext);
            return loadAccountFilters(mContext, mDeviceLocalFactory);
        }
        }


        @Override
        @Override
@@ -117,7 +123,8 @@ public class AccountFilterUtil {
        }
        }
    }
    }


    private static List<ContactListFilter> loadAccountFilters(Context context) {
    private static List<ContactListFilter> loadAccountFilters(Context context,
            DeviceLocalAccountTypeFactory deviceAccountTypeFactory) {
        final ArrayList<ContactListFilter> accountFilters = Lists.newArrayList();
        final ArrayList<ContactListFilter> accountFilters = Lists.newArrayList();
        final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(context);
        final AccountTypeManager accountTypeManager = AccountTypeManager.getInstance(context);
        accountTypeManager.sortAccounts(/* defaultAccount */ getDefaultAccount(context));
        accountTypeManager.sortAccounts(/* defaultAccount */ getDefaultAccount(context));
@@ -127,13 +134,15 @@ public class AccountFilterUtil {
        for (AccountWithDataSet account : accounts) {
        for (AccountWithDataSet account : accounts) {
            final AccountType accountType =
            final AccountType accountType =
                    accountTypeManager.getAccountType(account.type, account.dataSet);
                    accountTypeManager.getAccountType(account.type, account.dataSet);
            if (accountType.isExtension() && !account.hasData(context)) {
            if ((accountType.isExtension() || DeviceLocalAccountTypeFactory.Util.isLocalAccountType(
                // Hide extensions with no raw_contacts.
                    deviceAccountTypeFactory, account.type)) && !account.hasData(context)) {
                // Hide extensions and device accounts with no raw_contacts.
                continue;
                continue;
            }
            }
            final Drawable icon = accountType != null ? accountType.getDisplayIcon(context) : null;
            final Drawable icon = accountType != null ? accountType.getDisplayIcon(context) : null;
            if (account.isLocalAccount()) {
            if (DeviceLocalAccountTypeFactory.Util.isLocalAccountType(
                accountFilters.add(ContactListFilter.createDeviceContactsFilter(icon));
                    deviceAccountTypeFactory, account.type)) {
                accountFilters.add(ContactListFilter.createDeviceContactsFilter(icon, account));
            } else {
            } else {
                accountFilters.add(ContactListFilter.createAccountFilter(
                accountFilters.add(ContactListFilter.createAccountFilter(
                        account.type, account.name, account.dataSet, icon));
                        account.type, account.name, account.dataSet, icon));
Loading