1

I'm trying to get contacts that are not localy stored on my device, but found on a Microsoft Exchange ActiveSync directory, by providing a phone number. I've followed igorepst's post that provides a simple solution for retrieving contacts by name and I've tried to modify it to suit my needs, but I'm stuck.

This is the code let's me grab contacts by name

MainActivity

public class MainActivity extends AppCompatActivity {

    static final String TAG = "MAIN";
    private ArrayList<Long> dirIds;
    private String[] projection;
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.textView);

        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.WRITE_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.WRITE_CONTACTS}, 1);
        }

        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_CONTACTS}, 1);
        }

        CursorQueryWrapper wrapper = new CursorQueryWrapper(TAG);
        dirIds = new ArrayList<Long>();
        wrapper.query(this, ContactsContract.Directory.CONTENT_URI, new String[]{
                        ContactsContract.Directory._ID, ContactsContract.Directory.ACCOUNT_NAME, ContactsContract.Directory.ACCOUNT_TYPE
                }, null, null, null,
                new CursorQueryWrapper.CursorResultIterator() {
                    @Override
                    public void iterate(Cursor cursor) throws Exception {
                        long id = cursor.getLong(0);
                        if (ContactsContract.Directory.DEFAULT != id && ContactsContract.Directory.LOCAL_INVISIBLE != id) {
                            dirIds.add(id);
                            Log.d(TAG, "Account: id=" + id + " name=" + cursor.getString(1) + " type=" + cursor.getString(2));
                        }
                    }
                });
        if (dirIds.isEmpty()) {
            String result = "Cannot find additional accounts";
            Log.e(TAG, result);
            textView.setText(result);
        }else{
            HashSet<String> projSet = new HashSet<String>();
            projSet.add(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
            projSet.add(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
            projSet.add(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
            projSet.add(ContactsContract.CommonDataKinds.Email.ADDRESS);
            projSet.add(ContactsContract.CommonDataKinds.Phone.NUMBER);
            projSet.add(ContactsContract.Contacts.Data.MIMETYPE);
            projSet.add(ContactsContract.CommonDataKinds.Email.TYPE);
            projSet.add(ContactsContract.CommonDataKinds.Phone.TYPE);
            projection = projSet.toArray(new String[projSet.size()]);

            final String searchStr = "SOME NAME";

            new Thread(new Runnable() {
                @Override
                public void run() {
                    final String result;
                    if (TextUtils.isEmpty(searchStr)) {
                        result = "No input";
                    } else {
                        result = search(searchStr);
                    }

                    System.out.println(result);
                }
            }).start();

        }
    }

    private String search(final String searchString) {
        final StringBuilder bld = new StringBuilder();
        CursorQueryWrapper wrapper = new CursorQueryWrapper(TAG);
        final Context context = this;
        for (Long id : dirIds) {
            final String idStr = String.valueOf(id);
            Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon().appendEncodedPath(searchString)
                    .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, idStr).build();

            final ArrayList<String> lookupKeys = new ArrayList<String>();
            wrapper.query(context, uri, new String[] {
                    ContactsContract.Contacts.LOOKUP_KEY
            }, null, null, null, new CursorQueryWrapper.CursorResultIterator() {
                @Override
                public void iterate(Cursor cursor) throws Exception {
                    lookupKeys.add(cursor.getString(0));
                }
            });
            if (lookupKeys.isEmpty()) {
                continue;
            }

            for (String lookupKey : lookupKeys) {
                uri = ContactsContract.Contacts.CONTENT_LOOKUP_URI.buildUpon().appendEncodedPath(lookupKey)
                        .appendPath(ContactsContract.Contacts.Entity.CONTENT_DIRECTORY)
                        .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, idStr).build();
                wrapper.query(context, uri, projection, null, null, null, new CursorQueryWrapper.CursorResultIterator() {
                    @Override
                    public void iterate(Cursor cursor) throws Exception {
                        String mime = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.Data.MIMETYPE));
                        if (ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE.equals(mime)) {
                            String result = "Given name:"
                                    + cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME))
                                    + " Family name:"
                                    + cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME))
                                    + " Display name:"
                                    + cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME));
                            Log.d(TAG, result);
                            bld.append(result).append('\n');
                        } else if (ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE.equals(mime)) {
                            String result = "Email address:"
                                    + cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS))
                                    + " with type:"
                                    + ContactsContract.CommonDataKinds.Email.getTypeLabel(context.getResources(), cursor.getInt(cursor
                                    .getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE)), null);
                            Log.d(TAG, result);
                            bld.append(result).append('\n');
                        }
                        else if (ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE.equals(mime)) {
                            String result = "Phone num:"
                                    + cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
                                    + " with type:"
                                    + ContactsContract.CommonDataKinds.Phone.getTypeLabel(context.getResources(), cursor.getInt(cursor
                                    .getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE)), null);
                            Log.d(TAG, result);
                            bld.append(result).append('\n');
                        }
                    }
                });
                String result = "*************************************";
                Log.d(TAG, result);
                bld.append(result).append('\n');
            }
        }
        if (bld.length() == 0) {
            String result = "Cannot find matching contacts for the string '" + searchString + "'";
            Log.d(TAG, result);
            return result;
        }
        return bld.toString();
    }
}

CursorQueryWrapper

public class CursorQueryWrapper {

    private final String tag;
    private QueryInterface queryInterface;

    public static class CursorIteratonInterrupt extends Exception {
        private static final long serialVersionUID = -1124533346986767621L;
    }

    public static abstract class CursorResultIterator {
        public void iterate(Cursor cursor) throws Exception {
        }

        public boolean shouldIterate() {
            return true;
        }

        public void prepareForIterations(Cursor cursor) {
        }
    }

    public interface QueryInterface {
        Cursor query(Context context, Uri uri, String[] projection,
                     String selection, String[] selectionArgs, String sortOrder);
    }

    public static class ContextQuery implements QueryInterface {

        @Override
        public Cursor query(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs,
                            String sortOrder) {
            return context.getContentResolver()
                    .query(uri, projection, selection, selectionArgs, sortOrder);
        }

    }

    public CursorQueryWrapper(final String tag) {
        this(tag, null);
    }

    public CursorQueryWrapper(final String tag, QueryInterface queryInterface) {
        this.tag = tag;
        this.queryInterface = queryInterface == null ? new ContextQuery() : queryInterface;
    }

    public boolean query(Context context, Uri uri, String[] projection,
                         String selection, String[] selectionArgs, String sortOrder, CursorResultIterator iterator) {
        Cursor cursor = null;
        Log.d(tag, "Starting query");
        try {
            StringBuilder bld = new StringBuilder(
                    "Running query");
            bld.append("\nUri: ").append(uri.toString());
            bld.append("\nProjection: ").append(projection == null ? "null" : TextUtils.join(", ", projection));
            bld.append("\nSelection: ").append(selection);
            bld.append("\nSelectionArgs: ").append(
                    selectionArgs == null ? "null" : TextUtils.join(", ", selectionArgs));
            bld.append("\nSortOrder: ").append(sortOrder);
            Log.d(tag, bld.toString());
            cursor = queryInterface.query(context, uri, projection, selection, selectionArgs, sortOrder);
            if (cursor == null) {
                Log.e(tag, "Cannot process the query. The cursor is null as a result of some error.");
                return false;
            }
            Log.d(tag, "Cursor's count is " + cursor.getCount());
            iterator.prepareForIterations(cursor);
            if (iterator.shouldIterate()) {
                while (cursor.moveToNext()) {
                    iterator.iterate(cursor);
                }
            }
        } catch (Exception e) {
            if (!(e instanceof CursorIteratonInterrupt)) {
                Log.e(tag,
                        "Cannot process the query.", e);
                return false;
            }
        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
        Log.d(tag, "The query is ended successfully");
        return true;
    }

}

Now for grabbing contacts by number I've changed the search-method's (MainActivity) first Uri to this:

    Uri uri = ContactsContract.Contacts.CONTENT_FILTER_URI.buildUpon().appendEncodedPath("SOME PHONE NUMBER")
        .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY, idStr).build();

But it never finds any result. What have I missed here?

Community
  • 1
  • 1
ProfessorChaos
  • 201
  • 3
  • 12
  • I found the problem. The directory in question did not support search by numbers, only names. According to the google-docs a directory must support Contacts.CONTENT_FILTER_URI. CommonDataKinds.Phone.CONTENT_FILTER_URI, however, is optional. – ProfessorChaos May 18 '16 at 13:03

0 Answers0