{"id":13902415,"url":"https://github.com/vestrel00/contacts-android","last_synced_at":"2025-07-18T00:31:32.487Z","repository":{"id":37237369,"uuid":"223332584","full_name":"vestrel00/contacts-android","owner":"vestrel00","description":"Android Contacts API Library written in Kotlin with Java interoperability. No more ContentProviders and cursors. Say goodbye to ContactsContract. Build your own contacts app!","archived":false,"fork":false,"pushed_at":"2024-04-21T06:32:39.000Z","size":15000,"stargazers_count":588,"open_issues_count":29,"forks_count":35,"subscribers_count":12,"default_branch":"main","last_synced_at":"2024-08-07T22:33:43.989Z","etag":null,"topics":["android","android-contacts","android-library","contacts","contacts-android","contacts-api","contacts-app","contacts-library","contacts-management","contacts-manager","java","java-library","kotlin","kotlin-android","kotlin-library"],"latest_commit_sha":null,"homepage":"https://vestrel00.github.io/contacts-android/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vestrel00.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2019-11-22T05:48:05.000Z","updated_at":"2024-08-01T06:50:17.000Z","dependencies_parsed_at":"2024-03-30T23:32:36.504Z","dependency_job_id":"6e8787fd-ce57-4a8d-9a36-8c5685363bbd","html_url":"https://github.com/vestrel00/contacts-android","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vestrel00%2Fcontacts-android","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vestrel00%2Fcontacts-android/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vestrel00%2Fcontacts-android/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vestrel00%2Fcontacts-android/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vestrel00","download_url":"https://codeload.github.com/vestrel00/contacts-android/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226310588,"owners_count":17604606,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","android-contacts","android-library","contacts","contacts-android","contacts-api","contacts-app","contacts-library","contacts-management","contacts-manager","java","java-library","kotlin","kotlin-android","kotlin-library"],"created_at":"2024-08-06T22:01:08.428Z","updated_at":"2025-07-18T00:31:32.472Z","avatar_url":"https://github.com/vestrel00.png","language":"Kotlin","readme":"# Android Contacts, Reborn\n\n\u003e Written with ♥️ and 🔥 since December 2018. Open sourced since October 2021. \n\n![Android Contacts, Reborn banner](/docs/assets/images/banner.gif)\n\n[![JitPack](https://jitpack.io/v/vestrel00/contacts-android.svg)](https://jitpack.io/#vestrel00/contacts-android)\n\n[![Google Dev Library](https://img.shields.io/badge/Google%20Dev%20Library-Entry-2872e8.svg?style=flat\u0026logo=google)](https://devlibrary.withgoogle.com/products/android/repos/vestrel00-contacts-android)\n[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-Entry-green.svg?style=flat\u0026logo=android)](https://android-arsenal.com/details/1/8393)\n[![Android Weekly](https://img.shields.io/badge/AndroidWeekly-%23491-2299cc.svg?style=flat\u0026logo=android)](https://androidweekly.net/issues/issue-491)\n[![Kotlin Weekly](https://img.shields.io/badge/KotlinWeekly-%23275-7549b5.svg?style=flat\u0026logo=kotlin)](https://us12.campaign-archive.com/?u=f39692e245b94f7fb693b6d82\u0026id=c864ecd437)\n[![Java Trends](https://img.shields.io/badge/JavaTrends-%2358-f8981c.svg?style=flat\u0026logo=java)](https://dormoshe.io/newsletters/ag/java/58)\n[![Android Trends](https://img.shields.io/badge/AndroidTrends-%2381-3ddc84.svg?style=flat\u0026logo=android)](https://dormoshe.io/newsletters/ag/android/81)\n[![Kotlin Trends](https://img.shields.io/badge/KotlinTrends-%2364-7f51ff.svg?style=flat\u0026logo=kotlin)](https://dormoshe.io/newsletters/ag/kotlin/64)\n[![onCreate](https://img.shields.io/badge/onCreate-%23102-3ddc84.svg?style=flat\u0026logo=android)](https://www.oncreatedigest.com/issues/oncreate-digest-issue-102-1101232)\n[![ProAndroidDev](https://img.shields.io/badge/ProAndroidDev-Android%20Contacts,%20Reborn!-f53e28.svg?style=flat\u0026logo=medium)](https://proandroiddev.com/android-contacts-reborn-19985c73ad43)\n[![droidcon](https://img.shields.io/badge/droidcon-Curated-blue.svg?style=flat\u0026logo=android)](https://www.droidcon.com/2021/11/23/android-contacts-reborn/)\n[![Dev.to](https://img.shields.io/badge/Dev.to%20-3%20years%20to%20open%20source-0a0a0a.svg?style=flat\u0026logo=devdotto)](https://dev.to/vestrel00/i-spent-3-years-writing-an-android-contacts-api-in-kotlin-with-java-interop-what-ive-learned-54hp)\n[![Reddit](https://img.shields.io/badge/Reddit%20-Shared%20with%20the%20community-ff4500.svg?style=flat\u0026logo=reddit)](https://www.reddit.com/r/androiddev/comments/rz370s/i_dedicated_3_years_to_building_this_android/)\n\nThis library provides a complete set of APIs to do everything you need with Contacts in Android. \nYou no longer have to deal with the [Contacts Provider][contacts-provider], database operations, \nand cursors. \n\nWhether you just need to get all or some Contacts for a small part of your app (written in Kotlin\nor Java), or you are looking to create your own full-fledged Contacts app with the same capabilities\nas the AOSP Android Contacts app and Google Contacts app, this library is for you!\n\n**[Please help support this project 🙏❤️⭐️](https://github.com/vestrel00/contacts-android/discussions/189)**\n\n## Quick links\n\n- 📜 [Documentation][github-pages]\n- 🚉 [Current Release - 0.4.0](https://github.com/vestrel00/contacts-android/releases/tag/0.4.0)\n- 🚂 [Upcoming Release - 0.5.0](https://github.com/vestrel00/contacts-android/discussions/368)\n- ℹ️ [Project Status][project-status]\n- 🗺 [Project Roadmap][project-roadmap]\n- 💌 [Why use this library?][why-use-this]\n\n## Features\n\nThe `core` module provides,\n\n- ✅ [**All data kinds**](/docs/entities/about-api-entities.md) in the Contacts Provider;\n  _address, email, event, group membership, IM, name, nickname, note, organization, phone, photo, relation, SIP address, and website_\n- ✅ [**Custom data** integration](/docs/customdata/integrate-custom-data.md)\n- ✅ [**Broad queries**](/docs/basics/query-contacts.md) and [**advanced queries**](/docs/basics/query-contacts-advanced.md) of Contacts and RawContacts from zero or more Accounts and/or Groups\n- ✅ [**Queries using lookup keys**](/docs/basics/query-contacts-by-lookup-key.md)\n- ✅ [**Phone lookup queries**](/docs/basics/query-contacts-by-phone-or-sip.md) for specialized matching of phone or SIP\n- ✅ [Include only desired fields](/docs/basics/include-only-desired-data.md) in read/write operations to **optimize CPU and memory**\n- ✅ Powerful, **type-safe query DSL**\n- ✅ **Pagination** using order by, limit, and offset database functions.\n- ✅ [**Insert**](/docs/basics/insert-contacts.md) one or more RawContacts with an associated Account,\n  causing automatic insertion of a new Contact subject to automatic aggregation by the Contacts Provider\n- ✅ [**Update**](/docs/basics/update-contacts.md) one or more Contacts, RawContacts, and Data\n- ✅ [**Delete**](/docs/basics/delete-contacts.md) one or more Contacts, RawContacts, and Data\n- ✅ [Query](/docs/profile/query-profile.md), [insert](/docs/profile/insert-profile.md),\n  [update](/docs/profile/update-profile.md), and [delete](/docs/profile/delete-profile.md)\n   **Profile (device owner)** Contact, RawContact, and Data\n- ✅ [Query](/docs/groups/query-groups.md), [insert](/docs/groups/insert-groups.md),\n  [update](/docs/groups/update-groups.md), and [delete](/docs/groups/delete-groups.md) **Groups**\n- ✅ [Query](/docs/data/query-data-sets.md), [insert](/docs/data/insert-data-sets.md)\n  [update](/docs/data/update-data-sets.md ), and [delete](/docs/data/delete-data-sets.md) **specific kinds of data**\n- ✅ [Query](/docs/customdata/query-custom-data.md), [insert](/docs/customdata/insert-custom-data.md), \n  [update](/docs/customdata/update-custom-data.md), and [delete](/docs/customdata/delete-custom-data.md) **custom data**\n- ✅ [Query](/docs/blockednumbers/query-blocked-numbers.md), [insert](/docs/blockednumbers/insert-blocked-numbers.md),\n  and [delete](/docs/blockednumbers/delete-blocked-numbers.md) **Blocked Numbers**\n- ✅ [Query](/docs/sim/query-sim-contacts.md), [insert](/docs/sim/insert-sim-contacts.md),\n  [update](/docs/sim/update-sim-contacts.md), and [delete](/docs/sim/delete-sim-contacts.md) **SIM card contacts**\n- ✅ [Query](/docs/accounts/query-accounts.md) for Accounts in the system or RawContacts table\n- ✅ [Query](/docs/basics/query-raw-contacts.md) for just RawContacts\n- ✅ [Move RawContacts across Accounts](/docs/accounts/move-raw-contacts-across-accounts.md)\n- ✅ [**Link/unlink**](/docs/other/link-unlink-contacts.md) two or more Contacts\n- ✅ [Get/set contact options](/docs/other/get-set-clear-contact-raw-contact-options.md);\n  **_starred (favorite), custom ringtone, send to voicemail_**\n- ✅ [Get/set Contacts/RawContact **photo and thumbnail**](/docs/other/get-set-remove-contact-raw-contact-photo.md)\n- ✅ [Get/set **default (primary) Contact Data**](/docs/other/get-set-clear-default-data.md)\n  (e.g. default/primary phone number, email, etc)\n- ✅ [Share contacts via vCard (.VCF)](/docs/other/share-contacts-vcard.md)\n- ✅ [Convenience functions](/docs/other/convenience-functions.md)\n- ✅ [Contact data is synced automatically across devices](/docs/entities/sync-contact-data.md)\n- ✅ [Support for **logging API input and output**](/docs/logging/log-api-input-output.md)\n- ✅ [**Redactable entities** and API input and output](/docs/entities/redact-apis-and-entities.md)\n  for production-safe logging that upholds user data privacy laws to meet GDPR guidelines \n  _(this is not legal advice)_\n- ✅ [Full **in-depth documentation/guides**][github-pages].\n- ✅ Full **Java interoperability**\n- ✅ Core APIs have **zero dependency**\n- ✅ Clean separation between **Contacts vs RawContacts**\n- ✅ Clear distinction between truly deeply immutable, mutable, new, and existing entities allowing for **thread safety and JetPack compose optimizations**\n\nThere are also extensions that add functionality to every core function,\n\n- 🧰 [**Asynchronous** work using **Kotlin Coroutines**](/docs/async/async-execution-coroutines.md)\n- 🧰 [**Permissions** request/handling using **Kotlin Coroutines**](/docs/permissions/permissions-handling-coroutines.md)\n- 🔜 [**Kotlin Flow** extensions](https://github.com/vestrel00/contacts-android/milestone/8)\n- 🔜 [**RxJava** extensions](https://github.com/vestrel00/contacts-android/milestone/9)\n\nAlso included are some pre-baked goodies to be used as is or just for reference,\n\n- 🍬 [Gender custom data](/docs/customdata/integrate-gender-custom-data.md)\n- 🍬 [Google Contacts custom data](/docs/customdata/integrate-googlecontacts-custom-data.md)\n- 🍬 [Handle name custom data](/docs/customdata/integrate-handlename-custom-data.md)\n- 🍬 [Multiple notes custom data](/docs/customdata/integrate-multiple-notes-custom-data.md)\n- 🍬 [Pokemon custom data](/docs/customdata/integrate-pokemon-custom-data.md)\n- 🍬 [Role Playing Game (RPG) custom data](/docs/customdata/integrate-rpg-custom-data.md)\n- 🍬 [Rudimentary contacts-integrated UI components](/docs/ui/integrate-rudimentary-contacts-integrated-ui-components.md)\n- 🍬 [Debug functions to aid in development](/docs/debug/debug-contacts-provider-tables.md)\n\nThere are also more features that are on the way!\n\n1. ☢️ [Work profile contacts](https://github.com/vestrel00/contacts-android/issues/186)\n2. ☢️ [Dynamically integrate custom data from other apps](https://github.com/vestrel00/contacts-android/issues/112)\n3. ☢️ [Auto-generated custom data using annotations](https://github.com/vestrel00/contacts-android/issues/210)\n4. ☢️ [Read/write from/to .VCF file](https://github.com/vestrel00/contacts-android/issues/26)\n5. ☢️ [Multi-SIM card support](https://github.com/vestrel00/contacts-android/issues/336)\n\n## Installation\n\n\u003e ℹ️ This library is a multi-module project published with JitPack\n\u003e [![JitPack](https://jitpack.io/v/vestrel00/contacts-android.svg)](https://jitpack.io/#vestrel00/contacts-android)\n\nFirst, include JitPack in the repositories list,\n\n```groovy\nrepositories {\n    maven { url \"https://jitpack.io\" }\n}\n```\n\nTo install individual modules,\n\n```groovy\ndependencies {\n    implementation 'com.github.vestrel00.contacts-android:core:0.4.0'\n    \n    implementation 'com.github.vestrel00.contacts-android:async:0.4.0'\n    implementation 'com.github.vestrel00.contacts-android:customdata-gender:0.4.0'\n    implementation 'com.github.vestrel00.contacts-android:customdata-googlecontacts:0.4.0'\n    implementation 'com.github.vestrel00.contacts-android:customdata-handlename:0.4.0'\n    // Intentionally commented out multiple notes in case someone just copy-pastes this.\n    // Multiple notes custom data overrides the built-in note data kind so users should only \n    // integrate it if they know exactly what they are doing.\n    // implementation 'com.github.vestrel00.contacts-android:customdata-multiplenotes:0.4.0'\n    implementation 'com.github.vestrel00.contacts-android:customdata-pokemon:0.4.0'\n    implementation 'com.github.vestrel00.contacts-android:customdata-rpg:0.4.0'\n    implementation 'com.github.vestrel00.contacts-android:debug:0.4.0'\n    implementation 'com.github.vestrel00.contacts-android:permissions:0.4.0'\n    implementation 'com.github.vestrel00.contacts-android:test:0.4.0'\n    implementation 'com.github.vestrel00.contacts-android:ui:0.4.0'\n    // Notice that when importing specific modules/subprojects, the first \":\" comes after \"contacts-android\".\n}\n```\n\n**The `core` module is really all you need. All other modules are optional.**\n\nTo install all modules in a single line,\n\n```groovy\ndependencies {\n    implementation 'com.github.vestrel00:contacts-android:0.4.0'\n    // Notice that when importing all modules, the first \":\" comes after \"vestrel00\".\n}\n```\n\n\u003e ℹ️ Starting with version 0.2.0, installing all modules in a single line is only supported when \n\u003e using the [`dependencyResolutionManagement` in `settings.gradle`](https://developer.android.com/studio/build/dependencies#remote-repositories).\n\u003e You are still able to install all modules by specifying them individually.\n\nFor more info about the different modules and dependency resolution management, \nread the [Installation guide](/docs/setup/installation.md).\n\n## Setup\n\nThere is no setup required. It's up to you how you want to create and retain instances of the\n`contacts.core.Contacts(context)` API. For more info, read [Contacts API Setup](/docs/setup/setup-contacts-api.md).\n\nIt is also useful to read about [API Entities](/docs/entities/about-api-entities.md).\n\n## Quick Start\n\nTo retrieve all contacts containing all available contact data,\n\n```kotlin\nval contacts = Contacts(context).query().find()\n```\n\nTo simply search for Contacts, yielding the exact same results as the AOSP Contacts app,\n\n```kotlin\nval contacts = Contacts(context)\n    .broadQuery()\n    .wherePartiallyMatches(searchText)\n    .find()\n```\n\n\u003e ℹ️ For more info, read [Query contacts](/docs/basics/query-contacts.md).\n\nSomething a bit more advanced...\n\nTo retrieve the first 5 contacts (including only the contact id, display name, and phone numbers in\nthe results) ordered by display name in descending order, matching ALL of these rules;\n- a first name starting with \"leo\"\n- has emails from gmail or hotmail\n- lives in the US\n- has been born prior to making this query\n- is favorited (starred)\n- has a nickname of \"DarEdEvil\" (case sensitive)\n- works for Facebook\n- has a note\n- belongs to the account of \"john.doe@gmail.com\" or \"john.doe@myspace.com\"\n\n```kotlin\nval contacts = Contacts(context)\n    .query()\n    .where {\n        (Name.GivenName startsWith \"leo\") and\n        (Email.Address { endsWith(\"gmail.com\") or endsWith(\"hotmail.com\") }) and\n        (Address.Country equalToIgnoreCase \"us\") and\n        (Event { (Date lessThan Date().toWhereString()) and (Type equalTo EventEntity.Type.BIRTHDAY) }) and\n        (Contact.Options.Starred equalTo true) and\n        (Nickname.Name equalTo \"DarEdEvil\") and\n        (Organization.Company `in` listOf(\"facebook\", \"FB\")) and\n        (Note.Note.isNotNullOrEmpty())\n    }\n    .accounts(\n        Account(\"john.doe@gmail.com\", \"com.google\"),\n        Account(\"john.doe@myspace.com\", \"com.myspace\"),\n    )\n    .include { setOf(\n        Contact.Id,\n        Contact.DisplayNamePrimary,\n        Phone.Number\n    ) }\n    .orderBy(ContactsFields.DisplayNamePrimary.desc())\n    .offset(0)\n    .limit(5)\n    .find()\n```\n\n\u003e ℹ️ For more info, read [Query contacts (advanced)](/docs/basics/query-contacts-advanced.md).\n\nOnce you have the contacts, you now have access to all of their data!\n\n```kotlin\nval contact: Contact\nLog.d(\n    \"Contact\",\n    \"\"\"\n        ID: ${contact.id}\n        Lookup Key: ${contact.lookupKey}\n\n        Display name: ${contact.displayNamePrimary}\n        Display name alt: ${contact.displayNameAlt}\n\n        Photo Uri: ${contact.photoUri}\n        Thumbnail Uri: ${contact.photoThumbnailUri}\n\n        Last updated: ${contact.lastUpdatedTimestamp}\n\n        Starred?: ${contact.options?.starred}\n        Send to voicemail?: ${contact.options?.sendToVoicemail}\n        Ringtone: ${contact.options?.customRingtone}\n\n        Aggregate data from all RawContacts of the contact\n        -----------------------------------\n        Addresses: ${contact.addressList()}\n        Emails: ${contact.emailList()}\n        Events: ${contact.eventList()}\n        Group memberships: ${contact.groupMembershipList()}\n        IMs: ${contact.imList()}\n        Names: ${contact.nameList()}\n        Nicknames: ${contact.nicknameList()}\n        Notes: ${contact.noteList()}\n        Organizations: ${contact.organizationList()}\n        Phones: ${contact.phoneList()}\n        Relations: ${contact.relationList()}\n        SipAddresses: ${contact.sipAddressList()}\n        Websites: ${contact.websiteList()}\n        -----------------------------------\n    \"\"\".trimIndent()\n    // There are also aggregate data functions that return a sequence instead of a list.\n)\n```\n\n\u003e ℹ️ For more info, read about [API Entities](/docs/entities/about-api-entities.md).\n\n## More than enough APIs that will allow you to build your own contacts app!\n\nThis library is capable of doing more than just querying contacts. Actually, you can build your own\nfull-fledged contacts app with it!\n\nLet's take a look at a few other APIs this library provides...\n\nTo get the first 20 gmail emails ordered by email address in descending order,\n\n```kotlin\nval emails = Contacts(context)\n    .data()\n    .query()\n    .emails()\n    .where { Email.Address endsWith \"gmail.com\" }\n    .orderBy(Fields.Email.Address.desc(ignoreCase = true))\n    .offset(0)\n    .limit(20)\n    .find()\n```\n\nIt's not just for emails. It's for all data kinds (including custom data).\n\n\u003e ℹ️ For more info, read [Query specific data kinds](/docs/data/query-data-sets.md).\n\nTo **CREATE/INSERT** a contact with a name of \"John Doe\" who works at Amazon with a work email of\n\"john.doe@amazon.com\" (in Kotlin),\n\n```kotlin\nval insertResult = Contacts(context)\n    .insert()\n    .rawContacts(NewRawContact().apply {\n        name = NewName().apply {\n            givenName = \"John\"\n            familyName = \"Doe\"\n        }\n        organization = NewOrganization().apply {\n            company = \"Amazon\"\n            title = \"Superstar\"\n        }\n        emails.add(NewEmail().apply {\n            address = \"john.doe@amazon.com\"\n            type = EmailEntity.Type.WORK\n        })\n    })\n    .commit()\n```\n\nOr alternatively, in a more Kotlinized style using named arguments,\n\n```kotlin\nval insertResult = Contacts(context)\n    .insert()\n    .rawContacts(NewRawContact(\n        name = NewName(\n            givenName = \"John\",\n            familyName = \"Doe\"\n        ),\n        organization = NewOrganization(\n            company = \"Amazon\",\n            title = \"Superstar\"\n        ),\n        emails = mutableListOf(NewEmail(\n            address = \"john.doe@amazon.com\",\n            type = EmailEntity.Type.WORK\n        ))\n    ))\n    .commit()\n```\n\nOr alternatively, using extension functions,\n\n```kotlin\nval insertResult = Contacts(context)\n    .insert()\n    .rawContact {\n        setName {\n            givenName = \"John\"\n            familyName = \"Doe\"\n        }\n        setOrganization {\n            company = \"Amazon\"\n            title = \"Superstar\"\n        }\n        addEmail {\n            address = \"john.doe@amazon.com\"\n            type = EmailEntity.Type.WORK\n        }\n    }\n    .commit()\n```\n\n\u003e ℹ️ For more info, read [Insert contacts](/docs/basics/insert-contacts.md).\n\nIf John Doe switches jobs and heads over to Microsoft, we can **UPDATE** his data,\n\n```kotlin\nContacts(context)\n    .update()\n    .contacts(johnDoe.mutableCopy {\n        setOrganization {\n            company = \"Microsoft\"\n            title = \"Newb\"\n        }\n        emails().first().apply {\n            address = \"john.doe@microsoft.com\"\n        }\n    })\n    .commit()\n```\n\n\u003e ℹ️ For more info, read [Update contacts](/docs/basics/update-contacts.md).\n\nIf we no longer like John Doe, we can **DELETE** him from our life,\n\n```kotlin\nContacts(context)\n    .delete()\n    .contacts(johnDoe)\n    .commit()\n```\n\n\u003e ℹ️ For more info, read [Delete Contacts](/docs/basics/delete-contacts.md).\n\n## Threading and permissions\n\nThis library provides Kotlin coroutine extensions in the `permissions` module for all API functions\nto handle permissions and `async` module for executing work in background threads.\n\n```kotlin\nlaunch {\n    val contacts = Contacts(context)\n        .queryWithPermission()\n        ...\n        .findWithContext()\n\n    val deferredResult = Contacts(context)\n        .insertWithPermission()\n        ...\n        .commitAsync()\n    val result = deferredResult.await()\n}\n```\n\n\u003e ℹ️ For more info, read [Permissions handling using coroutines](/docs/permissions/permissions-handling-coroutines.md)\n\u003e and [Execute work outside of the UI thread using coroutines](/docs/async/async-execution-coroutines.md).\n\nSo, if we call the above function and we don't yet have permission. The user will be prompted to\ngive the appropriate permissions before the query proceeds. Then, the work is done in the coroutine\ncontext of choice (default is Dispatchers.IO). If the user does not give permission, the query will\nreturn no results.\n\n\u003e ℹ️ Extensions for Kotlin Flow and RxJava are also in the project roadmap, which includes APIs for \n\u003e listening to Contacts database changes.\n\n## Full documentation, guides, and samples\n\n**The above examples barely scratches the surface of what this library provides.** For more in-depth\ndocumentation, visit the [GitHub Pages][github-pages]. For a sample app reference, take a look at \nand run the `sample` module.\n\n## All APIs in the library are optimized!\n\nSome other APIs or util functions out there typically perform one internal database query per \ncontact returned. They do this to fetch the data per contact. This means that if there are \n1,000 matching contacts, then an extra 1,000 internal database queries are performed! \nThis is not cool!\n\nTo address this issue, the query APIs provided in the Contacts, Reborn library, perform only at \nleast two internal database queries no matter how many contacts are matched! Even if there are \n10,000 contacts matched, the library will only perform two internal database queries (depending on \nyour query parameters). Fetch 10,000 contacts as fast as **99 milliseconds** (varies per device)!\n\n\u003e ℹ️ For more info, read [Optimizing queries](/docs/basics/include-only-desired-data.md#optimizing-queries).\n\nOf course, if you don't want to fetch all hundreds of thousands of contacts, the query APIs support \n**pagination** with `limit` and `offset` functions!\n\n**Cancellations** are also supported! To cancel a query amid execution,\n\n```kotlin\n.find { returnTrueIfQueryShouldBeCancelled() }\n```\n\nThe find function optionally takes in a function that, if it returns true, will cancel query \nprocessing as soon as possible. The function is called numerous times during query processing to \ncheck if processing should stop or continue. This gives you the option to cancel the query.\n\nThis is useful when used in multi-threaded environments. One scenario where this would be frequently \nused is when performing queries as the user types a search text. You are able to cancel the current\nquery when the user enters new text.\n\nFor example, to automatically cancel the query inside a Kotlin coroutine when the coroutine is \ncancelled,\n\n```kotlin\nlaunch {\n    withContext(coroutineContext) {\n        val contacts = query.find { !isActive }\n    }\n    // Or, using the coroutine extensions in the async module...\n    val contacts = query.findWithContext()\n}\n```\n\n## All core APIs are framework-agnostic and works well with Java and Kotlin\n\n**The API does not and will not force you to use any frameworks (e.g. RxJava or Coroutines/Flow)!**\nAll core functions of the API live in the `core` module, which you can import to your project all by\nitself. Don't believe me? Take a look at the dependencies in the `core/build.gradle` :D \n\nSo, feel free to use the core API however you want with whatever libraries or frameworks you want, \nsuch as Reactive, Coroutines/Flow, AsyncTask (hope not), WorkManager, and whatever permissions \nhandling APIs you want to use.\n\nAll other modules in this library are **optional** and are just there for your convenience or for\nreference.\n\nI also made sure that **all core functions and entities are interoperable with Java.** So, if \nyou were wondering why I’m using a semi-builder pattern instead of using named arguments with \ndefault values, that is why. I’ve also made some other intentional decisions about API design to \nensure the best possible experience for both Kotlin and Java consumers without sacrificing Kotlin \nlanguage standards. It is Kotlin-first, Java-second (with love and care).\n\n\u003e ⚠️ Modules other than the core module are not guaranteed to be compatible with Java.\n\n## Requirements\n\n- Min SDK 19+\n\n## Proguard\n\nIf you use Proguard and the `async` and/or `permissions` modules, then you may need to add rules for\n[Coroutines][coroutines-proguard].\n\n## License\n\n    Copyright 2023 Contacts Contributors\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       https://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n[project-roadmap]: https://github.com/vestrel00/contacts-android/wiki/Project-Roadmap\n[project-status]: https://github.com/vestrel00/contacts-android/discussions/284#discussioncomment-11923170\n[why-use-this]: https://github.com/vestrel00/contacts-android/wiki/Why-use-this-library%3F\n[github-pages]: https://vestrel00.github.io/contacts-android/\n[contacts-provider]: https://developer.android.com/guide/topics/providers/contacts-provider\n[coroutines-proguard]: https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/jvm/resources/META-INF/proguard/coroutines.pro\n","funding_links":[],"categories":["Kotlin"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvestrel00%2Fcontacts-android","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvestrel00%2Fcontacts-android","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvestrel00%2Fcontacts-android/lists"}