# 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`
  `ADDRESS`
  Requests the contact's postal addresses, which populates `Contact#getAddresses()`.
  `static final int`
  `ALL_FIELDS`
  Every field a picker can be asked for.
  `static final int`
  `BIRTHDAY`
  Requests the contact's birthday, which populates `Contact#getBirthday()`.
  `static final int`
  `EMAIL`
  Requests the contact's email addresses, which populates `Contact#getEmails()` and `Contact#getPrimaryEmail()`.
  `static final int`
  `MAXIMUM_SELECTION_LIMIT`
  The largest value `#setSelectionLimit(int)` accepts.
  `static final int`
  `NAME`
  Requests the contact's name, which populates `Contact#getFirstName()`, `Contact#getFamilyName()` and `Contact#getDisplayName()`.
  `static final int`
  `PHONE`
  Requests the contact's phone numbers, which populates `Contact#getPhoneNumbers()` and `Contact#getPrimaryPhoneNumber()`.
  `static final int`
  `PHOTO`
  Requests the contact's photo, which populates `Contact#getPhoto()`.
  `static final int`
  `WEBSITE`
  Requests the contact's web sites, which populates `Contact#getUrls()`.

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `ContactPicker()`

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static Contact[]`
  `getPickedContacts(ActionEvent ev)`
  Extracts the selection from the event delivered to `#pick(ActionListener)`.
  `int`
  `getRequestedFields()`
  The fields the picker is asked for, as a bit set of the constants on this class.
  `int`
  `getSelectionLimit()`
  The largest number of contacts the user may pick.
  `boolean`
  `isMultiSelect()`
  Whether the user may pick more than one contact.
  `boolean`
  `isRequireAllRequestedFields()`
  Whether a contact has to carry every requested field to be offered.
  `static boolean`
  `isSupported()`
  Returns true when the platform provides a contact picker.
  `void`
  `pick(ActionListener<ActionEvent> response)`
  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:
      - Constant Field Values

  - ### PHONE

    public static final int PHONE
    Requests the contact's phone numbers, which populates `Contact#getPhoneNumbers()` and `Contact#getPrimaryPhoneNumber()`.
    See Also:
      - Constant Field Values

  - ### EMAIL

    public static final int EMAIL
    Requests the contact's email addresses, which populates `Contact#getEmails()` and `Contact#getPrimaryEmail()`.
    See Also:
      - Constant Field Values

  - ### ADDRESS

    public static final int ADDRESS
    Requests the contact's postal addresses, which populates `Contact#getAddresses()`.
    See Also:
      - Constant Field Values

  - ### PHOTO

    public static final int PHOTO
    Requests the contact's photo, which populates `Contact#getPhoto()`.
    See Also:
      - Constant Field Values

  - ### 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:
      - Constant Field Values

  - ### WEBSITE

    public static final int WEBSITE
    Requests the contact's web sites, which populates `Contact#getUrls()`.
    See Also:
      - Constant Field Values

  - ### 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:
      - Constant Field Values

  - ### MAXIMUM_SELECTION_LIMIT

    public static final int MAXIMUM_SELECTION_LIMIT
    The largest value `#setSelectionLimit(int)` accepts. Android rejects a larger request outright.
    See Also:
      - Constant Field Values

- ## 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