Class ContactPicker

java.lang.Object
com.codename1.contacts.ContactPicker

public class ContactPicker extends Object

Lets the user hand the application a small number of contacts they chose themselves, without the application gaining access to the address book.

This is the privacy-minimized counterpart to ContactsManager. Where ContactsManager enumerates the whole address book -- and therefore needs the broad contacts permission -- this class shows the platform's own contact picker. The user selects, the platform copies just the fields that were asked for out of just the contacts that were selected, and the application never gets to see anything else.

Prefer it whenever the application needs "a phone number the user picked" rather than "the address book". Google Play requires exactly that distinction: from 2027-01-27, an app targeting Android 17 (API level 37) or later that carries READ_CONTACTS without core-functionality justification has to pass a Play Console declaration, and an app that only ever calls this class never asks for that permission in the first place.

Requesting fields

The requested fields are a bit set of the constants on this class. Only those fields are populated on the returned contacts; everything else is left null or zero. Asking for less is not merely polite -- on Android the request also decides which contacts the picker offers, and the platform refuses to return anything that was not asked for.

ContactPicker picker = new ContactPicker();
picker.setRequestedFields(ContactPicker.NAME | ContactPicker.PHONE);
picker.pick(new ActionListener<ActionEvent>() {
    public void actionPerformed(ActionEvent ev) {
        Contact[] picked = ContactPicker.getPickedContacts(ev);
        if(picked.length == 0) {
            // the user backed out
            return;
        }
        numberField.setText(picked[0].getPrimaryPhoneNumber());
    }
});
The result is a snapshot

The contacts handed to the callback are plain copies. The application has no continuing access to them: it cannot re-read them later, and on Android the temporary grant behind them is gone by the time the callback returns. Anything that has to outlive the callback must be copied out of the Contact and stored by the application.

One getter does not follow the rule that an unrequested field stays null, and cannot be made to. Contact#getDisplayName() never returns null: on a contact carrying no name it makes one up from the primary phone number, the primary email or the id, and caches it. That is how every Contact in the framework behaves, not only a picked one, so a picker that suppressed it would be the odd one out rather than the correct one. Ask Contact#getFirstName() and Contact#getFamilyName() when what you need to know is whether a name was actually supplied.

For the same reason Contact#getId() on a picked contact is only an opaque platform identifier useful for telling two picked contacts apart. Passing it to ContactsManager#getContactById(String) needs full address-book access, which is the thing this class exists to avoid.

What a platform can actually deliver

A picker returns what its platform is able to hand over without the broad permission, and that is not the same everywhere. Read every field you asked for defensively: a null one means the user's contact did not carry it, or the platform could not supply it.

Android 17 and later, iOS and the simulator serve every field on this class. Android before 17 has no contact picker of its own, so the fallback is the contacts app's own single-row picker: it returns one contact carrying one kind of data, #NAME plus whichever of #PHONE, #EMAIL and #ADDRESS was requested first. #PHOTO, #BIRTHDAY and #WEBSITE are best-effort there -- they are read through the granted contact's own data rows, which some devices allow and some refuse -- and #setMultiSelect(boolean) and #setRequireAllRequestedFields(boolean) have no effect. None of that ever escalates into a permission prompt; the fields simply come back null.

Availability

#isSupported() reports whether the platform has a picker at all. Where it does not, #pick(ActionListener) reports an empty selection rather than quietly falling back to reading the address book, because that fallback would need the permission the caller was trying not to ask for.

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final int
    Requests the contact's postal addresses, which populates Contact#getAddresses().
    static final int
    Every field a picker can be asked for.
    static final int
    Requests the contact's birthday, which populates Contact#getBirthday().
    static final int
    Requests the contact's email addresses, which populates Contact#getEmails() and Contact#getPrimaryEmail().
    static final int
    The largest value #setSelectionLimit(int) accepts.
    static final int
    Requests the contact's name, which populates Contact#getFirstName(), Contact#getFamilyName() and Contact#getDisplayName().
    static final int
    Requests the contact's phone numbers, which populates Contact#getPhoneNumbers() and Contact#getPrimaryPhoneNumber().
    static final int
    Requests the contact's photo, which populates Contact#getPhoto().
    static final int
    Requests the contact's web sites, which populates Contact#getUrls().
  • Constructor Summary

    Constructors
    Constructor
    Description
     
  • Method Summary

    Modifier and Type
    Method
    Description
    static Contact[]
    Extracts the selection from the event delivered to #pick(ActionListener).
    int
    The fields the picker is asked for, as a bit set of the constants on this class.
    int
    The largest number of contacts the user may pick.
    boolean
    Whether the user may pick more than one contact.
    boolean
    Whether a contact has to carry every requested field to be offered.
    static boolean
    Returns true when the platform provides a contact picker.
    void
    Shows the platform's contact picker and reports the selection.
    void
    setMultiSelect(boolean multiSelect)
    Sets whether the user may pick more than one contact.
    void
    setRequestedFields(int requestedFields)
    Sets the fields the picker is asked for.
    void
    setRequireAllRequestedFields(boolean requireAllRequestedFields)
    Sets whether a contact has to carry every requested field to be offered by the picker.
    void
    setSelectionLimit(int selectionLimit)
    Sets the largest number of contacts the user may pick, which only has an effect together with #setMultiSelect(boolean).

    Methods inherited from class Object

    clone, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • NAME

      public static final int NAME
      Requests the contact's name, which populates Contact#getFirstName(), Contact#getFamilyName() and Contact#getDisplayName().
      See Also:
    • PHONE

      public static final int PHONE
      Requests the contact's phone numbers, which populates Contact#getPhoneNumbers() and Contact#getPrimaryPhoneNumber().
      See Also:
    • EMAIL

      public static final int EMAIL
      Requests the contact's email addresses, which populates Contact#getEmails() and Contact#getPrimaryEmail().
      See Also:
    • ADDRESS

      public static final int ADDRESS
      Requests the contact's postal addresses, which populates Contact#getAddresses().
      See Also:
    • PHOTO

      public static final int PHOTO
      Requests the contact's photo, which populates Contact#getPhoto().
      See Also:
    • BIRTHDAY

      public static final int BIRTHDAY

      Requests the contact's birthday, which populates Contact#getBirthday().

      The one field a picker cannot filter on exactly. Android groups birthdays with anniversaries and custom dates, so #setRequireAllRequestedFields(boolean) may still offer a contact that turns out to have an anniversary and no birthday; the contact comes back with a zero birthday rather than being withheld.

      See Also:
    • WEBSITE

      public static final int WEBSITE
      Requests the contact's web sites, which populates Contact#getUrls().
      See Also:
    • ALL_FIELDS

      public static final int ALL_FIELDS
      Every field a picker can be asked for. Convenient for a one-off "import this person" flow, and the wrong choice for anything else: asking for a field the application will not read hands it data it did not need, which is what the picker exists to prevent.
      See Also:
    • MAXIMUM_SELECTION_LIMIT

      public static final int MAXIMUM_SELECTION_LIMIT
      The largest value #setSelectionLimit(int) accepts. Android rejects a larger request outright.
      See Also:
  • Constructor Details

    • ContactPicker

      public ContactPicker()
  • Method Details

    • isSupported

      public static boolean isSupported()

      Returns true when the platform provides a contact picker.

      It answers for the platform rather than for the device. Android says yes wherever the application is running normally, because deciding otherwise would mean asking the package manager what handles the picker intent, and from Android 11 that question is filtered by package visibility -- it would report no picker on ordinary devices where the picker works. A device that really has no contacts application reports an empty selection from #pick(ActionListener), which is what a cancelled pick reports, so a listener that checks the selection handles it already.

      Returns

      true if the platform has a picker, false if #pick(ActionListener) will report an empty selection without showing anything

    • getPickedContacts

      public static Contact[] getPickedContacts(ActionEvent ev)

      Extracts the selection from the event delivered to #pick(ActionListener).

      Parameters
      • ev: the event handed to the listener, which may be null
      Returns

      the contacts the user picked, in the order the platform reported them, or a zero length array when the user cancelled or the platform has no picker. Never null.

    • getRequestedFields

      public int getRequestedFields()

      The fields the picker is asked for, as a bit set of the constants on this class.

      Returns

      the requested fields, NAME | PHONE unless it was changed

    • setRequestedFields

      public void setRequestedFields(int requestedFields)

      Sets the fields the picker is asked for.

      Parameters
      • requestedFields: a bit set of the constants on this class, which must name at least one field
    • isMultiSelect

      public boolean isMultiSelect()

      Whether the user may pick more than one contact.

      Returns

      true if the picker allows a multiple selection, false by default

    • setMultiSelect

      public void setMultiSelect(boolean multiSelect)

      Sets whether the user may pick more than one contact.

      A platform whose picker is single-select ignores this and returns at most one contact, so the callback must cope with a shorter selection than it allowed for. Android before version 17 is such a platform.

      Parameters
      • multiSelect: true to allow a multiple selection
    • getSelectionLimit

      public int getSelectionLimit()

      The largest number of contacts the user may pick.

      Returns

      the selection limit, MAXIMUM_SELECTION_LIMIT unless it was changed

    • setSelectionLimit

      public void setSelectionLimit(int selectionLimit)

      Sets the largest number of contacts the user may pick, which only has an effect together with #setMultiSelect(boolean).

      The selection handed to the listener never exceeds it. Whether the user is stopped at the cap or merely has the surplus dropped depends on the platform: Android and the simulator stop accepting the tick that would exceed it, and so does iOS for a limit of one, which it serves with its single-select picker. iOS cannot cap a larger multiple selection -- its picker has no such setting -- so a user who confirms more than the cap has the extras dropped, keeping the ones they chose first.

      Parameters
      • selectionLimit: a count between 1 and MAXIMUM_SELECTION_LIMIT inclusive
    • isRequireAllRequestedFields

      public boolean isRequireAllRequestedFields()

      Whether a contact has to carry every requested field to be offered.

      Returns

      true to offer only contacts holding all of the requested fields, false by default, which offers a contact holding any of them

    • setRequireAllRequestedFields

      public void setRequireAllRequestedFields(boolean requireAllRequestedFields)

      Sets whether a contact has to carry every requested field to be offered by the picker.

      Use it when a partial contact is useless to the application, for instance an invitation flow that needs both a name and an email address. Leave it off when any one of the requested fields will do.

      A platform applies it as far as its own picker can. Android 17 and later enforce it exactly; iOS enforces it over phone numbers, email addresses and postal addresses and cannot filter on the rest; Android before 17 has no picker predicate at all and ignores it. So the listener still has to cope with a contact that turned out to be missing one.

      Parameters
      • requireAllRequestedFields: true to require every requested field
    • pick

      public void pick(ActionListener<ActionEvent> response)

      Shows the platform's contact picker and reports the selection.

      The call returns at once; the picker runs on top of the application and the listener is invoked on the EDT when the user is done. A cancelled pick and a platform with no picker both report an empty selection, so #getPickedContacts(ActionEvent) is the only thing the listener has to check.

      Parameters
      • response: invoked with the selection once the user is done