Why does adding contact with intent discard structured address? - android

Based on "Modifying Contacts Using Intents" (Android developer documentation) and the answer to "Start add new contact activity and pass structured data", I've devised a way of populating the Android contact picker with data to be edited and saved by the user.
I also have a comparable "headless" method using ContentProviderOperation, which works as intended for all contact fields I've tried (name, phone number, e-mail, structured address etc.).
However, when using the intent, somehow the structured address gets discarded and does not appear in the contact picker. A website URL added with the same method works fine.
This is my code, somewhat condensed:
Intent intent = new Intent(Intent.ACTION_INSERT);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
ArrayList<ContentValues> data = new ArrayList<ContentValues>();
ContentValues addressRow = new ContentValues();
addressRow.put(Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
// The string values are prepared earlier, and I check that none of them is null.
// The ContentProviderOperation way doesn't seem to mind nulls, however.
addressRow.put(ContactsContract.CommonDataKinds.StructuredPostal.STREET, street);
addressRow.put(ContactsContract.CommonDataKinds.StructuredPostal.POBOX, pobox);
addressRow.put(ContactsContract.CommonDataKinds.StructuredPostal.NEIGHBORHOOD, neighborhood);
addressRow.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, city);
addressRow.put(ContactsContract.CommonDataKinds.StructuredPostal.REGION, region);
addressRow.put(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, postcode);
addressRow.put(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, country);
addressRow.put(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, addressType);
data.add(addressRow);
// This website address is shown in the contact edit screen, as expected:
ContentValues urlRow = new ContentValues();
urlRow.put(Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
urlRow.put(ContactsContract.CommonDataKinds.Website.URL, urlValue);
data.add(urlRow);
intent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, data);
startActivityForResult(intent, ADD_CONTACT_REQUEST); // my own request code
Please note that using an intent and using a ContentProviderOperation are different ways of achieving the same thing, both appropriate for their respective scenarios. My question is about the intent, so the answers to the following SO questions were not too helpful:
"Not able to insert address of contacts in android"
"How to add structured data to a new contact Intent"
Any suggestions as to what I'm messing up here?

Related

Make calendar entry readonly

I inserted a calender contract entry like this:
ContentValues values = new ContentValues();
values.put(CalendarContract.Calendars.ACCOUNT_NAME, account.name);
values.put(CalendarContract.Calendars.ACCOUNT_TYPE, account.type);
values.put(CalendarContract.Calendars.NAME, name);
values.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, getDisplayName(account));
values.put(CalendarContract.Calendars.CALENDAR_COLOR, 0xffff0000);
values.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_READ);
values.put(CalendarContract.Calendars.OWNER_ACCOUNT, getMailAddressOf(account));
values.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, TimeZone.getTimeZone("GMT").getDisplayName());
values.put(CalendarContract.Calendars.SYNC_EVENTS, 1);
Uri.Builder builder = CalendarContract.Calendars.CONTENT_URI.buildUpon();
builder.appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, account.name);
builder.appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, account.type);
builder.appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true");
Uri result = getContext().getContentResolver().insert(builder.build(), values);
This works great, I can enter calender entries etc. But I need to make it now read only so that the user cannot edit the calendar entry.
I thought that when I set CALENDAR_ACCESS_LEVEL to CAL_ACCESS_READ it should be enough to make the calendar read only.
Any idea how to achieve that? By the way I'm testing on a Pixel with Android O.
Don't make the user to be the organizer. When adding the event, the default organizer will be the user. To change it, add this line to the ContentValues when adding the event, assign an organizer email address like this
values.put(CalendarContract.Events.ORGANIZER,"an_organizer_name#gmail.com";
Since the user is not the organizer, the user can still delete the event but not able to edit the event content such as time, title, description, etc.
Well that took some time. In the end I found out that I have to change the mail address of the CalendarContract.Events.ORGANIZER value to prevent that I can edit the calender entry. Just as a hint for others how I sloved the problem I tried a lot of stupid things but then I had the idea to check how it is done in AOSP. So I just searched for "calendar aosp code" and found the code mirrowed on GitHub. After using the code search within the repo I found the method canModifyEvent(...). Now it became oblivious:
public static boolean canModifyEvent(CalendarEventModel model) {
return canModifyCalendar(model)
&& (model.mIsOrganizer || model.mGuestsCanModify);
}
Make sure that the event cannot been edited by guests and by don't be the organizer.
Happy Coding!

How to send specific id to intent picking contacts

I can pick multi contact data via
Intent phonebookIntent = new Intent("intent.action.INTERACTION_TOPMENU");
phonebookIntent.putExtra("additional", "phone-multi");
phonebookIntent.putExtra("maxRecipientCount", MAX_PICK_CONTACT);
phonebookIntent.putExtra("FromMMS", true);
startActivityForResult(phonebookIntent, REQUEST_CODE_PICK_CONTACT);
but when I want to add another contact to present data , the selected contact data disappears.Is there an intent filter like "selectedList" by which I can send id list to contact picker intent
That could be impossible to do using implicit intent. You can always create your own activity, get the contacts using ContentProvider, pass the parameters you want and handle the logic there.

AutoCompleteTextView for contacts email can't get LIKE to work properly

I am creating an AutoCompleteTextView field on a form that I want to possibly populate with a matching selection from the CONTACTS email addresses.
Doing some searching, I was able to find some older examples on here (that have alot of depreciated code... nothing newer) but with some trial and error I was able to get it to work matching the first characters of the email address as I type... although I don't have a 100% understanding of exactly how this works.
What I would really like to do is have it show ANY match ANYWHERE in the email addresses on file. That is, if I type gma, I would like it to show: gmartin#xyz.com, gregmaster#yahoo.com, jim#gmail.com, sam#gmail.com, etc.
As I understand it, I need to use a LIKE command in the query. But no matter how I format it, I get the same results... only matches the start of the email address.
Here is my current code attempt with the LIKE....
ArrayList<String> emailAddressCollection = new ArrayList<String>();
ContentResolver cr = getContentResolver();
String[] projection={ContactsContract.CommonDataKinds.Email.DATA};
Cursor emailCur = cr.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, projection, ContactsContract.CommonDataKinds.Email.ADDRESS + " LIKE '%A%'", null, null);
while (emailCur.moveToNext())
{
String email = emailCur.getString(emailCur.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
emailAddressCollection.add(email);
}
emailCur.close();
String[] emailAddresses = new String[emailAddressCollection.size()];
emailAddressCollection.toArray(emailAddresses);
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line, emailAddresses);
AutoCompleteTextView actextView = (AutoCompleteTextView)findViewById(idTo);
actextView.setAdapter(adapter);
Any idea what I am missing here?
Also, another somewhat related question, in my dropdownlist, i would like to show the email address match plus the NAME listed in that record... and just return the email address when selected.
Can this be accomplished using this code or do I need to look at something else?
AutoCompleteTextView is designed by default to match based ONLY on the starting characters. So the gma in sam#gmail.com will not be recognized. You can implement your own widget which does a lookup based on the 'LIKE' criteria. Android only searches through the first few characters for each entry in the adapter elements.
If you must choose to search by 'LIKE' criteria, it is possible although it would be quite a task in itself. You could simply search by whether the string contains the text and then choose to filter by that - no need to query everytime. Alternatively, you could try searching for a library which does this.

How to avoid duplicate contact restore in android

I'm doing an android application which does Backup & Restore Phone contacts into remote server as vcf file type.Suppose if I have 5 contacts, I could do Backup it into server well & good. After that If I delete 2 contacts in the mobile,now totally 3. But server has 5 contacts. Then If I restore from server, that 3 Contacts will gets duplicated. Below is my code. How could I avoid that duplication while restore contacts.
Code:
final MimeTypeMap mime = MimeTypeMap.getSingleton();
String tmptype = mime.getMimeTypeFromExtension("vcf");
final File file = new File(Environment.getExternalStorageDirectory().toString()+ "/contacts.vcf");
Intent i = new Intent();
i.setAction(android.content.Intent.ACTION_VIEW);
i.setDataAndType(Uri.fromFile(file), "text/x-vcard");
startActivity(i);
Add your contact in ArrayList < String> arrDupContact and while delete contact remove contact from arrDupContact also.While fetching contact from server check whether it contain that particular contact or not it is contain then bypass it, if not the add it.
I would you Set cont = new HashSet(), becasuse HashSet don`t allow duplicates by default.
Please find this quick summary here:
http://www.codejava.net/java-core/collections/java-collections-framework-summary-table
Please find a massive summary here:
https://docs.oracle.com/javase/8/docs/technotes/guides/collections/overview.html

insert contact intent, multiple phone / email / etc types?

android allows me to launch an intent to create a new contact. i can put extras into the intent to pre-fill the new contact fields.
Intent intent = new Intent(Intent.ACTION_INSERT);
intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
intent.putExtra(ContactsContract.Intents.Insert.NAME, "Foo Bar");
intent.putExtra(ContactsContract.Intents.Insert.PHONE, "(408) 555-1212");
intent.putExtra(ContactsContract.Intents.Insert.EMAIL, "foo.bar#foobar.com");
startActivityForResult(intent, INSERT_CONTACT_REQUEST);
this works, but i don't see how to handle multiple types of a given field, say phone number. in the intent, i can put extra a phone number, and i can put extra a phone number type, but how do i put extra an additional phone number, with a different (or perhaps even the same) type?
ContactsContract.Intents.Insert allows for PHONE, SECONDARY_PHONE and TERTIARY_PHONE - the same applies for EMAIL and it suggests three of each might be the maximum.
I don't know if it's possible to have more than one phone of the same 'type' - my phones contacts editor removes 'Home' from the list of choices once I've assigned a home number for example. You can, however, assign your own 'custom' type. For example, suppose your friend has two home numbers...
intent.putExtra(ContactsContract.Intents.Insert.PHONE, "(123) 456-1212");
intent.putExtra(ContactsContract.Intents.Insert.PHONE_TYPE, "HOME-1");
intent.putExtra(ContactsContract.Intents.Insert.SECONDARY_PHONE, "(123) 456-2121");
intent.putExtra(ContactsContract.Intents.Insert.SECONDARY_PHONE_TYPE, "HOME-2");

Categories

Resources