summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Garnes <matt@cyngn.com>2015-04-30 11:16:26 -0700
committerMatt Garnes <matt@cyngn.com>2015-04-30 11:16:26 -0700
commit1d6073e5d62800910e9d0f5c701b4e19b49588e9 (patch)
tree60f952095770b38e34394288409f21a0b0e21948
parentfae1598668b4266cad74dec51f0a413075282039 (diff)
parent402701dafda192618d02483ea6e513be4af064e7 (diff)
downloadpackages_apps_ContactsCommon-1d6073e5d62800910e9d0f5c701b4e19b49588e9.tar.gz
packages_apps_ContactsCommon-1d6073e5d62800910e9d0f5c701b4e19b49588e9.tar.bz2
packages_apps_ContactsCommon-1d6073e5d62800910e9d0f5c701b4e19b49588e9.zip
Merge remote-tracking branch 'caf/LA.BR.1.2.3' into HEAD
-rw-r--r--res/layout/default_account_checkbox.xml36
-rw-r--r--res/layout/select_account_list_item.xml53
-rw-r--r--res/values-zh-rCN/strings.xml1
-rw-r--r--res/values/colors.xml3
-rw-r--r--res/values/strings.xml8
-rw-r--r--src/com/android/contacts/common/CallUtil.java7
-rw-r--r--src/com/android/contacts/common/ContactsUtils.java17
-rwxr-xr-xsrc/com/android/contacts/common/interactions/ImportExportDialogFragment.java20
-rwxr-xr-xsrc/com/android/contacts/common/list/ContactListAdapter.java3
-rw-r--r--src/com/android/contacts/common/list/ContactListItemView.java16
-rwxr-xr-xsrc/com/android/contacts/common/list/CustomContactListFilterActivity.java7
-rw-r--r--src/com/android/contacts/common/list/DefaultContactListAdapter.java13
-rw-r--r--src/com/android/contacts/common/list/ProfileAndContactsLoader.java4
-rw-r--r--src/com/android/contacts/common/list/ViewPagerTabs.java7
-rw-r--r--src/com/android/contacts/common/location/UpdateCountryService.java4
-rw-r--r--src/com/android/contacts/common/model/ContactLoader.java59
-rw-r--r--src/com/android/contacts/common/model/account/ExternalAccountType.java62
-rw-r--r--src/com/android/contacts/common/model/dataitem/EventDataItem.java7
-rw-r--r--src/com/android/contacts/common/model/dataitem/ImDataItem.java25
-rw-r--r--src/com/android/contacts/common/model/dataitem/RelationDataItem.java7
-rw-r--r--src/com/android/contacts/common/preference/ContactsPreferences.java4
-rw-r--r--src/com/android/contacts/common/util/BitmapUtil.java52
-rw-r--r--src/com/android/contacts/common/util/ContactDisplayUtils.java84
-rw-r--r--src/com/android/contacts/common/util/ContactsCommonRcsUtil.java136
-rw-r--r--src/com/android/contacts/common/util/LocalizedNameResolver.java25
-rw-r--r--src/com/android/contacts/common/util/MaterialColorMapUtils.java68
-rw-r--r--src/com/android/contacts/common/vcard/NotificationImportExportListener.java4
-rw-r--r--src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java217
28 files changed, 826 insertions, 123 deletions
diff --git a/res/layout/default_account_checkbox.xml b/res/layout/default_account_checkbox.xml
new file mode 100644
index 00000000..9a1a4504
--- /dev/null
+++ b/res/layout/default_account_checkbox.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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:id="@+id/default_account_checkbox_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="4dp"
+ android:orientation="vertical">
+ <CheckBox
+ android:id="@+id/default_account_checkbox_view"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="15dip"
+ android:layout_marginLeft="13dip"
+ android:layout_marginBottom="20dip"
+ android:gravity="center"
+ android:textAlignment="viewStart"
+ android:text="@string/set_default_account"
+ android:textColor="@color/dialtacts_secondary_text_color"
+ />
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/select_account_list_item.xml b/res/layout/select_account_list_item.xml
new file mode 100644
index 00000000..39a5af05
--- /dev/null
+++ b/res/layout/select_account_list_item.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<!-- Layout of a single item in the InCallUI Account Chooser Dialog. -->
+<view class="com.android.contacts.common.widget.ActivityTouchLinearLayout"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="8dp" >
+
+ <ImageView android:id="@+id/icon"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:tint="@color/dialtacts_secondary_text_color"
+ android:scaleType="center" />
+
+ <LinearLayout
+ android:id="@+id/text"
+ android:gravity="start|center_vertical"
+ android:layout_marginLeft="8dp"
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+ <TextView android:id="@+id/label"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="@color/dialtacts_primary_text_color"
+ android:includeFontPadding="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ <TextView android:id="@+id/number"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:includeFontPadding="false"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone" />
+ </LinearLayout>
+
+</view>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 66d3455b..c300e05a 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -283,4 +283,5 @@
<string name="no_ip_number_on_sim_card">SIM卡上没有IP号</string>
<string name="ipcall_dialog_title">IP电话设置</string>
<string name="ipcall_dialog_edit_hint">请输入IP电话前缀</string>
+ <string name="label_groups">群组</string>
</resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 1da07fb8..e12634a6 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -46,6 +46,9 @@
<!-- Color of image view placeholder. -->
<color name="image_placeholder">#DDDDDD</color>
+ <!-- Primary text color in the Phone app -->
+ <color name="dialtacts_primary_text_color">#333333</color>
+
<!-- Secondary text color in the Phone app -->
<color name="dialtacts_secondary_text_color">#737373</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9695179e..296d5878 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -840,4 +840,12 @@ a ren't members of any other group. [CHAR LIMIT=25] -->
<string name="import_contacts_sim">Import contacts from SIM?</string>
<string name="import_contacts_sim_confirm">Import</string>
<string name="import_contacts_sim_cancel">Cancel</string>
+ <!-- Title for Select Account Dialog [CHAR LIMIT=30] -->
+ <string name="select_account_dialog_title">Select Account</string>
+
+ <!-- Label for the check box to toggle default sim card setting [CHAR LIMIT=35]-->
+ <string name="set_default_account">Always use this for calls</string>
+
+ <!-- Title for dialog to select Phone Account for outgoing call. [CHAR LIMIT=40] -->
+ <string name="select_phone_account_for_calls">Call with</string>
</resources>
diff --git a/src/com/android/contacts/common/CallUtil.java b/src/com/android/contacts/common/CallUtil.java
index 7a280f26..ed22a731 100644
--- a/src/com/android/contacts/common/CallUtil.java
+++ b/src/com/android/contacts/common/CallUtil.java
@@ -141,6 +141,13 @@ public class CallUtil {
}
/**
+ * A variant of {@link #getCallIntent(android.net.Uri)} for calling Voicemail.
+ */
+ public static Intent getVoicemailIntent() {
+ return getCallIntent(Uri.fromParts(PhoneAccount.SCHEME_VOICEMAIL, "", null));
+ }
+
+ /**
* A variant of {@link #getCallIntent(android.net.Uri)} but also accept a call
* origin and {@code Account} and {@code VideoCallProfile} state.
* For more information about call origin, see comments in Phone package (PhoneApp).
diff --git a/src/com/android/contacts/common/ContactsUtils.java b/src/com/android/contacts/common/ContactsUtils.java
index 857450d9..a6e0e0e8 100644
--- a/src/com/android/contacts/common/ContactsUtils.java
+++ b/src/com/android/contacts/common/ContactsUtils.java
@@ -41,6 +41,8 @@ public class ContactsUtils {
public static final String SCHEME_MAILTO = "mailto";
public static final String SCHEME_SMSTO = "smsto";
+ private static final int DEFAULT_THUMBNAIL_SIZE = 96;
+
private static int sThumbnailSize = -1;
// TODO find a proper place for the canonical version of these
@@ -139,14 +141,17 @@ public class ContactsUtils {
final Cursor c = context.getContentResolver().query(
DisplayPhoto.CONTENT_MAX_DIMENSIONS_URI,
new String[] { DisplayPhoto.THUMBNAIL_MAX_DIM }, null, null, null);
- try {
- c.moveToFirst();
- sThumbnailSize = c.getInt(0);
- } finally {
- c.close();
+ if (c != null) {
+ try {
+ if (c.moveToFirst()) {
+ sThumbnailSize = c.getInt(0);
+ }
+ } finally {
+ c.close();
+ }
}
}
- return sThumbnailSize;
+ return sThumbnailSize != -1 ? sThumbnailSize : DEFAULT_THUMBNAIL_SIZE;
}
private static Intent getCustomImIntent(ImDataItem im, int protocol) {
diff --git a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
index ef99300a..63fe01d6 100755
--- a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
@@ -580,6 +580,26 @@ public class ImportExportDialogFragment extends AnalyticsDialogFragment
TOAST_EXPORT_FAILED, insertCount, 0));
break;
} else {
+ // Failed to insert to SIM card
+ int anrNumber = 0;
+ if (!TextUtils.isEmpty(anrNum)) {
+ anrNumber += anrNum.toString().split(
+ SimContactsConstants.ANR_SEP).length;
+ }
+ // reset emptyNumber and emptyAnr to the value before
+ // the insert operation
+ emptyAnr += anrNumber;
+ emptyNumber += anrNumber;
+ if (!TextUtils.isEmpty(num)) {
+ emptyNumber++;
+ }
+
+ if (!TextUtils.isEmpty(email)) {
+ // reset emptyEmail to the value before the insert
+ // operation
+ emptyEmail += email.toString().split(
+ SimContactsConstants.EMAIL_SEP).length;
+ }
continue;
}
}
diff --git a/src/com/android/contacts/common/list/ContactListAdapter.java b/src/com/android/contacts/common/list/ContactListAdapter.java
index b987e4d8..ea2d8539 100755
--- a/src/com/android/contacts/common/list/ContactListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactListAdapter.java
@@ -407,8 +407,7 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter {
super.changeCursor(partitionIndex, cursor);
// Check if a profile exists
- if (cursor != null && cursor.getCount() > 0) {
- cursor.moveToFirst();
+ if (cursor != null && cursor.moveToFirst()) {
setProfileExists(cursor.getInt(ContactQuery.CONTACT_IS_USER_PROFILE) == 1);
}
}
diff --git a/src/com/android/contacts/common/list/ContactListItemView.java b/src/com/android/contacts/common/list/ContactListItemView.java
index 281f7ea3..913eb20a 100644
--- a/src/com/android/contacts/common/list/ContactListItemView.java
+++ b/src/com/android/contacts/common/list/ContactListItemView.java
@@ -50,6 +50,7 @@ import com.android.contacts.common.ContactPresenceIconUtil;
import com.android.contacts.common.ContactStatusUtil;
import com.android.contacts.common.R;
import com.android.contacts.common.format.TextHighlighter;
+import com.android.contacts.common.util.ContactDisplayUtils;
import com.android.contacts.common.util.SearchUtil;
import com.android.contacts.common.util.ViewUtil;
import com.android.contacts.common.util.ContactsCommonRcsUtil;
@@ -1190,6 +1191,13 @@ public class ContactListItemView extends ViewGroup
} else {
mTextHighlighter.setPrefixText(getSnippetView(), text, mHighlightedPrefix);
mSnippetView.setVisibility(VISIBLE);
+ if (ContactDisplayUtils.isPossiblePhoneNumber(text)) {
+ // Give the text-to-speech engine a hint that it's a phone number
+ mSnippetView.setContentDescription(
+ ContactDisplayUtils.getTelephoneTtsSpannable(text));
+ } else {
+ mSnippetView.setContentDescription(null);
+ }
}
}
@@ -1334,6 +1342,14 @@ public class ContactListItemView extends ViewGroup
name = mUnknownNameText;
}
setMarqueeText(getNameTextView(), name);
+
+ if (ContactDisplayUtils.isPossiblePhoneNumber(name)) {
+ // Give the text-to-speech engine a hint that it's a phone number
+ mNameTextView.setContentDescription(
+ ContactDisplayUtils.getTelephoneTtsSpannable(name.toString()));
+ } else {
+ mNameTextView.setContentDescription(null);
+ }
}
public void hideDisplayName() {
diff --git a/src/com/android/contacts/common/list/CustomContactListFilterActivity.java b/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
index b0bf9c3d..5066b294 100755
--- a/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
+++ b/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
@@ -148,9 +148,12 @@ public class CustomContactListFilterActivity extends Activity
if (account.dataSet != null) {
groupsUri.appendQueryParameter(Groups.DATA_SET, account.dataSet).build();
}
+ final Cursor cursor = resolver.query(groupsUri.build(), null, null, null, null);
+ if (cursor == null) {
+ continue;
+ }
android.content.EntityIterator iterator =
- ContactsContract.Groups.newEntityIterator(resolver.query(
- groupsUri.build(), null, null, null, null));
+ ContactsContract.Groups.newEntityIterator(cursor);
try {
boolean hasGroups = false;
diff --git a/src/com/android/contacts/common/list/DefaultContactListAdapter.java b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
index 452e0bb7..cce1909b 100644
--- a/src/com/android/contacts/common/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
@@ -273,16 +273,17 @@ public class DefaultContactListAdapter extends ContactListAdapter {
if (ContactsCommonRcsUtil.getIsRcs()) {
Long contactId = cursor.getLong(ContactQuery.CONTACT_ID);
- boolean isUserProfile = cursor
- .getInt(ContactQuery.CONTACT_IS_USER_PROFILE) == 1;
- if (ContactsCommonRcsUtil.RcsCapabilityMapCache.containsKey(contactId)) {
+ boolean isUserProfile = cursor.getInt(ContactQuery.CONTACT_IS_USER_PROFILE) == 1;
+ if (ContactsCommonRcsUtil.RcsCapabilityMapCache.containsKey(contactId)
+ && ContactsCommonRcsUtil.RcsCapabilityMapCache.get(contactId) != null
+ && ContactsCommonRcsUtil.RcsCapabilityMapCache.get(contactId)) {
ContactsCommonRcsUtil.RcsCapabilityMap.put(contactId,
ContactsCommonRcsUtil.RcsCapabilityMapCache
.get(contactId));
}
- if (!isUserProfile
- && ContactsCommonRcsUtil.RcsCapabilityMap
- .containsKey(contactId)) {
+ if (!isUserProfile && ContactsCommonRcsUtil.RcsCapabilityMap.containsKey(contactId)
+ && ContactsCommonRcsUtil.RcsCapabilityMapCache.get(contactId) != null
+ && ContactsCommonRcsUtil.RcsCapabilityMapCache.get(contactId)) {
view.setRCSCapability(mContext.getDrawable(R.drawable.rcs_capacity_icon),
ContactsCommonRcsUtil.RcsCapabilityMap.get(contactId));
} else {
diff --git a/src/com/android/contacts/common/list/ProfileAndContactsLoader.java b/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
index c19737d9..698ef96f 100644
--- a/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
+++ b/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
@@ -61,8 +61,8 @@ public class ProfileAndContactsLoader extends CursorLoader {
Cursor cursor = null;
try {
cursor = super.loadInBackground();
- } catch (NullPointerException e) {
- // Ignore NPEs thrown by providers
+ } catch (NullPointerException | SecurityException e) {
+ // Ignore NPEs and SecurityExceptions thrown by providers
}
final Cursor contactsCursor = cursor;
cursors.add(contactsCursor);
diff --git a/src/com/android/contacts/common/list/ViewPagerTabs.java b/src/com/android/contacts/common/list/ViewPagerTabs.java
index ec95de6f..006d6321 100644
--- a/src/com/android/contacts/common/list/ViewPagerTabs.java
+++ b/src/com/android/contacts/common/list/ViewPagerTabs.java
@@ -198,7 +198,12 @@ public class ViewPagerTabs extends HorizontalScrollView implements ViewPager.OnP
@Override
public void onPageSelected(int position) {
position = getRtlPosition(position);
- if (mPrevSelected >= 0) {
+ int tabStripChildCount = mTabStrip.getChildCount();
+ if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) {
+ return;
+ }
+
+ if (mPrevSelected >= 0 && mPrevSelected < tabStripChildCount) {
mTabStrip.getChildAt(mPrevSelected).setSelected(false);
}
final View selectedChild = mTabStrip.getChildAt(position);
diff --git a/src/com/android/contacts/common/location/UpdateCountryService.java b/src/com/android/contacts/common/location/UpdateCountryService.java
index e339306f..9403187e 100644
--- a/src/com/android/contacts/common/location/UpdateCountryService.java
+++ b/src/com/android/contacts/common/location/UpdateCountryService.java
@@ -38,6 +38,10 @@ public class UpdateCountryService extends IntentService {
@Override
protected void onHandleIntent(Intent intent) {
+ if (intent == null) {
+ Log.d(TAG, "onHandleIntent: could not handle null intent");
+ return;
+ }
if (ACTION_UPDATE_COUNTRY.equals(intent.getAction())) {
final Location location = (Location) intent.getParcelableExtra(KEY_INTENT_LOCATION);
final String country = getCountryFromLocation(getApplicationContext(), location);
diff --git a/src/com/android/contacts/common/model/ContactLoader.java b/src/com/android/contacts/common/model/ContactLoader.java
index eba825b1..59ab292e 100644
--- a/src/com/android/contacts/common/model/ContactLoader.java
+++ b/src/com/android/contacts/common/model/ContactLoader.java
@@ -63,9 +63,11 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -316,7 +318,7 @@ public class ContactLoader extends AsyncTaskLoader<Contact> {
resultIsCached = true;
} else {
if (uriCurrentFormat.getLastPathSegment().equals(Constants.LOOKUP_URI_ENCODED)) {
- result = loadEncodedContactEntity(uriCurrentFormat);
+ result = loadEncodedContactEntity(uriCurrentFormat, mLookupUri);
} else {
result = loadContactEntity(resolver, uriCurrentFormat);
}
@@ -349,7 +351,22 @@ public class ContactLoader extends AsyncTaskLoader<Contact> {
}
}
- private Contact loadEncodedContactEntity(Uri uri) throws JSONException {
+ /**
+ * Parses a {@link Contact} stored as a JSON string in a lookup URI.
+ *
+ * @param lookupUri The contact information to parse .
+ * @return The parsed {@code Contact} information.
+ * @throws JSONException
+ */
+ public static Contact parseEncodedContactEntity(Uri lookupUri) {
+ try {
+ return loadEncodedContactEntity(lookupUri, lookupUri);
+ } catch (JSONException je) {
+ return null;
+ }
+ }
+
+ private static Contact loadEncodedContactEntity(Uri uri, Uri lookupUri) throws JSONException {
final String jsonString = uri.getEncodedFragment();
final JSONObject json = new JSONObject(jsonString);
@@ -363,7 +380,7 @@ public class ContactLoader extends AsyncTaskLoader<Contact> {
final String photoUri = json.optString(Contacts.PHOTO_URI, null);
final Contact contact = new Contact(
uri, uri,
- mLookupUri,
+ lookupUri,
directoryId,
null /* lookupKey */,
-1 /* id */,
@@ -423,7 +440,7 @@ public class ContactLoader extends AsyncTaskLoader<Contact> {
return contact;
}
- private void processOneRecord(RawContact rawContact, JSONObject item, String mimetype)
+ private static void processOneRecord(RawContact rawContact, JSONObject item, String mimetype)
throws JSONException {
final ContentValues itemValues = new ContentValues();
itemValues.put(Data.MIMETYPE, mimetype);
@@ -758,6 +775,34 @@ public class ContactLoader extends AsyncTaskLoader<Contact> {
}
}
+ static private class AccountKey {
+ private final String mAccountName;
+ private final String mAccountType;
+ private final String mDataSet;
+
+ public AccountKey(String accountName, String accountType, String dataSet) {
+ mAccountName = accountName;
+ mAccountType = accountType;
+ mDataSet = dataSet;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAccountName, mAccountType, mDataSet);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof AccountKey)) {
+ return false;
+ }
+ final AccountKey other = (AccountKey) obj;
+ return Objects.equals(mAccountName, other.mAccountName)
+ && Objects.equals(mAccountType, other.mAccountType)
+ && Objects.equals(mDataSet, other.mDataSet);
+ }
+ }
+
/**
* Loads groups meta-data for all groups associated with all constituent raw contacts'
* accounts.
@@ -765,11 +810,15 @@ public class ContactLoader extends AsyncTaskLoader<Contact> {
private void loadGroupMetaData(Contact result) {
StringBuilder selection = new StringBuilder();
ArrayList<String> selectionArgs = new ArrayList<String>();
+ final HashSet<AccountKey> accountsSeen = new HashSet<>();
for (RawContact rawContact : result.getRawContacts()) {
final String accountName = rawContact.getAccountName();
final String accountType = rawContact.getAccountTypeString();
final String dataSet = rawContact.getDataSet();
- if (accountName != null && accountType != null) {
+ final AccountKey accountKey = new AccountKey(accountName, accountType, dataSet);
+ if (accountName != null && accountType != null &&
+ !accountsSeen.contains(accountKey)) {
+ accountsSeen.add(accountKey);
if (selection.length() != 0) {
selection.append(" OR ");
}
diff --git a/src/com/android/contacts/common/model/account/ExternalAccountType.java b/src/com/android/contacts/common/model/account/ExternalAccountType.java
index e4cef522..53089b84 100644
--- a/src/com/android/contacts/common/model/account/ExternalAccountType.java
+++ b/src/com/android/contacts/common/model/account/ExternalAccountType.java
@@ -17,9 +17,10 @@
package com.android.contacts.common.model.account;
import android.content.Context;
-import android.content.pm.PackageInfo;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -48,12 +49,15 @@ import java.util.List;
public class ExternalAccountType extends BaseAccountType {
private static final String TAG = "ExternalAccountType";
+ private static final String SYNC_META_DATA = "android.content.SyncAdapter";
+
/**
* The metadata name for so-called "contacts.xml".
*
* On LMP and later, we also accept the "alternate" name.
* This is to allow sync adapters to have a contacts.xml without making it visible on older
- * platforms.
+ * platforms. If you modify this also update the corresponding list in
+ * ContactsProvider/PhotoPriorityResolver
*/
private static final String[] METADATA_CONTACTS_NAMES = new String[] {
"android.provider.ALTERNATE_CONTACTS_STRUCTURE",
@@ -114,15 +118,9 @@ public class ExternalAccountType extends BaseAccountType {
this.resourcePackageName = packageName;
this.syncAdapterPackageName = packageName;
- final PackageManager pm = context.getPackageManager();
final XmlResourceParser parser;
if (injectedMetadata == null) {
- try {
- parser = loadContactsXml(context, packageName);
- } catch (NameNotFoundException e1) {
- // If the package name is not found, we can't initialize this account type.
- return;
- }
+ parser = loadContactsXml(context, packageName);
} else {
parser = injectedMetadata;
}
@@ -181,35 +179,41 @@ public class ExternalAccountType extends BaseAccountType {
/**
* Returns the CONTACTS_STRUCTURE metadata (aka "contacts.xml") in the given apk package.
*
- * Unfortunately, there's no public way to determine which service defines a sync service for
- * which account type, so this method looks through all services in the package, and just
- * returns the first CONTACTS_STRUCTURE metadata defined in any of them.
+ * This method looks through all services in the package that handle sync adapter
+ * intents for the first one that contains CONTACTS_STRUCTURE metadata. We have to look
+ * through all sync adapters in the package in case there are contacts and other sync
+ * adapters (eg, calendar) in the same package.
*
* Returns {@code null} if the package has no CONTACTS_STRUCTURE metadata. In this case
* the account type *will* be initialized with minimal configuration.
- *
- * On the other hand, if the package is not found, it throws a {@link NameNotFoundException},
- * in which case the account type will *not* be initialized.
*/
- private XmlResourceParser loadContactsXml(Context context, String resPackageName)
- throws NameNotFoundException {
+ public static XmlResourceParser loadContactsXml(Context context, String resPackageName) {
final PackageManager pm = context.getPackageManager();
- PackageInfo packageInfo = pm.getPackageInfo(resPackageName,
- PackageManager.GET_SERVICES|PackageManager.GET_META_DATA);
- for (ServiceInfo serviceInfo : packageInfo.services) {
- for (String metadataName : METADATA_CONTACTS_NAMES) {
- final XmlResourceParser parser = serviceInfo.loadXmlMetaData(pm,
- metadataName);
- if (parser != null) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, String.format("Metadata loaded from: %s, %s, %s",
- serviceInfo.packageName, serviceInfo.name,
- metadataName));
+ final Intent intent = new Intent(SYNC_META_DATA).setPackage(resPackageName);
+ final List<ResolveInfo> intentServices = pm.queryIntentServices(intent,
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
+
+ if (intentServices != null) {
+ for (final ResolveInfo resolveInfo : intentServices) {
+ final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+ if (serviceInfo == null) {
+ continue;
+ }
+ for (String metadataName : METADATA_CONTACTS_NAMES) {
+ final XmlResourceParser parser = serviceInfo.loadXmlMetaData(
+ pm, metadataName);
+ if (parser != null) {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, String.format("Metadata loaded from: %s, %s, %s",
+ serviceInfo.packageName, serviceInfo.name,
+ metadataName));
+ }
+ return parser;
}
- return parser;
}
}
}
+
// Package was found, but that doesn't contain the CONTACTS_STRUCTURE metadata.
return null;
}
diff --git a/src/com/android/contacts/common/model/dataitem/EventDataItem.java b/src/com/android/contacts/common/model/dataitem/EventDataItem.java
index aae00e97..5096fea2 100644
--- a/src/com/android/contacts/common/model/dataitem/EventDataItem.java
+++ b/src/com/android/contacts/common/model/dataitem/EventDataItem.java
@@ -20,6 +20,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Event;
+import android.text.TextUtils;
/**
* Represents an event data item, wrapping the columns in
@@ -46,12 +47,14 @@ public class EventDataItem extends DataItem {
}
final EventDataItem that = (EventDataItem) t;
// Events can be different (anniversary, birthday) but have the same start date
- if (!getStartDate().equals(that.getStartDate())) {
+ if (!TextUtils.equals(getStartDate(), that.getStartDate())) {
return false;
+ } else if (!hasKindTypeColumn(mKind) || !that.hasKindTypeColumn(that.getDataKind())) {
+ return hasKindTypeColumn(mKind) == that.hasKindTypeColumn(that.getDataKind());
} else if (getKindTypeColumn(mKind) != that.getKindTypeColumn(that.getDataKind())) {
return false;
} else if (getKindTypeColumn(mKind) == Event.TYPE_CUSTOM &&
- !getLabel().equals(that.getLabel())) {
+ !TextUtils.equals(getLabel(), that.getLabel())) {
// Check if custom types are not the same
return false;
}
diff --git a/src/com/android/contacts/common/model/dataitem/ImDataItem.java b/src/com/android/contacts/common/model/dataitem/ImDataItem.java
index d1af2462..f89e5c6a 100644
--- a/src/com/android/contacts/common/model/dataitem/ImDataItem.java
+++ b/src/com/android/contacts/common/model/dataitem/ImDataItem.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
import android.provider.ContactsContract.CommonDataKinds.Im;
+import android.text.TextUtils;
/**
* Represents an IM data item, wrapping the columns in
@@ -91,21 +92,21 @@ public class ImDataItem extends DataItem {
// IM can have the same data put different protocol. These should not collapse.
if (!getData().equals(that.getData())) {
return false;
- } else if (isProtocolValid() && that.isProtocolValid() &&
- getProtocol() != that.getProtocol()) {
+ } else if (!isProtocolValid() || !that.isProtocolValid()) {
+ // Deal with invalid protocol as if it was custom. If either has a non valid
+ // protocol, check to see if the other has a valid that is not custom
+ if (isProtocolValid()) {
+ return getProtocol() == Im.PROTOCOL_CUSTOM;
+ } else if (that.isProtocolValid()) {
+ return that.getProtocol() == Im.PROTOCOL_CUSTOM;
+ }
+ return true;
+ } else if (getProtocol() != that.getProtocol()) {
return false;
- } else if (isProtocolValid() && that.isProtocolValid() &&
- getProtocol() == Im.PROTOCOL_CUSTOM &&
- !getCustomProtocol().equals(that.getCustomProtocol())) {
+ } else if (getProtocol() == Im.PROTOCOL_CUSTOM &&
+ !TextUtils.equals(getCustomProtocol(), that.getCustomProtocol())) {
// Check if custom protocols are not the same
return false;
- } else if ((isProtocolValid() && !that.isProtocolValid() &&
- getProtocol() != Im.PROTOCOL_CUSTOM) ||
- (that.isProtocolValid() && !isProtocolValid() &&
- that.getProtocol() != Im.PROTOCOL_CUSTOM)) {
- // Deal with invalid protocol as if it was custom. If either has a non valid protocol,
- // check to see if the other has a valid that is not custom
- return false;
}
return true;
}
diff --git a/src/com/android/contacts/common/model/dataitem/RelationDataItem.java b/src/com/android/contacts/common/model/dataitem/RelationDataItem.java
index 1ba3fcfb..9e883fef 100644
--- a/src/com/android/contacts/common/model/dataitem/RelationDataItem.java
+++ b/src/com/android/contacts/common/model/dataitem/RelationDataItem.java
@@ -20,6 +20,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Relation;
+import android.text.TextUtils;
/**
* Represents a relation data item, wrapping the columns in
@@ -46,12 +47,14 @@ public class RelationDataItem extends DataItem {
}
final RelationDataItem that = (RelationDataItem) t;
// Relations can have different types (assistant, father) but have the same name
- if (!getName().equals(that.getName())) {
+ if (!TextUtils.equals(getName(), that.getName())) {
return false;
+ } else if (!hasKindTypeColumn(mKind) || !that.hasKindTypeColumn(that.getDataKind())) {
+ return hasKindTypeColumn(mKind) == that.hasKindTypeColumn(that.getDataKind());
} else if (getKindTypeColumn(mKind) != that.getKindTypeColumn(that.getDataKind())) {
return false;
} else if (getKindTypeColumn(mKind) == Relation.TYPE_CUSTOM &&
- !getLabel().equals(that.getLabel())) {
+ !TextUtils.equals(getLabel(), that.getLabel())) {
// Check if custom types are not the same
return false;
}
diff --git a/src/com/android/contacts/common/preference/ContactsPreferences.java b/src/com/android/contacts/common/preference/ContactsPreferences.java
index 5c07f83f..4bd6be82 100644
--- a/src/com/android/contacts/common/preference/ContactsPreferences.java
+++ b/src/com/android/contacts/common/preference/ContactsPreferences.java
@@ -47,6 +47,8 @@ public final class ContactsPreferences implements OnSharedPreferenceChangeListen
public static final String DISPLAY_ORDER_KEY = "android.contacts.DISPLAY_ORDER";
+ private static final String LAST_UPDATED_MILLIS = "last_updated_millis";
+
/**
* The value for the SORT_ORDER key corresponding to sort by given name first.
*/
@@ -194,6 +196,8 @@ public final class ContactsPreferences implements OnSharedPreferenceChangeListen
mDisplayOrder = getDisplayOrder();
} else if (SORT_ORDER_KEY.equals(key)) {
mSortOrder = getSortOrder();
+ } else if (LAST_UPDATED_MILLIS.equals(key)) {
+ return;
}
if (mListener != null) mListener.onChange();
}
diff --git a/src/com/android/contacts/common/util/BitmapUtil.java b/src/com/android/contacts/common/util/BitmapUtil.java
index a70831ec..66ab00f5 100644
--- a/src/com/android/contacts/common/util/BitmapUtil.java
+++ b/src/com/android/contacts/common/util/BitmapUtil.java
@@ -19,6 +19,11 @@ package com.android.contacts.common.util;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.BitmapDrawable;
@@ -107,4 +112,51 @@ public class BitmapUtil {
return new BitmapDrawable(resources,rotated);
}
+
+ /**
+ * Given an input bitmap, scales it to the given width/height and makes it round.
+ *
+ * @param input {@link Bitmap} to scale and crop
+ * @param targetWidth desired output width
+ * @param targetHeight desired output height
+ * @return output bitmap scaled to the target width/height and cropped to an oval. The
+ * cropping algorithm will try to fit as much of the input into the output as possible,
+ * while preserving the target width/height ratio.
+ */
+ public static Bitmap getRoundedBitmap(Bitmap input, int targetWidth, int targetHeight) {
+ if (input == null) {
+ return null;
+ }
+ final Bitmap result = Bitmap.createBitmap(targetWidth, targetHeight, input.getConfig());
+ final Canvas canvas = new Canvas(result);
+ final Paint paint = new Paint();
+ canvas.drawARGB(0, 0, 0, 0);
+ paint.setAntiAlias(true);
+ canvas.drawOval(0, 0, targetWidth, targetHeight, paint);
+
+ // Specifies that only pixels present in the destination (i.e. the drawn oval) should
+ // be overwritten with pixels from the input bitmap.
+ paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
+
+ final int inputWidth = input.getWidth();
+ final int inputHeight = input.getHeight();
+
+ // Choose the largest scale factor that will fit inside the dimensions of the
+ // input bitmap.
+ final float scaleBy = Math.min((float) inputWidth / targetWidth,
+ (float) inputHeight / targetHeight);
+
+ final int xCropAmountHalved = (int) (scaleBy * targetWidth / 2);
+ final int yCropAmountHalved = (int) (scaleBy * targetHeight / 2);
+
+ final Rect src = new Rect(
+ inputWidth / 2 - xCropAmountHalved,
+ inputHeight / 2 - yCropAmountHalved,
+ inputWidth / 2 + xCropAmountHalved,
+ inputHeight / 2 + yCropAmountHalved);
+
+ final RectF dst = new RectF(0, 0, targetWidth, targetHeight);
+ canvas.drawBitmap(input, src, dst, paint);
+ return result;
+ }
}
diff --git a/src/com/android/contacts/common/util/ContactDisplayUtils.java b/src/com/android/contacts/common/util/ContactDisplayUtils.java
index 7ec751a2..bb91b531 100644
--- a/src/com/android/contacts/common/util/ContactDisplayUtils.java
+++ b/src/com/android/contacts/common/util/ContactDisplayUtils.java
@@ -19,10 +19,18 @@ package com.android.contacts.common.util;
import static android.provider.ContactsContract.CommonDataKinds.Phone;
import android.content.Context;
+import android.telephony.PhoneNumberUtils;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.TtsSpan;
import android.util.Log;
+import android.util.Patterns;
import com.android.contacts.common.R;
+import com.android.i18n.phonenumbers.NumberParseException;
+import com.android.i18n.phonenumbers.PhoneNumberUtil;
+import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber;
import com.google.common.base.Preconditions;
/**
@@ -187,4 +195,80 @@ public class ContactDisplayUtils {
}
}
+ /**
+ * Whether the given text could be a phone number.
+ *
+ * Note this will miss many things that are legitimate phone numbers, for example,
+ * phone numbers with letters.
+ */
+ public static boolean isPossiblePhoneNumber(CharSequence text) {
+ return text == null ? false : Patterns.PHONE.matcher(text.toString()).matches();
+ }
+
+ /**
+ * Returns a Spannable for the given phone number with a telephone {@link TtsSpan} set over
+ * the entire length of the given phone number.
+ */
+ public static Spannable getTelephoneTtsSpannable(String phoneNumber) {
+ if (phoneNumber == null) {
+ return null;
+ }
+ final Spannable spannable = new SpannableString(phoneNumber);
+ final TtsSpan ttsSpan = getTelephoneTtsSpan(phoneNumber);
+ spannable.setSpan(ttsSpan, 0, phoneNumber.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ return spannable;
+ }
+
+ /**
+ * Returns a Spannable for the given message with a telephone {@link TtsSpan} set for
+ * the given phone number text wherever it is found within the message.
+ */
+ public static Spannable getTelephoneTtsSpannable(String message, String phoneNumber) {
+ if (message == null) {
+ return null;
+ }
+ final Spannable spannable = new SpannableString(message);
+ int start = phoneNumber == null ? -1 : message.indexOf(phoneNumber);
+ while (start >= 0) {
+ final int end = start + phoneNumber.length();
+ final TtsSpan ttsSpan = getTelephoneTtsSpan(phoneNumber);
+ spannable.setSpan(ttsSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ start = message.indexOf(phoneNumber, end);
+ }
+ return spannable;
+ }
+
+ /**
+ * Returns a telephone {@link TtsSpan} for the given phone number.
+ */
+ public static TtsSpan getTelephoneTtsSpan(String phoneNumberString) {
+ if (phoneNumberString == null) {
+ throw new NullPointerException();
+ }
+
+ // Parse the phone number
+ final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
+ PhoneNumber phoneNumber = null;
+ try {
+ // Don't supply a defaultRegion so this fails for non-international numbers because
+ // we don't want to TalkBalk to read a country code (e.g. +1) if it is not already
+ // present
+ phoneNumber = phoneNumberUtil.parse(phoneNumberString, /* defaultRegion */ null);
+ } catch (NumberParseException ignored) {
+ }
+
+ // Build a telephone tts span
+ final TtsSpan.TelephoneBuilder builder = new TtsSpan.TelephoneBuilder();
+ if (phoneNumber == null) {
+ // Strip separators otherwise TalkBack will be silent
+ // (this behavior was observed with TalkBalk 4.0.2 from their alpha channel)
+ builder.setNumberParts(PhoneNumberUtils.stripSeparators(phoneNumberString));
+ } else {
+ if (phoneNumber.hasCountryCode()) {
+ builder.setCountryCode(Integer.toString(phoneNumber.getCountryCode()));
+ }
+ builder.setNumberParts(Long.toString(phoneNumber.getNationalNumber()));
+ }
+ return builder.build();
+ }
}
diff --git a/src/com/android/contacts/common/util/ContactsCommonRcsUtil.java b/src/com/android/contacts/common/util/ContactsCommonRcsUtil.java
index 4075262d..bc808fbb 100644
--- a/src/com/android/contacts/common/util/ContactsCommonRcsUtil.java
+++ b/src/com/android/contacts/common/util/ContactsCommonRcsUtil.java
@@ -27,19 +27,29 @@ import java.util.ArrayList;
import java.util.HashMap;
import com.android.contacts.common.list.DefaultContactListAdapter;
+import com.suntek.mway.rcs.client.api.voip.impl.RichScreenApi;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Contacts.Data;
+import android.text.TextUtils;
+import android.util.Log;
public class ContactsCommonRcsUtil {
+ public static final String TAG = "ContactsCommonRcsUtil";
+
+ public static final boolean DEBUG = false;
+
public static final String RCS_CAPABILITY_CHANGED = "rcs_capability_changed";
public static final String RCS_CAPABILITY_CHANGED_CONTACT_ID = "rcs_capability_changed_contact_id";
@@ -48,12 +58,19 @@ public class ContactsCommonRcsUtil {
public static final String RCS_CAPABILITY_MIMETYPE = "vnd.android.cursor.item/capability";
+ // User requst to update enhance screen
+ public static final String UPDATE_ENHANCE_SCREEN_PHONE_EVENT = "933 10 12000";
+
+ private static int DEFAULT_NUMBER_LENGTH = 11;
+
public static final HashMap<Long, Boolean> RcsCapabilityMap = new HashMap<Long, Boolean>();
public static final HashMap<Long, Boolean> RcsCapabilityMapCache = new HashMap<Long, Boolean>();
private static boolean isRcs = false;
+ private static RichScreenApi mRichScreenApi = null;
+
// private static long rcsCapabilityUpdatedContactId = -1;
/*
@@ -82,15 +99,18 @@ public class ContactsCommonRcsUtil {
@Override
protected Void doInBackground(Void... params) {
ContentResolver resolver = context.getContentResolver();
- Cursor c = resolver.query(Contacts.CONTENT_URI, new String[] {
- Contacts._ID
- }, null, null, null);
- ArrayList<Long> contactIdList = new ArrayList<Long>();
+ Cursor c = resolver.query(ContactsContract.Data.CONTENT_URI,
+ new String[] {
+ ContactsContract.Data.DATA1
+ }, Data.MIMETYPE + " = ?" + " and " +
+ ContactsContract.Data.DATA2 + " = ?", new String[] {
+ RCS_CAPABILITY_MIMETYPE, String.valueOf(1)
+ }, null);
try {
if (c != null && c.moveToFirst()) {
do {
Long contactId = c.getLong(0);
- contactIdList.add(contactId);
+ RcsCapabilityMap.put(contactId, true);
} while (c.moveToNext());
}
} finally {
@@ -98,13 +118,6 @@ public class ContactsCommonRcsUtil {
c.close();
}
}
- for (Long contactId : contactIdList) {
- if (ContactsCommonRcsUtil.isRCSUser(context, contactId)) {
- RcsCapabilityMap.put(contactId, true);
- } else {
- RcsCapabilityMap.put(contactId, false);
- }
- }
return null;
}
@@ -116,27 +129,86 @@ public class ContactsCommonRcsUtil {
}.execute();
}
- public static boolean isRCSUser(final Context context, long contactId) {
- Cursor c = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI,
- new String[] {
- ContactsContract.Data.DATA2
- }, Data.MIMETYPE + " = ? and " + ContactsContract.Data.DATA1 + " = ?",
- new String[] {
- RCS_CAPABILITY_MIMETYPE, String.valueOf(contactId)
- }, null);
- try {
- if (c != null && c.moveToFirst()) {
- do {
- if (c.getInt(0) == 1) {
- return true;
+ public static void setRichScreenApi(RichScreenApi richScreenApi) {
+ mRichScreenApi = richScreenApi;
+ }
+
+ public static RichScreenApi getRichScreenApi(Context context) {
+ if (mRichScreenApi == null) {
+ mRichScreenApi = new RichScreenApi(null);
+ mRichScreenApi.init(context, null);
+ Log.d(TAG, "_______mRichScreenApi init______");
+ }
+ return mRichScreenApi;
+ }
+
+ private static boolean isWifiEnabled(Context context) {
+ WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
+ if (wifiManager.getWifiState() == WifiManager.WIFI_STATE_ENABLED) {
+ ConnectivityManager connManager = (ConnectivityManager)context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo wifiInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+ return wifiInfo.isConnected();
+ } else {
+ return false;
+ }
+ }
+
+ public static String getFormatNumber(String number){
+ if(null == number){
+ return "";
+ }
+ number = number.replaceAll("-", "");
+ number = number.replaceAll(" ", "");
+ number = number.replaceAll(",", "");
+ int numberLen = number.length();
+ if(numberLen > DEFAULT_NUMBER_LENGTH){
+ number = number.substring(numberLen - DEFAULT_NUMBER_LENGTH, numberLen);
+ }
+ return number;
+ }
+
+ public static void updateAllEnhanceScreeen(final Context context) {
+ if (!isWifiEnabled(context))
+ return;
+ Thread t = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ ArrayList<String> phoneNumberList = new ArrayList<String>();
+ Cursor phonecursor = context.getContentResolver().query(
+ ContactsContract.CommonDataKinds.Phone.CONTENT_URI, new String[] {
+ Phone.NUMBER
+ }, null, null, null);
+ try {
+ if (phonecursor != null && phonecursor.moveToFirst()) {
+ // boolean hasTryToGet = false;
+ do {
+ String phoneNumber = phonecursor.getString(0);
+ phoneNumberList.add(getFormatNumber(phoneNumber));
+ } while (phonecursor.moveToNext());
}
- } while (c.moveToNext());
- }
- } finally {
- if(null != c){
- c.close();
+ } finally {
+ if (null != phonecursor) {
+ phonecursor.close();
+ }
+ }
+ try {
+ for (String aPhoneNumber : phoneNumberList) {
+ if (!TextUtils.isEmpty(aPhoneNumber)) {
+ if (DEBUG) {
+ Log.d(TAG, "Phone Number is: " + aPhoneNumber);
+ Log.d(TAG, "Calling downloadRichScrnObj for " + aPhoneNumber);
+ }
+ mRichScreenApi.downloadRichScrnObj(aPhoneNumber,
+ UPDATE_ENHANCE_SCREEN_PHONE_EVENT);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return;
+ }
}
- }
- return false;
+ });
+ t.start();
}
}
diff --git a/src/com/android/contacts/common/util/LocalizedNameResolver.java b/src/com/android/contacts/common/util/LocalizedNameResolver.java
index 3c21946a..92104c44 100644
--- a/src/com/android/contacts/common/util/LocalizedNameResolver.java
+++ b/src/com/android/contacts/common/util/LocalizedNameResolver.java
@@ -19,10 +19,8 @@ package com.android.contacts.common.util;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorDescription;
import android.content.Context;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
import android.content.res.TypedArray;
@@ -32,6 +30,7 @@ import android.util.Log;
import android.util.Xml;
import com.android.contacts.common.R;
+import com.android.contacts.common.model.account.ExternalAccountType;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -45,11 +44,6 @@ import java.io.IOException;
public class LocalizedNameResolver {
private static final String TAG = "LocalizedNameResolver";
- /**
- * Meta-data key for the contacts configuration associated with a sync service.
- */
- private static final String METADATA_CONTACTS = "android.provider.CONTACTS_STRUCTURE";
-
private static final String CONTACTS_DATA_KIND = "ContactsDataKind";
/**
@@ -82,20 +76,9 @@ public class LocalizedNameResolver {
* reads the picture priority from that file.
*/
private static String resolveAllContactsNameFromMetaData(Context context, String packageName) {
- final PackageManager pm = context.getPackageManager();
- try {
- PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SERVICES
- | PackageManager.GET_META_DATA);
- if (pi != null && pi.services != null) {
- for (ServiceInfo si : pi.services) {
- final XmlResourceParser parser = si.loadXmlMetaData(pm, METADATA_CONTACTS);
- if (parser != null) {
- return loadAllContactsNameFromXml(context, parser, packageName);
- }
- }
- }
- } catch (NameNotFoundException e) {
- Log.w(TAG, "Problem loading \"All Contacts\"-name: " + e.toString());
+ final XmlResourceParser parser = ExternalAccountType.loadContactsXml(context, packageName);
+ if (parser != null) {
+ return loadAllContactsNameFromXml(context, parser, packageName);
}
return null;
}
diff --git a/src/com/android/contacts/common/util/MaterialColorMapUtils.java b/src/com/android/contacts/common/util/MaterialColorMapUtils.java
index 9c8862c3..e12422f4 100644
--- a/src/com/android/contacts/common/util/MaterialColorMapUtils.java
+++ b/src/com/android/contacts/common/util/MaterialColorMapUtils.java
@@ -20,6 +20,8 @@ import com.android.contacts.common.R;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.Trace;
public class MaterialColorMapUtils {
@@ -34,13 +36,71 @@ public class MaterialColorMapUtils {
com.android.contacts.common.R.array.letter_tile_colors_dark);
}
- public static class MaterialPalette {
+ public static class MaterialPalette implements Parcelable {
public MaterialPalette(int primaryColor, int secondaryColor) {
mPrimaryColor = primaryColor;
mSecondaryColor = secondaryColor;
}
public final int mPrimaryColor;
public final int mSecondaryColor;
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ MaterialPalette other = (MaterialPalette) obj;
+ if (mPrimaryColor != other.mPrimaryColor) {
+ return false;
+ }
+ if (mSecondaryColor != other.mSecondaryColor) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + mPrimaryColor;
+ result = prime * result + mSecondaryColor;
+ return result;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mPrimaryColor);
+ dest.writeInt(mSecondaryColor);
+ }
+
+ private MaterialPalette(Parcel in) {
+ mPrimaryColor = in.readInt();
+ mSecondaryColor = in.readInt();
+ }
+
+ public static final Creator<MaterialPalette> CREATOR = new Creator<MaterialPalette>() {
+ @Override
+ public MaterialPalette createFromParcel(Parcel in) {
+ return new MaterialPalette(in);
+ }
+
+ @Override
+ public MaterialPalette[] newArray(int size) {
+ return new MaterialPalette[size];
+ }
+ };
}
/**
@@ -79,6 +139,12 @@ public class MaterialColorMapUtils {
return new MaterialPalette(primaryColor, secondaryColor);
}
+ public static MaterialPalette getDefaultInCallPrimaryAndSecondaryColors(Resources resources) {
+ final int primaryColor = resources.getColor(R.color.dialer_theme_color);
+ final int secondaryColor = resources.getColor(R.color.dialer_theme_color_dark);
+ return new MaterialPalette(primaryColor, secondaryColor);
+ }
+
/**
* Returns the hue component of a color int.
*
diff --git a/src/com/android/contacts/common/vcard/NotificationImportExportListener.java b/src/com/android/contacts/common/vcard/NotificationImportExportListener.java
index 7117f9f5..7e04ae3f 100644
--- a/src/com/android/contacts/common/vcard/NotificationImportExportListener.java
+++ b/src/com/android/contacts/common/vcard/NotificationImportExportListener.java
@@ -30,6 +30,7 @@ import android.provider.ContactsContract.RawContacts;
import android.widget.Toast;
import com.android.contacts.common.R;
+import com.android.contacts.common.util.ContactsCommonRcsUtil;
import com.android.vcard.VCardEntry;
public class NotificationImportExportListener implements VCardImportExportListener,
@@ -130,6 +131,9 @@ public class NotificationImportExportListener implements VCardImportExportListen
VCardService.TYPE_IMPORT, description, null, intent);
mNotificationManager.notify(NotificationImportExportListener.DEFAULT_NOTIFICATION_TAG,
jobId, notification);
+ if (ContactsCommonRcsUtil.getIsRcs()) {
+ ContactsCommonRcsUtil.updateAllEnhanceScreeen(mContext);
+ }
}
@Override
diff --git a/src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java b/src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
new file mode 100644
index 00000000..86db1747
--- /dev/null
+++ b/src/com/android/contacts/common/widget/SelectPhoneAccountDialogFragment.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2014 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.common.widget;
+
+import android.telecom.PhoneAccount;
+import android.telecom.PhoneAccountHandle;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.FragmentManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.telecom.TelecomManager;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import com.android.contacts.common.R;
+
+import java.util.List;
+
+/**
+ * Dialog that allows the user to select a phone accounts for a given action. Optionally provides
+ * the choice to set the phone account as default.
+ */
+public class SelectPhoneAccountDialogFragment extends DialogFragment {
+ private int mTitleResId;
+ private boolean mCanSetDefault;
+ private List<PhoneAccountHandle> mAccountHandles;
+ private boolean mIsSelected;
+ private boolean mIsDefaultChecked;
+ private TelecomManager mTelecomManager;
+ private SelectPhoneAccountListener mListener;
+
+ /**
+ * Shows the account selection dialog.
+ * This is the preferred way to show this dialog.
+ *
+ * @param fragmentManager The fragment manager.
+ * @param accountHandles The {@code PhoneAccountHandle}s available to select from.
+ * @param listener The listener for the results of the account selection.
+ */
+ public static void showAccountDialog(FragmentManager fragmentManager,
+ List<PhoneAccountHandle> accountHandles, SelectPhoneAccountListener listener) {
+ showAccountDialog(fragmentManager, R.string.select_account_dialog_title, false,
+ accountHandles, listener);
+ }
+
+ /**
+ * Shows the account selection dialog.
+ * This is the preferred way to show this dialog.
+ * This method also allows specifying a custom title and "set default" checkbox.
+ *
+ * @param fragmentManager The fragment manager.
+ * @param titleResId The resource ID for the string to use in the title of the dialog.
+ * @param canSetDefault {@code true} if the dialog should include an option to set the selection
+ * as the default. False otherwise.
+ * @param accountHandles The {@code PhoneAccountHandle}s available to select from.
+ * @param listener The listener for the results of the account selection.
+ */
+ public static void showAccountDialog(FragmentManager fragmentManager, int titleResId,
+ boolean canSetDefault, List<PhoneAccountHandle> accountHandles,
+ SelectPhoneAccountListener listener) {
+ SelectPhoneAccountDialogFragment fragment =
+ new SelectPhoneAccountDialogFragment(
+ titleResId, canSetDefault, accountHandles, listener);
+ fragment.show(fragmentManager, "selectAccount");
+ }
+
+ public SelectPhoneAccountDialogFragment(int titleResId, boolean canSetDefault,
+ List<PhoneAccountHandle> accountHandles, SelectPhoneAccountListener listener) {
+ super();
+ mTitleResId = titleResId;
+ mCanSetDefault = canSetDefault;
+ mAccountHandles = accountHandles;
+ mListener = listener;
+ }
+
+ public interface SelectPhoneAccountListener {
+ void onPhoneAccountSelected(PhoneAccountHandle selectedAccountHandle, boolean setDefault);
+ void onDialogDismissed();
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ mIsSelected = false;
+ mIsDefaultChecked = false;
+ mTelecomManager =
+ (TelecomManager) getActivity().getSystemService(Context.TELECOM_SERVICE);
+
+ final DialogInterface.OnClickListener selectionListener =
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ mIsSelected = true;
+ PhoneAccountHandle selectedAccountHandle = mAccountHandles.get(which);
+ mListener.onPhoneAccountSelected(selectedAccountHandle, mIsDefaultChecked);
+ }
+ };
+
+ final CompoundButton.OnCheckedChangeListener checkListener =
+ new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton check, boolean isChecked) {
+ mIsDefaultChecked = isChecked;
+ }
+ };
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ ListAdapter selectAccountListAdapter = new SelectAccountListAdapter(
+ builder.getContext(),
+ R.layout.select_account_list_item,
+ mAccountHandles);
+
+ AlertDialog dialog = builder.setTitle(mTitleResId)
+ .setAdapter(selectAccountListAdapter, selectionListener)
+ .create();
+
+ if (mCanSetDefault) {
+ // Generate custom checkbox view
+ LinearLayout checkboxLayout = (LinearLayout) getActivity()
+ .getLayoutInflater()
+ .inflate(R.layout.default_account_checkbox, null);
+
+ CheckBox cb =
+ (CheckBox) checkboxLayout.findViewById(R.id.default_account_checkbox_view);
+ cb.setOnCheckedChangeListener(checkListener);
+
+ dialog.getListView().addFooterView(checkboxLayout);
+ }
+
+ return dialog;
+ }
+
+ private class SelectAccountListAdapter extends ArrayAdapter<PhoneAccountHandle> {
+ private int mResId;
+
+ public SelectAccountListAdapter(
+ Context context, int resource, List<PhoneAccountHandle> accountHandles) {
+ super(context, resource, accountHandles);
+ mResId = resource;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ LayoutInflater inflater = (LayoutInflater)
+ getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ View rowView;
+ final ViewHolder holder;
+
+ if (convertView == null) {
+ // Cache views for faster scrolling
+ rowView = inflater.inflate(mResId, null);
+ holder = new ViewHolder();
+ holder.labelTextView = (TextView) rowView.findViewById(R.id.label);
+ holder.numberTextView = (TextView) rowView.findViewById(R.id.number);
+ holder.imageView = (ImageView) rowView.findViewById(R.id.icon);
+ rowView.setTag(holder);
+ }
+ else {
+ rowView = convertView;
+ holder = (ViewHolder) rowView.getTag();
+ }
+
+ PhoneAccountHandle accountHandle = getItem(position);
+ PhoneAccount account = mTelecomManager.getPhoneAccount(accountHandle);
+ holder.labelTextView.setText(account.getLabel());
+ if (account.getAddress() == null ||
+ TextUtils.isEmpty(account.getAddress().getSchemeSpecificPart())) {
+ holder.numberTextView.setVisibility(View.GONE);
+ } else {
+ holder.numberTextView.setVisibility(View.VISIBLE);
+ holder.numberTextView.setText(account.getAddress().getSchemeSpecificPart());
+ }
+ holder.imageView.setImageDrawable(account.createIconDrawable(getContext()));
+ return rowView;
+ }
+
+ private class ViewHolder {
+ TextView labelTextView;
+ TextView numberTextView;
+ ImageView imageView;
+ }
+ }
+
+ @Override
+ public void onPause() {
+ if (!mIsSelected) {
+ mListener.onDialogDismissed();
+ }
+ super.onPause();
+ }
+}