Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SIM card query, insert, update, and delete #25

Closed
7 tasks done
vestrel00 opened this issue Nov 1, 2021 · 4 comments
Closed
7 tasks done

SIM card query, insert, update, and delete #25

vestrel00 opened this issue Nov 1, 2021 · 4 comments
Assignees
Labels
enhancement New feature or request

Comments

@vestrel00
Copy link
Owner

vestrel00 commented Nov 1, 2021

Enables importing from and exporting(?) to SIM card.

Query will definitely be possible. I'm not sure if insert, update, and delete operations are possible. We will see.

EDIT: Query, Insert, Update, and Delete operations are ALL supported!

  • core
  • permissions
  • async
  • Howto pages
  • Update README
  • Update MkDocs nav

If insert and update operations are supported,

  • Check max character limits for name, number, and emails. This can depend per SIM card or OEM but it's good to have a general idea.
@vestrel00 vestrel00 added the enhancement New feature or request label Nov 1, 2021
@vestrel00 vestrel00 added this to the Additional features for v1 milestone Nov 1, 2021
@vestrel00 vestrel00 self-assigned this Jan 4, 2022
@vestrel00 vestrel00 pinned this issue Feb 26, 2022
@vestrel00
Copy link
Owner Author

vestrel00 commented Mar 2, 2022

It seems like there are new APIs around SIM Contacts that were introduced in API 31;

Those APIs are too new to be used by this library, which supports API levels down to 19. So, we'll stick with using the "content://icc/adn" uri to read/write to SIM card. It's probably not ideal and a completely correct but it should hopefully work for the most part.

@vestrel00
Copy link
Owner Author

vestrel00 commented Mar 23, 2022

Okay! Finally got started working on this. Got a SIM card now and an old non-smartphone to play around with 🎉. I'm taking the SIM card back and forth between the non-smartphone and a Nexus 6P (Android 8) and Samsung Galaxy A71 (Android 11) smart-smartphones 😬

Few things I've noticed so far;

I. Samsung / OEMs + Syncing SIM contacts with Contacts Provider

Samsung phones import contacts from SIM into the Contacts Provider automatically unlike vanilla Android in the Nexus 6P. When using the builtin Samsung Contacts app, modifications made to the SIM contacts from the Contacts Provider are propagated to the SIM card and vice versa.

Samsung is most likely syncing the SIM contacts with the copy in the Contacts Provider via SyncAdapters. The RawContacts created in the Contacts Provider have a non-remote account name and type (pointing to the SIM card);

accountName: primary.sim.account_name, accountType: vnd.sec.contact.sim

Furthermore, SIM contacts imported into the Contacts Provider have the same restrictions as the SIM card in that only columns available in the SIM are editable (_id, name, number, emails). Editing SIM contacts using 3rd party apps such as the Google Contacts app are not supported.

This means that behavior of SIM contacts may vary greatly between different OEMs / different build/flavors of Android!

II. Query SIM contacts

Getting a cursor to all SIM contacts is straightforward,

val cursor: Cursor? = contentResolver.query(Uri.parse("content://icc/adn"), null, null, null, null)

Printing all of the column names,

Log.d("COLUMN_NAMES", cursor.columnNames.joinToString())

gives us; name, number, emails, _id

III. Email(s)

On my Samsung Galaxy A71 running Android 11...

The column name is actually "emails" with an "s" (plural). This may vary but based on my observations...

  • no email = ","
  • at least one email = "email,"

there seems to be a trailing "," regardless.

It seems like the emails are in CSV format (comma separated values).

I was not able to delete rows with email in them. The builtin Samsung Contacts app is able to delete and update rows just fine but they have their fork of Android to work with and we simply rely on vanilla Android so 🤷

On my Nexus 6P running Android 8...

Emails are completely unsupported!!!

EDIT: Apart from Samsung sing their own modified version of the Android OS, it seems that support for SIM email CRUD operations have not been implemented until Android 12 (and IMO still is bad)! Look for "TODO" comments in the IccProvider.java. You will see TODOs for email in Android 11 but not Android 12.

IV. ID is not constant!!

The _id in the SIM table always starts at 0. When there are 10 contacts, there are 10 rows with IDs from 0 to 9. When deleting a contact at row 0 and 2 and then inserting two new contacts, the two new contacts are assigned the id of 0 and 2!

I guess this is due to the memory restrictions in SIM cards. Perhaps ints are supported but not longs, therefore the row IDs behave like this.

But this is probably why selection by id is not supported!

V. Projections are NOT supported

So, in the following code,

val projection = arrayOf("_id", "number")
val cursor: Cursor? = contentResolver.query(Uri.parse("content://icc/adn"), projection, null, null, null)

val id = cursor.getString(0)
val number = cursor.getString(1)

Even though we only want the _id and number, we still get all of the columns. The name and emails will be included in the cursor! Since the projection is ignored, the positioning of the column names defined in the projection is different than expected. In the above code snippet, the val id will have the value of the name because that is the column in 0-th index in the cursor.

Note that we, at the API library level, can still provide our consumers an include function for SIM queries for in-memory optimization. However, as discussed later, there isn't really any non-trivial memory and cpu impact here so it's not worth the trouble of adding support for it.

So, the correct query is,

val cursor: Cursor? = contentResolver.query(Uri.parse("content://icc/adn"), null, null, null, null)
val id = cursor.getString(cursor.getColumnIndexOrThrow("_id"))
val name = cursor.getString(cursor.getColumnIndexOrThrow("name"))
val number = cursor.getString(cursor.getColumnIndexOrThrow("number"))
val emails = cursor.getString(cursor.getColumnIndexOrThrow("emails"))

VI. Selections are NOT supported

The following code snippet will return all rows even though we only want to select one row with the id.

val selection = "_id = '1'"
val cursor: Cursor? = contentResolver.query(Uri.parse("content://icc/adn"), null, selection, null, null)

Ordering, limit, and offset are NOT supported

The following code snippet will not order, offset, or limit the results ☹️

val cursor: Cursor? = contentResolver.query(Uri.parse("content://icc/adn"), null, null, null, "number DESC LIMIT 1 OFFSET 1")

VII. All queries will return all contacts in the SIM card

This is due to all of the above mentioned limitations.

Depending on memory size, SIM cards can hold 200 to 500+ contacts. The most common being around 250. Most, if not all, SIM cards have less than 1mb memory (averaging 32KB to 64KB). Therefore, memory and speed should not be affected much by not being able to sort/order and paginate. Consumers of this library can perform their own sorting and pagination if they wish.

Source: https://www.quora.com/How-many-contacts-can-I-save-on-my-SIM-card

vestrel00 added a commit that referenced this issue Mar 23, 2022
vestrel00 added a commit that referenced this issue Mar 23, 2022
vestrel00 added a commit that referenced this issue Mar 23, 2022
vestrel00 added a commit that referenced this issue Mar 23, 2022
vestrel00 added a commit that referenced this issue Mar 23, 2022
vestrel00 added a commit that referenced this issue Mar 23, 2022
vestrel00 added a commit that referenced this issue Mar 23, 2022
vestrel00 added a commit that referenced this issue Mar 23, 2022
vestrel00 added a commit that referenced this issue Mar 24, 2022
vestrel00 added a commit that referenced this issue Mar 24, 2022
vestrel00 added a commit that referenced this issue Mar 24, 2022
vestrel00 added a commit that referenced this issue Mar 25, 2022
vestrel00 added a commit that referenced this issue Mar 25, 2022
vestrel00 added a commit that referenced this issue Mar 25, 2022
@vestrel00
Copy link
Owner Author

It's done! #200

@vestrel00 vestrel00 unpinned this issue Mar 25, 2022
@vestrel00
Copy link
Owner Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant