Merge "append final"
diff --git a/res/layout-sw580dp/group_editor_account_header.xml b/res/layout-sw580dp/group_editor_account_header.xml
new file mode 100644
index 0000000..a38266d
--- /dev/null
+++ b/res/layout-sw580dp/group_editor_account_header.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Account info header for group editor -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent"
+    android:layout_marginBottom="10dip"
+    android:orientation="horizontal">
+
+    <TextView
+        android:id="@+id/account_type"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorPrimary"
+        android:singleLine="true"
+        android:layout_gravity="center_vertical" />
+
+    <ImageView
+        android:id="@+id/account_icon"
+        android:layout_width="30dip"
+        android:layout_height="30dip"
+        android:layout_marginLeft="7dip"
+        android:layout_marginRight="7dip"
+        android:layout_centerVertical="true"/>
+
+    <TextView
+        android:id="@+id/account_name"
+        android:layout_width="0dip"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="?android:attr/textColorPrimary"
+        android:layout_gravity="center_vertical"
+        android:gravity="right"
+        android:singleLine="true" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout-sw580dp/group_editor_fragment.xml b/res/layout-sw580dp/group_editor_fragment.xml
new file mode 100644
index 0000000..bc41710
--- /dev/null
+++ b/res/layout-sw580dp/group_editor_fragment.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingTop="50dip"
+    android:paddingLeft="50dip"
+    android:paddingRight="100dip"
+    android:orientation="horizontal"
+    android:background="@color/background_primary">
+
+    <LinearLayout
+        android:id="@+id/group_members"
+        android:layout_width="0dip"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:orientation="vertical">
+
+        <include
+            layout="@layout/group_editor_autocomplete_view"
+            android:id="@+id/add_member_field"/>
+
+        <include
+            layout="@layout/group_editor_existing_member_list"
+            android:id="@android:id/list"/>
+
+    </LinearLayout>
+
+    <include
+        layout="@layout/group_editor_header"
+        android:id="@+id/header"/>
+
+</LinearLayout>
diff --git a/res/layout/group_editor_account_header.xml b/res/layout/group_editor_account_header.xml
index a38266d..7ff3107 100644
--- a/res/layout/group_editor_account_header.xml
+++ b/res/layout/group_editor_account_header.xml
@@ -19,7 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
-    android:layout_marginBottom="10dip"
+    android:paddingLeft="10dip"
     android:orientation="horizontal">
 
     <TextView
@@ -33,21 +33,9 @@
 
     <ImageView
         android:id="@+id/account_icon"
-        android:layout_width="30dip"
-        android:layout_height="30dip"
-        android:layout_marginLeft="7dip"
-        android:layout_marginRight="7dip"
-        android:layout_centerVertical="true"/>
-
-    <TextView
-        android:id="@+id/account_name"
-        android:layout_width="0dip"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:textColor="?android:attr/textColorPrimary"
-        android:layout_gravity="center_vertical"
-        android:gravity="right"
-        android:singleLine="true" />
+        android:layout_width="20dip"
+        android:layout_height="20dip"
+        android:layout_marginLeft="10dip"
+        android:layout_gravity="center_vertical"/>
 
 </LinearLayout>
\ No newline at end of file
diff --git a/res/layout/group_editor_autocomplete_view.xml b/res/layout/group_editor_autocomplete_view.xml
new file mode 100644
index 0000000..6b35cae
--- /dev/null
+++ b/res/layout/group_editor_autocomplete_view.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- Autocomplete text input field for adding new members to a group in the group editor -->
+
+<AutoCompleteTextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:textColor="?android:attr/textColorPrimary"
+    android:hint="@string/enter_contact_name"/>
\ No newline at end of file
diff --git a/res/layout/group_editor_existing_member_list.xml b/res/layout/group_editor_existing_member_list.xml
new file mode 100644
index 0000000..1407a18
--- /dev/null
+++ b/res/layout/group_editor_existing_member_list.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- List of existing members for the group editor -->
+
+<ListView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_marginTop="@dimen/group_editor_padding"
+    android:cacheColorHint="@android:color/transparent"
+    android:divider="@null" />
\ No newline at end of file
diff --git a/res/layout/group_editor_fragment.xml b/res/layout/group_editor_fragment.xml
index 2c5b32a..dc82642 100644
--- a/res/layout/group_editor_fragment.xml
+++ b/res/layout/group_editor_fragment.xml
@@ -18,39 +18,44 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:paddingTop="50dip"
-    android:paddingLeft="50dip"
-    android:paddingRight="100dip"
-    android:orientation="horizontal"
-    android:background="@color/background_primary">
-
-    <LinearLayout
-        android:id="@+id/group_members"
-        android:layout_width="0dip"
-        android:layout_height="match_parent"
-        android:layout_weight="1"
-        android:orientation="vertical">
-
-        <AutoCompleteTextView
-            android:id="@+id/add_member_field"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:textColor="?android:attr/textColorPrimary"
-            android:hint="@string/enter_contact_name" />
-
-        <ListView
-            android:id="@android:id/list"
-            android:layout_width="match_parent"
-            android:layout_height="@dimen/group_editor_member_list_height"
-            android:layout_marginTop="10dip"
-            android:cacheColorHint="@android:color/transparent"
-            android:divider="@null" />
-
-    </LinearLayout>
+    android:orientation="vertical"
+    android:background="@color/background_primary"
+    android:paddingTop="@dimen/group_editor_padding"
+    android:paddingLeft="@dimen/group_editor_padding"
+    android:paddingRight="@dimen/group_editor_padding" >
 
     <include
-        layout="@layout/group_editor_header"
-        android:id="@+id/header"/>
+        layout="@layout/group_editor_account_header"
+        android:id="@+id/account_header" />
+
+    <TextView
+        android:id="@+id/account_name"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="@dimen/group_editor_padding"
+        android:paddingLeft="10dip"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:textColor="?android:attr/textColorPrimary"
+        android:singleLine="true" />
+
+    <include
+        layout="@layout/edit_divider"
+        android:id="@+id/divider"/>
+
+    <EditText
+        android:id="@+id/group_name"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:inputType="textCapWords"
+        android:layout_marginBottom="@dimen/group_editor_padding"/>
+
+    <include
+        layout="@layout/group_editor_autocomplete_view"
+        android:id="@+id/add_member_field"/>
+
+    <include
+        layout="@layout/group_editor_existing_member_list"
+        android:id="@android:id/list"/>
 
 </LinearLayout>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index eb40382..b0624cb 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -169,6 +169,9 @@
     <!-- Height of the member list in the group editor -->
     <dimen name="group_editor_member_list_height">550dip</dimen>
 
+    <!-- Side padding of the header in the group editor -->
+    <dimen name="group_editor_padding">5dip</dimen>
+
     <!-- Height for directory headers in contact lists -->
     <dimen name="directory_header_height">28dip</dimen>
 
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index 43b3bee..43376ca 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -114,8 +114,8 @@
         mInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
         mResources = getResources();
 
-        mPhoneCallDetailsViews = new PhoneCallDetailsViews(getWindow().getDecorView());
-        mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(getResources());
+        mPhoneCallDetailsViews = PhoneCallDetailsViews.fromView(getWindow().getDecorView());
+        mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(getResources(), getVoicemailNumber());
         mCallActionView = findViewById(R.id.call);
         mContactPhotoView = (ImageView) findViewById(R.id.contact_photo);
         mContactBackgroundView = (ImageView) findViewById(R.id.contact_background);
@@ -307,6 +307,12 @@
         return getString(R.string.callDetailsDurationFormat, minutes, seconds);
     }
 
+    private String getVoicemailNumber() {
+        TelephonyManager telephonyManager =
+                (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
+        return telephonyManager.getVoiceMailNumber();
+    }
+
     static final class ViewEntry {
         public int icon = -1;
         public String text = null;
diff --git a/src/com/android/contacts/PhoneCallDetailsHelper.java b/src/com/android/contacts/PhoneCallDetailsHelper.java
index 6542f7d..fc96a89 100644
--- a/src/com/android/contacts/PhoneCallDetailsHelper.java
+++ b/src/com/android/contacts/PhoneCallDetailsHelper.java
@@ -17,6 +17,7 @@
 package com.android.contacts;
 
 import com.android.contacts.format.FormatUtils;
+import com.android.internal.telephony.CallerInfo;
 
 import android.content.res.Resources;
 import android.graphics.Typeface;
@@ -33,6 +34,7 @@
  */
 public class PhoneCallDetailsHelper {
     private final Resources mResources;
+    private final String mVoicemailNumber;
     private final String mTypeIncomingText;
     private final String mTypeOutgoingText;
     private final String mTypeMissedText;
@@ -44,8 +46,9 @@
      *
      * @param resources used to look up strings
      */
-    public PhoneCallDetailsHelper(Resources resources) {
+    public PhoneCallDetailsHelper(Resources resources, String voicemailNumber) {
         mResources = resources;
+        mVoicemailNumber = voicemailNumber;
         mTypeIncomingText = mResources.getString(R.string.type_incoming);
         mTypeOutgoingText = mResources.getString(R.string.type_outgoing);
         mTypeMissedText = mResources.getString(R.string.type_missed);
@@ -98,11 +101,11 @@
         CharSequence nameText;
         CharSequence numberText;
         if (TextUtils.isEmpty(name)) {
-            nameText = number;
+            nameText = getDisplayNumber(number);
             numberText = "";
         } else {
             nameText = name;
-            numberText = number;
+            numberText = getDisplayNumber(number);
             if (callType != 0 && numberFormattedLabel != null) {
                 numberText = FormatUtils.applyStyleToSpan(Typeface.BOLD,
                         numberFormattedLabel + " " + number, 0,
@@ -124,4 +127,23 @@
             views.mNumberView.setVisibility(View.GONE);
         }
     }
+
+    private CharSequence getDisplayNumber(CharSequence number) {
+        if (TextUtils.isEmpty(number)) {
+            return "";
+        }
+        if (number.equals(CallerInfo.UNKNOWN_NUMBER)) {
+            return mResources.getString(R.string.unknown);
+        }
+        if (number.equals(CallerInfo.PRIVATE_NUMBER)) {
+            return mResources.getString(R.string.private_num);
+        }
+        if (number.equals(CallerInfo.PAYPHONE_NUMBER)) {
+            return mResources.getString(R.string.payphone);
+        }
+        if (PhoneNumberUtils.extractNetworkPortion(number.toString()).equals(mVoicemailNumber)) {
+            return mResources.getString(R.string.voicemail);
+        }
+        return number;
+    }
 }
diff --git a/src/com/android/contacts/PhoneCallDetailsViews.java b/src/com/android/contacts/PhoneCallDetailsViews.java
index f9f8572..c2819c3 100644
--- a/src/com/android/contacts/PhoneCallDetailsViews.java
+++ b/src/com/android/contacts/PhoneCallDetailsViews.java
@@ -27,14 +27,27 @@
     public final TextView mCallTypeAndDateView;
     public final TextView mNumberView;
 
+    private PhoneCallDetailsViews(TextView nameView, TextView callTypeAndDateView,
+            TextView numberView) {
+        mNameView = nameView;
+        mCallTypeAndDateView = callTypeAndDateView;
+        mNumberView = numberView;
+    }
+
     /**
-     * Creates a new instance and caches its views.
-     *
-     * @param view the view which contains the elements to fill
+     * Create a new instance by extracting the elements from the given view.
+     * <p>
+     * The view should contain three text views with identifiers {@code R.id.name},
+     * {@code R.id.call_type}, and {@code R.id.number}.
      */
-    public PhoneCallDetailsViews(View view) {
-        mNameView = (TextView) view.findViewById(R.id.name);
-        mCallTypeAndDateView = (TextView) view.findViewById(R.id.call_type);
-        mNumberView = (TextView) view.findViewById(R.id.number);
+    public static PhoneCallDetailsViews fromView(View view) {
+        return new PhoneCallDetailsViews((TextView) view.findViewById(R.id.name),
+                (TextView) view.findViewById(R.id.call_type),
+                (TextView) view.findViewById(R.id.number));
+    }
+
+    public static PhoneCallDetailsViews createForTest(TextView nameView,
+            TextView callTypeAndDateView, TextView numberView) {
+        return new PhoneCallDetailsViews(nameView, callTypeAndDateView, numberView);
     }
 }
diff --git a/src/com/android/contacts/activities/GroupDetailActivity.java b/src/com/android/contacts/activities/GroupDetailActivity.java
index ee1af57..5d50efc 100644
--- a/src/com/android/contacts/activities/GroupDetailActivity.java
+++ b/src/com/android/contacts/activities/GroupDetailActivity.java
@@ -20,6 +20,7 @@
 import com.android.contacts.R;
 import com.android.contacts.group.GroupDetailFragment;
 
+import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 
@@ -59,7 +60,10 @@
 
         @Override
         public void onEditRequested(Uri groupUri) {
-            // TODO: Disabling editor activity for phone right now because it's not ready
+            final Intent intent = new Intent(GroupDetailActivity.this, GroupEditorActivity.class);
+            intent.setData(groupUri);
+            intent.setAction(Intent.ACTION_EDIT);
+            startActivity(intent);
         }
     };
 }
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 9af426d..d6661db 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -836,9 +836,6 @@
 
         @Override
         public void onEditRequested(Uri groupUri) {
-            // TODO: Send off an intent with the groups URI, so we don't need to specify
-            // the editor activity class. Then it would be declared as:
-            // new Intent(Intent.ACTION_EDIT, groupUri), SUBACTIVITY_EDIT_GROUP);
             final Intent intent = new Intent(PeopleActivity.this, GroupEditorActivity.class);
             intent.setData(groupUri);
             intent.setAction(Intent.ACTION_EDIT);
diff --git a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
new file mode 100644
index 0000000..ab00382
--- /dev/null
+++ b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2010 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;
+
+import com.android.internal.telephony.CallerInfo;
+
+import android.content.Context;
+import android.provider.CallLog.Calls;
+import android.test.AndroidTestCase;
+import android.widget.TextView;
+
+/**
+ * Unit tests for {@link PhoneCallDetailsHelper}.
+ */
+public class PhoneCallDetailsHelperTest extends AndroidTestCase {
+    /** The number to be used to access the voicemail. */
+    private static final String TEST_VOICEMAIL_NUMBER = "125";
+    /** The date of the call log entry. */
+    private static final long TEST_DATE = 1300000000;
+
+    /** The object under test. */
+    private PhoneCallDetailsHelper mHelper;
+    /** The views to fill. */
+    private PhoneCallDetailsViews mViews;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        Context context = getContext();
+        mHelper = new PhoneCallDetailsHelper(context.getResources(), TEST_VOICEMAIL_NUMBER);
+        mViews = PhoneCallDetailsViews.createForTest(new TextView(context), new TextView(context),
+                new TextView(context));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        mViews = null;
+        mHelper = null;
+        super.tearDown();
+    }
+
+    public void testSetPhoneCallDetails_Unknown() {
+        setPhoneCallDetailsWithNumber(CallerInfo.UNKNOWN_NUMBER);
+        assertNameEqualsResource(R.string.unknown);
+    }
+
+    public void testSetPhoneCallDetails_Private() {
+        setPhoneCallDetailsWithNumber(CallerInfo.PRIVATE_NUMBER);
+        assertNameEqualsResource(R.string.private_num);
+    }
+
+    public void testSetPhoneCallDetails_Payphone() {
+        setPhoneCallDetailsWithNumber(CallerInfo.PAYPHONE_NUMBER);
+        assertNameEqualsResource(R.string.payphone);
+    }
+
+    public void testSetPhoneCallDetails_Voicemail() {
+        setPhoneCallDetailsWithNumber(TEST_VOICEMAIL_NUMBER);
+        assertNameEqualsResource(R.string.voicemail);
+    }
+
+    public void testSetPhoneCallDetails_Normal() {
+        setPhoneCallDetailsWithNumber("1-412-555-1212");
+        assertNameEquals("1-412-555-1212");
+    }
+
+    /** Asserts that the name text field contains the value of the given string resource. */
+    private void assertNameEqualsResource(int resId) {
+        assertNameEquals(getContext().getString(resId));
+    }
+
+    /** Asserts that the name text field contains the given string value. */
+    private void assertNameEquals(String text) {
+        assertEquals(text, mViews.mNameView.getText().toString());
+    }
+
+    /** Sets the phone call details with default values and the given number. */
+    private void setPhoneCallDetailsWithNumber(String number) {
+        mHelper.setPhoneCallDetails(mViews, TEST_DATE, Calls.INCOMING_TYPE, "", number, 0, "");
+    }
+}