Merge "Show the call option menu in Favorite tab too."
diff --git a/src/com/android/contacts/ContactLoader.java b/src/com/android/contacts/ContactLoader.java
index b49a357..dbfe411 100644
--- a/src/com/android/contacts/ContactLoader.java
+++ b/src/com/android/contacts/ContactLoader.java
@@ -23,6 +23,7 @@
 import com.android.contacts.util.StreamItemPhotoEntry;
 import com.google.android.collect.Lists;
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Sets;
 
 import android.content.ContentResolver;
 import android.content.ContentUris;
@@ -62,6 +63,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Loads a single Contact and all it constituent RawContacts.
@@ -76,7 +78,7 @@
     private Result mContact;
     private ForceLoadContentObserver mObserver;
     private boolean mDestroyed;
-
+    private final Set<Long> mNotifiedRawContactIds = Sets.newHashSet();
 
     public interface Listener {
         public void onContactLoaded(Result contact);
@@ -1115,6 +1117,11 @@
         Context context = getContext();
         for (Entity entity : mContact.getEntities()) {
             final ContentValues entityValues = entity.getEntityValues();
+            final long rawContactId = entityValues.getAsLong(RawContacts.Entity._ID);
+            if (mNotifiedRawContactIds.contains(rawContactId)) {
+                continue; // Already notified for this raw contact.
+            }
+            mNotifiedRawContactIds.add(rawContactId);
             final String type = entityValues.getAsString(RawContacts.ACCOUNT_TYPE);
             final String dataSet = entityValues.getAsString(RawContacts.DATA_SET);
             final AccountType accountType = AccountTypeManager.getInstance(context).getAccountType(
@@ -1122,7 +1129,6 @@
             final String serviceName = accountType.getViewContactNotifyServiceClassName();
             final String resPackageName = accountType.resPackageName;
             if (!TextUtils.isEmpty(serviceName) && !TextUtils.isEmpty(resPackageName)) {
-                final long rawContactId = entityValues.getAsLong(RawContacts.Entity._ID);
                 final Uri uri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
                 final Intent intent = new Intent();
                 intent.setClassName(resPackageName, serviceName);
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index 76cbc7d..45ce4fe 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -16,10 +16,10 @@
 
 package com.android.contacts;
 
-import com.google.i18n.phonenumbers.NumberParseException;
-import com.google.i18n.phonenumbers.PhoneNumberUtil;
-import com.google.i18n.phonenumbers.PhoneNumberUtil.MatchType;
-import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+import com.android.i18n.phonenumbers.NumberParseException;
+import com.android.i18n.phonenumbers.PhoneNumberUtil;
+import com.android.i18n.phonenumbers.PhoneNumberUtil.MatchType;
+import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
 
 import android.content.Context;
 import android.content.Intent;
diff --git a/src/com/android/contacts/interactions/PhoneNumberInteraction.java b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
index 0448bd5..918dac0 100644
--- a/src/com/android/contacts/interactions/PhoneNumberInteraction.java
+++ b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
@@ -24,11 +24,11 @@
 import com.android.contacts.model.AccountType.StringInflater;
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.model.DataKind;
+import com.android.i18n.phonenumbers.NumberParseException;
+import com.android.i18n.phonenumbers.PhoneNumberUtil;
+import com.android.i18n.phonenumbers.PhoneNumberUtil.MatchType;
+import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.i18n.phonenumbers.NumberParseException;
-import com.google.i18n.phonenumbers.PhoneNumberUtil;
-import com.google.i18n.phonenumbers.PhoneNumberUtil.MatchType;
-import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
 
 import android.app.Activity;
 import android.app.AlertDialog;
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index b517c2c..04b3fa8 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -16,12 +16,12 @@
 
 package com.android.contacts.model;
 
+import com.android.i18n.phonenumbers.PhoneNumberUtil;
 import com.android.internal.util.Objects;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 import com.google.android.collect.Sets;
 import com.google.common.annotations.VisibleForTesting;
-import com.google.i18n.phonenumbers.PhoneNumberUtil;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
diff --git a/tests/src/com/android/contacts/activities/CallLogActivityTests.java b/tests/src/com/android/contacts/activities/CallLogActivityTests.java
index a0fce2d..5926fd9 100644
--- a/tests/src/com/android/contacts/activities/CallLogActivityTests.java
+++ b/tests/src/com/android/contacts/activities/CallLogActivityTests.java
@@ -22,6 +22,7 @@
 import com.android.contacts.calllog.CallLogFragment;
 import com.android.contacts.calllog.CallLogListItemViews;
 import com.android.contacts.calllog.CallLogQuery;
+import com.android.contacts.calllog.CallLogQueryTestUtils;
 import com.android.contacts.calllog.ContactInfo;
 import com.android.contacts.calllog.IntentProvider;
 import com.android.internal.telephony.CallerInfo;
@@ -477,30 +478,19 @@
      * @param type Either Call.OUTGOING_TYPE or Call.INCOMING_TYPE or Call.MISSED_TYPE.
      */
     private void insert(String number, long date, int duration, int type) {
-        MatrixCursor.RowBuilder row = mCursor.newRow();
-        row.add(mIndex);
-        mIndex ++;
-        row.add(number);
-        if (NOW == date) {
-            row.add(new Date().getTime());
-        } else {
-            row.add(date);
-        }
-        if (duration < 0) {
-            duration = mRnd.nextInt(10 * 60);  // 0 - 10 minutes random.
-        }
-        row.add(duration);  // duration
+        Object[] values = CallLogQueryTestUtils.createTestExtendedValues();
+        values[CallLogQuery.ID] = mIndex;
+        values[CallLogQuery.NUMBER] = number;
+        values[CallLogQuery.DATE] = date == NOW ? new Date().getTime() : date;
+        values[CallLogQuery.DURATION] = duration < 0 ? mRnd.nextInt(10 * 60) : duration;
         if (mVoicemail != null && mVoicemail.equals(number)) {
             assertEquals(Calls.OUTGOING_TYPE, type);
         }
-        row.add(type);  // type
-        row.add(TEST_COUNTRY_ISO);  // country ISO
-        row.add(null);  // voicemail_uri
-        row.add(null);  // geocoded_location
-        row.add(null);  // cached_name
-        row.add(0);  // cached_number_type
-        row.add(null);  // cached_number_label
-        row.add(CallLogQuery.SECTION_OLD_ITEM);  // section
+        values[CallLogQuery.CALL_TYPE] = type;
+        values[CallLogQuery.COUNTRY_ISO] = TEST_COUNTRY_ISO;
+        values[CallLogQuery.SECTION] = CallLogQuery.SECTION_OLD_ITEM;
+        mCursor.addRow(values);
+        ++mIndex;
     }
 
     /**
@@ -511,30 +501,19 @@
      * @param duration In seconds of the call. Use RAND_DURATION to pick a random one.
      */
     private void insertVoicemail(String number, long date, int duration) {
-        MatrixCursor.RowBuilder row = mCursor.newRow();
+        Object[] values = CallLogQueryTestUtils.createTestExtendedValues();
+        values[CallLogQuery.ID] = mIndex;
+        values[CallLogQuery.NUMBER] = number;
+        values[CallLogQuery.DATE] = date == NOW ? new Date().getTime() : date;
+        values[CallLogQuery.DURATION] = duration < 0 ? mRnd.nextInt(10 * 60) : duration;
+        values[CallLogQuery.CALL_TYPE] = Calls.VOICEMAIL_TYPE;
+        values[CallLogQuery.COUNTRY_ISO] = TEST_COUNTRY_ISO;
         // Must have the same index as the row.
-        Uri voicemailUri =
+        values[CallLogQuery.VOICEMAIL_URI] =
                 ContentUris.withAppendedId(VoicemailContract.Voicemails.CONTENT_URI, mIndex);
-        row.add(mIndex);
-        mIndex ++;
-        row.add(number);
-        if (NOW == date) {
-            row.add(new Date().getTime());
-        } else {
-            row.add(date);
-        }
-        if (duration < 0) {
-            duration = mRnd.nextInt(10 * 60);  // 0 - 10 minutes random.
-        }
-        row.add(duration);  // duration
-        row.add(Calls.VOICEMAIL_TYPE);  // type
-        row.add(TEST_COUNTRY_ISO);  // country ISO
-        row.add(voicemailUri);  // voicemail_uri
-        row.add(null);  // geocoded_location
-        row.add(null);  // cached_name
-        row.add(0);  // cached_number_type
-        row.add(null);  // cached_number_label
-        row.add(CallLogQuery.SECTION_OLD_ITEM);  // section
+        values[CallLogQuery.SECTION] = CallLogQuery.SECTION_OLD_ITEM;
+        mCursor.addRow(values);
+        ++mIndex;
     }
 
     /**
diff --git a/tests/src/com/android/contacts/calllog/CallLogGroupBuilderTest.java b/tests/src/com/android/contacts/calllog/CallLogGroupBuilderTest.java
index 67b72dd..31ad548 100644
--- a/tests/src/com/android/contacts/calllog/CallLogGroupBuilderTest.java
+++ b/tests/src/com/android/contacts/calllog/CallLogGroupBuilderTest.java
@@ -221,9 +221,12 @@
             throw new IllegalArgumentException("not an item section: " + section);
         }
         mCursor.moveToNext();
-        mCursor.addRow(new Object[]{
-                mCursor.getPosition(), number, 0L, 0L, type, "", "", "", null, 0, null, section
-        });
+        Object[] values = CallLogQueryTestUtils.createTestExtendedValues();
+        values[CallLogQuery.ID] = mCursor.getPosition();
+        values[CallLogQuery.NUMBER] = number;
+        values[CallLogQuery.CALL_TYPE] = type;
+        values[CallLogQuery.SECTION] = section;
+        mCursor.addRow(values);
     }
 
     /** Adds the old section header to the call log. */
@@ -243,9 +246,10 @@
             throw new IllegalArgumentException("not a header section: " + section);
         }
         mCursor.moveToNext();
-        mCursor.addRow(new Object[]{
-                mCursor.getPosition(), "", 0L, 0L, 0, "", "", "", null, 0, null, section
-        });
+        Object[] values = CallLogQueryTestUtils.createTestExtendedValues();
+        values[CallLogQuery.ID] = mCursor.getPosition();
+        values[CallLogQuery.SECTION] = section;
+        mCursor.addRow(values);
     }
 
     /** Asserts that the group matches the given values. */
diff --git a/tests/src/com/android/contacts/calllog/CallLogQueryTestUtils.java b/tests/src/com/android/contacts/calllog/CallLogQueryTestUtils.java
new file mode 100644
index 0000000..0e1952a
--- /dev/null
+++ b/tests/src/com/android/contacts/calllog/CallLogQueryTestUtils.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.calllog;
+
+import static junit.framework.Assert.assertEquals;
+import junit.framework.Assert;
+
+/**
+ * Helper class to create test values for {@link CallLogQuery}.
+ */
+public class CallLogQueryTestUtils {
+    public static Object[] createTestValues() {
+        Object[] values = new Object[]{ -1L, "", 0L, 0L, 0, "", "", "", null, 0, null };
+        assertEquals(CallLogQuery._PROJECTION.length, values.length);
+        return values;
+    }
+
+    public static Object[] createTestExtendedValues() {
+        Object[] values = new Object[]{ -1L, "", 0L, 0L, 0, "", "", "", null, 0, null, 0 };
+        Assert.assertEquals(CallLogQuery.EXTENDED_PROJECTION.length, values.length);
+        return values;
+    }
+}