Merge "Update list header only when contacts in default directory are loaded" into ub-contactsdialer-f-dev
am: dc36620ee8
Change-Id: I19bc9abeaa17c49eda5e7186fc03087fe500fc45
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index cee45a2..0bedf6b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -16,8 +16,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.contacts"
- android:versionCode="10513"
- android:versionName="1.5.13">
+ android:versionCode="10512"
+ android:versionName="1.5.12">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="25" />
diff --git a/res/drawable-hdpi/ic_add_to_circles_black_24.png b/res/drawable-hdpi/ic_add_to_circles_black_24.png
deleted file mode 100644
index 6eb1fcc..0000000
--- a/res/drawable-hdpi/ic_add_to_circles_black_24.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_add_to_circles_black_24.png b/res/drawable-mdpi/ic_add_to_circles_black_24.png
deleted file mode 100644
index fbffc97..0000000
--- a/res/drawable-mdpi/ic_add_to_circles_black_24.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_add_to_circles_black_24.png b/res/drawable-xhdpi/ic_add_to_circles_black_24.png
deleted file mode 100644
index 79116b5..0000000
--- a/res/drawable-xhdpi/ic_add_to_circles_black_24.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_add_to_circles_black_24.png b/res/drawable-xxhdpi/ic_add_to_circles_black_24.png
deleted file mode 100644
index 23a2084..0000000
--- a/res/drawable-xxhdpi/ic_add_to_circles_black_24.png
+++ /dev/null
Binary files differ
diff --git a/res/layout/editor_save_button.xml b/res/layout/editor_save_button.xml
new file mode 100644
index 0000000..024ddcb
--- /dev/null
+++ b/res/layout/editor_save_button.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ style="?android:attr/buttonBarButtonStyle"
+ android:id="@+id/editor_menu_save_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/menu_save"
+ android:textColor="@color/action_bar_button_text_color"
+ android:textSize="14sp">
+</Button>
diff --git a/res/menu/edit_contact.xml b/res/menu/edit_contact.xml
index 256edb6..9bf067f 100644
--- a/res/menu/edit_contact.xml
+++ b/res/menu/edit_contact.xml
@@ -18,7 +18,7 @@
<item
android:id="@+id/menu_save"
android:showAsAction="always"
- android:icon="@drawable/ic_done_wht_24dp"
+ android:actionLayout="@layout/editor_save_button"
android:title="@string/menu_save" />
<item
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7a81940..909b684 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -663,7 +663,7 @@
<string name="toast_text_copied">Text copied</string>
<!-- Contents of the alert dialog when the user hits the Cancel button in the editor [CHAR LIMIT=128] -->
- <string name="cancel_confirmation_dialog_message">Discard your changes and quit editing?</string>
+ <string name="cancel_confirmation_dialog_message">Discard changes?</string>
<!-- Positive button text for the cancel editing confirmation dialog.
Pushing this button indicates that the user wishes to discard the changes they have already
@@ -673,7 +673,7 @@
<!-- Negative button text for the cancel editing confirmation dialog.
Pushing this button indicates that the user wishes to continue editing
and return to the editor [CHAR LIMIT=30] -->
- <string name="cancel_confirmation_dialog_keep_editing_button">Keep editing</string>
+ <string name="cancel_confirmation_dialog_keep_editing_button">Cancel</string>
<!-- Description of a call log entry, made of a call type and a date -->
<string name="call_type_and_date">
@@ -751,8 +751,7 @@
<!-- Toast that appears when you are copying a directory contact into your personal contacts -->
<string name="toast_making_personal_copy">Creating a personal copy…</string>
- <!-- Timestamp string for interactions from yesterday. [CHAR LIMIT=40] -->
- <string name="yesterday">Yesterday</string>
+ <!-- Timestamp string for interactions from tomorrow. [CHAR LIMIT=40] -->
<string name="tomorrow">Tomorrow</string>
<!-- Timestamp string for interactions from today. [CHAR LIMIT=40] -->
<string name="today">Today</string>
diff --git a/src/com/android/contacts/activities/ContactEditorBaseActivity.java b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
index 97095f0..c4abd58 100644
--- a/src/com/android/contacts/activities/ContactEditorBaseActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorBaseActivity.java
@@ -231,6 +231,7 @@
actionBar.setTitle(getResources().getString(mActionBarTitleResId));
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeAsUpIndicator(R.drawable.ic_close_dk);
}
}
diff --git a/src/com/android/contacts/editor/ContactEditorBaseFragment.java b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
index c1e5af8..d149f16 100644
--- a/src/com/android/contacts/editor/ContactEditorBaseFragment.java
+++ b/src/com/android/contacts/editor/ContactEditorBaseFragment.java
@@ -788,6 +788,15 @@
// Save menu is invisible when there's only one read only contact in the editor.
saveMenu.setVisible(!mRawContactDisplayAloneIsReadOnly);
+ if (saveMenu.isVisible()) {
+ // Since we're using a custom action layout we have to manually hook up the handler.
+ saveMenu.getActionView().setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ onOptionsItemSelected(saveMenu);
+ }
+ });
+ }
if (mRawContactIdToDisplayAlone != -1 || mIsUserProfile) {
sendToVoiceMailMenu.setVisible(false);
diff --git a/src/com/android/contacts/interactions/ContactInteractionUtil.java b/src/com/android/contacts/interactions/ContactInteractionUtil.java
index 98d45ee..8ec0547 100644
--- a/src/com/android/contacts/interactions/ContactInteractionUtil.java
+++ b/src/com/android/contacts/interactions/ContactInteractionUtil.java
@@ -26,9 +26,6 @@
import java.util.Calendar;
-import com.android.contacts.R;
-
-
/**
* Utility methods for interactions and their loaders
*/
@@ -61,8 +58,7 @@
* compareCalendar.
* This formats the date based on a few conditions:
* 1. If the timestamp is today, the time is shown
- * 2. If the timestamp occurs tomorrow or yesterday, that is displayed
- * 3. Otherwise {Month Date} format is used
+ * 2. Otherwise show full date and time
*/
@NeededForTesting
public static String formatDateStringFromTimestamp(long timestamp, Context context,
@@ -76,19 +72,9 @@
interactionCalendar.getTime());
}
- // Turn compareCalendar to yesterday
- compareCalendar.add(Calendar.DAY_OF_YEAR, -1);
- if (compareCalendarDayYear(interactionCalendar, compareCalendar)) {
- return context.getString(R.string.yesterday);
- }
-
- // Turn compareCalendar to tomorrow
- compareCalendar.add(Calendar.DAY_OF_YEAR, 2);
- if (compareCalendarDayYear(interactionCalendar, compareCalendar)) {
- return context.getString(R.string.tomorrow);
- }
- return DateUtils.formatDateTime(context, interactionCalendar.getTimeInMillis(),
- DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_YEAR);
+ return DateUtils.formatDateTime(context, timestamp, DateUtils.FORMAT_SHOW_TIME
+ | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY
+ | DateUtils.FORMAT_SHOW_YEAR);
}
/**
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index e918233..c595f23 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -239,7 +239,6 @@
private static final String MIMETYPE_GPLUS_PROFILE =
"vnd.android.cursor.item/vnd.googleplus.profile";
- private static final String GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE = "addtocircle";
private static final String GPLUS_PROFILE_DATA_5_VIEW_PROFILE = "view";
private static final String MIMETYPE_HANGOUTS =
"vnd.android.cursor.item/vnd.googleplus.profile.comm";
@@ -2108,30 +2107,7 @@
// Build advanced entry for known 3p types. Otherwise default to ResolveCache icon.
switch (mimetype) {
case MIMETYPE_GPLUS_PROFILE:
- // If a secondDataItem is available, use it to build an entry with
- // alternate actions
- if (secondDataItem != null) {
- icon = res.getDrawable(R.drawable.ic_google_plus_black_24dp);
- alternateIcon = res.getDrawable(R.drawable.ic_add_to_circles_black_24);
- final GPlusOrHangoutsDataItemModel itemModel =
- new GPlusOrHangoutsDataItemModel(intent, alternateIntent,
- dataItem, secondDataItem, alternateContentDescription,
- header, text, context);
-
- populateGPlusOrHangoutsDataItemModel(itemModel);
- intent = itemModel.intent;
- alternateIntent = itemModel.alternateIntent;
- alternateContentDescription = itemModel.alternateContentDescription;
- header = itemModel.header;
- text = itemModel.text;
- } else {
- if (GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE.equals(
- intent.getDataString())) {
- icon = res.getDrawable(R.drawable.ic_add_to_circles_black_24);
- } else {
- icon = res.getDrawable(R.drawable.ic_google_plus_black_24dp);
- }
- }
+ icon = res.getDrawable(R.drawable.ic_google_plus_black_24dp);
break;
case MIMETYPE_HANGOUTS:
// If a secondDataItem is available, use it to build an entry with
@@ -2139,12 +2115,12 @@
if (secondDataItem != null) {
icon = res.getDrawable(R.drawable.ic_hangout_24dp);
alternateIcon = res.getDrawable(R.drawable.ic_hangout_video_24dp);
- final GPlusOrHangoutsDataItemModel itemModel =
- new GPlusOrHangoutsDataItemModel(intent, alternateIntent,
+ final HangoutsDataItemModel itemModel =
+ new HangoutsDataItemModel(intent, alternateIntent,
dataItem, secondDataItem, alternateContentDescription,
header, text, context);
- populateGPlusOrHangoutsDataItemModel(itemModel);
+ populateHangoutsDataItemModel(itemModel);
intent = itemModel.intent;
alternateIntent = itemModel.alternateIntent;
alternateContentDescription = itemModel.alternateContentDescription;
@@ -2216,9 +2192,10 @@
private List<Entry> dataItemsToEntries(List<DataItem> dataItems,
MutableString aboutCardTitleOut) {
// Hangouts and G+ use two data items to create one entry.
- if (dataItems.get(0).getMimeType().equals(MIMETYPE_GPLUS_PROFILE) ||
- dataItems.get(0).getMimeType().equals(MIMETYPE_HANGOUTS)) {
- return gPlusOrHangoutsDataItemsToEntries(dataItems);
+ if (dataItems.get(0).getMimeType().equals(MIMETYPE_GPLUS_PROFILE)) {
+ return gPlusDataItemsToEntries(dataItems);
+ } else if (dataItems.get(0).getMimeType().equals(MIMETYPE_HANGOUTS)) {
+ return hangoutsDataItemsToEntries(dataItems);
} else {
final List<Entry> entries = new ArrayList<>();
for (DataItem dataItem : dataItems) {
@@ -2233,15 +2210,10 @@
}
/**
- * G+ and Hangout entries are unique in that a single ExpandingEntryCardView.Entry consists
- * of two data items. This method attempts to build each entry using the two data items if
- * they are available. If there are more or less than two data items, a fall back is used
- * and each data item gets its own entry.
+ * Put the data items into buckets based on the raw contact id
*/
- private List<Entry> gPlusOrHangoutsDataItemsToEntries(List<DataItem> dataItems) {
- final List<Entry> entries = new ArrayList<>();
+ private Map<Long, List<DataItem>> dataItemsToBucket(List<DataItem> dataItems) {
final Map<Long, List<DataItem>> buckets = new HashMap<>();
- // Put the data items into buckets based on the raw contact id
for (DataItem dataItem : dataItems) {
List<DataItem> bucket = buckets.get(dataItem.getRawContactId());
if (bucket == null) {
@@ -2250,10 +2222,43 @@
}
bucket.add(dataItem);
}
+ return buckets;
+ }
+
+ /**
+ * For G+ entries, a single ExpandingEntryCardView.Entry consists of two data items. This
+ * method use only the View profile to build entry.
+ */
+ private List<Entry> gPlusDataItemsToEntries(List<DataItem> dataItems) {
+ final List<Entry> entries = new ArrayList<>();
+
+ for (List<DataItem> bucket : dataItemsToBucket(dataItems).values()) {
+ for (DataItem dataItem : bucket) {
+ if (GPLUS_PROFILE_DATA_5_VIEW_PROFILE.equals(
+ dataItem.getContentValues().getAsString(Data.DATA5))) {
+ final Entry entry = dataItemToEntry(dataItem, /* secondDataItem = */ null,
+ this, mContactData, /* aboutCardName = */ null);
+ if (entry != null) {
+ entries.add(entry);
+ }
+ }
+ }
+ }
+ return entries;
+ }
+
+ /**
+ * For Hangouts entries, a single ExpandingEntryCardView.Entry consists of two data items. This
+ * method attempts to build each entry using the two data items if they are available. If there
+ * are more or less than two data items, a fall back is used and each data item gets its own
+ * entry.
+ */
+ private List<Entry> hangoutsDataItemsToEntries(List<DataItem> dataItems) {
+ final List<Entry> entries = new ArrayList<>();
// Use the buckets to build entries. If a bucket contains two data items, build the special
// entry, otherwise fall back to the normal entry.
- for (List<DataItem> bucket : buckets.values()) {
+ for (List<DataItem> bucket : dataItemsToBucket(dataItems).values()) {
if (bucket.size() == 2) {
// Use the pair to build an entry
final Entry entry = dataItemToEntry(bucket.get(0),
@@ -2276,10 +2281,10 @@
}
/**
- * Used for statically passing around G+ or Hangouts data items and entry fields to
- * populateGPlusOrHangoutsDataItemModel.
+ * Used for statically passing around Hangouts data items and entry fields to
+ * populateHangoutsDataItemModel.
*/
- private static final class GPlusOrHangoutsDataItemModel {
+ private static final class HangoutsDataItemModel {
public Intent intent;
public Intent alternateIntent;
public DataItem dataItem;
@@ -2289,7 +2294,7 @@
public String text;
public Context context;
- public GPlusOrHangoutsDataItemModel(Intent intent, Intent alternateIntent, DataItem dataItem,
+ public HangoutsDataItemModel(Intent intent, Intent alternateIntent, DataItem dataItem,
DataItem secondDataItem, StringBuilder alternateContentDescription, String header,
String text, Context context) {
this.intent = intent;
@@ -2303,18 +2308,16 @@
}
}
- private static void populateGPlusOrHangoutsDataItemModel(
- GPlusOrHangoutsDataItemModel dataModel) {
+ private static void populateHangoutsDataItemModel(
+ HangoutsDataItemModel dataModel) {
final Intent secondIntent = new Intent(Intent.ACTION_VIEW);
secondIntent.setDataAndType(ContentUris.withAppendedId(Data.CONTENT_URI,
dataModel.secondDataItem.getId()), dataModel.secondDataItem.getMimeType());
// There is no guarantee the order the data items come in. Second
// data item does not necessarily mean it's the alternate.
- // Hangouts video and Add to circles should be alternate. Swap if needed
+ // Hangouts video should be alternate. Swap if needed
if (HANGOUTS_DATA_5_VIDEO.equals(
- dataModel.dataItem.getContentValues().getAsString(Data.DATA5)) ||
- GPLUS_PROFILE_DATA_5_ADD_TO_CIRCLE.equals(
- dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
+ dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
dataModel.alternateIntent = dataModel.intent;
dataModel.alternateContentDescription = new StringBuilder(dataModel.header);
@@ -2323,9 +2326,7 @@
dataModel.secondDataItem.getDataKind());
dataModel.text = dataModel.secondDataItem.getDataKind().typeColumn;
} else if (HANGOUTS_DATA_5_MESSAGE.equals(
- dataModel.dataItem.getContentValues().getAsString(Data.DATA5)) ||
- GPLUS_PROFILE_DATA_5_VIEW_PROFILE.equals(
- dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
+ dataModel.dataItem.getContentValues().getAsString(Data.DATA5))) {
dataModel.alternateIntent = secondIntent;
dataModel.alternateContentDescription = new StringBuilder(
dataModel.secondDataItem.buildDataStringForDisplay(dataModel.context,
diff --git a/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java b/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java
index 4802b46..86167c1 100644
--- a/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java
+++ b/tests/src/com/android/contacts/interactions/ContactInteractionUtilTest.java
@@ -15,12 +15,9 @@
*/
package com.android.contacts.interactions;
-import com.android.contacts.common.R;
-
import android.content.res.Configuration;
import android.content.res.Resources;
import android.test.AndroidTestCase;
-import android.text.format.DateUtils;
import java.util.Calendar;
import java.util.Locale;
@@ -80,50 +77,15 @@
getContext()));
}
- public void testFormatDateStringFromTimestamp_yesterday() {
- // Test yesterday and tomorrow (Yesterday or Tomorrow shown)
- calendar.add(Calendar.DAY_OF_YEAR, -1);
- assertEquals(getContext().getResources().getString(R.string.yesterday),
- ContactInteractionUtil.formatDateStringFromTimestamp(calendar.getTimeInMillis(),
- getContext()));
- }
-
- public void testFormatDateStringFromTimestamp_yesterdayLastYear() {
- // Set to non leap year
- calendar.set(Calendar.YEAR, 1999);
- calendar.set(Calendar.DAY_OF_YEAR, 365);
- long lastYear = calendar.getTimeInMillis();
- calendar.add(Calendar.DAY_OF_YEAR, 1);
-
- assertEquals(getContext().getResources().getString(R.string.yesterday),
- ContactInteractionUtil.formatDateStringFromTimestamp(lastYear,
- getContext(), calendar));
- }
-
- public void testFormatDateStringFromTimestamp_tomorrow() {
- calendar.add(Calendar.DAY_OF_YEAR, 1);
- assertEquals(getContext().getResources().getString(R.string.tomorrow),
- ContactInteractionUtil.formatDateStringFromTimestamp(calendar.getTimeInMillis(),
- getContext()));
- }
-
- public void testFormatDateStringFromTimestamp_tomorrowNewYear() {
- calendar.set(Calendar.DAY_OF_YEAR, 1);
- long thisYear = calendar.getTimeInMillis();
- calendar.add(Calendar.DAY_OF_YEAR, -1);
-
- assertEquals(getContext().getResources().getString(R.string.tomorrow),
- ContactInteractionUtil.formatDateStringFromTimestamp(thisYear,
- getContext(), calendar));
- }
-
public void testFormatDateStringFromTimestamp_other() {
// Test other (Month Date)
calendar.set(
/* year = */ 1991,
/* month = */ Calendar.MONTH,
- /* day = */ 11);
- assertEquals("March 11",
+ /* day = */ 11,
+ /* hourOfDay = */ 8,
+ /* minute = */ 8);
+ assertEquals("Monday, March 11, 1991, 8:08 AM",
ContactInteractionUtil.formatDateStringFromTimestamp(calendar.getTimeInMillis(),
getContext()));
}