Merge "Modify action bar for group editor and group card"
diff --git a/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml b/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml
index 9dd3690..f4c95f8 100644
--- a/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml
+++ b/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml
@@ -32,8 +32,9 @@
<!-- Real list -->
<LinearLayout
android:orientation="horizontal"
+ android:layout_weight="1"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="0dip">
<ImageView android:id="@+id/photo"
android:scaleType="centerCrop"
diff --git a/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml b/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
index 2de488d..22f0412 100644
--- a/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
+++ b/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
@@ -47,9 +47,24 @@
android:layout_height="wrap_content"
android:visibility="gone" />
- <TextView
- android:id="@+id/type"
- style="@style/ContactDetailItemType" />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/type"
+ style="@style/ContactDetailItemType" />
+
+ <View
+ android:id="@+id/primary_indicator"
+ android:layout_width="16dip"
+ android:layout_height="16dip"
+ android:visibility="gone"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/ic_menu_mark" />
+
+ </LinearLayout>
</FrameLayout>
diff --git a/res/layout-w470dp/contact_detail_fragment.xml b/res/layout-w470dp/contact_detail_fragment.xml
index 42266d5..17cbc2d 100644
--- a/res/layout-w470dp/contact_detail_fragment.xml
+++ b/res/layout-w470dp/contact_detail_fragment.xml
@@ -14,15 +14,17 @@
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/contact_detail"
+ android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="0px"
+ android:layout_weight="1" >
<ImageView android:id="@+id/photo"
android:scaleType="centerCrop"
@@ -87,5 +89,5 @@
android:layout_alignParentTop="true"
android:background="@android:color/transparent"
android:visibility="gone"/>
-</RelativeLayout>
+</LinearLayout>
diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml
index 2d0b9b5..ff7dd4b 100644
--- a/res/layout/call_log_fragment.xml
+++ b/res/layout/call_log_fragment.xml
@@ -18,7 +18,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
->
+ android:paddingBottom="?android:attr/actionBarSize">
+
<FrameLayout
android:id="@+id/voicemail_status"
android:layout_width="match_parent"
diff --git a/res/layout/contact_detail_list_item.xml b/res/layout/contact_detail_list_item.xml
index 4fcd881..e96b7f0 100644
--- a/res/layout/contact_detail_list_item.xml
+++ b/res/layout/contact_detail_list_item.xml
@@ -45,9 +45,24 @@
android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceMedium" />
- <TextView
- android:id="@+id/type"
- style="@style/ContactDetailItemType" />
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/type"
+ style="@style/ContactDetailItemType" />
+
+ <View
+ android:id="@+id/primary_indicator"
+ android:layout_width="16dip"
+ android:layout_height="16dip"
+ android:visibility="gone"
+ android:layout_gravity="center_vertical"
+ android:background="@drawable/ic_menu_mark" />
+
+ </LinearLayout>
<TextView
android:id="@+id/footer"
diff --git a/res/layout/contact_tile_frequent_phone.xml b/res/layout/contact_tile_frequent_phone.xml
new file mode 100644
index 0000000..e0ea0fb
--- /dev/null
+++ b/res/layout/contact_tile_frequent_phone.xml
@@ -0,0 +1,72 @@
+<?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.
+-->
+<view
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.contacts.list.ContactTileView"
+ android:focusable="true"
+ android:background="@drawable/list_selector"
+ android:paddingRight="16dip"
+ android:paddingLeft="16dip" >
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <QuickContactBadge
+ android:id="@+id/contact_tile_quick"
+ android:layout_width="64dip"
+ android:layout_height="64dip"
+ android:scaleType="centerCrop"
+ android:layout_alignParentLeft="true" />
+
+ <TextView
+ android:id="@+id/contact_tile_name"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:layout_marginLeft="8dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_marginTop="8dip"
+ android:layout_toRightOf="@id/contact_tile_quick" />
+
+ <TextView
+ android:id="@+id/contact_tile_phone_number"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="12sp"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:textColor="#cccccc"
+ android:layout_marginLeft="12dip"
+ android:layout_toRightOf="@id/contact_tile_quick"
+ android:layout_below="@id/contact_tile_name" />
+
+ <TextView
+ android:id="@+id/contact_tile_phone_type"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="12sp"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:textColor="#cccccc"
+ android:layout_marginLeft="12dip"
+ android:layout_alignParentRight="true"
+ android:layout_alignTop="@id/contact_tile_phone_number" />
+
+ </RelativeLayout>
+
+</view>
diff --git a/res/layout/contact_tile_list.xml b/res/layout/contact_tile_list.xml
index c72386e..2047b13 100644
--- a/res/layout/contact_tile_list.xml
+++ b/res/layout/contact_tile_list.xml
@@ -17,7 +17,8 @@
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:paddingBottom="?attr/favorites_padding_bottom">
<ListView
android:id="@+id/contact_tile_list"
diff --git a/res/layout/contact_tile_starred_secondary_target.xml b/res/layout/contact_tile_starred_secondary_target.xml
index 5d4e55e..f7b8673 100644
--- a/res/layout/contact_tile_starred_secondary_target.xml
+++ b/res/layout/contact_tile_starred_secondary_target.xml
@@ -35,29 +35,24 @@
android:layout_alignParentBottom="true"
style="@style/ContactTileStarredShadowBox" />
- <LinearLayout
+ <TextView
+ android:id="@+id/contact_tile_name"
android:layout_width="match_parent"
- android:layout_height="48dip"
+ android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
- android:orientation="horizontal" >
+ android:layout_alignParentLeft="true"
+ android:layout_marginLeft="8dip"
+ android:layout_marginBottom="20dip"
+ android:textColor="@android:color/white"
+ stlye="@style/ContactTileStarredName" />
- <TextView
- android:id="@+id/contact_tile_name"
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_vertical"
- android:layout_marginLeft="8dip"
- android:textColor="@android:color/white"
- stlye="@style/ContactTileStarredName" />
-
- <ImageButton
- android:id="@+id/contact_tile_secondary_button"
- android:src="@drawable/ic_tab_unselected_contacts"
- android:layout_height="match_parent"
- android:layout_width="wrap_content" />
-
- </LinearLayout>
+ <ImageButton
+ android:id="@+id/contact_tile_secondary_button"
+ android:src="@drawable/ic_tab_unselected_contacts"
+ android:layout_height="@dimen/contact_tile_shadowbox_height"
+ android:layout_width="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentRight="true" />
</RelativeLayout>
diff --git a/res/layout/dialtacts_activity.xml b/res/layout/dialtacts_activity.xml
index 14fb137..6484d87 100644
--- a/res/layout/dialtacts_activity.xml
+++ b/res/layout/dialtacts_activity.xml
@@ -16,7 +16,8 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:layout_marginTop="?android:attr/actionBarSize">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3a5cb8e..1ca7158 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1581,6 +1581,15 @@
<!-- Joined contact indicator displayed in the contact detail [CHAR LIMIT=64] -->
<string name="indicator_joined_contact">Joined contact</string>
+ <!-- Option displayed in context menu to copy long pressed item to clipboard [CHAR LIMIT=64] -->
+ <string name="copy_text">Copy to clipboard</string>
+
+ <!-- Option displayed in context menu to set long pressed item as default contact method [CHAR LIMIT=64] -->
+ <string name="set_default">Set default</string>
+
+ <!-- Option displayed in context menu to clear long pressed item as default contact method [CHAR LIMIT=64] -->
+ <string name="clear_default">Clear default</string>
+
<!-- Toast shown when text is copied to the clipboard [CHAR LIMIT=64] -->
<string name="toast_text_copied">Text copied</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index f32ae4c..e98175d 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -14,7 +14,9 @@
limitations under the License.
-->
<resources>
- <style name="DialtactsTheme" parent="android:Theme.Holo.SplitActionBarWhenNarrow">
+ <style name="DialtactsTheme"
+ parent="android:Theme.Holo.SolidActionBar.SplitActionBarWhenNarrow">
+ <item name="android:windowActionBarOverlay">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowBackground">@android:color/black</item>
<item name="activated_background">@drawable/list_item_activated_background</item>
@@ -51,6 +53,8 @@
<item name="call_log_voicemail_status_height">40dip</item>
<item name="call_log_voicemail_status_background_color">#FFFFE0</item>
<item name="call_log_voicemail_status_text_color">#000000</item>
+ <!-- Favorites -->
+ <item name="favorites_padding_bottom">?android:attr/actionBarSize</item>
</style>
<style name="CallDetailActivityTheme" parent="android:Theme.Holo.SplitActionBarWhenNarrow">
@@ -161,6 +165,10 @@
<attr name="call_log_voicemail_status_text_color" format="color" />
</declare-styleable>
+ <declare-styleable name="Favorites">
+ <attr name="favorites_padding_bottom" format="dimension" />
+ </declare-styleable>
+
<style name="PeopleTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
<item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
<item name="list_item_height">?android:attr/listPreferredItemHeight</item>
@@ -188,6 +196,8 @@
<item name="list_item_header_underline_height">1px</item>
<item name="list_item_header_underline_color">@color/people_app_theme_color</item>
<item name="contact_filter_popup_width">320dip</item>
+ <!-- Favorites -->
+ <item name="favorites_padding_bottom">0dip</item>
</style>
<style name="ContactsActionBarStyle" parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
diff --git a/src/com/android/contacts/ContactTileLoaderFactory.java b/src/com/android/contacts/ContactTileLoaderFactory.java
index 41532c2..30bd7e4 100644
--- a/src/com/android/contacts/ContactTileLoaderFactory.java
+++ b/src/com/android/contacts/ContactTileLoaderFactory.java
@@ -21,7 +21,9 @@
import android.content.CursorLoader;
import android.net.Uri;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Contacts.Data;
/**
* Used to create {@link CursorLoader}s to load different groups of {@link ContactTileView}s
@@ -36,14 +38,36 @@
public final static int CONTACT_PRESENCE = 5;
public final static int CONTACT_STATUS = 6;
+ // Only used for StrequentPhoneOnlyLoader
+ public final static int PHONE_NUMBER = 5;
+ public final static int PHONE_NUMBER_TYPE = 6;
+ public final static int PHONE_NUMBER_LABEL = 7;
+
private static final String[] COLUMNS = new String[] {
- Contacts._ID,
- Contacts.DISPLAY_NAME,
- Contacts.STARRED,
- Contacts.PHOTO_URI,
- Contacts.LOOKUP_KEY,
- Contacts.CONTACT_PRESENCE,
- Contacts.CONTACT_STATUS,
+ Contacts._ID, // ..........................................0
+ Contacts.DISPLAY_NAME, // .................................1
+ Contacts.STARRED, // ......................................2
+ Contacts.PHOTO_URI, // ....................................3
+ Contacts.LOOKUP_KEY, // ...................................4
+ Contacts.CONTACT_PRESENCE, // .............................5
+ Contacts.CONTACT_STATUS, // ...............................6
+ };
+
+ /**
+ * Projection used for the {@link Contacts#CONTENT_STREQUENT_URI}
+ * query when {@link ContactsContract#STREQUENT_PHONE_ONLY} flag
+ * is set to true. The main difference is the lack of presence
+ * and status data and the addition of phone number and label.
+ */
+ private static final String[] COLUMNS_PHONE_ONLY = new String[] {
+ Contacts._ID, // ..........................................0
+ Contacts.DISPLAY_NAME, // .................................1
+ Contacts.STARRED, // ......................................2
+ Contacts.PHOTO_URI, // ....................................3
+ Contacts.LOOKUP_KEY, // ...................................4
+ Phone.NUMBER, // ..........................................5
+ Phone.TYPE, // ............................................6
+ Phone.LABEL // ............................................7
};
public static CursorLoader createStrequentLoader(Context context) {
@@ -54,7 +78,7 @@
Uri uri = Contacts.CONTENT_STREQUENT_URI.buildUpon()
.appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true").build();
- return new CursorLoader(context, uri, COLUMNS, null, null, null);
+ return new CursorLoader(context, uri, COLUMNS_PHONE_ONLY, null, null, null);
}
public static CursorLoader createStarredLoader(Context context) {
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index 7e41a5c..01212f5 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -122,7 +122,12 @@
}
private class PageChangeListener implements OnPageChangeListener {
- private int mPreviousPosition = -1; // Invalid at first
+ private int mCurrentPosition = -1;
+ /**
+ * Used during page migration, to remember the next position {@link #onPageSelected(int)}
+ * specified.
+ */
+ private int mNextPosition = -1;
@Override
public void onPageScrolled(
@@ -132,34 +137,38 @@
@Override
public void onPageSelected(int position) {
final ActionBar actionBar = getActionBar();
- if (mPreviousPosition == position) {
+ if (mCurrentPosition == position) {
Log.w(TAG, "Previous position and next position became same (" + position + ")");
}
- if (mPreviousPosition >= 0) {
- sendFragmentVisibilityChange(mPreviousPosition, false);
- }
- sendFragmentVisibilityChange(position, true);
-
actionBar.selectTab(actionBar.getTabAt(position));
-
- // Activity#onPrepareOptionsMenu() may not be called when Fragment has it's own
- // options menu. We force this Activity to call it to hide/show bottom bar. Also
- // we don't want to do so when it is unnecessary (buttons may flicker).
- if (mPreviousPosition == TAB_INDEX_DIALER || position == TAB_INDEX_DIALER) {
- // Force this Activity to prepare Menu again.
- invalidateOptionsMenu();
- }
-
- mPreviousPosition = position;
+ mNextPosition = position;
}
public void setCurrentPosition(int position) {
- mPreviousPosition = position;
+ mCurrentPosition = position;
}
@Override
public void onPageScrollStateChanged(int state) {
+ switch (state) {
+ case ViewPager.SCROLL_STATE_IDLE: {
+ if (mCurrentPosition >= 0) {
+ sendFragmentVisibilityChange(mCurrentPosition, false);
+ }
+ if (mNextPosition >= 0) {
+ sendFragmentVisibilityChange(mNextPosition, true);
+ }
+ invalidateOptionsMenu();
+
+ mCurrentPosition = mNextPosition;
+ break;
+ }
+ case ViewPager.SCROLL_STATE_DRAGGING:
+ case ViewPager.SCROLL_STATE_SETTLING:
+ default:
+ break;
+ }
}
}
@@ -246,7 +255,11 @@
new OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
- // Ignore.
+ View view = getCurrentFocus();
+ if (view != null) {
+ hideInputMethod(view);
+ view.clearFocus();
+ }
return true;
}
@@ -265,16 +278,12 @@
* the search UI and let users go back to usual Phone UI.
*
* This does _not_ handle back button.
- *
- * TODO: need "up" button instead of close button
*/
private final OnCloseListener mPhoneSearchCloseListener =
new OnCloseListener() {
@Override
public boolean onClose() {
- if (TextUtils.isEmpty(mSearchView.getQuery())) {
- exitSearchUi();
- } else {
+ if (!TextUtils.isEmpty(mSearchView.getQuery())) {
mSearchView.setQuery(null, true);
}
return true;
@@ -636,13 +645,20 @@
// Instantiate or reset SearchView in ActionBar.
if (mSearchView == null) {
- // TODO: layout is not what we want. Need "up" button instead of "close" button, etc.
final View searchViewLayout =
getLayoutInflater().inflate(R.layout.custom_action_bar, null);
mSearchView = (SearchView) searchViewLayout.findViewById(R.id.search_view);
- mSearchView.setQueryHint(getString(R.string.hint_findContacts));
mSearchView.setOnQueryTextListener(mPhoneSearchQueryTextListener);
mSearchView.setOnCloseListener(mPhoneSearchCloseListener);
+ // Since we're using a custom layout for showing SearchView instead of letting the
+ // search menu icon do that job, we need to manually configure the View so it looks
+ // "shown via search menu".
+ // - it should be iconified by default
+ // - it should not be iconified at this time
+ // See also comments for onActionViewExpanded()/onActionViewCollapsed()
+ mSearchView.setIconifiedByDefault(true);
+ mSearchView.setQueryHint(getString(R.string.hint_findContacts));
+ mSearchView.setIconified(false);
mSearchView.requestFocus();
// Show soft keyboard when SearchView has a focus. Need to delay the request in order
// to let InputMethodManager handle it correctly.
@@ -681,6 +697,9 @@
transaction.commit();
mViewPager.setVisibility(View.GONE);
+ // We need to call this and onActionViewCollapsed() manually, since we are using a custom
+ // layout instead of asking the search menu item to take care of SearchView.
+ mSearchView.onActionViewExpanded();
mInSearchUi = true;
}
@@ -723,6 +742,8 @@
// Request to update option menu.
invalidateOptionsMenu();
+ // See comments in onActionViewExpanded()
+ mSearchView.onActionViewCollapsed();
mInSearchUi = false;
}
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 8f7cfa8..abc9adf 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -989,19 +989,16 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
- inflater.inflate(R.menu.call_log_options, menu);
+ if (mShowOptionsMenu) {
+ inflater.inflate(R.menu.call_log_options, menu);
+ }
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
- menu.findItem(R.id.delete_all).setVisible(mShowOptionsMenu);
- menu.findItem(R.id.show_voicemails_only).setVisible(mShowOptionsMenu);
- final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings_call_log);
if (mShowOptionsMenu) {
- callSettingsMenuItem.setVisible(true);
- callSettingsMenuItem.setIntent(DialtactsActivity.getCallSettingsIntent());
- } else {
- callSettingsMenuItem.setVisible(false);
+ menu.findItem(R.id.menu_call_settings_call_log)
+ .setIntent(DialtactsActivity.getCallSettingsIntent());
}
}
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index a6ba6b0..1dae19f 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -47,6 +47,7 @@
import android.app.Activity;
import android.app.Fragment;
import android.app.SearchManager;
+import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -87,15 +88,18 @@
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.CheckBox;
@@ -113,12 +117,18 @@
import java.util.Map;
public class ContactDetailFragment extends Fragment implements FragmentKeyListener, FragmentOverlay,
- OnItemClickListener, OnItemLongClickListener, SelectAccountDialogFragment.Listener {
+ OnItemClickListener, SelectAccountDialogFragment.Listener {
private static final String TAG = "ContactDetailFragment";
private static final int LOADER_DETAILS = 1;
+ private interface ContextMenuIds {
+ static final int COPY_TEXT = 0;
+ static final int CLEAR_DEFAULT = 1;
+ static final int SET_DEFAULT = 2;
+ }
+
private static final String KEY_CONTACT_URI = "contactUri";
private static final String LOADER_ARG_CONTACT_URI = "contactUri";
@@ -255,7 +265,7 @@
mListView = (ListView) mView.findViewById(android.R.id.list);
mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
mListView.setOnItemClickListener(this);
- mListView.setOnItemLongClickListener(this);
+ registerForContextMenu(mListView);
mListView.setOnScrollListener(mVerticalScrollListener);
// Don't set it to mListView yet. We do so later when we bind the adapter.
@@ -1328,12 +1338,14 @@
public ImageView secondaryActionButton;
public View secondaryActionButtonContainer;
public View secondaryActionDivider;
+ public View primaryIndicator;
public DetailViewCache(View view, OnClickListener secondaryActionClickListener) {
kind = (TextView) view.findViewById(R.id.kind);
type = (TextView) view.findViewById(R.id.type);
data = (TextView) view.findViewById(R.id.data);
footer = (TextView) view.findViewById(R.id.footer);
+ primaryIndicator = view.findViewById(R.id.primary_indicator);
presenceIcon = (ImageView) view.findViewById(R.id.presence_icon);
secondaryActionButton = (ImageView) view.findViewById(
R.id.secondary_action_button);
@@ -1511,6 +1523,9 @@
views.footer.setVisibility(View.GONE);
}
+ // Set the default contact method
+ views.primaryIndicator.setVisibility(entry.isPrimary ? View.VISIBLE : View.GONE);
+
// Set the presence icon
final Drawable presenceIcon = ContactPresenceIconUtil.getPresenceIcon(
mContext, entry.presence);
@@ -1642,18 +1657,105 @@
}
@Override
- public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
- if (mListener == null) return false;
- final DetailViewCache cache = (DetailViewCache) view.getTag();
- if (cache == null) return false;
- CharSequence text = cache.data.getText();
- if (TextUtils.isEmpty(text)) return false;
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
- ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
+ AdapterView.AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
+ DetailViewEntry selectedEntry = (DetailViewEntry) mAllEntries.get(info.position);
+
+ menu.setHeaderTitle(selectedEntry.data);
+ menu.add(ContextMenu.NONE, ContextMenuIds.COPY_TEXT,
+ ContextMenu.NONE, getString(R.string.copy_text));
+
+ String selectedMimeType = selectedEntry.mimetype;
+
+ // Only allow primary support for Phone and Email content types
+ if (Phone.CONTENT_ITEM_TYPE.equals(selectedMimeType) ||
+ Email.CONTENT_ITEM_TYPE.equals(selectedMimeType)) {
+
+ // Used to determine if entry is the only mime type of its kind
+ boolean isUniqueMimeType = true;
+
+ // Checking for unique mime type
+ for (int positionCounter = 0; positionCounter < mAllEntries.size(); positionCounter++) {
+ final ViewEntry entry = mAllEntries.get(positionCounter);
+
+ // Ignoring cases where entry is not a detail entry
+ if (entry.getViewType() != ViewAdapter.VIEW_TYPE_DETAIL_ENTRY) continue;
+
+ final DetailViewEntry checkEntry = (DetailViewEntry) entry;
+ if (positionCounter != info.position &&
+ checkEntry.mimetype.equalsIgnoreCase(selectedMimeType)) {
+ isUniqueMimeType = false;
+ break;
+ }
+ }
+
+ // Checking for previously set default
+ if (selectedEntry.isPrimary) {
+ menu.add(ContextMenu.NONE, ContextMenuIds.CLEAR_DEFAULT,
+ ContextMenu.NONE, getString(R.string.clear_default));
+ } else if (!isUniqueMimeType) {
+ menu.add(ContextMenu.NONE, ContextMenuIds.SET_DEFAULT,
+ ContextMenu.NONE, getString(R.string.set_default));
+ }
+ }
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ AdapterView.AdapterContextMenuInfo menuInfo;
+ try {
+ menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+ } catch (ClassCastException e) {
+ Log.e(TAG, "bad menuInfo", e);
+ return false;
+ }
+
+ switch (item.getItemId()) {
+ case ContextMenuIds.COPY_TEXT:
+ copyToClipboard(menuInfo.position);
+ return true;
+ case ContextMenuIds.SET_DEFAULT:
+ setDefaultContactMethod(mListView.getItemIdAtPosition(menuInfo.position));
+ return true;
+ case ContextMenuIds.CLEAR_DEFAULT:
+ clearDefaultContactMethod(mListView.getItemIdAtPosition(menuInfo.position));
+ return true;
+ default:
+ throw new IllegalArgumentException("Unknown menu option " + item.getItemId());
+ }
+ }
+
+ private void setDefaultContactMethod(long id) {
+ Intent setIntent = ContactSaveService.createSetSuperPrimaryIntent(mContext, id);
+ mContext.startService(setIntent);
+ }
+
+ private void clearDefaultContactMethod(long id) {
+ Intent clearIntent = ContactSaveService.createClearPrimaryIntent(mContext, id);
+ mContext.startService(clearIntent);
+ }
+
+ private void copyToClipboard(int viewEntryPosition) {
+ // Getting the text to copied
+ DetailViewEntry detailViewEntry = (DetailViewEntry) mAllEntries.get(viewEntryPosition);
+ CharSequence textToCopy = detailViewEntry.data;
+
+ // Checking for empty string
+ if (TextUtils.isEmpty(textToCopy)) return;
+
+ // Adding item to clipboard
+ ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(
Context.CLIPBOARD_SERVICE);
- cm.setText(text);
- Toast.makeText(getActivity(), R.string.toast_text_copied, Toast.LENGTH_SHORT).show();
- return true;
+ String[] mimeTypes = new String[]{detailViewEntry.mimetype};
+ ClipData.Item clipDataItem = new ClipData.Item(textToCopy);
+ ClipData cd = new ClipData(detailViewEntry.typeString, mimeTypes, clipDataItem);
+ clipboardManager.setPrimaryClip(cd);
+
+ // Display Confirmation Toast
+ String toastText = getString(R.string.toast_text_copied);
+ Toast.makeText(getActivity(), toastText, Toast.LENGTH_SHORT).show();
}
@Override
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index 6acbc85..add6b80 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -538,10 +538,8 @@
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
-
- // If the hardware doesn't have a hardware menu key, we'll show soft menu button on the
- // right side of digits EditText.
- if (ViewConfiguration.get(getActivity()).hasPermanentMenuKey()) {
+ if (mShowOptionsMenu && ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
+ mDialpadChooser != null && mDigits != null) {
inflater.inflate(R.menu.dialpad_options, menu);
}
}
@@ -549,16 +547,9 @@
@Override
public void onPrepareOptionsMenu(Menu menu) {
// Hardware menu key should be available and Views should already be ready.
- if (ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
+ if (mShowOptionsMenu && ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
mDialpadChooser != null && mDigits != null) {
- if (mShowOptionsMenu) {
- setupMenuItems(menu);
- } else {
- menu.findItem(R.id.menu_call_settings_dialpad).setVisible(false);
- menu.findItem(R.id.menu_add_contacts).setVisible(false);
- menu.findItem(R.id.menu_2s_pause).setVisible(false);
- menu.findItem(R.id.menu_add_wait).setVisible(false);
- }
+ setupMenuItems(menu);
}
}
diff --git a/src/com/android/contacts/list/ContactTileAdapter.java b/src/com/android/contacts/list/ContactTileAdapter.java
index 6150670..53b744d 100644
--- a/src/com/android/contacts/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/list/ContactTileAdapter.java
@@ -19,11 +19,16 @@
import com.android.contacts.ContactTileLoaderFactory;
import com.android.contacts.GroupMemberLoader;
import com.android.contacts.R;
+import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
import android.view.View;
import android.view.View.OnClickListener;
@@ -62,6 +67,13 @@
private int mPresenceIndex;
private int mStatusIndex;
+ /**
+ * Only valid when {@link DisplayType#STREQUENT_PHONE_ONLY} is true
+ */
+ private int mPhoneNumberIndex;
+ private int mPhoneNumberTypeIndex;
+ private int mPhoneNumberLabelIndex;
+
private boolean mIsQuickContactEnabled = false;
/**
@@ -151,6 +163,10 @@
mStarredIndex = ContactTileLoaderFactory.STARRED;
mPresenceIndex = ContactTileLoaderFactory.CONTACT_PRESENCE;
mStatusIndex = ContactTileLoaderFactory.CONTACT_STATUS;
+
+ mPhoneNumberIndex = ContactTileLoaderFactory.PHONE_NUMBER;
+ mPhoneNumberTypeIndex = ContactTileLoaderFactory.PHONE_NUMBER_TYPE;
+ mPhoneNumberLabelIndex = ContactTileLoaderFactory.PHONE_NUMBER_LABEL;
}
}
@@ -168,7 +184,7 @@
/**
* Iterates over the {@link Cursor}
* Returns position of the first NON Starred Contact
- * Returns -1 if not {@link DisplayType#}
+ * Returns -1 if not {@link DisplayType#STREQUENT} or {@link DisplayType#STREQUENT_PHONE_ONLY}
*/
private int getDividerPosition(Cursor cursor) {
if (cursor == null || cursor.isClosed() || (mDisplayType != DisplayType.STREQUENT
@@ -204,6 +220,17 @@
Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id);
contact.presence = cursor.isNull(mPresenceIndex) ? null : cursor.getInt(mPresenceIndex);
+ if (mDisplayType == DisplayType.STREQUENT_PHONE_ONLY) {
+ int phoneNumberType = cursor.getInt(mPhoneNumberTypeIndex);
+ String phoneNumberCustomLabel = cursor.getString(mPhoneNumberLabelIndex);
+ contact.phoneLabel = (String) Phone.getTypeLabel(mContext.getResources(),
+ phoneNumberType, phoneNumberCustomLabel);
+ contact.phoneNumber = cursor.getString(mPhoneNumberIndex);
+ } else {
+ contact.status = cursor.getString(mStatusIndex);
+ contact.presence = cursor.isNull(mPresenceIndex) ? null : cursor.getInt(mPresenceIndex);
+ }
+
return contact;
}
@@ -345,7 +372,8 @@
return mIsQuickContactEnabled ?
R.layout.contact_tile_starred_quick_contact : R.layout.contact_tile_starred;
case ViewTypes.FREQUENT:
- return R.layout.contact_tile_frequent;
+ return mDisplayType == DisplayType.STREQUENT_PHONE_ONLY ?
+ R.layout.contact_tile_frequent_phone : R.layout.contact_tile_frequent;
case ViewTypes.STARRED_WITH_SECONDARY_ACTION:
return R.layout.contact_tile_starred_secondary_target;
default:
@@ -466,6 +494,8 @@
public static class ContactEntry {
public String name;
public String status;
+ public String phoneLabel;
+ public String phoneNumber;
public Uri photoUri;
public Uri lookupKey;
public Integer presence;
diff --git a/src/com/android/contacts/list/ContactTileView.java b/src/com/android/contacts/list/ContactTileView.java
index 6374c23..3839573 100644
--- a/src/com/android/contacts/list/ContactTileView.java
+++ b/src/com/android/contacts/list/ContactTileView.java
@@ -21,9 +21,8 @@
import com.android.contacts.list.ContactTileAdapter.ContactEntry;
import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.provider.ContactsContract.StatusUpdates;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -32,9 +31,6 @@
import android.widget.QuickContactBadge;
import android.widget.TextView;
-import android.provider.ContactsContract.StatusUpdates;
-
-
/**
* A ContactTile displays the contact's picture overlayed with their name
*/
@@ -47,6 +43,8 @@
private QuickContactBadge mQuickContact;
private TextView mName;
private TextView mStatus;
+ private TextView mPhoneLabel;
+ private TextView mPhoneNumber;
private ContactPhotoManager mPhotoManager = null;
public ContactTileView(Context context, AttributeSet attrs) {
@@ -63,6 +61,8 @@
mPhoto = (ImageView) findViewById(R.id.contact_tile_image);
mPresence = (ImageView) findViewById(R.id.contact_tile_presence);
mStatus = (TextView) findViewById(R.id.contact_tile_status);
+ mPhoneLabel = (TextView) findViewById(R.id.contact_tile_phone_type);
+ mPhoneNumber = (TextView) findViewById(R.id.contact_tile_phone_number);
}
public void setPhotoManager(ContactPhotoManager photoManager) {
@@ -97,6 +97,15 @@
mStatus.setText(statusText);
}
+ if (mPhoneLabel != null) {
+ mPhoneLabel.setText(entry.phoneLabel);
+ }
+
+ if (mPhoneNumber != null) {
+ // TODO: Format number correctly
+ mPhoneNumber.setText(entry.phoneNumber);
+ }
+
if (mQuickContact != null) {
mQuickContact.assignContactUri(mLookupUri);
mQuickContact.setImageBitmap(null);
diff --git a/tests/src/com/android/contacts/ContactLoaderTest.java b/tests/src/com/android/contacts/ContactLoaderTest.java
index 1d3fb20..3d0ddb4 100644
--- a/tests/src/com/android/contacts/ContactLoaderTest.java
+++ b/tests/src/com/android/contacts/ContactLoaderTest.java
@@ -297,6 +297,9 @@
Data.STATUS_LABEL, Data.STATUS_TIMESTAMP,
Contacts.PHOTO_URI,
+
+ Contacts.SEND_TO_VOICEMAIL,
+ Contacts.CUSTOM_RINGTONE,
})
.withSortOrder(Contacts.Entity.RAW_CONTACT_ID)
.returnRow(
@@ -330,7 +333,10 @@
"Having dinner", "mockPkg3", 0,
20, 0,
- "content:some.photo.uri"
+ "content:some.photo.uri",
+
+ 0,
+ null
);
}