Fix #477: "Device" contacts get deleted by account changes from across the system - #497
Open
Adam-Winwood wants to merge 2 commits into
Open
Fix #477: "Device" contacts get deleted by account changes from across the system#497Adam-Winwood wants to merge 2 commits into
Adam-Winwood wants to merge 2 commits into
Conversation
added 2 commits
July 30, 2026 14:19
Warning ------- This doesn't fix you-apps#477 for previously existing contacts - it only changes how they are handled in the live app representation. Context ------- Previous to this commit, contacts were saved through the ContactsProvider with accountName and accountType set to fake account values ("Device" and "com.android.contacts" resp.). Unfortunately, Android occasionally deletes contacts that have an account that doesn't currently exist on this device - this includes all contacts we make with the fake account values. Intent ------ In this commit we instead write out (null, null) through ContactsProvider. This is the way Android intends you to represent the no-account case. Expand AccountType's conceptual scope to represent the whole idea of an account within the app. This explicitly recognises the special case within the data model, makes certain invalid states unrepresentable, makes it easier for the compiler to check exhaustiveness of related code, and centralises serialization (to/from for prefs/contacts). Changes ------- Rewrite AccountType as a sealed interface - normal case -> RealAccountType - device special case -> DeviceAccountType - handles to and from storage in preferences - handles to and from ContactsProvider account columns Use AccountType directly in ContactData rather than separate accountName and accountType fields.
Warning
-------
It shouldn't throw any exceptions, however I can't guarantee all OEM
versions of Android are safe - for instance Samsung has a bug which
throws IllegalArgumentException. If there are any **other** issues like
this, we will soon find out about it as that would mean a crash on app
startup!
Details
-------
This commit migrates pre-existing contacts from the legacy DEVICE
account values ("Device", "com.android.contacts") to null. This is
Android's intended way to store contacts that aren't owned by a
sync-ing account.
This completes the fix of you-apps#477 that the previous commit began.
Implemented as a function fired from app startup, gated behind a
preference value so it never fires again.
Note that we guard against the possibility of a real account having
these values and retry later if so.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The issue
Issue #477 and #275 both have contacts disappearing after some amount of delay. This could readily be explained by the following: contacts made under the DEVICE account are saved using the dummy account values ("DEVICE", "com.android.contacts"); whenever an account is added or removed on the device, Android cleans up all contacts which have invalid (non-existing) accounts. So all contacts made in the app under DEVICE will be deleted.
The fix
The fix comes in two commits:
Tested on emulator and my actual Samsung device (though the migration is a no-op on the Samsung).
Known limitations
At least one version of Samsung's Android has a bug where trying to set account_type and account_name to null just throws an exception. In this case the migration gives up and doesn't run again.
Either we accept that the issue is fixed for all new contacts Samsung users create and we abandon the pre-existing ones to deletion, or we write some code to delete and then re-create the relevant contacts which is a more aggressive operation. I don't feel comfortable making the call on that.
Another concern is that, if there can be a bug in one OEM version of Android, then there could be another. Perhaps we should wrap the whole function in a catch all to prevent a repeated crash-on-startup?
Notes
This attempt at fixing the issue used no AI.