What’s changing
Apps that target the upcoming Android release will no longer be able to directly write to contacts with the WRITE_CONTACTS permission. Instead, you can use the standard contact intents (ACTION_INSERT, ACTION_EDIT, and ACTION_INSERT_OR_EDIT). For a complete reference implementation, see the developer guide on how to modify contacts using intents.
On devices running the upcoming Android release, these three contact intents will behave consistently and need no permission at all. If your app targets the upcoming Android release or later and attempts to write to contacts directly, those writes will be rejected and result in a SecurityException or permission denial. For the small set of apps which require broad access to create and modify contacts, a new special app access permission, MANAGE_CONTACTS, arrives in Android 17 QPR2 (Q4 2026). Google Play is publishing updated guidelines for contact access, including MANAGE_CONTACTS, today.
Why we’re doing this
Currently, if your app needs to save even one contact, you might be requesting WRITE_CONTACTS. But that permission grants broad access, allowing an app to make widespread changes to contacts across the device in the background, even without user interaction. Most apps don’t need such broad permission.
While alternatives exist, we’ve heard from you that they need to be more standardized across the ecosystem. Previously, the contact intents behaved differently from one device to the next. Some editors dropped the data you passed in, like a contact photo. On some devices, the back button saved the contact without the user meaning to or the “create new contact” option was hard to find. So asking for permission was the rational choice. We’re fixing all these issues in the upcoming Android version and requiring devices running it to follow the same standards.
What to use instead
Add or edit a contact: use the contact intents
When you use these intents – ACTION_INSERT, ACTION_EDIT, and ACTION_INSERT_OR_EDIT – the system handles the heavy lifting by presenting a clean, standardized contact editor experience. It opens a quick half-sheet form for new entries, or allows the user to easily search and add information to an existing contact. Users can seamlessly expand this into a full-page editor to fill out more details, all without your app ever needing direct write permissions. View the tentative UX mocks below:
Figure 1: Create a New Contact *UX not Final*
Figure 2: Add Info to an Existing Contact *UX not Final*
Note: Different device manufacturers may modify the user experience to match their OS style but the behaviour will remain consistent.
You can further streamline the creation process by passing optional data payloads, known as Extras, alongside your intent:
- EXTRA_ACCOUNT suggests which account the contact saves to, which helps if your app syncs contacts. This extra already existed, but support varied by device. Starting in the upcoming Android release, support is standardized across devices.
- EXTRA_PHOTO_URI passes a photo to pre-fill the contact picture. The editor handles the URI read permission for you. This is new with the upcoming Android release and will be supported across the ecosystem.
Before: writing directly with WRITE_CONTACTS (Results in a SecurityException or permission denial once your app targets the upcoming Android release.)
// Requires android.permission.WRITE_CONTACTS
fun saveContactDirectly(context: Context, name: String, phone: String, account: Account) {
val ops = arrayListOf(
ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, account.type)
.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, account.name)
.build(),
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(
ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE
)
.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)
.build(),
ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
.withValue(
ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE
)
.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
.build()
)
context.contentResolver.applyBatch(ContactsContract.AUTHORITY, ops)
}
After: opening the contact editor (No permission needed.)
fun saveContactWithEditor(
context: Context,
name: String,
phone: String,
account: Account,
photoUri: Uri
) {
val intent = Intent(Intent.ACTION_INSERT, ContactsContract.Contacts.CONTENT_URI).apply {
putExtra(ContactsContract.Intents.Insert.NAME, name)
putExtra(ContactsContract.Intents.Insert.PHONE, phone)
// Suggest which account the contact is saved to
putExtra(ContactsContract.Intents.Insert.EXTRA_ACCOUNT, account)
// New in the upcoming Android release: pre-fill the contact photo
putExtra(ContactsContract.Intents.Insert.EXTRA_PHOTO_URI, photoUri)
clipData = ClipData.newRawUri(“”, photoUri)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
context.startActivity(intent)
}
Before: updating an existing contact directly
// Requires android.permission.WRITE_CONTACTS
fun addPhoneDirectly(context: Context, rawContactId: Long, phone: String) {
val values = ContentValues().apply {
put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId)
put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
}
context.contentResolver.insert(ContactsContract.Data.CONTENT_URI, values)
}
After: letting the user choose a contact to update, or create a new one
fun addPhoneWithEditor(context: Context, phone: String) {
val intent = Intent(Intent.ACTION_INSERT_OR_EDIT).apply {
type = ContactsContract.Contacts.CONTENT_ITEM_TYPE
putExtra(ContactsContract.Intents.Insert.PHONE, phone)
}
context.startActivity(intent)
}
If you already know which contact to update, use ACTION_EDIT with that contact’s URI:
fun editKnownContact(context: Context, contactUri: Uri, phone: String) {
val intent = Intent(Intent.ACTION_EDIT, contactUri).apply {
putExtra(ContactsContract.Intents.Insert.PHONE, phone)
}
context.startActivity(intent)
}
Pick a contact: use the Contact Picker
If you only need to read contacts the user chooses, use the Contact Picker, available since Android 17. It needs no permission.
Calling and messaging apps: use People Directory
Some apps add “Call with…” or “Message with…” actions to contacts so people can start a call or chat from the Phone or Contacts app. If your app does this today by writing extra entries into the user’s contacts, move to People Directory, arriving in Android QPR2 (Q4 2026). It’s a new system directory where your app publishes how people can reach each other in your app, without editing the user’s contacts.
Examples of how apps can migrate
To see how these alternatives work in practice, here are a few examples of how different types of apps can approach contact access:
Example app type (non-exclusive).Recommended migration pathSocial, P2P Payment, & Ride-Sharing AppsIf your app lets users find friends, split a bill, or share a trip status, you don’t need contact permissions at all. Use the Contact Picker for one-time contact selection, and launch ACTION_INSERT with EXTRA_PHOTO_URI when a user taps “Save to Contacts” on a profile.Business Card Scanners & Event Networking AppsIf your app scans a badge or QR code and saves a new contact – or adds a work phone number to an existing colleague’s entry – use ACTION_INSERT or ACTION_INSERT_OR_EDIT. The standardized half-sheet editor pre-fills the parsed fields (name, company, phone, email, and photo) so the user can verify and save in one tap without granting background permissions.VoIP Calling & Messaging AppsRather than requesting WRITE_CONTACTS to inject custom “Call with…” or “Message with…” rows into the user’s address book, publish reachability metadata through People Directory and use ACTION_INSERT when users add a new contact from a chat thread.Enterprise CRM & Cloud Sync AppsIf your app performs continuous, two-way background contact synchronization with a cloud or enterprise account – where prompting the user with an intent UI for every record isn’t feasible – your app qualifies to declare MANAGE_CONTACTS
Changes to check for
- Custom data types aren’t supported in the editor. If you pass Insert.DATA rows with MIME types other than the standard ContactsContract.CommonDataKinds types, those MIME types will be silently ignored by the editor.
- SHOW_OR_CREATE_CONTACT isn’t handled by the system editor. Contacts apps that come with the device can still handle it. For consistent behavior across devices, use ACTION_INSERT_OR_EDIT.
- Writes fail by default. Once you target the upcoming Android release, any direct write without MANAGE_CONTACTS results in a SecurityException or permission denial. Test for it.
Do I need MANAGE_CONTACTS?
Probably not. If your app saves or edits contacts because a user asked it to, the intents above cover you, with no permission and no Play Console declaration.
MANAGE_CONTACTS is for apps whose core purpose is managing contacts, where the intents aren’t enough. For example:
Your app…Need MANAGE_CONTACTS?Saves a contact from a chat, business card, or order.No, use ACTION_INSERTAdds a number or email to an existing contact.No, use ACTION_INSERT_OR_EDIT or ACTION_EDITLets users pick contacts to invite, share with, or pay.No, use the Contact PickerAdds call or message actions to contacts.No, use People DirectoryHas its own branded contact editing screen.No, a custom interface alone doesn’t qualifyIs a dedicated contact manager or dialer replacement app.Likely yesIs a caller ID & spam protection app that mass-updates address book entries.Likely yesSyncs contacts with an enterprise or cloud account in the background.Likely yesPerforms bulk contact backup/restore or device-to-device phone transfer.Likely yesSets custom ringtones for individual contacts.Likely yes
How it works:
- MANAGE_CONTACTS is a special app access permission. It isn’t a runtime dialog. Users turn it on under Settings > Special app access > Manage contacts.
// Opens Settings > Apps > Special app access > Manage contacts
val intent = Intent(Settings.ACTION_MANAGE_CONTACTS, Uri.fromParts(“package”, packageName, null))
context.startActivity(intent)
- It covers reading, adding, editing, and deleting contacts, accounts and People Directory data. You don’t need to request READ_CONTACTS as well.
- To publish on Google Play with MANAGE_CONTACTS, you submit a declaration in Play Console explaining why the intents aren’t enough for your app’s core functionality.
Migration steps
- Find your contact writes. Search your code for WRITE_CONTACTS, ContactsContract.RawContacts.CONTENT_URI, ContactsContract.Data.CONTENT_URI, and applyBatch(ContactsContract.AUTHORITY, …).
- Replace each user-driven write with an intent: ACTION_INSERT for new contacts, and ACTION_EDIT or ACTION_INSERT_OR_EDIT for updates.
- Use only standard data types in Insert.DATA. Move call or message actions to People Directory.
- Decide whether you truly need MANAGE_CONTACTS using the table above. If you do, plan your Play Console declaration.
- Remove WRITE_CONTACTS from your manifest once no code path needs it.
Timeline
WhenWhat happensOctober 21, 2026Google Play announces the MANAGE_CONTACTS policy2026 (Android 17 Quarterly Platform Release 2)MANAGE_CONTACTS permission becomes available2027 (Upcoming Android release)WRITE_CONTACTS no longer grants write access to apps targeting the upcoming Android release. Contact intents are standardized across devices2027, not earlier than the upcoming Android releasePlay Console asks apps that use MANAGE_CONTACTS to submit a declaration2027, not earlier than the upcoming Android releasePlay policy compliance required
FAQ
- Does this affect every app?
- The WRITE_CONTACTS deprecation change applies only to apps that target the upcoming Android release and after. Apps targeting older versions keep their current behavior, however, the new standardized contact editor will be available to all apps running on the new OS, regardless of their target SDK.
- Can my app delete contacts with intent?
- No. There’s no intent for deleting contacts. Users delete contacts in their contacts app. Apps with MANAGE_CONTACTS can delete contacts directly.
- I already have my own contact editing screen. Can I keep it?
- Only if your app qualifies for MANAGE_CONTACTS. Wanting to keep a custom design isn’t a qualifying reason on its own.
- Does MANAGE_CONTACTS replace READ_CONTACTS?
- MANAGE_CONTACTS includes read access so you don’t need to request both, but many apps qualify for READ_CONTACTS that do not need to modify contacts at all. These apps may continue to request READ_CONTACTS.
- What about my users on older Android versions?
- The contact intents work on older versions too, handled by the device’s contacts app. Most apps will work well on all devices using these intents. If your app is affected by a specific consistency issue only solved in the latest versions, you can keep the WRITE_CONTACTS permission in your manifest scoped with an appropriate maxSdkVersion.

