summaryrefslogtreecommitdiffstats
path: root/src/com/android/contacts/quickcontact/QuickContactActivity.java
diff options
context:
space:
mode:
authorErica Chang <echang@cyngn.com>2016-01-21 19:02:40 -0800
committerErica Chang <echang@cyngn.com>2016-04-07 12:05:10 -0700
commita7f0f11091c69868142597f972cc22cd95e27a76 (patch)
tree5cfd4766564a5b630453fd4ba46bea3371cc8aac /src/com/android/contacts/quickcontact/QuickContactActivity.java
parent1e2ad0157e708d06728ef575aa556c1e0455d278 (diff)
downloadpackages_apps_Contacts-a7f0f11091c69868142597f972cc22cd95e27a76.tar.gz
packages_apps_Contacts-a7f0f11091c69868142597f972cc22cd95e27a76.tar.bz2
packages_apps_Contacts-a7f0f11091c69868142597f972cc22cd95e27a76.zip
Contacts: incall plugin implementation
Contacts Card: fixed encoded contact Uri invite intent -When a contacts card is launched from a dialed phone number history, the particular contact does not exist in contacts so the uri is encoded. In this case we'll provide either the display name or phone number as the Uri argument for getInvitePendingIntent. CD-346 Contacts Card: fix callog -added in cm-12.1 calllog related changes that accidentally didn't get merged in CD-354 Contacts Card: removed redundant code from cm-13.0 creation -in Quick contact card onclick handler there's redundant code since cm-13.0 was created Contacts Card: fix multiple ContacLoader calls issue -consodliate one AsynTask to load contact data -added a synchronized method checkAndBindContactData to fix contact card update condition Note. The internal implementation of AsyncTask.doInBackground is done on FutureTask; onPostExecute run on a main loop via Message. If the onPostExecute is already placed on the main loop, it can no longer be cancelled. cancel() is the most effective while an AsyncTask is still running doInBackground, upon completion, it'd either execute onCancelled() or onPostExecute() CD-324 Contacts: lookup plugin account handles as a backup -Need to rely on AccountManager to lookup logged in plugin account handles just in case the plugin fails to return a valid one CD-422 (2/2) Contacts: refactor -makes use of PhoneCommon/CallMethodInfo.java, CallMethodHelper -new InCallPluginHelper extends CallMethodHelper -InCallPluginUtils uses CallMethodHelper singleton and StartInCallCallReceiver CD-301,CD-374,CD-423 Change-Id: Iaa6f3f4539969a8cdad7c719f71ffaad8dd8cc39
Diffstat (limited to 'src/com/android/contacts/quickcontact/QuickContactActivity.java')
-rw-r--r--src/com/android/contacts/quickcontact/QuickContactActivity.java563
1 files changed, 524 insertions, 39 deletions
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index 65c4d3cf7..d2ce66ee5 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -23,14 +23,16 @@ import android.app.Activity;
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.LoaderManager.LoaderCallbacks;
+import android.app.PendingIntent;
import android.app.SearchManager;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.ContentValues;
import android.content.ContentUris;
-import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
@@ -47,9 +49,11 @@ import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Trace;
+import android.preference.PreferenceManager;
import android.provider.CalendarContract;
import android.os.Handler;
import android.os.Message;
+import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Event;
import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
@@ -61,7 +65,7 @@ import android.provider.ContactsContract.CommonDataKinds.Organization;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Relation;
import android.provider.ContactsContract.CommonDataKinds.SipAddress;
-import android.provider.ContactsContract.CommonDataKinds.Organization;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.CommonDataKinds.Website;
import android.provider.ContactsContract.Contacts;
@@ -139,8 +143,6 @@ import com.android.contacts.common.model.dataitem.StructuredPostalDataItem;
import com.android.contacts.common.model.dataitem.WebsiteDataItem;
import com.android.contacts.common.util.BlockContactHelper;
import com.android.contacts.common.util.ImplicitIntentsUtil;
-import com.android.contacts.common.MoreContactUtils;
-import com.android.contacts.common.SimContactsConstants;
import com.android.contacts.common.util.BitmapUtil;
import com.android.contacts.common.util.DateUtils;
import com.android.contacts.common.util.MaterialColorMapUtils;
@@ -150,7 +152,10 @@ import com.android.contacts.common.util.ViewUtil;
import com.android.contacts.detail.ContactDisplayUtils;
import com.android.contacts.editor.ContactEditorFragment;
import com.android.contacts.editor.EditorIntents;
+import com.android.contacts.incall.InCallPluginHelper;
+import com.android.contacts.incall.InCallPluginUtils;
import com.android.contacts.interactions.CalendarInteractionsLoader;
+import com.android.contacts.interactions.CallLogInteraction;
import com.android.contacts.interactions.CallLogInteractionsLoader;
import com.android.contacts.interactions.ContactDeletionInteraction;
import com.android.contacts.interactions.ContactInteraction;
@@ -168,6 +173,10 @@ import com.android.contacts.util.StructuredPostalUtils;
import com.android.contacts.widget.MultiShrinkScroller;
import com.android.contacts.widget.MultiShrinkScroller.MultiShrinkScrollerListener;
import com.android.contacts.widget.QuickContactImageView;
+import com.android.phone.common.incall.CallMethodHelper;
+import com.android.phone.common.incall.CallMethodInfo;
+import com.cyanogen.ambient.incall.extension.OriginCodes;
+import com.cyanogen.ambient.plugin.PluginStatus;
import com.android.contactsbind.HelpUtils;
import com.cyanogen.lookup.phonenumber.provider.LookupProviderImpl;
@@ -183,9 +192,12 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Mostly translucent {@link Activity} that shows QuickContact dialog. It loads
@@ -203,6 +215,7 @@ public class QuickContactActivity extends ContactsActivity implements
public static final int MODE_FULLY_EXPANDED = 4;
private static final String TAG = "QuickContact";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String KEY_THEME_COLOR = "theme_color";
@@ -215,6 +228,16 @@ public class QuickContactActivity extends ContactsActivity implements
/** This is the Intent action to install a shortcut in the launcher. */
private static final String ACTION_INSTALL_SHORTCUT =
"com.android.launcher.action.INSTALL_SHORTCUT";
+ public static final String ACTION_INCALL_PLUGIN_LOGIN =
+ "com.android.contacts.quickcontact.INCALL_PLUGIN_LOGIN";
+ public static final String ACTION_INCALL_PLUGIN_INVITE =
+ "com.android.contacts.quickcontact.INCALL_PLUGIN_INVITE";
+ public static final String ACTION_INCALL_PLUGIN_DIRECTORY_SEARCH =
+ "com.android.contacts.quickcontact.INCALL_PLUGIN_DIRECTORY_SEARCH";
+ public static final String ACTION_INCALL_PLUGIN_INSTALL =
+ "com.android.contacts.quickcontact.ACTION_INCALL_PLUGIN_INSTALL";
+ public static final String ACTION_INCALL_PLUGIN_DISMISS_NUDGE =
+ "com.android.contacts.quickcontact.ACTION_INCALL_PLUGIN_DISMISS_NUDGE";
@SuppressWarnings("deprecation")
private static final String LEGACY_AUTHORITY = android.provider.Contacts.AUTHORITY;
@@ -250,8 +273,11 @@ public class QuickContactActivity extends ContactsActivity implements
private ExpandingEntryCardView mAboutCard;
private MultiShrinkScroller mScroller;
private SelectAccountDialogFragmentListener mSelectAccountFragmentListener;
- private AsyncTask<Void, Void, Cp2DataCardModel> mEntriesAndActionsTask;
+ private AsyncTask<Contact, Void, Cp2DataCardModel> mEntriesAndActionsTask;
private AsyncTask<Void, Void, Void> mRecentDataTask;
+ private AtomicBoolean mIsUpdating;
+ private boolean mNeedPluginUpdate = false;
+ private static final String CALL_METHOD_SUBSCRIBER_ID = TAG;
/**
* The last copy of Cp2DataCardModel that was passed to {@link #populateContactAndAboutCard}.
*/
@@ -283,7 +309,7 @@ public class QuickContactActivity extends ContactsActivity implements
private Target mContactBitmapTarget;
private BlockContactHelper mBlockContactHelper;
-
+ private Object mLock = new Object();
/**
* {@link #LEADING_MIMETYPES} is used to sort MIME-types.
*
@@ -307,11 +333,23 @@ public class QuickContactActivity extends ContactsActivity implements
Identity.CONTENT_ITEM_TYPE,
Note.CONTENT_ITEM_TYPE);
+ // Common mime types that are loaded and present to users before plugins load to avoid delays
+ private static final List<String> COMMON_MIMETYPES = Lists.newArrayList(
+ Email.CONTENT_ITEM_TYPE,
+ Nickname.CONTENT_ITEM_TYPE,
+ Phone.CONTENT_ITEM_TYPE,
+ SipAddress.CONTENT_ITEM_TYPE,
+ StructuredName.CONTENT_ITEM_TYPE,
+ StructuredPostal.CONTENT_ITEM_TYPE);
+
private static final BidiFormatter sBidiFormatter = BidiFormatter.getInstance();
/** Id for the background contact loader */
private static final int LOADER_CONTACT_ID = 0;
+ private static final String KEY_LOADER_EXTRA_PLUGIN_INFO =
+ QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_PLUGIN_INFO";
+
private static final String KEY_LOADER_EXTRA_PHONES =
QuickContactActivity.class.getCanonicalName() + ".KEY_LOADER_EXTRA_PHONES";
@@ -336,7 +374,8 @@ public class QuickContactActivity extends ContactsActivity implements
private static final int MIN_NUM_CONTACT_ENTRIES_SHOWN = 3;
private static final int MIN_NUM_COLLAPSED_RECENT_ENTRIES_SHOWN = 3;
private static final int CARD_ENTRY_ID_EDIT_CONTACT = -2;
-
+ private static final int CARD_ENTRY_ID_INCALL_PLUGIN = -3;
+ public static final int CARD_ENTRY_ID_INCALL_PLUGIN_CALL = -4;
private static final int MAX_NUM_LENGTH = 3; // add limit length to show IP call item
private static final int[] mRecentLoaderIds = new int[]{
@@ -363,13 +402,28 @@ public class QuickContactActivity extends ContactsActivity implements
}
final EntryTag entryTag = (EntryTag) entryTagObject;
final Intent intent = entryTag.getIntent();
- final int dataId = entryTag.getId();
+ int dataId = entryTag.getId();
if (dataId == CARD_ENTRY_ID_EDIT_CONTACT) {
editContact();
return;
}
+ // InCall plugin invite or nudges entries
+ if (dataId == CARD_ENTRY_ID_INCALL_PLUGIN) {
+ handleInCallPluginAction(entryTag);
+ return;
+ }
+
+ boolean isPlugin = false;
+ // InCall plugin callable entries, need to retrieve the data id
+ if (dataId == CARD_ENTRY_ID_INCALL_PLUGIN_CALL) {
+ dataId = (int) intent.getLongExtra(InCallPluginUtils.KEY_DATA_ID, -1);
+ if (intent.getAction() == null) {
+ isPlugin = true;
+ }
+ }
+
// Default to USAGE_TYPE_CALL. Usage is summed among all types for sorting each data id
// so the exact usage type is not necessary in all cases
String usageType = DataUsageFeedback.USAGE_TYPE_CALL;
@@ -414,7 +468,29 @@ public class QuickContactActivity extends ContactsActivity implements
mHasIntentLaunched = true;
try {
- ImplicitIntentsUtil.startActivityInAppIfPossible(QuickContactActivity.this, intent);
+ if (isPlugin) {
+ // it's an entry from plugin, route to this call
+ CallMethodInfo cmi = null;
+ if (entryTag.getEntry() == null ||
+ entryTag.getEntry().getCallMethodInfo() == null) {
+ cmi = InCallPluginHelper.getCallMethod(ComponentName.unflattenFromString(
+ intent.getStringExtra(InCallPluginUtils.KEY_COMPONENT)));
+ cmi.placeCall(OriginCodes.CONTACTS_CARD,
+ intent.getStringExtra(InCallPluginUtils.KEY_NUMBER),
+ getBaseContext(), false, false,
+ intent.getStringExtra(InCallPluginUtils.KEY_MIMETYPE));
+ } else {
+ cmi = entryTag.getEntry().getCallMethodInfo();
+ cmi.placeCall(OriginCodes.CONTACTS_CARD,
+ intent.getStringExtra(InCallPluginUtils.KEY_NUMBER),
+ getBaseContext(), false,
+ TextUtils.isEmpty(intent.getStringExtra(InCallPluginUtils
+ .KEY_MIMETYPE)), null);
+ }
+ } else {
+ ImplicitIntentsUtil
+ .startActivityInAppIfPossible(QuickContactActivity.this, intent);
+ }
} catch (SecurityException ex) {
Toast.makeText(QuickContactActivity.this, R.string.missing_app,
Toast.LENGTH_SHORT).show();
@@ -872,6 +948,7 @@ public class QuickContactActivity extends ContactsActivity implements
}
});
}
+ mIsUpdating = new AtomicBoolean(false);
processIntent(getIntent());
mBlockContactHelper = new BlockContactHelper(this, new LookupProviderImpl(this));
if (mContactData != null) {
@@ -930,7 +1007,18 @@ public class QuickContactActivity extends ContactsActivity implements
mLookupUri = lookupUri;
mExcludeMimes = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES);
+ Contact contact = null;
+ if (mLookupUri == null) {
+ // See if a URI has been attached as an extra
+ mLookupUri = intent.getParcelableExtra(Contact.CONTACT_URI_EXTRA);
+ if (mLookupUri != null) {
+ contact = ContactLoader.parseEncodedContactEntity(mLookupUri,
+ ContactLoader.EncodedContactEntitySchemaVersion.ENHANCED_CALLER_META_DATA);
+ }
+ }
+
if (mLookupUri == null) {
+ if (DEBUG) Log.d(TAG, "mLookupUri null!");
finish();
return;
}
@@ -943,7 +1031,8 @@ public class QuickContactActivity extends ContactsActivity implements
}
if (contact != null) {
- bindContactData(contact);
+ // looked up encoded contact
+ checkAndBindContactData(contact, false, false);
} else if (oldLookupUri == null) {
mContactLoader = (ContactLoader) getLoaderManager().initLoader(
LOADER_CONTACT_ID, null, mLoaderContactCallbacks);
@@ -1076,36 +1165,58 @@ public class QuickContactActivity extends ContactsActivity implements
Trace.endSection();
- mEntriesAndActionsTask = new AsyncTask<Void, Void, Cp2DataCardModel>() {
+ mEntriesAndActionsTask = new EntriesAndActionTask().execute(data);
+ }
- @Override
- protected Cp2DataCardModel doInBackground(
- Void... params) {
- return generateDataModelFromContact(data);
+ private class EntriesAndActionTask extends AsyncTask<Contact, Void, Cp2DataCardModel> {
+ private Contact mData;
+
+ @Override
+ protected Cp2DataCardModel doInBackground(Contact... params) {
+ // gather plugin information
+ if (DEBUG) Log.d(TAG, "+++doInBackground");
+ if (isCancelled()) {
+ // onCancelled will be called upon return
+ if (DEBUG) Log.d(TAG, "+++doInBackground cancelled");
+ return null;
}
+ mData = params[0];
+ Cp2DataCardModel model = generateDataModelFromContact(mData);
+ if (DEBUG) Log.d(TAG, "---doInBackground");
+ return model;
+ }
- @Override
- protected void onPostExecute(Cp2DataCardModel cardDataModel) {
- super.onPostExecute(cardDataModel);
- // Check that original AsyncTask parameters are still valid and the activity
- // is still running before binding to UI. A new intent could invalidate
- // the results, for example.
- if (data == mContactData && !isCancelled()) {
- bindDataToCards(cardDataModel);
- showActivity();
- }
+ @Override
+ protected void onPostExecute(Cp2DataCardModel cardDataModel) {
+ super.onPostExecute(cardDataModel);
+ // Check that original AsyncTask parameters are still valid and the activity
+ // is still running before binding to UI. A new intent could invalidate
+ // the results, for example.
+ if (DEBUG) Log.d(TAG, "+++onPostExecute");
+ if (mData == mContactData && !isCancelled() && cardDataModel != null) {
+ bindDataToCards(cardDataModel);
+ showActivity();
+ mIsUpdating.set(false);
}
- };
- mEntriesAndActionsTask.execute();
+ if (mNeedPluginUpdate) {
+ mNeedPluginUpdate = false;
+ updatePlugins(null);
+ }
+ if (DEBUG) Log.d(TAG, "---onPostExecute");
+ }
}
private void bindDataToCards(Cp2DataCardModel cp2DataCardModel) {
+ if (DEBUG) Log.d(TAG, "+++bindDataToCards");
startInteractionLoaders(cp2DataCardModel);
populateContactAndAboutCard(cp2DataCardModel);
+ if (DEBUG) Log.d(TAG, "---bindDataToCards");
}
private void startInteractionLoaders(Cp2DataCardModel cp2DataCardModel) {
final Map<String, List<DataItem>> dataItemsMap = cp2DataCardModel.dataItemsMap;
+ final Map<ComponentName, List<String>> pluginAccountsMap = cp2DataCardModel
+ .pluginAccountsMap;
final List<DataItem> phoneDataItems = dataItemsMap.get(Phone.CONTENT_ITEM_TYPE);
if (phoneDataItems != null && phoneDataItems.size() == 1) {
mOnlyOnePhoneNumber = true;
@@ -1119,7 +1230,7 @@ public class QuickContactActivity extends ContactsActivity implements
}
final Bundle phonesExtraBundle = new Bundle();
phonesExtraBundle.putStringArray(KEY_LOADER_EXTRA_PHONES, phoneNumbers);
-
+ phonesExtraBundle.putSerializable(KEY_LOADER_EXTRA_PLUGIN_INFO, (HashMap)pluginAccountsMap);
Trace.beginSection("start sms loader");
getLoaderManager().initLoader(
LOADER_SMS_ID,
@@ -1190,6 +1301,12 @@ public class QuickContactActivity extends ContactsActivity implements
@Override
protected void onResume() {
super.onResume();
+ if (InCallPluginHelper.subscribe(CALL_METHOD_SUBSCRIBER_ID, pluginsUpdatedReceiver)) {
+ if (DEBUG) Log.d(TAG, "InCallPluginHelper infoReady");
+ InCallPluginHelper.refreshDynamicItems();
+ } else {
+ if (DEBUG) Log.d(TAG, "InCallPluginHelper info NOT Ready");
+ }
// If returning from a launched activity, repopulate the contact and about card
if (mHasIntentLaunched) {
mHasIntentLaunched = false;
@@ -1205,7 +1322,14 @@ public class QuickContactActivity extends ContactsActivity implements
}
}
- private void populateContactAndAboutCard(Cp2DataCardModel cp2DataCardModel) {
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ InCallPluginHelper.unsubscribe(CALL_METHOD_SUBSCRIBER_ID);
+ }
+
+ private synchronized void populateContactAndAboutCard(Cp2DataCardModel cp2DataCardModel) {
mCachedCp2DataCardModel = cp2DataCardModel;
if (mHasIntentLaunched || cp2DataCardModel == null) {
return;
@@ -1283,7 +1407,7 @@ public class QuickContactActivity extends ContactsActivity implements
mExpandingEntryCardViewListener,
mScroller);
- if (contactCardEntries.size() == 0 && aboutCardEntries.size() == 0) {
+ if ((contactCardEntries.size() == 0 && aboutCardEntries.size() == 0)) {
initializeNoContactDetailCard();
} else {
mNoContactDetailsCard.setVisibility(View.GONE);
@@ -1379,13 +1503,31 @@ public class QuickContactActivity extends ContactsActivity implements
* amongst mimetype. The map goes from mimetype string to the sorted list of data items within
* mimetype
*/
- private Cp2DataCardModel generateDataModelFromContact(
- Contact data) {
+ private Cp2DataCardModel generateDataModelFromContact(Contact data) {
Trace.beginSection("Build data items map");
final Map<String, List<DataItem>> dataItemsMap = new HashMap<>();
final ResolveCache cache = ResolveCache.getInstance(this);
+ Set<String> pluginMimeExcluded;
+ Set<String> pluginMimeIncluded;
+ if (InCallPluginHelper.infoReady()) {
+ mCallMethodMap = (HashMap<ComponentName, CallMethodInfo>)
+ InCallPluginHelper.getAllEnabledAndHiddenCallMethods();
+ pluginMimeExcluded = InCallPluginHelper.getAllEnabledVideoImMimeSet();
+ pluginMimeIncluded = InCallPluginHelper.getAllEnabledVoiceMimeSet();
+ if (DEBUG) {
+ Log.d(TAG, "plugins size:" + mCallMethodMap.size());
+ Log.d(TAG, "mimeExcluded size:" + pluginMimeExcluded.size());
+ Log.d(TAG, "mimeIncluded size:" + pluginMimeIncluded.size());
+ }
+ } else {
+ mCallMethodMap = new HashMap<ComponentName, CallMethodInfo>();
+ pluginMimeExcluded = new HashSet<String>();
+ pluginMimeIncluded = new HashSet<String>();
+ }
+
+ HashMap<String, RawContact> pluginRawContactsMap = new HashMap<String, RawContact>();
for (RawContact rawContact : data.getRawContacts()) {
for (DataItem dataItem : rawContact.getDataItems()) {
dataItem.setRawContactId(rawContact.getId());
@@ -1402,6 +1544,11 @@ public class QuickContactActivity extends ContactsActivity implements
final boolean hasData = !TextUtils.isEmpty(dataItem.buildDataString(this,
dataKind));
+ // the mime type has been consolidated in the plugin entry, skip
+ if (pluginMimeExcluded.contains(mimeType)) continue;
+ if (pluginMimeIncluded.contains(mimeType)) {
+ pluginRawContactsMap.put(mimeType, rawContact);
+ }
if (isMimeExcluded(mimeType) || !hasData) continue;
@@ -1443,13 +1590,25 @@ public class QuickContactActivity extends ContactsActivity implements
final List<List<Entry>> contactCardEntries = new ArrayList<>();
final List<List<Entry>> aboutCardEntries = buildAboutCardEntries(dataItemsMap);
final MutableString aboutCardName = new MutableString();
-
+ HashMap<ComponentName, List<String>> pluginAccountsMap = new HashMap<ComponentName,
+ List<String>>();
for (int i = 0; i < dataItemsList.size(); ++i) {
final List<DataItem> dataItemsByMimeType = dataItemsList.get(i);
final DataItem topDataItem = dataItemsByMimeType.get(0);
if (SORTED_ABOUT_CARD_MIMETYPES.contains(topDataItem.getMimeType())) {
// About card mimetypes are built in buildAboutCardEntries, skip here
continue;
+ } else if (pluginRawContactsMap.containsKey(topDataItem.getMimeType())) {
+ List<Entry> pluginEntries = incallPluginDataItemsToEntries(dataItemsByMimeType,
+ data, pluginRawContactsMap.get(topDataItem.getMimeType()),
+ contactCardEntries, pluginAccountsMap);
+ if (pluginEntries.size() > 0) {
+ if (DEBUG) {
+ Log.d(TAG, "pluginEntries added to contactCardEntries:" +
+ pluginEntries.size());
+ }
+ contactCardEntries.add(pluginEntries);
+ }
} else {
List<Entry> contactEntries = dataItemsToEntries(dataItemsList.get(i),
aboutCardName);
@@ -1458,6 +1617,10 @@ public class QuickContactActivity extends ContactsActivity implements
}
}
}
+ if (!mContactData.isUserProfile() && InCallPluginHelper.infoReady() && mCallMethodMap
+ .size() > 0) {
+ addAllInCallPluginOtherEntries(contactCardEntries, pluginRawContactsMap);
+ }
Trace.endSection();
@@ -1466,6 +1629,7 @@ public class QuickContactActivity extends ContactsActivity implements
dataModel.aboutCardEntries = aboutCardEntries;
dataModel.contactCardEntries = contactCardEntries;
dataModel.dataItemsMap = dataItemsMap;
+ dataModel.pluginAccountsMap = pluginAccountsMap;
return dataModel;
}
@@ -1479,9 +1643,11 @@ public class QuickContactActivity extends ContactsActivity implements
* are in sorted order using mWithinMimeTypeDataItemComparator.
*/
public Map<String, List<DataItem>> dataItemsMap;
+ public Map<String, List<DataItem>> hideDataItemsMap;
public List<List<Entry>> aboutCardEntries;
public List<List<Entry>> contactCardEntries;
public String customAboutCardName;
+ public Map<ComponentName, List<String>> pluginAccountsMap;
}
private static class MutableString {
@@ -2220,7 +2386,18 @@ public class QuickContactActivity extends ContactsActivity implements
if (interaction == null) {
continue;
}
- entries.add(new Entry(/* id = */ -1,
+ boolean applyColor = true;
+ int dataId = -1;
+ // only CallLogInteraction classes can be from plugin (not SmsInteraction
+ // and CalendarInteraction)
+ if (CallLogInteraction.class.isInstance(interaction) && !TextUtils.isEmpty(
+ ((CallLogInteraction)interaction).getPluginPkgName())) {
+ applyColor = false;
+ dataId = CARD_ENTRY_ID_INCALL_PLUGIN_CALL;
+ }
+
+ // need to associate number as well
+ entries.add(new Entry(dataId,
interaction.getIcon(this),
interaction.getViewHeader(this),
interaction.getViewBody(this),
@@ -2232,7 +2409,7 @@ public class QuickContactActivity extends ContactsActivity implements
/* alternateIcon = */ null,
/* alternateIntent = */ null,
/* alternateContentDescription = */ null,
- /* shouldApplyColor = */ true,
+ applyColor,
/* isEditable = */ false,
/* EntryContextMenuInfo = */ null,
/* thirdIcon = */ null,
@@ -2276,10 +2453,7 @@ public class QuickContactActivity extends ContactsActivity implements
finish();
return;
}
- mBlockContactHelper.setContactInfo(data);
- mBlockContactHelper.gatherDataInBackground();
- bindContactData(data);
-
+ checkAndBindContactData(data, true, false);
} finally {
Trace.endSection();
}
@@ -2298,6 +2472,33 @@ public class QuickContactActivity extends ContactsActivity implements
}
};
+ private synchronized void checkAndBindContactData(Contact contact, boolean withBlockHelper,
+ boolean onlyStartAsyncTask) {
+ if (DEBUG) Log.d(TAG, "checkAndBindContactData," + withBlockHelper + " " +
+ onlyStartAsyncTask);
+ // Update pending Intents
+ InCallPluginHelper.refreshPendingIntents(InCallPluginUtils.getInCallContactInfo(contact));
+
+ if (mIsUpdating.get() && mEntriesAndActionsTask != null && !mEntriesAndActionsTask
+ .isCancelled()) {
+ mEntriesAndActionsTask.cancel(true);
+ }
+ mIsUpdating.set(true);
+ if (withBlockHelper) {
+ destroyInteractionLoaders();
+ mBlockContactHelper.setContactInfo(contact);
+ mBlockContactHelper.gatherDataInBackground();
+ bindContactData(contact);
+ } else {
+ destroyInteractionLoaders();
+ if (onlyStartAsyncTask) {
+ mEntriesAndActionsTask = new EntriesAndActionTask().execute(contact);
+ } else {
+ bindContactData(contact);
+ }
+ }
+ }
+
@Override
public void onBackPressed() {
if (mScroller != null) {
@@ -2351,6 +2552,7 @@ public class QuickContactActivity extends ContactsActivity implements
loader = new CallLogInteractionsLoader(
QuickContactActivity.this,
args.getStringArray(KEY_LOADER_EXTRA_PHONES),
+ (HashMap) args.getSerializable(KEY_LOADER_EXTRA_PLUGIN_INFO),
MAX_CALL_LOG_RETRIEVE);
}
return loader;
@@ -2461,6 +2663,7 @@ public class QuickContactActivity extends ContactsActivity implements
protected void onStop() {
super.onStop();
+ mIsUpdating.set(false);
if (mEntriesAndActionsTask != null) {
// Once the activity is stopped, we will no longer want to bind mEntriesAndActionsTask's
// results on the UI thread. In some circumstances Activities are killed without
@@ -3245,4 +3448,286 @@ public class QuickContactActivity extends ContactsActivity implements
return true;
return false;
}
+
+ private void addAllInCallPluginOtherEntries(List<List<Entry>> parentList,
+ HashMap<String, RawContact> pluginRawContactMap) {
+ for (ComponentName cn : mCallMethodMap.keySet()) {
+ CallMethodInfo cmi = mCallMethodMap.get(cn);
+ addInCallPluginEntries(cmi, parentList, pluginRawContactMap.containsKey(cmi.mMimeType));
+ }
+ }
+
+ private void addInCallPluginEntries(CallMethodInfo cmi, List<List<Entry>> parentList,
+ boolean hasPluginAccount) {
+ final Resources res = getResources();
+ List<Entry> containerList;
+ Entry entry;
+ if (cmi.mStatus == PluginStatus.HIDDEN) {
+ if (cmi.mLoginNudgeEnable) {
+ containerList = new ArrayList<Entry>();
+ // install nudge
+ entry = new Entry(CARD_ENTRY_ID_INCALL_PLUGIN,
+ cmi.mBrandIcon,
+ null,
+ cmi.mInstallNudgeSubtitle,
+ null,
+ cmi.mInstallNudgeActionText,
+ new Intent(ACTION_INCALL_PLUGIN_INSTALL),
+ res.getDrawable(R.drawable.ic_close),
+ new Intent(ACTION_INCALL_PLUGIN_DISMISS_NUDGE),
+ null,
+ null,
+ null,
+ cmi.mBrandIconId,
+ cmi,
+ containerList, parentList);
+ if (DEBUG) Log.d(TAG, "Adding INSTALL NUDGE");
+ containerList.add(entry);
+ parentList.add(containerList);
+ }
+ } else if (cmi.mStatus == PluginStatus.ENABLED) {
+ if (!hasPluginAccount) {
+ if (cmi.mIsAuthenticated) {
+ // Invite
+ containerList = new ArrayList<Entry>();
+ entry = new Entry(CARD_ENTRY_ID_INCALL_PLUGIN,
+ cmi.mBrandIcon,
+ res.getString(R.string.incall_plugin_directory_search, cmi.mName),
+ null,
+ null,
+ null,
+ new Intent(ACTION_INCALL_PLUGIN_DIRECTORY_SEARCH),
+ null,
+ null,
+ res.getString(R.string.incall_plugin_invite),
+ null,
+ new Intent(ACTION_INCALL_PLUGIN_INVITE),
+ cmi.mBrandIconId,
+ cmi,
+ containerList, parentList);
+ if (DEBUG) Log.d(TAG, "Adding INVITE ENTRY");
+ containerList.add(entry);
+ parentList.add(containerList);
+ } else {
+ // login nudge
+ if (cmi.mLoginNudgeEnable) {
+ containerList = new ArrayList<Entry>();
+ entry = new Entry(CARD_ENTRY_ID_INCALL_PLUGIN,
+ cmi.mBrandIcon,
+ null,
+ cmi.mInstallNudgeSubtitle,
+ null,
+ cmi.mInstallNudgeActionText,
+ new Intent(ACTION_INCALL_PLUGIN_LOGIN),
+ res.getDrawable(R.drawable.ic_close),
+ new Intent(ACTION_INCALL_PLUGIN_DISMISS_NUDGE),
+ null,
+ null,
+ null,
+ cmi.mBrandIconId,
+ cmi,
+ containerList, parentList);
+ if (DEBUG) Log.d(TAG, "Adding LOGIN NUDGE");
+ containerList.add(entry);
+ parentList.add(containerList);
+ }
+ }
+ }
+ }
+ }
+
+ // Create new Entries
+ private List<Entry> incallPluginDataItemsToEntries(List<DataItem> dataItems, Contact contact,
+ RawContact rawContact, List<List<Entry>> parentList, HashMap<ComponentName,
+ List<String>> pluginAccountMap) {
+ List<Entry> entries = new ArrayList<Entry>();
+ for (DataItem dataItem : dataItems) {
+ CallMethodInfo cmi =
+ InCallPluginHelper.getMethodForMimeType(dataItem.getMimeType(), true);
+ Entry entry;
+ String contactAccountHandle = rawContact.getSourceId();
+ if (cmi.mIsAuthenticated) {
+ // user signed in, consolidate entries
+ InCallPluginUtils.PresenceInfo presenceInfo = InCallPluginUtils.lookupPresenceInfo(
+ this, contact, rawContact);
+ Intent callIntent = InCallPluginUtils.getVoiceMimeIntent(cmi.mMimeType, dataItem,
+ cmi, contactAccountHandle);
+ entry = new Entry(CARD_ENTRY_ID_INCALL_PLUGIN_CALL,
+ cmi.mBrandIcon,
+ contactAccountHandle,
+ presenceInfo.mStatusMsg,
+ presenceInfo.mPresenceIcon,
+ null,
+ callIntent,
+ cmi.mImIcon,
+ InCallPluginUtils.getImMimeIntent(cmi.mImMimeType, rawContact),
+ null,
+ cmi.mVoiceIcon,
+ callIntent,
+ cmi.mBrandIconId,
+ cmi,
+ entries, parentList);
+ if (DEBUG) Log.d(TAG, "Adding CALL ENTRY");
+ } else {
+ // user signed out, list the contact's account name, and action set to
+ // launch sign in
+ final Resources res = getResources();
+ entry = new Entry(CARD_ENTRY_ID_INCALL_PLUGIN,
+ cmi.mBrandIcon,
+ contactAccountHandle,
+ res.getString(R.string.incall_plugin_account_subheader, cmi.mName),
+ null, null,
+ new Intent(ACTION_INCALL_PLUGIN_LOGIN),
+ null, null, null, null,
+ null, cmi.mBrandIconId,
+ cmi, entries, parentList);
+ if (DEBUG) Log.d(TAG, "Adding ACCOUNT ENTRY");
+ }
+ entries.add(entry);
+ // gather account list for interactions
+ List<String> accountsList;
+ if (!pluginAccountMap.containsKey(cmi.mComponent)) {
+ accountsList = new ArrayList<String>();
+ pluginAccountMap.put(cmi.mComponent, accountsList);
+ } else {
+ accountsList = pluginAccountMap.get(cmi.mComponent);
+ }
+ accountsList.add(contactAccountHandle);
+
+ }
+ return entries;
+ }
+
+ private void handleInCallPluginAction(EntryTag tag) {
+ if (tag == null) {
+ return;
+ }
+ Entry entry = tag.getEntry();
+ if (entry == null) {
+ return;
+ }
+ CallMethodInfo cmiStored = entry.getCallMethodInfo();
+ CallMethodInfo cmi = InCallPluginHelper.getCallMethod(cmiStored.mComponent);
+ Intent intent = tag.getIntent();
+ if (cmi == null || intent == null) {
+ return;
+ }
+ try {
+ if(intent.getAction().equals(ACTION_INCALL_PLUGIN_INSTALL)) {
+ startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" +
+ cmi.mDependentPackage)));
+ } else if (intent.getAction().equals(ACTION_INCALL_PLUGIN_DISMISS_NUDGE)) {
+ String nudgeKey = intent.getStringExtra(InCallPluginUtils
+ .KEY_NUDGE_KEY);
+ dismissNudge(tag, nudgeKey);
+ } else if (intent.getAction().equals(ACTION_INCALL_PLUGIN_LOGIN)) {
+ if (cmi.mLoginIntent != null) {
+ cmi.mLoginIntent.send();
+ }
+ } else if (intent.getAction().equals(ACTION_INCALL_PLUGIN_INVITE)) {
+ if (cmi.mInviteIntent != null) {
+ cmi.mInviteIntent.send();
+ } else {
+ cmi.mInviteIntent = InCallPluginHelper.getInviteIntentSync(cmi.mComponent,
+ InCallPluginUtils.getInCallContactInfo(mContactData));
+ if (cmi.mInviteIntent != null) {
+ cmi.mInviteIntent.send();
+ }
+ }
+ } else if (intent.getAction().equals(ACTION_INCALL_PLUGIN_DIRECTORY_SEARCH)) {
+ if (cmi.mDirectorySearchIntent != null) {
+ cmi.mDirectorySearchIntent.send();
+ } else {
+ cmi.mDirectorySearchIntent =
+ InCallPluginHelper.getDirectorySearchIntentSync(cmi.mComponent,
+ InCallPluginUtils.getInCallContactInfo(mContactData).mLookupUri);
+ if (cmi.mDirectorySearchIntent != null) {
+ cmi.mDirectorySearchIntent.send();
+ }
+ }
+ }
+ } catch (PendingIntent.CanceledException e) {
+ if (DEBUG) Log.d(TAG, "handleInCallPluginAction ", e);
+ }
+ }
+
+ private void dismissNudge(EntryTag tag, String nudgeKey) {
+ // Write the dimissal to preferences
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
+ SharedPreferences.Editor editor = sp.edit();
+ if (tag == null) {
+ return;
+ }
+ Entry entry = tag.getEntry();
+ CallMethodInfo cmi = entry.getCallMethodInfo();
+ final List<List<Entry>> cardEntries = entry.getParentList();
+ List<Entry> containerList = entry.getContainerList();
+
+ // disable the nudge type
+ editor.putBoolean(cmi.mComponent.getClassName() + "." + nudgeKey, false);
+ editor.apply();
+ // Find the entry and remove it
+ cardEntries.remove(containerList);
+
+ // Repopulate the view
+ mContactCard.initialize(cardEntries,
+ MIN_NUM_CONTACT_ENTRIES_SHOWN,
+ mContactCard.isExpanded(),
+ false,
+ mExpandingEntryCardViewListener,
+ mScroller);
+ mContactCard.setVisibility(View.VISIBLE);
+ }
+
+ private CallMethodHelper.CallMethodReceiver pluginsUpdatedReceiver =
+ new CallMethodHelper.CallMethodReceiver() {
+ @Override
+ public void onChanged(HashMap<ComponentName, CallMethodInfo> callMethodInfos) {
+ updatePlugins(callMethodInfos);
+ }
+ };
+
+ // Global CallMethod map that keeps track of the currently displayed plugins
+ HashMap<ComponentName, CallMethodInfo> mCallMethodMap = new HashMap<ComponentName, CallMethodInfo>();
+
+ private void updatePlugins(HashMap<ComponentName, CallMethodInfo> callMethods) {
+ if (DEBUG) Log.d(TAG, "+++updatePlugins");
+ HashMap<ComponentName, CallMethodInfo> newCmMap = (HashMap<ComponentName, CallMethodInfo>)
+ InCallPluginHelper.getAllEnabledAndHiddenCallMethods();
+ boolean updateNeeded = false;
+ if (mContactData == null) {
+ return;
+ }
+ if (mIsUpdating.get() || mCachedCp2DataCardModel == null) {
+ if (DEBUG) Log.d(TAG, "---updatePlugins null return");
+ checkAndBindContactData(mContactData, false, true);
+ return;
+ }
+ // Check if update or removal is needed
+ for (ComponentName cn : mCallMethodMap.keySet()) {
+ CallMethodInfo cmi = mCallMethodMap.get(cn);
+ if (newCmMap.containsKey(cn)) {
+ // Check if update needed
+ CallMethodInfo newCmi = newCmMap.remove(cn);
+ if (!newCmi.equals(cmi) || newCmi.mIsAuthenticated != cmi.mIsAuthenticated) {
+ updateNeeded = true;
+ }
+ } else {
+ // need to remove plugins
+ if (DEBUG) Log.d(TAG, "updatePlugins removed");
+ updateNeeded = true;
+ }
+ }
+ // Check if need to add new plugins
+ if (newCmMap.size() > 0) {
+ if (DEBUG) Log.d(TAG, "updatePlugins new plugins");
+ updateNeeded = true;
+ }
+
+ if (updateNeeded) {
+ if (DEBUG) Log.d(TAG, "updatePlugins updateNeeded");
+ checkAndBindContactData(mContactData, false, true);
+ }
+ if (DEBUG) Log.d(TAG, "---updatePlugins return");
+ }
}