summaryrefslogtreecommitdiffstats
path: root/src/com/android/mail/compose/RecipientAdapter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/mail/compose/RecipientAdapter.java')
-rw-r--r--src/com/android/mail/compose/RecipientAdapter.java229
1 files changed, 228 insertions, 1 deletions
diff --git a/src/com/android/mail/compose/RecipientAdapter.java b/src/com/android/mail/compose/RecipientAdapter.java
index 2f84eea65..d11e88440 100644
--- a/src/com/android/mail/compose/RecipientAdapter.java
+++ b/src/com/android/mail/compose/RecipientAdapter.java
@@ -1,5 +1,6 @@
/**
* Copyright (c) 2007, Google Inc.
+ * Copyright (c) 2015, The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,14 +16,240 @@
*/
package com.android.mail.compose;
+import com.android.emailcommon.provider.EmailContent;
+import com.android.emailcommon.provider.SuggestedContact;
import com.android.ex.chips.BaseRecipientAdapter;
+import com.android.ex.chips.RecipientEntry;
+import com.android.mail.preferences.MailPrefs;
import com.android.mail.providers.Account;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentUris;
import android.content.Context;
+import android.content.OperationApplicationException;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Contacts.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.util.Log;
+
+public class RecipientAdapter extends BaseRecipientAdapter
+implements OnSharedPreferenceChangeListener {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "RecipientAdapter";
+
+ private static final int MAX_SUGGESTED_CONTACTS_ENTRIES = 3;
+
+ private static final int MAX_DAYS_FOR_RECENTS_SUGGESTED_CONTACTS = -7;
+
+ private String mSuggestedContactsMode;
+ private long mAccountId;
-public class RecipientAdapter extends BaseRecipientAdapter {
public RecipientAdapter(Context context, Account account) {
super(context);
setAccount(account.getAccountManagerAccount());
+ mAccountId = -1;
+
+ // Load the account id because we needed to access the suggested contacts data
+ // (in async mode because will do i/o writes)
+ loadAccountKey(account);
+
+ mSuggestedContactsMode = MailPrefs.get(getContext()).getSuggestedContactMode();
+ MailPrefs.get(context).registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ MailPrefs.get(getContext()).unregisterOnSharedPreferenceChangeListener(this);
+ super.finalize();
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (key.equals(MailPrefs.PreferenceKeys.SUGGESTED_CONTACTS_MODE)) {
+ mSuggestedContactsMode = MailPrefs.get(getContext()).getSuggestedContactMode();
+ }
+ }
+
+ @Override
+ protected Set<SuggestionEntry> loadSuggestedEntries(CharSequence constraint, int maxResults) {
+ Set<SuggestionEntry> entries = new HashSet<>();
+ if (!mSuggestedContactsMode.equals(MailPrefs.SuggestedContactsMode.NONE)) {
+ boolean recentsMode = mSuggestedContactsMode.equals(
+ MailPrefs.SuggestedContactsMode.RECENTS);
+
+ String selection = SuggestedContact.ACCOUNT_KEY + " = ?" +
+ " and LOWER(" + SuggestedContact.DISPLAY_NAME + ") like LOWER(?) ESCAPE '\\' ";
+ String[] args = new String[recentsMode ? 3 : 2];
+ args[0] = String.valueOf(mAccountId);
+ args[1] = "%" + constraint + "%";
+ String sort = SuggestedContact.LAST_SEEN + " DESC LIMIT "
+ + Math.min(MAX_SUGGESTED_CONTACTS_ENTRIES, maxResults);
+ if (recentsMode) {
+ Calendar c = Calendar.getInstance(Locale.getDefault());
+ c.add(Calendar.DAY_OF_YEAR, MAX_DAYS_FOR_RECENTS_SUGGESTED_CONTACTS);
+ selection += SuggestedContact.LAST_SEEN + " >= ? ";
+ args[2] = String.valueOf(c.getTimeInMillis());
+ }
+
+ Cursor cursor = getContext().getContentResolver().query(SuggestedContact.CONTENT_URI,
+ SuggestedContact.PROJECTION, selection, args, sort);
+ try {
+ if (cursor != null) {
+ Set<String> cachedAddresses = new HashSet<>();
+ Map<String, Integer> cachedContacts = new HashMap<>();
+ int contactsIds = -100;
+ while (cursor.moveToNext()) {
+ long suggestionId = cursor.getLong(
+ cursor.getColumnIndexOrThrow(SuggestedContact._ID));
+ String address = cursor.getString(
+ cursor.getColumnIndexOrThrow(SuggestedContact.ADDRESS));
+ String name = cursor.getString(
+ cursor.getColumnIndexOrThrow(SuggestedContact.NAME));
+ String displayName = cursor.getString(
+ cursor.getColumnIndexOrThrow(SuggestedContact.DISPLAY_NAME));
+
+ if (!cachedAddresses.contains(address)) {
+ int contactId = (cachedContacts.containsKey(name)) ?
+ cachedContacts.get(name) : contactsIds++;
+ SuggestionEntry entry = new SuggestionEntry(
+ suggestionId, displayName, address, name, contactId);
+ entries.add(entry);
+ cachedAddresses.add(address);
+
+ cachedContacts.put(name, contactId);
+ }
+ }
+ }
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Failed to perform search over suggested contacts table", e);
+
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ if (DEBUG) {
+ Log.i(TAG, "Found " + entries.size() + " entries in suggested contacts");
+ }
+
+ return entries;
+ }
+
+ protected void onAddSuggestion(final RecipientEntry entry, final SuggestionAddCallback cb) {
+ new AsyncTask<Void, Void, Boolean>() {
+ @Override
+ protected Boolean doInBackground(Void... args) {
+ return createSuggestedContact(entry);
+ }
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (result) {
+ cb.onSucess();
+ } else {
+ cb.onFailed();
+ }
+ }
+ }.execute();
+ }
+
+ protected void onDeleteSuggestion(final RecipientEntry entry,
+ final SuggestionRemoveCallback cb) {
+ new AsyncTask<Void, Void, Boolean>() {
+ @Override
+ protected Boolean doInBackground(Void... args) {
+ return deleteSuggestedContact(entry);
+ }
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (result) {
+ cb.onSucess();
+ } else {
+ cb.onFailed();
+ }
+ }
+ }.execute();
+ }
+
+ private void loadAccountKey(final Account account) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ Cursor c = getContext().getContentResolver().query(
+ com.android.emailcommon.provider.Account.CONTENT_URI,
+ EmailContent.ID_PROJECTION,
+ com.android.emailcommon.provider.Account.AccountColumns.EMAIL_ADDRESS
+ + " = ?",
+ new String[]{account.getAccountId()}, null);
+ try {
+ if (c != null && c.moveToFirst()) {
+ mAccountId = c.getLong(0);
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ return null;
+ }
+ }.execute();
+ }
+
+ private boolean createSuggestedContact(RecipientEntry entry) {
+ ContentResolver cr = getContext().getContentResolver();
+ ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
+ int rawContactInsertIndex = ops.size();
+
+ ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
+ .withValue(RawContacts.ACCOUNT_TYPE, null)
+ .withValue(RawContacts.ACCOUNT_NAME, null)
+ .build());
+ ops.add(ContentProviderOperation
+ .newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
+ .withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
+ .withValue(StructuredName.DISPLAY_NAME, entry.getDisplayName())
+ .build());
+ ops.add(ContentProviderOperation
+ .newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(Data.RAW_CONTACT_ID, rawContactInsertIndex)
+ .withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE)
+ .withValue(Email.DATA, entry.getDestination())
+ .withValue(Email.TYPE, Email.TYPE_OTHER)
+ .build());
+
+ try {
+ cr.applyBatch(ContactsContract.AUTHORITY, ops);
+ return true;
+
+ } catch (RemoteException | OperationApplicationException e) {
+ Log.e(TAG, "Failed to create the suggested contact.", e);
+ }
+ return false;
+ }
+
+ private boolean deleteSuggestedContact(RecipientEntry entry) {
+ ContentResolver cr = getContext().getContentResolver();
+ final Uri uri = ContentUris.withAppendedId(SuggestedContact.CONTENT_URI, entry.getDataId());
+ return cr.delete(uri, null, null) == 1;
}
}