Merge "Fix for "Next" instead of Search showing up the first time" into jb-dev
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index fcc6510..5d188fb 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -1254,11 +1254,11 @@
             final AccountType accountType = AccountTypeManager.getInstance(context).getAccountType(
                     type, dataSet);
             final String serviceName = accountType.getViewContactNotifyServiceClassName();
-            final String resPackageName = accountType.resPackageName;
-            if (!TextUtils.isEmpty(serviceName) && !TextUtils.isEmpty(resPackageName)) {
+            final String servicePackageName = accountType.getViewContactNotifyServicePackageName();
+            if (!TextUtils.isEmpty(serviceName) && !TextUtils.isEmpty(servicePackageName)) {
                 final Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
                 final Intent intent = new Intent();
-                intent.setClassName(resPackageName, serviceName);
+                intent.setClassName(servicePackageName, serviceName);
                 intent.setAction(Intent.ACTION_VIEW);
                 intent.setDataAndType(uri, RawContacts.CONTENT_ITEM_TYPE);
                 try {
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index 9a014f4..ca32ff8 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -204,16 +204,16 @@
      * Returns the intent to launch for the given invitable account type and contact lookup URI.
      * This will return null if the account type is not invitable (i.e. there is no
      * {@link AccountType#getInviteContactActivityClassName()} or
-     * {@link AccountType#resPackageName}).
+     * {@link AccountType#syncAdapterPackageName}).
      */
     public static Intent getInvitableIntent(AccountType accountType, Uri lookupUri) {
-        String resPackageName = accountType.resPackageName;
+        String syncAdapterPackageName = accountType.syncAdapterPackageName;
         String className = accountType.getInviteContactActivityClassName();
-        if (TextUtils.isEmpty(resPackageName) || TextUtils.isEmpty(className)) {
+        if (TextUtils.isEmpty(syncAdapterPackageName) || TextUtils.isEmpty(className)) {
             return null;
         }
         Intent intent = new Intent();
-        intent.setClassName(resPackageName, className);
+        intent.setClassName(syncAdapterPackageName, className);
 
         intent.setAction(ContactsContract.Intents.INVITE_CONTACT);
 
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index d591b42..9dde2dd 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -207,7 +207,7 @@
                     account.type, account.dataSet);
 
             Intent intent = new Intent();
-            intent.setClassName(accountType.resPackageName,
+            intent.setClassName(accountType.syncAdapterPackageName,
                     accountType.getCreateContactActivityClassName());
             intent.setAction(Intent.ACTION_INSERT);
             intent.setType(Contacts.CONTENT_ITEM_TYPE);
@@ -232,7 +232,7 @@
                     account.type, account.dataSet);
 
             Intent intent = new Intent();
-            intent.setClassName(accountType.resPackageName,
+            intent.setClassName(accountType.syncAdapterPackageName,
                     accountType.getEditContactActivityClassName());
             intent.setAction(Intent.ACTION_EDIT);
             intent.setData(rawContactUri);
diff --git a/src/com/android/contacts/activities/GroupDetailActivity.java b/src/com/android/contacts/activities/GroupDetailActivity.java
index 6562278..e49789e 100644
--- a/src/com/android/contacts/activities/GroupDetailActivity.java
+++ b/src/com/android/contacts/activities/GroupDetailActivity.java
@@ -147,7 +147,8 @@
                 final Uri uri = ContentUris.withAppendedId(Groups.CONTENT_URI,
                         mFragment.getGroupId());
                 final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-                intent.setClassName(accountType.resPackageName, accountType.getViewGroupActivity());
+                intent.setClassName(accountType.syncAdapterPackageName,
+                        accountType.getViewGroupActivity());
                 startActivity(intent);
             }
         });
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index f180c1b..c3ccfa2 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -1193,7 +1193,6 @@
         public String mimetype;
 
         public Context context = null;
-        public String resPackageName = null;
         public boolean isPrimary = false;
         public int secondaryActionIcon = -1;
         public int secondaryActionDescription = -1;
@@ -1229,7 +1228,6 @@
             entry.kind = (kind.titleRes == -1 || kind.titleRes == 0) ? ""
                     : context.getString(kind.titleRes);
             entry.data = buildDataString(kind, values, context);
-            entry.resPackageName = kind.resPackageName;
 
             if (kind.typeColumn != null && values.containsKey(kind.typeColumn)) {
                 entry.type = values.getAsInteger(kind.typeColumn);
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index 6c35682..e8ce622 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -67,7 +67,7 @@
             final Uri uri = ContentUris.withAppendedId(StreamItems.CONTENT_URI,
                     streamItemEntry.getId());
             final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-            intent.setClassName(accountType.resPackageName,
+            intent.setClassName(accountType.syncAdapterPackageName,
                     accountType.getViewStreamItemActivity());
             startActivity(intent);
         }
@@ -84,7 +84,7 @@
             final AccountType accountType = getAccountTypeForStreamItemEntry(tag.streamItem);
 
             final Intent intent = new Intent(Intent.ACTION_VIEW, tag.getStreamItemPhotoUri());
-            intent.setClassName(accountType.resPackageName,
+            intent.setClassName(accountType.syncAdapterPackageName,
                     accountType.getViewStreamItemPhotoActivity());
             startActivity(intent);
         }
diff --git a/src/com/android/contacts/group/GroupDetailFragment.java b/src/com/android/contacts/group/GroupDetailFragment.java
index 068a641..9e19735 100644
--- a/src/com/android/contacts/group/GroupDetailFragment.java
+++ b/src/com/android/contacts/group/GroupDetailFragment.java
@@ -375,7 +375,7 @@
                 public void onClick(View v) {
                     final Uri uri = ContentUris.withAppendedId(Groups.CONTENT_URI, mGroupId);
                     final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-                    intent.setClassName(accountType.resPackageName,
+                    intent.setClassName(accountType.syncAdapterPackageName,
                             accountType.getViewGroupActivity());
                     startActivity(intent);
                 }
diff --git a/src/com/android/contacts/model/AccountType.java b/src/com/android/contacts/model/AccountType.java
index 3cc54f1..7e48d83 100644
--- a/src/com/android/contacts/model/AccountType.java
+++ b/src/com/android/contacts/model/AccountType.java
@@ -21,7 +21,6 @@
 import com.google.android.collect.Maps;
 import com.google.common.annotations.VisibleForTesting;
 
-import android.accounts.Account;
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -29,7 +28,6 @@
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.Contacts;
-import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.RawContacts;
 import android.view.inputmethod.EditorInfo;
 import android.widget.EditText;
@@ -62,11 +60,25 @@
     public String dataSet = null;
 
     /**
-     * Package that resources should be loaded from, either defined through an
-     * {@link Account} or for matching against {@link Data#RES_PACKAGE}.
+     * Package that resources should be loaded from.  Will be null for embedded types, in which
+     * case resources are stored in this package itself.
+     *
+     * TODO Clean up {@link #resourcePackageName}, {@link #syncAdapterPackageName} and
+     * {@link #getViewContactNotifyServicePackageName()}.
+     *
+     * There's the following invariants:
+     * - {@link #syncAdapterPackageName} is always set to the actual sync adapter package name.
+     * - {@link #resourcePackageName} too is set to the same value, unless {@link #isEmbedded()},
+     *   in which case it'll be null.
+     * There's an unfortunate exception of {@link FallbackAccountType}.  Even though it
+     * {@link #isEmbedded()}, but we set non-null to {@link #resourcePackageName} for unit tests.
      */
-    public String resPackageName;
-    public String summaryResPackageName;
+    public String resourcePackageName;
+    /**
+     * The package name for the authenticator (for the embedded types, i.e. Google and Exchange)
+     * or the sync adapter (for external type, including extensions).
+     */
+    public String syncAdapterPackageName;
 
     public int titleRes;
     public int iconRes;
@@ -125,24 +137,33 @@
     public abstract boolean areContactsWritable();
 
     /**
-     * Returns an optional custom edit activity.  The activity class should reside
-     * in the sync adapter package as determined by {@link #resPackageName}.
+     * Returns an optional custom edit activity.
+     *
+     * Only makes sense for non-embedded account types.
+     * The activity class should reside in the sync adapter package as determined by
+     * {@link #syncAdapterPackageName}.
      */
     public String getEditContactActivityClassName() {
         return null;
     }
 
     /**
-     * Returns an optional custom new contact activity. The activity class should reside
-     * in the sync adapter package as determined by {@link #resPackageName}.
+     * Returns an optional custom new contact activity.
+     *
+     * Only makes sense for non-embedded account types.
+     * The activity class should reside in the sync adapter package as determined by
+     * {@link #syncAdapterPackageName}.
      */
     public String getCreateContactActivityClassName() {
         return null;
     }
 
     /**
-     * Returns an optional custom invite contact activity. The activity class should reside
-     * in the sync adapter package as determined by {@link #resPackageName}.
+     * Returns an optional custom invite contact activity.
+     *
+     * Only makes sense for non-embedded account types.
+     * The activity class should reside in the sync adapter package as determined by
+     * {@link #syncAdapterPackageName}.
      */
     public String getInviteContactActivityClassName() {
         return null;
@@ -151,13 +172,25 @@
     /**
      * Returns an optional service that can be launched whenever a contact is being looked at.
      * This allows the sync adapter to provide more up-to-date information.
+     *
      * The service class should reside in the sync adapter package as determined by
-     * {@link #resPackageName}.
+     * {@link #getViewContactNotifyServicePackageName()}.
      */
     public String getViewContactNotifyServiceClassName() {
         return null;
     }
 
+    /**
+     * TODO This is way too hacky should be removed.
+     *
+     * This is introduced for {@link GoogleAccountType} where {@link #syncAdapterPackageName}
+     * is the authenticator package name but the notification service is in the sync adapter
+     * package.  See {@link #resourcePackageName} -- we should clean up those.
+     */
+    public String getViewContactNotifyServicePackageName() {
+        return syncAdapterPackageName;
+    }
+
     /** Returns an optional Activity string that can be used to view the group. */
     public String getViewGroupActivity() {
         return null;
@@ -174,7 +207,8 @@
     }
 
     public CharSequence getDisplayLabel(Context context) {
-        return getResourceText(context, summaryResPackageName, titleRes, accountType);
+        // Note this resource is defined in the sync adapter package, not resourcePackageName.
+        return getResourceText(context, syncAdapterPackageName, titleRes, accountType);
     }
 
     /**
@@ -213,7 +247,8 @@
      * the contact card.  (If not defined, returns null.)
      */
     public CharSequence getInviteContactActionLabel(Context context) {
-        return getResourceText(context, summaryResPackageName, getInviteContactActionResId(), "");
+        // Note this resource is defined in the sync adapter package, not resourcePackageName.
+        return getResourceText(context, syncAdapterPackageName, getInviteContactActionResId(), "");
     }
 
     /**
@@ -221,8 +256,9 @@
      * own "View Updates" string
      */
     public CharSequence getViewGroupLabel(Context context) {
+        // Note this resource is defined in the sync adapter package, not resourcePackageName.
         final CharSequence customTitle =
-                getResourceText(context, summaryResPackageName, getViewGroupLabelResId(), null);
+                getResourceText(context, syncAdapterPackageName, getViewGroupLabelResId(), null);
 
         return customTitle == null
                 ? context.getText(R.string.view_updates_from_group)
@@ -250,9 +286,9 @@
     }
 
     public Drawable getDisplayIcon(Context context) {
-        if (this.titleRes != -1 && this.summaryResPackageName != null) {
+        if (this.titleRes != -1 && this.syncAdapterPackageName != null) {
             final PackageManager pm = context.getPackageManager();
-            return pm.getDrawable(this.summaryResPackageName, this.iconRes, null);
+            return pm.getDrawable(this.syncAdapterPackageName, this.iconRes, null);
         } else if (this.titleRes != -1) {
             return context.getResources().getDrawable(this.iconRes);
         } else {
@@ -306,7 +342,7 @@
                     "mime type '" + kind.mimeType + "' is already registered");
         }
 
-        kind.resPackageName = this.resPackageName;
+        kind.resourcePackageName = this.resourcePackageName;
         this.mKinds.add(kind);
         this.mMimeKinds.put(kind.mimeType, kind);
         return kind;
diff --git a/src/com/android/contacts/model/DataKind.java b/src/com/android/contacts/model/DataKind.java
index c697e6f..0d60317 100644
--- a/src/com/android/contacts/model/DataKind.java
+++ b/src/com/android/contacts/model/DataKind.java
@@ -40,7 +40,7 @@
     public static final String PSEUDO_MIME_TYPE_PHONETIC_NAME = "#phoneticName";
     public static final String PSEUDO_COLUMN_PHONETIC_NAME = "#phoneticName";
 
-    public String resPackageName;
+    public String resourcePackageName;
     public String mimeType;
     public int titleRes;
     public int iconAltRes;
@@ -110,7 +110,7 @@
     public String toString() {
         final StringBuilder sb = new StringBuilder();
         sb.append("DataKind:");
-        sb.append(" resPackageName=").append(resPackageName);
+        sb.append(" resPackageName=").append(resourcePackageName);
         sb.append(" mimeType=").append(mimeType);
         sb.append(" titleRes=").append(titleRes);
         sb.append(" iconAltRes=").append(iconAltRes);
diff --git a/src/com/android/contacts/model/ExchangeAccountType.java b/src/com/android/contacts/model/ExchangeAccountType.java
index 21a30f8..1e3f6ee 100644
--- a/src/com/android/contacts/model/ExchangeAccountType.java
+++ b/src/com/android/contacts/model/ExchangeAccountType.java
@@ -43,10 +43,10 @@
 
     public static final String ACCOUNT_TYPE = "com.android.exchange";
 
-    public ExchangeAccountType(Context context, String resPackageName) {
+    public ExchangeAccountType(Context context, String authenticatorPackageName) {
         this.accountType = ACCOUNT_TYPE;
-        this.resPackageName = null;
-        this.summaryResPackageName = resPackageName;
+        this.resourcePackageName = null;
+        this.syncAdapterPackageName = authenticatorPackageName;
 
         try {
             addDataKindStructuredName(context);
diff --git a/src/com/android/contacts/model/ExternalAccountType.java b/src/com/android/contacts/model/ExternalAccountType.java
index f36e9e0..d7420af 100644
--- a/src/com/android/contacts/model/ExternalAccountType.java
+++ b/src/com/android/contacts/model/ExternalAccountType.java
@@ -101,17 +101,17 @@
      * @param injectedMetadata If non-null, it'll be used to initialize the type.  Only set by
      *     tests.  If null, the metadata is loaded from the specified package.
      */
-    ExternalAccountType(Context context, String resPackageName, boolean isExtension,
+    ExternalAccountType(Context context, String packageName, boolean isExtension,
             XmlResourceParser injectedMetadata) {
         this.mIsExtension = isExtension;
-        this.resPackageName = resPackageName;
-        this.summaryResPackageName = resPackageName;
+        this.resourcePackageName = packageName;
+        this.syncAdapterPackageName = packageName;
 
         final PackageManager pm = context.getPackageManager();
         final XmlResourceParser parser;
         if (injectedMetadata == null) {
             try {
-                parser = loadContactsXml(context, resPackageName);
+                parser = loadContactsXml(context, packageName);
             } catch (NameNotFoundException e1) {
                 // If the package name is not found, we can't initialize this account type.
                 return;
@@ -147,7 +147,7 @@
                 error.append(parser.getLineNumber());
             }
             error.append(" for external package ");
-            error.append(resPackageName);
+            error.append(packageName);
 
             Log.e(TAG, error.toString(), e);
             return;
@@ -159,13 +159,13 @@
 
         mExtensionPackageNames = new ArrayList<String>();
         mInviteActionLabelResId = resolveExternalResId(context, mInviteActionLabelAttribute,
-                summaryResPackageName, ATTR_INVITE_CONTACT_ACTION_LABEL);
+                syncAdapterPackageName, ATTR_INVITE_CONTACT_ACTION_LABEL);
         mViewGroupLabelResId = resolveExternalResId(context, mViewGroupLabelAttribute,
-                summaryResPackageName, ATTR_VIEW_GROUP_ACTION_LABEL);
+                syncAdapterPackageName, ATTR_VIEW_GROUP_ACTION_LABEL);
         titleRes = resolveExternalResId(context, mAccountTypeLabelAttribute,
-                this.resPackageName, ATTR_ACCOUNT_LABEL);
+                syncAdapterPackageName, ATTR_ACCOUNT_LABEL);
         iconRes = resolveExternalResId(context, mAccountTypeIconAttribute,
-                this.resPackageName, ATTR_ACCOUNT_ICON);
+                syncAdapterPackageName, ATTR_ACCOUNT_ICON);
 
         // If we reach this point, the account type has been successfully initialized.
         mIsInitialized = true;
diff --git a/src/com/android/contacts/model/FallbackAccountType.java b/src/com/android/contacts/model/FallbackAccountType.java
index 6ce7a43..892c049 100644
--- a/src/com/android/contacts/model/FallbackAccountType.java
+++ b/src/com/android/contacts/model/FallbackAccountType.java
@@ -31,8 +31,9 @@
         this.titleRes = R.string.account_phone;
         this.iconRes = R.mipmap.ic_launcher_contacts;
 
-        this.resPackageName = resPackageName;
-        this.summaryResPackageName = resPackageName;
+        // Note those are only set for unit tests.
+        this.resourcePackageName = resPackageName;
+        this.syncAdapterPackageName = resPackageName;
 
         try {
             addDataKindStructuredName(context);
@@ -65,7 +66,7 @@
      * {@code resPackageName} is injectable.
      */
     @NeededForTesting
-    static AccountType createForTest(Context context, String resPackageName) {
+    static AccountType createWithPackageNameForTest(Context context, String resPackageName) {
         return new FallbackAccountType(context, resPackageName);
     }
 
diff --git a/src/com/android/contacts/model/GoogleAccountType.java b/src/com/android/contacts/model/GoogleAccountType.java
index 822d829..a8a4069 100644
--- a/src/com/android/contacts/model/GoogleAccountType.java
+++ b/src/com/android/contacts/model/GoogleAccountType.java
@@ -39,10 +39,10 @@
     private static final List<String> mExtensionPackages =
             Lists.newArrayList("com.google.android.apps.plus");
 
-    public GoogleAccountType(Context context, String resPackageName) {
+    public GoogleAccountType(Context context, String authenticatorPackageName) {
         this.accountType = ACCOUNT_TYPE;
-        this.resPackageName = null;
-        this.summaryResPackageName = resPackageName;
+        this.resourcePackageName = null;
+        this.syncAdapterPackageName = authenticatorPackageName;
 
         try {
             addDataKindStructuredName(context);
@@ -183,4 +183,15 @@
     public boolean areContactsWritable() {
         return true;
     }
+
+    @Override
+    public String getViewContactNotifyServiceClassName() {
+        return "com.google.android.syncadapters.contacts." +
+                "SyncHighResPhotoIntentService";
+    }
+
+    @Override
+    public String getViewContactNotifyServicePackageName() {
+        return "com.google.android.syncadapters.contacts";
+    }
 }
diff --git a/src/com/android/contacts/quickcontact/DataAction.java b/src/com/android/contacts/quickcontact/DataAction.java
index 45565a1..ddec799 100644
--- a/src/com/android/contacts/quickcontact/DataAction.java
+++ b/src/com/android/contacts/quickcontact/DataAction.java
@@ -283,13 +283,13 @@
     public Drawable getAlternateIcon() {
         if (mAlternateIconRes == 0) return null;
 
-        final String resPackageName = mKind.resPackageName;
-        if (resPackageName == null) {
+        final String resourcePackageName = mKind.resourcePackageName;
+        if (resourcePackageName == null) {
             return mContext.getResources().getDrawable(mAlternateIconRes);
         }
 
         final PackageManager pm = mContext.getPackageManager();
-        return pm.getDrawable(resPackageName, mAlternateIconRes, null);
+        return pm.getDrawable(resourcePackageName, mAlternateIconRes, null);
     }
 
     @Override
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index d858e73..6b56470 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -224,7 +224,7 @@
                 final Uri uri = ContentUris.withAppendedId(StreamItems.CONTENT_URI,
                         streamItem.getId());
                 final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
-                intent.setClassName(accountType.resPackageName,
+                intent.setClassName(accountType.syncAdapterPackageName,
                         accountType.getViewStreamItemActivity());
                 views.setOnClickPendingIntent(R.id.name_and_snippet_container,
                         PendingIntent.getActivity(context, 0, intent, 0));
diff --git a/tests/src/com/android/contacts/model/AccountTypeTest.java b/tests/src/com/android/contacts/model/AccountTypeTest.java
index 8bc7429..6d4d6b0 100644
--- a/tests/src/com/android/contacts/model/AccountTypeTest.java
+++ b/tests/src/com/android/contacts/model/AccountTypeTest.java
@@ -66,8 +66,8 @@
 
         AccountType accountType = new AccountType() {
             {
-                resPackageName = packageName;
-                summaryResPackageName = packageName;
+                resourcePackageName = packageName;
+                syncAdapterPackageName = packageName;
             }
             @Override protected int getInviteContactActionResId() {
                 return externalResID;
diff --git a/tests/src/com/android/contacts/model/ExternalAccountTypeTest.java b/tests/src/com/android/contacts/model/ExternalAccountTypeTest.java
index 27c645a..4c47d68 100644
--- a/tests/src/com/android/contacts/model/ExternalAccountTypeTest.java
+++ b/tests/src/com/android/contacts/model/ExternalAccountTypeTest.java
@@ -126,8 +126,8 @@
 
         // Create a fallback type with the same resource package name, and compare all the data
         // kinds to its.
-        final AccountType reference = FallbackAccountType.createForTest(
-                getContext(), type.resPackageName);
+        final AccountType reference = FallbackAccountType.createWithPackageNameForTest(
+                getContext(), type.resourcePackageName);
 
         assertsDataKindEquals(reference.getSortedDataKinds(), type.getSortedDataKinds());
     }