summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiaojing Zhang <zhangx@codeaurora.org>2015-10-20 17:40:59 +0800
committerXiaojing Zhang <zhangx@codeaurora.org>2015-10-20 17:41:11 +0800
commitfaca3df8f57f70b676604ee7972ec2628b4796dd (patch)
tree92ca1a4f597e7a6a2a5a9ec7be6c6b6c983381f3
parent470bea576a33b5a2e85e63f750bec0b62e2d2d55 (diff)
parented28a1d8eccf352379768ae288c7fa4dda732d47 (diff)
downloadandroid_packages_apps_ContactsCommon-faca3df8f57f70b676604ee7972ec2628b4796dd.tar.gz
android_packages_apps_ContactsCommon-faca3df8f57f70b676604ee7972ec2628b4796dd.tar.bz2
android_packages_apps_ContactsCommon-faca3df8f57f70b676604ee7972ec2628b4796dd.zip
Merge remote-tracking branch 'remotes/quic/ui_dev_2.0' into HEAD
Change-Id: Ibc079218a348574499304da141f64282b756ed17
-rw-r--r--Android.mk2
-rw-r--r--TestCommon/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java5
-rw-r--r--TestCommon/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java20
-rwxr-xr-xres/drawable-hdpi/ic_contact_picture_sim.pngbin0 -> 1533 bytes
-rwxr-xr-xres/drawable-hdpi/ic_contact_picture_sim_1.pngbin0 -> 1447 bytes
-rwxr-xr-xres/drawable-hdpi/ic_contact_picture_sim_2.pngbin0 -> 1718 bytes
-rwxr-xr-xres/drawable-hdpi/ic_contact_picture_sim_business.pngbin0 -> 1690 bytes
-rwxr-xr-xres/drawable-hdpi/ic_contact_picture_sim_personal.pngbin0 -> 2010 bytes
-rwxr-xr-xres/drawable-hdpi/ic_contact_picture_sim_primary.pngbin0 -> 2288 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable-hdpi/ic_menu_settings_holo_light.pngbin1219 -> 1374 bytes
-rwxr-xr-xres/drawable-hdpi/phone_account.pngbin0 -> 1150 bytes
-rwxr-xr-xres/drawable-hdpi/sim1_account.pngbin0 -> 1236 bytes
-rwxr-xr-xres/drawable-hdpi/sim2_account.pngbin0 -> 1414 bytes
-rwxr-xr-xres/drawable-hdpi/simcard_account.pngbin0 -> 1207 bytes
-rwxr-xr-xres/drawable-mdpi/ic_contact_picture_sim.pngbin0 -> 1365 bytes
-rwxr-xr-xres/drawable-mdpi/ic_contact_picture_sim_1.pngbin0 -> 1260 bytes
-rwxr-xr-xres/drawable-mdpi/ic_contact_picture_sim_2.pngbin0 -> 1429 bytes
-rwxr-xr-xres/drawable-mdpi/ic_contact_picture_sim_business.pngbin0 -> 1400 bytes
-rwxr-xr-xres/drawable-mdpi/ic_contact_picture_sim_personal.pngbin0 -> 1559 bytes
-rwxr-xr-xres/drawable-mdpi/ic_contact_picture_sim_primary.pngbin0 -> 1690 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable-mdpi/ic_menu_settings_holo_light.pngbin850 -> 1233 bytes
-rwxr-xr-xres/drawable-mdpi/phone_account.pngbin0 -> 1098 bytes
-rwxr-xr-xres/drawable-mdpi/sim1_account.pngbin0 -> 1159 bytes
-rwxr-xr-xres/drawable-mdpi/sim2_account.pngbin0 -> 1289 bytes
-rwxr-xr-xres/drawable-mdpi/simcard_account.pngbin0 -> 1369 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_contact_picture_sim.pngbin0 -> 1734 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_contact_picture_sim_1.pngbin0 -> 1566 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_contact_picture_sim_2.pngbin0 -> 1871 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_contact_picture_sim_business.pngbin0 -> 1961 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_contact_picture_sim_personal.pngbin0 -> 2365 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_contact_picture_sim_primary.pngbin0 -> 2834 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable-xhdpi/ic_menu_settings_holo_light.pngbin1638 -> 1503 bytes
-rwxr-xr-xres/drawable-xhdpi/phone_account.pngbin0 -> 1187 bytes
-rwxr-xr-xres/drawable-xhdpi/sim1_account.pngbin0 -> 1352 bytes
-rwxr-xr-xres/drawable-xhdpi/sim2_account.pngbin0 -> 1539 bytes
-rwxr-xr-xres/drawable-xhdpi/simcard_account.pngbin0 -> 1281 bytes
-rwxr-xr-x[-rw-r--r--]res/drawable-xxhdpi/ic_menu_settings_holo_light.pngbin2506 -> 1727 bytes
-rwxr-xr-xres/drawable-xxhdpi/phone_account.pngbin0 -> 1317 bytes
-rwxr-xr-xres/drawable-xxhdpi/sim1_account.pngbin0 -> 1519 bytes
-rwxr-xr-xres/drawable-xxhdpi/sim2_account.pngbin0 -> 1826 bytes
-rwxr-xr-xres/drawable-xxhdpi/simcard_account.pngbin0 -> 1431 bytes
-rwxr-xr-xres/drawable-xxxhdpi/ic_menu_settings_holo_light.pngbin0 -> 2064 bytes
-rwxr-xr-xres/drawable-xxxhdpi/phone_account.pngbin0 -> 1406 bytes
-rwxr-xr-xres/drawable-xxxhdpi/sim1_account.pngbin0 -> 1601 bytes
-rwxr-xr-xres/drawable-xxxhdpi/sim2_account.pngbin0 -> 2040 bytes
-rwxr-xr-xres/drawable-xxxhdpi/simcard_account.pngbin0 -> 1517 bytes
-rw-r--r--res/layout/ip_prefix_dialog.xml43
-rw-r--r--res/values-zh-rCN/strings.xml35
-rw-r--r--res/values-zh-rTW/strings.xml20
-rw-r--r--res/values/strings.xml77
-rw-r--r--src/com/android/contacts/common/CallUtil.java24
-rw-r--r--src/com/android/contacts/common/ContactPhotoManager.java109
-rw-r--r--src/com/android/contacts/common/ContactTileLoaderFactory.java55
-rw-r--r--src/com/android/contacts/common/MoreContactUtils.java598
-rw-r--r--src/com/android/contacts/common/SimContactsConstants.java71
-rwxr-xr-xsrc/com/android/contacts/common/SimContactsOperation.java347
-rw-r--r--src/com/android/contacts/common/editor/SelectAccountDialogFragment.java2
-rwxr-xr-x[-rw-r--r--]src/com/android/contacts/common/interactions/ImportExportDialogFragment.java764
-rw-r--r--src/com/android/contacts/common/lettertiles/LetterTileDrawable.java50
-rw-r--r--src/com/android/contacts/common/list/AccountFilterActivity.java3
-rw-r--r--src/com/android/contacts/common/list/ContactEntry.java2
-rw-r--r--src/com/android/contacts/common/list/ContactEntryListAdapter.java20
-rw-r--r--src/com/android/contacts/common/list/ContactEntryListFragment.java26
-rw-r--r--src/com/android/contacts/common/list/ContactListAdapter.java29
-rw-r--r--src/com/android/contacts/common/list/ContactListFilter.java1
-rw-r--r--src/com/android/contacts/common/list/ContactListFilterView.java12
-rw-r--r--src/com/android/contacts/common/list/ContactTileAdapter.java15
-rw-r--r--src/com/android/contacts/common/list/ContactTileView.java6
-rw-r--r--src/com/android/contacts/common/list/CustomContactListFilterActivity.java26
-rw-r--r--src/com/android/contacts/common/list/DefaultContactListAdapter.java61
-rw-r--r--src/com/android/contacts/common/list/PhoneNumberListAdapter.java50
-rw-r--r--src/com/android/contacts/common/list/ShortcutIntentBuilder.java52
-rw-r--r--src/com/android/contacts/common/model/AccountTypeManager.java91
-rw-r--r--src/com/android/contacts/common/model/RawContactDelta.java138
-rw-r--r--src/com/android/contacts/common/model/ValuesDelta.java16
-rwxr-xr-x[-rw-r--r--]src/com/android/contacts/common/model/account/AccountType.java107
-rw-r--r--src/com/android/contacts/common/model/account/PhoneAccountType.java97
-rw-r--r--src/com/android/contacts/common/model/account/SimAccountType.java121
-rw-r--r--src/com/android/contacts/common/util/AccountSelectionUtil.java75
-rw-r--r--src/com/android/contacts/common/util/AccountsListAdapter.java33
-rw-r--r--src/com/android/contacts/common/vcard/ExportProcessor.java7
-rw-r--r--src/com/android/contacts/common/vcard/ExportVCardActivity.java5
-rw-r--r--src/com/android/contacts/common/vcard/ImportVCardActivity.java16
-rw-r--r--src/com/android/contacts/common/vcard/SelectAccountActivity.java5
-rw-r--r--src/com/android/contacts/common/vcard/VCardService.java10
85 files changed, 2985 insertions, 261 deletions
diff --git a/Android.mk b/Android.mk
index 52e18732..a628a62a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,7 +23,7 @@ res_dirs := res $(phone_common_dir)/res
LOCAL_SRC_FILES := $(call all-java-files-under, $(src_dirs))
LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, $(res_dirs))
-
+LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_AAPT_FLAGS := \
--auto-add-overlay \
--extra-packages com.android.phone.common
diff --git a/TestCommon/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java b/TestCommon/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java
index ab2d3954..d3dd722c 100644
--- a/TestCommon/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java
+++ b/TestCommon/src/com/android/contacts/common/test/mocks/MockAccountTypeManager.java
@@ -66,6 +66,11 @@ public class MockAccountTypeManager extends AccountTypeManager {
}
@Override
+ public List<AccountWithDataSet> getAccounts(boolean writableOnly, int flag) {
+ return Arrays.asList(mAccounts);
+ }
+
+ @Override
public List<AccountWithDataSet> getGroupWritableAccounts() {
return Arrays.asList(mAccounts);
}
diff --git a/TestCommon/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java b/TestCommon/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java
index db8f06f2..3b143deb 100644
--- a/TestCommon/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java
+++ b/TestCommon/src/com/android/contacts/common/test/mocks/MockContactPhotoManager.java
@@ -16,6 +16,7 @@
package com.android.contacts.common.test.mocks;
+import android.accounts.Account;
import android.graphics.Bitmap;
import android.net.Uri;
import android.view.View;
@@ -29,16 +30,19 @@ import com.android.contacts.common.ContactPhotoManager;
*/
public class MockContactPhotoManager extends ContactPhotoManager {
@Override
- public void loadThumbnail(ImageView view, long photoId, boolean darkTheme, boolean isCircular,
- DefaultImageRequest defaultImageRequest, DefaultImageProvider defaultProvider) {
- defaultProvider.applyDefaultImage(view, -1, darkTheme, null);
+ public void loadThumbnail(ImageView view, long photoId, Account account,
+ boolean darkTheme, boolean isCircular,
+ DefaultImageRequest defaultImageRequest,
+ DefaultImageProvider defaultProvider) {
+ defaultProvider.applyDefaultImage(view, account, -1, darkTheme, null);
}
@Override
- public void loadPhoto(ImageView view, Uri photoUri, int requestedExtent, boolean darkTheme,
- boolean isCircular, DefaultImageRequest defaultImageRequest,
+ public void loadPhoto(ImageView view, Uri photoUri, Account account,
+ int requestedExtent, boolean darkTheme, boolean isCircular,
+ DefaultImageRequest defaultImageRequest,
DefaultImageProvider defaultProvider) {
- defaultProvider.applyDefaultImage(view, requestedExtent, darkTheme, null);
+ defaultProvider.applyDefaultImage(view, account, requestedExtent, darkTheme, null);
}
@Override
@@ -69,4 +73,8 @@ public class MockContactPhotoManager extends ContactPhotoManager {
@Override
public void preloadPhotosInBackground() {
}
+
+ @Override
+ public void clear() {
+ }
}
diff --git a/res/drawable-hdpi/ic_contact_picture_sim.png b/res/drawable-hdpi/ic_contact_picture_sim.png
new file mode 100755
index 00000000..7b6cc26f
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture_sim_1.png b/res/drawable-hdpi/ic_contact_picture_sim_1.png
new file mode 100755
index 00000000..ec2ebcb5
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim_1.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture_sim_2.png b/res/drawable-hdpi/ic_contact_picture_sim_2.png
new file mode 100755
index 00000000..3b68c682
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim_2.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture_sim_business.png b/res/drawable-hdpi/ic_contact_picture_sim_business.png
new file mode 100755
index 00000000..4df1ecd5
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim_business.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture_sim_personal.png b/res/drawable-hdpi/ic_contact_picture_sim_personal.png
new file mode 100755
index 00000000..44f4b930
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim_personal.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_contact_picture_sim_primary.png b/res/drawable-hdpi/ic_contact_picture_sim_primary.png
new file mode 100755
index 00000000..a5bf9214
--- /dev/null
+++ b/res/drawable-hdpi/ic_contact_picture_sim_primary.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_settings_holo_light.png b/res/drawable-hdpi/ic_menu_settings_holo_light.png
index b7bb5c41..ca012b85 100644..100755
--- a/res/drawable-hdpi/ic_menu_settings_holo_light.png
+++ b/res/drawable-hdpi/ic_menu_settings_holo_light.png
Binary files differ
diff --git a/res/drawable-hdpi/phone_account.png b/res/drawable-hdpi/phone_account.png
new file mode 100755
index 00000000..f2324885
--- /dev/null
+++ b/res/drawable-hdpi/phone_account.png
Binary files differ
diff --git a/res/drawable-hdpi/sim1_account.png b/res/drawable-hdpi/sim1_account.png
new file mode 100755
index 00000000..2d9a51c0
--- /dev/null
+++ b/res/drawable-hdpi/sim1_account.png
Binary files differ
diff --git a/res/drawable-hdpi/sim2_account.png b/res/drawable-hdpi/sim2_account.png
new file mode 100755
index 00000000..c512d524
--- /dev/null
+++ b/res/drawable-hdpi/sim2_account.png
Binary files differ
diff --git a/res/drawable-hdpi/simcard_account.png b/res/drawable-hdpi/simcard_account.png
new file mode 100755
index 00000000..0ee3dac2
--- /dev/null
+++ b/res/drawable-hdpi/simcard_account.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim.png b/res/drawable-mdpi/ic_contact_picture_sim.png
new file mode 100755
index 00000000..dd63d11d
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim_1.png b/res/drawable-mdpi/ic_contact_picture_sim_1.png
new file mode 100755
index 00000000..4793a07e
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim_1.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim_2.png b/res/drawable-mdpi/ic_contact_picture_sim_2.png
new file mode 100755
index 00000000..665a6714
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim_2.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim_business.png b/res/drawable-mdpi/ic_contact_picture_sim_business.png
new file mode 100755
index 00000000..c266e266
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim_business.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim_personal.png b/res/drawable-mdpi/ic_contact_picture_sim_personal.png
new file mode 100755
index 00000000..f1e75966
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim_personal.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_contact_picture_sim_primary.png b/res/drawable-mdpi/ic_contact_picture_sim_primary.png
new file mode 100755
index 00000000..493067a9
--- /dev/null
+++ b/res/drawable-mdpi/ic_contact_picture_sim_primary.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_settings_holo_light.png b/res/drawable-mdpi/ic_menu_settings_holo_light.png
index 1ebc112e..45a5ff0f 100644..100755
--- a/res/drawable-mdpi/ic_menu_settings_holo_light.png
+++ b/res/drawable-mdpi/ic_menu_settings_holo_light.png
Binary files differ
diff --git a/res/drawable-mdpi/phone_account.png b/res/drawable-mdpi/phone_account.png
new file mode 100755
index 00000000..1fa24f6c
--- /dev/null
+++ b/res/drawable-mdpi/phone_account.png
Binary files differ
diff --git a/res/drawable-mdpi/sim1_account.png b/res/drawable-mdpi/sim1_account.png
new file mode 100755
index 00000000..cd80def2
--- /dev/null
+++ b/res/drawable-mdpi/sim1_account.png
Binary files differ
diff --git a/res/drawable-mdpi/sim2_account.png b/res/drawable-mdpi/sim2_account.png
new file mode 100755
index 00000000..fd52224a
--- /dev/null
+++ b/res/drawable-mdpi/sim2_account.png
Binary files differ
diff --git a/res/drawable-mdpi/simcard_account.png b/res/drawable-mdpi/simcard_account.png
new file mode 100755
index 00000000..e5a76881
--- /dev/null
+++ b/res/drawable-mdpi/simcard_account.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim.png b/res/drawable-xhdpi/ic_contact_picture_sim.png
new file mode 100755
index 00000000..a39b7df0
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim_1.png b/res/drawable-xhdpi/ic_contact_picture_sim_1.png
new file mode 100755
index 00000000..300c0288
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim_1.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim_2.png b/res/drawable-xhdpi/ic_contact_picture_sim_2.png
new file mode 100755
index 00000000..c7ce4223
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim_2.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim_business.png b/res/drawable-xhdpi/ic_contact_picture_sim_business.png
new file mode 100755
index 00000000..abf631f9
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim_business.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim_personal.png b/res/drawable-xhdpi/ic_contact_picture_sim_personal.png
new file mode 100755
index 00000000..e5f0cf0a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim_personal.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_contact_picture_sim_primary.png b/res/drawable-xhdpi/ic_contact_picture_sim_primary.png
new file mode 100755
index 00000000..543d6a7a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_contact_picture_sim_primary.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_settings_holo_light.png b/res/drawable-xhdpi/ic_menu_settings_holo_light.png
index 68ba92bd..91d0444d 100644..100755
--- a/res/drawable-xhdpi/ic_menu_settings_holo_light.png
+++ b/res/drawable-xhdpi/ic_menu_settings_holo_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/phone_account.png b/res/drawable-xhdpi/phone_account.png
new file mode 100755
index 00000000..a61f2034
--- /dev/null
+++ b/res/drawable-xhdpi/phone_account.png
Binary files differ
diff --git a/res/drawable-xhdpi/sim1_account.png b/res/drawable-xhdpi/sim1_account.png
new file mode 100755
index 00000000..c0ae46f2
--- /dev/null
+++ b/res/drawable-xhdpi/sim1_account.png
Binary files differ
diff --git a/res/drawable-xhdpi/sim2_account.png b/res/drawable-xhdpi/sim2_account.png
new file mode 100755
index 00000000..68fb25ce
--- /dev/null
+++ b/res/drawable-xhdpi/sim2_account.png
Binary files differ
diff --git a/res/drawable-xhdpi/simcard_account.png b/res/drawable-xhdpi/simcard_account.png
new file mode 100755
index 00000000..92b382ee
--- /dev/null
+++ b/res/drawable-xhdpi/simcard_account.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_settings_holo_light.png b/res/drawable-xxhdpi/ic_menu_settings_holo_light.png
index 5b672a3d..c87e0463 100644..100755
--- a/res/drawable-xxhdpi/ic_menu_settings_holo_light.png
+++ b/res/drawable-xxhdpi/ic_menu_settings_holo_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/phone_account.png b/res/drawable-xxhdpi/phone_account.png
new file mode 100755
index 00000000..04b06fda
--- /dev/null
+++ b/res/drawable-xxhdpi/phone_account.png
Binary files differ
diff --git a/res/drawable-xxhdpi/sim1_account.png b/res/drawable-xxhdpi/sim1_account.png
new file mode 100755
index 00000000..9293bdbe
--- /dev/null
+++ b/res/drawable-xxhdpi/sim1_account.png
Binary files differ
diff --git a/res/drawable-xxhdpi/sim2_account.png b/res/drawable-xxhdpi/sim2_account.png
new file mode 100755
index 00000000..4788f1cd
--- /dev/null
+++ b/res/drawable-xxhdpi/sim2_account.png
Binary files differ
diff --git a/res/drawable-xxhdpi/simcard_account.png b/res/drawable-xxhdpi/simcard_account.png
new file mode 100755
index 00000000..e98fd1d9
--- /dev/null
+++ b/res/drawable-xxhdpi/simcard_account.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_menu_settings_holo_light.png b/res/drawable-xxxhdpi/ic_menu_settings_holo_light.png
new file mode 100755
index 00000000..dfdd5798
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_menu_settings_holo_light.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/phone_account.png b/res/drawable-xxxhdpi/phone_account.png
new file mode 100755
index 00000000..3d726f60
--- /dev/null
+++ b/res/drawable-xxxhdpi/phone_account.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/sim1_account.png b/res/drawable-xxxhdpi/sim1_account.png
new file mode 100755
index 00000000..389569ac
--- /dev/null
+++ b/res/drawable-xxxhdpi/sim1_account.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/sim2_account.png b/res/drawable-xxxhdpi/sim2_account.png
new file mode 100755
index 00000000..ce5d8ddb
--- /dev/null
+++ b/res/drawable-xxxhdpi/sim2_account.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/simcard_account.png b/res/drawable-xxxhdpi/simcard_account.png
new file mode 100755
index 00000000..5f18f34b
--- /dev/null
+++ b/res/drawable-xxxhdpi/simcard_account.png
Binary files differ
diff --git a/res/layout/ip_prefix_dialog.xml b/res/layout/ip_prefix_dialog.xml
new file mode 100644
index 00000000..8a59b279
--- /dev/null
+++ b/res/layout/ip_prefix_dialog.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <EditText
+ android:id="@+id/ip_prefix_dialog_edit"
+ android:layout_width="match_parent"
+ android:layout_height="45dip"
+ android:layout_margin="10dip"
+ android:inputType="phone"
+ android:hint="@string/ipcall_dialog_edit_hint"/>
+
+</LinearLayout>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index edd3f3ef..bc9d5383 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!--
+<!--
~ Copyright (C) 2012 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
@@ -161,9 +161,11 @@
<string name="listCustomView" msgid="1915154113477432033">"自定义视图中的联系人"</string>
<string name="listSingleContact" msgid="8525131203887307088">"单个联系人"</string>
<string name="dialog_new_contact_account" msgid="4107520273478326011">"在以下帐户中创建联系人:"</string>
+ <string name="export_to_sim">"导出到 SIM 卡"</string>
<string name="import_from_sim" msgid="4749894687871835873">"从 SIM 卡导入"</string>
<string name="import_from_sim_summary" msgid="2306434118233541675">"从 SIM 卡“<xliff:g id="SIM_NAME">^1</xliff:g>” - <xliff:g id="SIM_NUMBER">^2</xliff:g> 导入"</string>
<string name="import_from_sim_summary_no_number" msgid="8498561004799710237">"从 SIM 卡“<xliff:g id="SIM_NAME">%1$s</xliff:g>”导入"</string>
+ <string name="export_to_sim">"导出到 SIM 卡"</string>
<string name="import_from_vcf_file" product="default" msgid="1381675161522633950">"从 .vcf 文件导入"</string>
<string name="cancel_import_confirmation_message" msgid="7764915400478970495">"要取消导入“<xliff:g id="FILENAME">%s</xliff:g>”吗?"</string>
<string name="cancel_export_confirmation_message" msgid="4063783315931861656">"要取消导出“<xliff:g id="FILENAME">%s</xliff:g>”吗?"</string>
@@ -178,6 +180,7 @@
<string name="fail_reason_too_many_vcard" product="nosdcard" msgid="8720294715223591581">"存储设备中的 vCard 文件过多。"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="3793454448838716962">"SD卡上的 vCard 文件过多。"</string>
<string name="fail_reason_io_error" msgid="7736686553669161933">"I/O 错误"</string>
+ <string name="fail_reason_import_vcard">I/O 错误,无法导入 vCard <xliff:g id="name">%s</xliff:g></string>
<string name="fail_reason_low_memory_during_import" msgid="3277485820827338116">"内存不足。该文件可能过大。"</string>
<string name="fail_reason_vcard_parse_error" msgid="514012644716565082">"由于意外原因而无法解析 vCard。"</string>
<string name="fail_reason_not_supported" msgid="388664373573337601">"不支持此格式。"</string>
@@ -228,6 +231,7 @@
<string name="dialog_import_export" msgid="1125776851100740858">"导入/导出联系人"</string>
<string name="dialog_import" msgid="5177004290082451296">"导入联系人"</string>
<string name="share_error" msgid="665756457151793108">"无法分享此联系人。"</string>
+ <string name="share_failed">"联系人太多,分享失败。"</string>
<string name="menu_search" msgid="7464453023659824700">"搜索"</string>
<string name="menu_contacts_filter" msgid="586356478145511794">"要显示的联系人"</string>
<string name="activity_title_contacts_filter" msgid="7689519428197855166">"要显示的联系人"</string>
@@ -245,9 +249,38 @@
<string name="contact_status_update_attribution" msgid="8419168578670128134">"来源:<xliff:g id="SOURCE">%1$s</xliff:g>"</string>
<string name="contact_status_update_attribution_with_date" msgid="7492465535645607473">"<xliff:g id="DATE">%1$s</xliff:g>,来源:<xliff:g id="SOURCE">%2$s</xliff:g>"</string>
<string name="action_menu_back_from_search" msgid="1138551123844019647">"停止搜索"</string>
+ <string name="exporting">"正在导出"</string>
+ <string name="reading_vcard_files">读取VCARD文件</string>
+ <string name="progressdialog_cancel">取消</string>
+ <string name="export_to_sim_failed">"导出失败,<xliff:g id="insertCount">%d</xliff:g>条成功导出"</string>
+ <string name="export_sim_card_full">"SIM卡已满,<xliff:g id="insertCount">%d</xliff:g>条成功导出"</string>
+ <string name="export_finished">"导出结束"</string>
+ <string name="tag_too_long">"发生错误,联系人姓名过长。"</string>
+ <string name="sim_contacts_not_load">发生错误,SIM卡联系人未完全加载</string>
+ <string name="export_cancelled">导出操作被取消,<xliff:g id="insertCount">%s</xliff:g>条成功导出</string>
+ <string name="export_no_phone_or_email">导出失败, <xliff:g id="name">%s</xliff:g>没有电话号码或者邮箱地址</string>
+ <string name="import_from_sim_select">"选择SIM卡进行导入"</string>
+ <string name="no_sdcard_title" product="nosdcard">"存储设备不存在"</string>
+ <string name="no_sdcard_title" product="default">"无 SD 卡"</string>
+ <string name="deleteConfirmation_title">"要删除联系人吗?"</string>
+ <string name="deleteConfirmation">"将会删除此联系人。"</string>
+ <string name="slot_name">"卡"</string>
+ <string name="copy_done">复制成功!</string>
+ <string name="copy_failure">复制失败!</string>
+ <string name="card_no_space">卡记录已满,部分信息未复制</string>
+ <string name="select_path">请选择路径</string>
+ <string name="sd_card">SD 卡</string>
+ <string name="phone_storage">手机内存</string>
<string name="description_clear_search" msgid="3893511425518852086">"清除搜索内容"</string>
<string name="settings_contact_display_options_title" msgid="1020420603072835628">"联系人显示选项"</string>
<string name="select_account_dialog_title" msgid="5509088895267310568">"帐户"</string>
<string name="set_default_account" msgid="3865970860434642695">"一律使用这张卡进行通话"</string>
<string name="select_phone_account_for_calls" msgid="933905607702811164">"用于外拨电话的帐户"</string>
+ <!-- Menu item used to initiate ip call -->
+ <string name="ip_call_by_slot">IP拨号通过<xliff:g id="subName">%s</xliff:g></string>
+ <string name="set_ip_number">设置IP号</string>
+ <string name="no_ip_number">没有IP号</string>
+ <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>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 3dc3cfd1..3e5ef1ab 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -161,6 +161,7 @@
<string name="listCustomView" msgid="1915154113477432033">"聯絡人自訂檢視"</string>
<string name="listSingleContact" msgid="8525131203887307088">"單一聯絡人"</string>
<string name="dialog_new_contact_account" msgid="4107520273478326011">"在帳戶下建立聯絡人"</string>
+ <string name="export_to_sim">"導出到 SIM 卡"</string>
<string name="import_from_sim" msgid="4749894687871835873">"從 SIM 卡匯入"</string>
<string name="import_from_sim_summary" msgid="2306434118233541675">"從 SIM 卡 <xliff:g id="SIM_NAME">^1</xliff:g> - <xliff:g id="SIM_NUMBER">^2</xliff:g> 匯入"</string>
<string name="import_from_sim_summary_no_number" msgid="8498561004799710237">"從 SIM 卡 <xliff:g id="SIM_NAME">%1$s</xliff:g> 匯入"</string>
@@ -178,6 +179,7 @@
<string name="fail_reason_too_many_vcard" product="nosdcard" msgid="8720294715223591581">"儲存裝置中的 vCard 檔案過多。"</string>
<string name="fail_reason_too_many_vcard" product="default" msgid="3793454448838716962">"SD 卡上的 vCard 檔案過多。"</string>
<string name="fail_reason_io_error" msgid="7736686553669161933">"I/O 錯誤"</string>
+ <string name="fail_reason_import_vcard">I/O 錯誤,無法匯入vCard <xliff:g id="name">%s</xliff:g></string>
<string name="fail_reason_low_memory_during_import" msgid="3277485820827338116">"記憶體不足,檔案可能過大。"</string>
<string name="fail_reason_vcard_parse_error" msgid="514012644716565082">"由於意外因素,導致無法剖析 vCard。"</string>
<string name="fail_reason_not_supported" msgid="388664373573337601">"不支援此格式。"</string>
@@ -247,6 +249,24 @@
<string name="action_menu_back_from_search" msgid="1138551123844019647">"停止搜尋"</string>
<string name="description_clear_search" msgid="3893511425518852086">"清除搜尋"</string>
<string name="settings_contact_display_options_title" msgid="1020420603072835628">"聯絡人顯示選項"</string>
+ <string name="settings_contact_display_options_description" msgid="4130259058302284077">"設定聯絡人的顯示和排序方式。"</string>
+ <string name="exporting">"正在導出"</string>
+ <string name="reading_vcard_files">讀取Vcard文件</string>
+ <string name="export_to_sim_failed">"導出失敗,<xliff:g id="insertCount">%d</xliff:g>條成功導出"</string>
+ <string name="export_sim_card_full">"SIM卡已滿,<xliff:g id="insertCount">%d</xliff:g>條成功導出"</string>
+ <string name="export_finished">"導出結束"</string>
+ <string name="export_no_phone_or_email">導出失敗, <xliff:g id="name">%s</xliff:g>沒有電話號碼或者郵箱地址</string>
+ <string name="tag_too_long">"發生錯誤,聯絡人姓名過長。"</string>
+ <string name="import_from_sim_select">"選擇SIM卡進行導入"</string>
+ <string name="no_sdcard_title" product="nosdcard">"無存儲設備"</string>
+ <string name="no_sdcard_title" product="default">"無 SD 卡"</string>
+ <string name="deleteConfirmation_title">"要刪除聯絡人嗎?"</string>
+ <string name="ContactMultiDeleteConfirmation">"將會刪除這些聯絡人。"</string>
+ <string name="slot_name">"卡"</string>
+
+ <string name="copy_done">複制成功!</string>
+ <string name="copy_failure">複制失敗!</string>
+ <string name="card_no_space">卡記錄已滿,部分信息未複制</string>
<string name="select_account_dialog_title" msgid="5509088895267310568">"帳戶"</string>
<string name="set_default_account" msgid="3865970860434642695">"一律使用這張 SIM 卡通話"</string>
<string name="select_phone_account_for_calls" msgid="933905607702811164">"選擇通話帳戶"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2c093e7a..dd5cefbf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -425,6 +425,12 @@ a ren't members of any other group. [CHAR LIMIT=25] -->
<!-- Action that exports all contacts to SIM -->
<string name="export_to_sim">Export to SIM card</string>
+ <!-- Action string for selecting SIM for importing contacts -->
+ <string name="import_from_sim">Import from SIM card</string>
+
+ <!-- Action string for selecting (USB) storage for importing contacts [CHAR LIMIT=30] -->
+ <string name="import_from_sdcard" product="default">Import from storage</string>
+
<!-- Action string for selecting a SIM subscription for importing contacts -->
<string name="import_from_sim_summary">Import from SIM <xliff:g id="sim_name">^1</xliff:g> - <xliff:g id="sim_number">^2</xliff:g></string>
@@ -493,6 +499,9 @@ a ren't members of any other group. [CHAR LIMIT=25] -->
emitted some I/O error. Exact reason will be appended by the system. [CHAR LIMIT=NONE] -->
<string name="fail_reason_io_error">I/O error</string>
+ <!--The failed reason shown when importting some a vCard file -->
+ <string name="fail_reason_import_vcard">I/O error,couldn\'t import vCard <xliff:g id="name">%s</xliff:g></string>
+
<!-- Failure reason show when Contacts app (especially vCard importer) encountered
low memory problem and could not proceed its import procedure. [CHAR LIMIT=NONE] -->
<string name="fail_reason_low_memory_during_import">Not enough memory. The file may be too large.</string>
@@ -645,6 +654,9 @@ a ren't members of any other group. [CHAR LIMIT=25] -->
<!-- Action that exports all contacts to a user selected destination. [CHAR LIMIT=25] -->
<string name="export_to_vcf_file" product="default">Export to .vcf file</string>
+ <!-- Action that exports all contacts to (USB) storage [CHAR LIMIT=25] -->
+ <string name="export_to_sdcard" product="default">Export to storage</string>
+
<!-- Contact preferences related strings -->
<!-- Label of the "sort by" display option -->
@@ -680,6 +692,8 @@ a ren't members of any other group. [CHAR LIMIT=25] -->
<!-- Toast indicating that sharing a contact has failed. [CHAR LIMIT=NONE] -->
<string name="share_error">This contact can\'t be shared.</string>
+ <!-- Toast indicating that sharing too many contact has failed. [CHAR LIMIT=NONE] -->
+ <string name="share_failed">Too many contacts, share failed</string>
<!-- Menu item to search contacts -->
<string name="menu_search">Search</string>
@@ -737,6 +751,52 @@ a ren't members of any other group. [CHAR LIMIT=25] -->
<!-- Attribution of a contact status update, when the time of update is known -->
<string name="contact_status_update_attribution_with_date"><xliff:g id="date" example="3 hours ago">%1$s</xliff:g> via <xliff:g id="source" example="Google Talk">%2$s</xliff:g></string>
+ <string name="label_groups">Group</string>
+
+ <string name="exporting">Exporting</string>
+
+ <!-- Message while reading multiple vCard files "(current number) of (total number) files"
+ The order of "current number" and "total number" cannot be changed -->
+ <string name="reading_vcard_files"><xliff:g id="current_number">%1$s</xliff:g> of <xliff:g id="total_number">%2$s</xliff:g> files</string>
+
+ <string name="progressdialog_cancel">Cancel</string>
+
+ <string name="export_to_sim_failed">Export failed, <xliff:g id="insertCount">%d</xliff:g> items are exported</string>
+
+ <string name="export_sim_card_full">Sim Card is full, <xliff:g id="insertCount">%d</xliff:g> items are exported</string>
+
+ <string name="export_failed">Export failed</string>
+
+ <string name="sim_card_full">Error, Sim Card is full.</string>
+
+ <string name="export_finished">Export finished</string>
+
+ <string name="tag_too_long">Error, Contact name is too long.</string>
+
+ <string name="sim_contacts_not_load">Error, SIM contacts have not been loaded completely.</string>
+
+ <string name="export_cancelled">Export is canceled, <xliff:g id="insertCount">%s</xliff:g>items are exported</string>
+
+ <string name="export_no_phone_or_email">Export failed, <xliff:g id="name">%s</xliff:g>has not phone number or
+ email address</string>
+
+ <string name="import_from_sim_select">Choose card to import</string>
+
+ <!-- Dialog title shown when (USB) storage does not exist [CHAR LIMIT=25] -->
+ <string name="no_sdcard_title" product="nosdcard">Storage unavailable</string>
+ <!-- Dialog title shown when SD Card does not exist -->
+ <string name="no_sdcard_title" product="default">No SD card</string>
+ <!-- Confirmation dialog title after users selects to delete a contact. [CHAR LIMIT=25]-->
+ <string name="deleteConfirmation_title">Delete contact?</string>
+
+ <!-- Confirmation dialog contents after users selects to delete a Writable contact. -->
+ <string name="deleteConfirmation">This contact will be deleted.</string>
+ <!-- The slot common name -->
+ <string name="slot_name">SIM</string>
+
+ <string name="copy_done">Copy done!</string>
+ <string name="copy_failure">Copy Failed!</string>
+ <string name="card_no_space">Card has no space ,some record copy failed</string>
<!-- Font family used when drawing letters for letter tile avatars.
Do not translate. -->
<string name="letter_tile_letter_font_family">sans-serif-light</string>
@@ -764,4 +824,21 @@ a ren't members of any other group. [CHAR LIMIT=25] -->
<!-- Title for dialog to select Phone Account for outgoing call. [CHAR LIMIT=40] -->
<string name="select_phone_account_for_calls">Call with</string>
+ <!-- Menu item used to initiate ip call -->
+ <string name="ip_call_by_slot">IP Call by <xliff:g id="subName">%s</xliff:g></string>
+ <string name="set_ip_number">Set IP Number</string>
+ <string name="no_ip_number">No IP number</string>
+ <string name="no_ip_number_on_sim_card">No IP number on SIM card</string>
+ <string name="ipcall_dialog_title">IP call setting</string>
+ <string name="ipcall_dialog_edit_hint">Please input the IP prefix</string>
+
+ <string name="Import_All">Import Contacts From All SIMs</string>
+ <string name="select_path">Select Path</string>
+ <string name="sd_card">SD card</string>
+ <string name="phone_storage">Phone storage</string>
+ <string name="select_sim">Select SIM</string>
+
+ <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>
</resources>
diff --git a/src/com/android/contacts/common/CallUtil.java b/src/com/android/contacts/common/CallUtil.java
index 1c62194b..7d131946 100644
--- a/src/com/android/contacts/common/CallUtil.java
+++ b/src/com/android/contacts/common/CallUtil.java
@@ -48,7 +48,7 @@ public class CallUtil {
* automatically.
*/
public static Intent getCallIntent(String number) {
- return getCallIntent(getCallUri(number));
+ return getCallIntent(number, null);
}
/**
@@ -60,6 +60,28 @@ public class CallUtil {
}
/**
+ * A variant of {@link #getCallIntent(String, String)} but also include {@code Account}.
+ */
+ public static Intent getCallIntent(
+ String number, PhoneAccountHandle accountHandle) {
+ return getCallIntent(CallUtil.getCallUri(number), accountHandle);
+ }
+
+ /**
+ * 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).
+ */
+ public static Intent getCallIntent(Uri uri, PhoneAccountHandle accountHandle) {
+ final Intent intent = new Intent(Intent.ACTION_CALL, uri);
+ if (accountHandle != null) {
+ intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, accountHandle);
+ }
+
+ return intent;
+ }
+
+ /**
* A variant of {@link #getCallIntent} for starting a video call.
*/
public static Intent getVideoCallIntent(String number, String callOrigin) {
diff --git a/src/com/android/contacts/common/ContactPhotoManager.java b/src/com/android/contacts/common/ContactPhotoManager.java
index deaf40e0..c4cde8bb 100644
--- a/src/com/android/contacts/common/ContactPhotoManager.java
+++ b/src/com/android/contacts/common/ContactPhotoManager.java
@@ -16,6 +16,7 @@
package com.android.contacts.common;
+import android.accounts.Account;
import android.app.ActivityManager;
import android.content.ComponentCallbacks2;
import android.content.ContentResolver;
@@ -122,17 +123,23 @@ public abstract class ContactPhotoManager implements ComponentCallbacks2 {
*/
public static Drawable getDefaultAvatarDrawableForContact(Resources resources, boolean hires,
DefaultImageRequest defaultImageRequest) {
+ return getDefaultAvatarDrawableForContact(null, resources, hires,
+ defaultImageRequest, null);
+ }
+
+ public static Drawable getDefaultAvatarDrawableForContact(Context context, Resources resources,
+ boolean hires, DefaultImageRequest defaultImageRequest, Account account) {
if (defaultImageRequest == null) {
if (sDefaultLetterAvatar == null) {
// Cache and return the letter tile drawable that is created by a null request,
// so that it doesn't have to be recreated every time it is requested again.
sDefaultLetterAvatar = LetterTileDefaultImageProvider.getDefaultImageForContact(
- resources, null);
+ context, resources, null, account);
}
return sDefaultLetterAvatar;
}
- return LetterTileDefaultImageProvider.getDefaultImageForContact(resources,
- defaultImageRequest);
+ return LetterTileDefaultImageProvider.getDefaultImageForContact(context, resources,
+ defaultImageRequest, account);
}
/**
@@ -374,6 +381,10 @@ public abstract class ContactPhotoManager implements ComponentCallbacks2 {
*/
public abstract void applyDefaultImage(ImageView view, int extent, boolean darkTheme,
DefaultImageRequest defaultImageRequest);
+
+ public void applyDefaultImage(ImageView view, Account account, int extent,
+ boolean darkTheme, DefaultImageRequest defaultImageRequest) {
+ }
}
/**
@@ -385,14 +396,21 @@ public abstract class ContactPhotoManager implements ComponentCallbacks2 {
@Override
public void applyDefaultImage(ImageView view, int extent, boolean darkTheme,
DefaultImageRequest defaultImageRequest) {
- final Drawable drawable = getDefaultImageForContact(view.getResources(),
- defaultImageRequest);
+ applyDefaultImage(view, null, extent, darkTheme, defaultImageRequest);
+ }
+
+ @Override
+ public void applyDefaultImage(ImageView view, Account account, int extent,
+ boolean darkTheme, DefaultImageRequest defaultImageRequest) {
+ final Drawable drawable = getDefaultImageForContact(view.getContext(),
+ view.getResources(), defaultImageRequest, account);
view.setImageDrawable(drawable);
}
- public static Drawable getDefaultImageForContact(Resources resources,
- DefaultImageRequest defaultImageRequest) {
- final LetterTileDrawable drawable = new LetterTileDrawable(resources);
+ public static Drawable getDefaultImageForContact(Context context, Resources resources,
+ DefaultImageRequest defaultImageRequest, Account account) {
+ final LetterTileDrawable drawable = new LetterTileDrawable(
+ context, resources, account);
if (defaultImageRequest != null) {
// If the contact identifier is null or empty, fallback to the
// displayName. In that case, use {@code null} for the contact's
@@ -448,6 +466,8 @@ public abstract class ContactPhotoManager implements ComponentCallbacks2 {
return new ContactPhotoManagerImpl(context);
}
+ public abstract void clear();
+
@VisibleForTesting
public static void injectContactPhotoManagerForTesting(ContactPhotoManager photoManager) {
sInstance = photoManager;
@@ -458,19 +478,32 @@ public abstract class ContactPhotoManager implements ComponentCallbacks2 {
* it is displayed immediately. Otherwise a request is sent to load the photo
* from the database.
*/
- public abstract void loadThumbnail(ImageView view, long photoId, boolean darkTheme,
- boolean isCircular, DefaultImageRequest defaultImageRequest,
+ public abstract void loadThumbnail(ImageView view, long photoId, Account account,
+ boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
DefaultImageProvider defaultProvider);
/**
* Calls {@link #loadThumbnail(ImageView, long, boolean, DefaultImageRequest,
* DefaultImageProvider)} using the {@link DefaultImageProvider} {@link #DEFAULT_AVATAR}.
*/
+ public final void loadThumbnail(ImageView view, long photoId, Account account,
+ boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest) {
+ loadThumbnail(view, photoId, account, darkTheme, isCircular,
+ defaultImageRequest, DEFAULT_AVATAR);
+ }
+
public final void loadThumbnail(ImageView view, long photoId, boolean darkTheme,
boolean isCircular, DefaultImageRequest defaultImageRequest) {
- loadThumbnail(view, photoId, darkTheme, isCircular, defaultImageRequest, DEFAULT_AVATAR);
+ loadThumbnail(view, photoId, null, darkTheme, isCircular,
+ defaultImageRequest, DEFAULT_AVATAR);
}
+ public final void loadThumbnail(ImageView view, long photoId, boolean darkTheme,
+ boolean isCircular, DefaultImageRequest defaultImageRequest,
+ DefaultImageProvider defaultProvider) {
+ loadThumbnail(view, photoId, null, darkTheme, isCircular,
+ defaultImageRequest, defaultProvider);
+ }
/**
* Load photo into the supplied image view. If the photo is already cached,
@@ -489,8 +522,9 @@ public abstract class ContactPhotoManager implements ComponentCallbacks2 {
* @param defaultProvider The provider of default avatars (this is used if photoUri doesn't
* refer to an existing image)
*/
- public abstract void loadPhoto(ImageView view, Uri photoUri, int requestedExtent,
- boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
+ public abstract void loadPhoto(ImageView view, Uri photoUri,
+ Account account, int requestedExtent, boolean darkTheme,
+ boolean isCircular, DefaultImageRequest defaultImageRequest,
DefaultImageProvider defaultProvider);
/**
@@ -501,12 +535,25 @@ public abstract class ContactPhotoManager implements ComponentCallbacks2 {
* @param defaultImageRequest {@link DefaultImageRequest} object that specifies how a default
* letter tile avatar should be drawn.
*/
+ public final void loadPhoto(ImageView view, Uri photoUri, Account account, int requestedExtent,
+ boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest) {
+ loadPhoto(view, photoUri, account, requestedExtent, darkTheme, isCircular,
+ defaultImageRequest, DEFAULT_AVATAR);
+ }
+
public final void loadPhoto(ImageView view, Uri photoUri, int requestedExtent,
boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest) {
- loadPhoto(view, photoUri, requestedExtent, darkTheme, isCircular,
+ loadPhoto(view, photoUri, null, requestedExtent, darkTheme, isCircular,
defaultImageRequest, DEFAULT_AVATAR);
}
+ public final void loadPhoto(ImageView view, Uri photoUri, int requestedExtent,
+ boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
+ DefaultImageProvider defaultProvider) {
+ loadPhoto(view, photoUri, null, requestedExtent, darkTheme, isCircular,
+ defaultImageRequest, defaultProvider);
+ }
+
/**
* Calls {@link #loadPhoto(ImageView, Uri, boolean, boolean, DefaultImageRequest,
* DefaultImageProvider)} with {@link #DEFAULT_AVATAR} and with the assumption, that
@@ -515,9 +562,17 @@ public abstract class ContactPhotoManager implements ComponentCallbacks2 {
* @param defaultImageRequest {@link DefaultImageRequest} object that specifies how a default
* letter tile avatar should be drawn.
*/
+ public final void loadDirectoryPhoto(ImageView view, Uri photoUri,
+ Account account, boolean darkTheme, boolean isCircular,
+ DefaultImageRequest defaultImageRequest) {
+ loadPhoto(view, photoUri, account, -1, darkTheme, isCircular,
+ defaultImageRequest, DEFAULT_AVATAR);
+ }
+
public final void loadDirectoryPhoto(ImageView view, Uri photoUri, boolean darkTheme,
boolean isCircular, DefaultImageRequest defaultImageRequest) {
- loadPhoto(view, photoUri, -1, darkTheme, isCircular, defaultImageRequest, DEFAULT_AVATAR);
+ loadPhoto(view, photoUri, null, -1, darkTheme, isCircular,
+ defaultImageRequest, DEFAULT_AVATAR);
}
/**
@@ -819,11 +874,12 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback {
}
@Override
- public void loadThumbnail(ImageView view, long photoId, boolean darkTheme, boolean isCircular,
- DefaultImageRequest defaultImageRequest, DefaultImageProvider defaultProvider) {
+ public void loadThumbnail(ImageView view, long photoId, Account account,
+ boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
+ DefaultImageProvider defaultProvider) {
if (photoId == 0) {
// No photo is needed
- defaultProvider.applyDefaultImage(view, -1, darkTheme, defaultImageRequest);
+ defaultProvider.applyDefaultImage(view, account, -1, darkTheme, defaultImageRequest);
mPendingRequests.remove(view);
} else {
if (DEBUG) Log.d(TAG, "loadPhoto request: " + photoId);
@@ -833,19 +889,19 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback {
}
@Override
- public void loadPhoto(ImageView view, Uri photoUri, int requestedExtent, boolean darkTheme,
- boolean isCircular, DefaultImageRequest defaultImageRequest,
+ public void loadPhoto(ImageView view, Uri photoUri, Account account, int requestedExtent,
+ boolean darkTheme, boolean isCircular, DefaultImageRequest defaultImageRequest,
DefaultImageProvider defaultProvider) {
if (photoUri == null) {
// No photo is needed
- defaultProvider.applyDefaultImage(view, requestedExtent, darkTheme,
+ defaultProvider.applyDefaultImage(view, account, requestedExtent, darkTheme,
defaultImageRequest);
mPendingRequests.remove(view);
} else {
if (DEBUG) Log.d(TAG, "loadPhoto request: " + photoUri);
if (isDefaultImageUri(photoUri)) {
- createAndApplyDefaultImageForUri(view, photoUri, requestedExtent, darkTheme,
- isCircular, defaultProvider);
+ createAndApplyDefaultImageForUri(view, account, photoUri, requestedExtent,
+ darkTheme, isCircular, defaultProvider);
} else {
loadPhotoByIdOrUri(view, Request.createFromUri(photoUri, requestedExtent,
darkTheme, isCircular, defaultProvider));
@@ -853,11 +909,12 @@ class ContactPhotoManagerImpl extends ContactPhotoManager implements Callback {
}
}
- private void createAndApplyDefaultImageForUri(ImageView view, Uri uri, int requestedExtent,
- boolean darkTheme, boolean isCircular, DefaultImageProvider defaultProvider) {
+ private void createAndApplyDefaultImageForUri(ImageView view,
+ Account account, Uri uri, int requestedExtent, boolean darkTheme,
+ boolean isCircular, DefaultImageProvider defaultProvider) {
DefaultImageRequest request = getDefaultImageRequestFromUri(uri);
request.isCircular = isCircular;
- defaultProvider.applyDefaultImage(view, requestedExtent, darkTheme, request);
+ defaultProvider.applyDefaultImage(view, account, requestedExtent, darkTheme, request);
}
private void loadPhotoByIdOrUri(ImageView view, Request request) {
diff --git a/src/com/android/contacts/common/ContactTileLoaderFactory.java b/src/com/android/contacts/common/ContactTileLoaderFactory.java
index f8b0c359..33d4ea68 100644
--- a/src/com/android/contacts/common/ContactTileLoaderFactory.java
+++ b/src/com/android/contacts/common/ContactTileLoaderFactory.java
@@ -23,6 +23,8 @@ import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
/**
* Used to create {@link CursorLoader}s to load different groups of
@@ -35,19 +37,22 @@ public final class ContactTileLoaderFactory {
public final static int STARRED = 2;
public final static int PHOTO_URI = 3;
public final static int LOOKUP_KEY = 4;
- public final static int CONTACT_PRESENCE = 5;
- public final static int CONTACT_STATUS = 6;
+ public final static int ACCOUNT_TYPE = 5;
+ public final static int ACCOUNT_NAME = 6;
+
+ public final static int CONTACT_PRESENCE = 7;
+ public final static int CONTACT_STATUS = 8;
// 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;
- public final static int IS_DEFAULT_NUMBER = 8;
- public final static int PINNED = 9;
+ public final static int PHONE_NUMBER = 7;
+ public final static int PHONE_NUMBER_TYPE = 8;
+ public final static int PHONE_NUMBER_LABEL = 9;
+ public final static int IS_DEFAULT_NUMBER = 10;
+ public final static int PINNED = 11;
// The _ID field returned for strequent items actually contains data._id instead of
// contacts._id because the query is performed on the data table. In order to obtain the
// contact id for strequent items, we thus have to use Phone.contact_id instead.
- public final static int CONTACT_ID_FOR_DATA = 10;
+ public final static int CONTACT_ID_FOR_DATA = 12;
private static final String[] COLUMNS = new String[] {
Contacts._ID, // ..........................................0
@@ -55,8 +60,10 @@ public final class ContactTileLoaderFactory {
Contacts.STARRED, // ......................................2
Contacts.PHOTO_URI, // ....................................3
Contacts.LOOKUP_KEY, // ...................................4
- Contacts.CONTACT_PRESENCE, // .............................5
- Contacts.CONTACT_STATUS, // ...............................6
+ RawContacts.ACCOUNT_TYPE, // 5
+ RawContacts.ACCOUNT_NAME, // 6
+ Contacts.CONTACT_PRESENCE, // .............................7
+ Contacts.CONTACT_STATUS, // ...............................8
};
/**
@@ -72,12 +79,14 @@ public final class ContactTileLoaderFactory {
Contacts.STARRED, // ......................................2
Contacts.PHOTO_URI, // ....................................3
Contacts.LOOKUP_KEY, // ...................................4
- Phone.NUMBER, // ..........................................5
- Phone.TYPE, // ............................................6
- Phone.LABEL, // ...........................................7
- Phone.IS_SUPER_PRIMARY, //.................................8
- Contacts.PINNED, // .......................................9
- Phone.CONTACT_ID //........................................10
+ RawContacts.ACCOUNT_TYPE, // 5
+ RawContacts.ACCOUNT_NAME, // 6
+ Phone.NUMBER, // ..........................................7
+ Phone.TYPE, // ............................................8
+ Phone.LABEL, // ............................................9
+ Phone.IS_SUPER_PRIMARY, //.................................10
+ Contacts.PINNED, // .......................................11
+ Phone.CONTACT_ID //........................................12
};
private static final String STARRED_ORDER = Contacts.DISPLAY_NAME+" COLLATE NOCASE ASC";
@@ -88,10 +97,16 @@ public final class ContactTileLoaderFactory {
}
public static CursorLoader createStrequentPhoneOnlyLoader(Context context) {
- Uri uri = Contacts.CONTENT_STREQUENT_URI.buildUpon()
- .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true").build();
-
- return new CursorLoader(context, uri, COLUMNS_PHONE_ONLY, null, null, null);
+ Uri.Builder builder = Contacts.CONTENT_STREQUENT_URI.buildUpon();
+ builder.appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true");
+ // Do not show contacts in disabled SIM card
+ String disabledSimFilter = MoreContactUtils.getDisabledSimFilter();
+ if (!TextUtils.isEmpty(disabledSimFilter)) {
+ builder.appendQueryParameter(RawContacts.ACCOUNT_NAME, disabledSimFilter);
+ builder.appendQueryParameter(SimContactsConstants
+ .WITHOUT_SIM_FLAG, "true");
+ }
+ return new CursorLoader(context, builder.build(), COLUMNS_PHONE_ONLY, null, null, null);
}
public static CursorLoader createStarredLoader(Context context) {
diff --git a/src/com/android/contacts/common/MoreContactUtils.java b/src/com/android/contacts/common/MoreContactUtils.java
index 9b9f800e..8f465ad4 100644
--- a/src/com/android/contacts/common/MoreContactUtils.java
+++ b/src/com/android/contacts/common/MoreContactUtils.java
@@ -1,6 +1,10 @@
/*
+ * Copyright (C) 2013-2015, The Linux Foundation. All Rights Reserved.
+ * Not a Contribution.
+ *
* Copyright (C) 2012 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
@@ -16,20 +20,55 @@
package com.android.contacts.common;
+import android.accounts.Account;
+
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import android.app.AlertDialog;
import android.content.Context;
+import android.content.DialogInterface;
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.ComponentName;
+import android.content.DialogInterface;
import android.content.Intent;
+import android.content.OperationApplicationException;
+import android.database.Cursor;
import android.graphics.Rect;
import android.net.Uri;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyManager;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.util.Log;
import android.view.View;
+import android.widget.EditText;
import android.widget.TextView;
+import com.android.internal.telephony.PhoneConstants;
import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.SimAccountType;
+import com.android.internal.telephony.uicc.AdnRecord;
+import com.android.internal.telephony.uicc.IccConstants;
+import com.android.internal.telephony.IIccPhoneBook;
+
+import java.util.ArrayList;
+import java.util.List;
/**
* Shared static contact utility methods.
@@ -37,7 +76,30 @@ import com.android.contacts.common.model.account.AccountType;
public class MoreContactUtils {
private static final String WAIT_SYMBOL_AS_STRING = String.valueOf(PhoneNumberUtils.WAIT);
+ private static final boolean DBG = true;
+ private static final String TAG = "MoreContactUtils";
+ public static final int MAX_LENGTH_NAME_IN_SIM = 14;
+ public static final int MAX_LENGTH_NAME_WITH_CHINESE_IN_SIM = 6;
+ public static final int MAX_LENGTH_NUMBER_IN_SIM = 20;
+ public static final int MAX_LENGTH_EMAIL_IN_SIM = 40;
+ private static final int NAME_POS = 0;
+ private static final int NUMBER_POS = 1;
+ private static final int EMAIL_POS = 2;
+ private static final int ANR_POS = 3;
+ private static final String PHONEBOOK = "simphonebook";
+ public static final String[] MULTI_SIM_NAME = { "perferred_name_sub1",
+ "perferred_name_sub2" };
+ public static final String PREFERRED_SIM_ICON_INDEX = "preferred_sim_icon_index";
+ public static final String[] IPCALL_PREFIX = { "ipcall_prefix1",
+ "ipcall_prefix2" };
+ public final static int[] IC_SIM_PICTURE = {
+ R.drawable.ic_contact_picture_sim_1,
+ R.drawable.ic_contact_picture_sim_2,
+ R.drawable.ic_contact_picture_sim_personal,
+ R.drawable.ic_contact_picture_sim_business,
+ R.drawable.ic_contact_picture_sim_primary
+ };
/**
* Returns true if two data with mimetypes which represent values in contact entries are
* considered equal for collapsing in the GUI. For caller-id, use
@@ -240,4 +302,540 @@ public class MoreContactUtils {
intent.setData(lookupUri);
return intent;
}
+
+ /** get disabled SIM card's name */
+ public static String getDisabledSimFilter() {
+ int count = TelephonyManager.getDefault().getPhoneCount();
+ StringBuilder simFilter = new StringBuilder("");
+
+ for (int i = 0; i < count; i++) {
+ if (TelephonyManager.SIM_STATE_UNKNOWN == TelephonyManager
+ .getDefault().getSimState(i)) {
+ simFilter.append(getSimAccountName(i) + ',');
+ }
+ }
+
+ return simFilter.toString();
+ }
+
+ public static boolean isAPMOnAndSIMPowerDown(Context context) {
+ if (context == null) {
+ return false;
+ }
+ boolean isAirPlaneMode = Settings.System.getInt(context.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+ boolean isSIMPowerDown = SystemProperties.getInt(
+ "persist.radio.apm_sim_not_pwdn", 0) == 0;
+ return isAirPlaneMode && isSIMPowerDown;
+ }
+
+ /**
+ * Get SIM card account name
+ */
+ public static String getSimAccountName(int subscription) {
+ if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+ return SimContactsConstants.SIM_NAME + (subscription + 1);
+ } else {
+ return SimContactsConstants.SIM_NAME;
+ }
+ }
+
+ public static int getSubscription(String accountType, String accountName) {
+ int subscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ if (accountType == null || accountName == null)
+ return subscription;
+ if (accountType.equals(SimContactsConstants.ACCOUNT_TYPE_SIM)) {
+ if (accountName.equals(SimContactsConstants.SIM_NAME)
+ || accountName.equals(SimContactsConstants.SIM_NAME_1)) {
+ subscription = PhoneConstants.SUB1;
+ } else if (accountName.equals(SimContactsConstants.SIM_NAME_2)) {
+ subscription = PhoneConstants.SUB2;
+ }
+ }
+ return subscription;
+ }
+
+ public static int getAnrCount(int slot) {
+ int anrCount = 0;
+ int[] subId = SubscriptionManager.getSubId(slot);
+ try {
+ IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+ ServiceManager.getService("simphonebook"));
+
+ if (iccIpb != null) {
+ if (subId != null
+ && TelephonyManager.getDefault().isMultiSimEnabled()) {
+ anrCount = iccIpb.getAnrCountUsingSubId(subId[0]);
+ } else {
+ anrCount = iccIpb.getAnrCount();
+ }
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return anrCount;
+ }
+
+ public static int getAdnCount(int slot) {
+ int adnCount = 0;
+ int[] subId = SubscriptionManager.getSubId(slot);
+ try {
+ IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+ ServiceManager.getService("simphonebook"));
+ if (iccIpb != null) {
+ if (subId != null
+ && TelephonyManager.getDefault().isMultiSimEnabled()) {
+ adnCount = iccIpb.getAdnCountUsingSubId(subId[0]);
+ } else {
+ adnCount = iccIpb.getAdnCount();
+ }
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+ return adnCount;
+ }
+
+ public static int getEmailCount(int slot) {
+ int emailCount = 0;
+ int[] subId = SubscriptionManager.getSubId(slot);
+ try {
+ IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(
+ ServiceManager.getService("simphonebook"));
+
+ if (iccIpb != null) {
+ if (subId != null
+ && TelephonyManager.getDefault().isMultiSimEnabled()) {
+ emailCount = iccIpb.getEmailCountUsingSubId(subId[0]);
+ } else {
+ emailCount = iccIpb.getEmailCount();
+ }
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ }
+
+ return emailCount;
+ }
+
+ /**
+ * Returns the subscription's card can save anr or not.
+ */
+ public static boolean canSaveAnr(int slot) {
+ return getAnrCount(slot) > 0 ? true : false;
+ }
+
+ /**
+ * Returns the subscription's card can save email or not.
+ */
+ public static boolean canSaveEmail(int subscription) {
+ return getEmailCount(subscription) > 0 ? true : false;
+ }
+
+ public static int getOneSimAnrCount(int sub) {
+ int count = 0;
+ int anrCount = getAnrCount(sub);
+ int adnCount = getAdnCount(sub);
+ if (adnCount > 0) {
+ count = anrCount % adnCount != 0 ? (anrCount / adnCount + 1)
+ : (anrCount / adnCount);
+ }
+ return count;
+ }
+
+ public static int getOneSimEmailCount(int sub) {
+ int count = 0;
+ int emailCount = getEmailCount(sub);
+ int adnCount = getAdnCount(sub);
+ if (adnCount > 0) {
+ count = emailCount % adnCount != 0 ? (emailCount / adnCount + 1)
+ : (emailCount / adnCount);
+ }
+ return count;
+ }
+
+ public static boolean insertToPhone(String[] values, final ContentResolver resolver,int sub) {
+ Account account = getAcount(sub);
+ final String name = values[NAME_POS];
+ final String phoneNumber = values[NUMBER_POS];
+ final String emailAddresses = values[EMAIL_POS];
+ final String anrs = values[ANR_POS];
+
+ final String[] emailAddressArray;
+ final String[] anrArray;
+ boolean success = true;
+ if (!TextUtils.isEmpty(emailAddresses)) {
+ emailAddressArray = emailAddresses.split(",");
+ } else {
+ emailAddressArray = null;
+ }
+ if (!TextUtils.isEmpty(anrs)) {
+ anrArray = anrs.split(SimContactsConstants.ANR_SEP);
+ } else {
+ anrArray = null;
+ }
+ if (DBG) {
+ Log.d(TAG, "insertToPhone: name= " + name + ", phoneNumber= " + phoneNumber
+ + ", emails= " + emailAddresses + ", anrs= " + anrs + ", account= " + account);
+ }
+ final ArrayList<ContentProviderOperation> operationList =
+ new ArrayList<ContentProviderOperation>();
+ ContentProviderOperation.Builder builder = ContentProviderOperation
+ .newInsert(RawContacts.CONTENT_URI);
+ builder.withValue(RawContacts.AGGREGATION_MODE, RawContacts.AGGREGATION_MODE_DISABLED);
+
+ if (account != null) {
+ builder.withValue(RawContacts.ACCOUNT_NAME, account.name);
+ builder.withValue(RawContacts.ACCOUNT_TYPE, account.type);
+ }
+ operationList.add(builder.build());
+
+ // do not allow empty value insert into database.
+ if (!TextUtils.isEmpty(name)) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(StructuredName.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ builder.withValue(StructuredName.DISPLAY_NAME, name);
+ operationList.add(builder.build());
+ }
+
+ if (!TextUtils.isEmpty(phoneNumber)) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ builder.withValue(Phone.TYPE, Phone.TYPE_MOBILE);
+ builder.withValue(Phone.NUMBER, phoneNumber);
+ builder.withValue(Data.IS_PRIMARY, 1);
+ operationList.add(builder.build());
+ }
+
+ if (anrArray != null) {
+ for (String anr : anrArray) {
+ if (!TextUtils.isEmpty(anr)) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Phone.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
+ builder.withValue(Phone.TYPE, Phone.TYPE_HOME);
+ builder.withValue(Phone.NUMBER, anr);
+ operationList.add(builder.build());
+ }
+ }
+ }
+
+ if (emailAddressArray != null) {
+ for (String emailAddress : emailAddressArray) {
+ if (!TextUtils.isEmpty(emailAddress)) {
+ builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+ builder.withValueBackReference(Email.RAW_CONTACT_ID, 0);
+ builder.withValue(Data.MIMETYPE, Email.CONTENT_ITEM_TYPE);
+ builder.withValue(Email.TYPE, Email.TYPE_MOBILE);
+ builder.withValue(Email.ADDRESS, emailAddress);
+ operationList.add(builder.build());
+ }
+ }
+ }
+
+ try {
+ ContentProviderResult[] results =
+ resolver.applyBatch(ContactsContract.AUTHORITY, operationList);
+ for (ContentProviderResult result: results) {
+ if (result.uri == null) {
+ success = false;
+ break;
+ }
+ }
+ return success;
+ } catch (RemoteException e) {
+ Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
+ return false;
+ } catch (OperationApplicationException e) {
+ Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
+ return false;
+ }
+ }
+
+ public static Uri insertToCard(Context context, String name, String number, String emails,
+ String anrNumber, int subscription) {
+ // add the max count limit of Chinese code or not
+ if (!TextUtils.isEmpty(name)) {
+ final int maxLen = hasChinese(name) ? MAX_LENGTH_NAME_WITH_CHINESE_IN_SIM
+ : MAX_LENGTH_NAME_IN_SIM;
+ if (name.length() > maxLen) {
+ name = name.substring(0, maxLen);
+ }
+ }
+ Uri result;
+ ContentValues mValues = new ContentValues();
+ mValues.clear();
+ mValues.put(SimContactsConstants.STR_TAG, name);
+ if (!TextUtils.isEmpty(number)) {
+ number = PhoneNumberUtils.stripSeparators(number);
+ if (number.length() > MAX_LENGTH_NUMBER_IN_SIM) {
+ number = number.substring(0, MAX_LENGTH_NUMBER_IN_SIM);
+ }
+
+ mValues.put(SimContactsConstants.STR_NUMBER, number);
+ }
+ if (!TextUtils.isEmpty(emails)) {
+ mValues.put(SimContactsConstants.STR_EMAILS, emails);
+ }
+ if (!TextUtils.isEmpty(anrNumber)) {
+ anrNumber = anrNumber.replaceAll("[^0123456789PWN\\,\\;\\*\\#\\+\\:]", "");
+ mValues.put(SimContactsConstants.STR_ANRS, anrNumber);
+ }
+
+ SimContactsOperation mSimContactsOperation = new SimContactsOperation(context);
+ result = mSimContactsOperation.insert(mValues, subscription);
+
+ if (result != null) {
+ // we should import the contact to the sim account at the same time.
+ String[] value = new String[] {
+ name, number, emails, anrNumber
+ };
+ insertToPhone(value, context.getContentResolver(),subscription);
+ } else {
+ Log.e(TAG, "export contact: [" + name + ", " + number + ", " + emails + "] to slot "
+ + subscription + " failed");
+ }
+ return result;
+ }
+
+ public static Account getAcount(int sub) {
+ Account account = null;
+ if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+ if (sub == PhoneConstants.SUB1) {
+ account = new Account(SimContactsConstants.SIM_NAME_1,
+ SimContactsConstants.ACCOUNT_TYPE_SIM);
+ } else if (sub == PhoneConstants.SUB2) {
+ account = new Account(SimContactsConstants.SIM_NAME_2,
+ SimContactsConstants.ACCOUNT_TYPE_SIM);
+ }
+ } else {
+ if (sub == PhoneConstants.SUB1) {
+ account = new Account(SimContactsConstants.SIM_NAME,
+ SimContactsConstants.ACCOUNT_TYPE_SIM);
+ }
+ }
+ if (account == null) {
+ account = new Account(SimContactsConstants.PHONE_NAME,
+ SimContactsConstants.ACCOUNT_TYPE_PHONE);
+ }
+ return account;
+ }
+
+ public static int getEnabledSimCount() {
+ int mPhoneCount = TelephonyManager.getDefault().getPhoneCount();
+ int enabledSimCount = 0;
+ for (int i = 0; i < mPhoneCount; i++) {
+ if (TelephonyManager.SIM_STATE_READY == TelephonyManager
+ .getDefault().getSimState(i)) {
+ enabledSimCount++;
+ }
+ }
+ return enabledSimCount;
+ }
+
+ public static int getSimFreeCount(Context context, int sub) {
+ String accountName = getAcount(sub).name;
+ int count = 0;
+
+ if (context == null) {
+ return 0;
+ }
+
+ Cursor queryCursor = context.getContentResolver().query(
+ RawContacts.CONTENT_URI,
+ new String[] {
+ RawContacts._ID
+ },
+ RawContacts.ACCOUNT_NAME + " = '" + accountName + "' AND " + RawContacts.DELETED
+ + " = 0", null, null);
+ if (queryCursor != null) {
+ try {
+ count = queryCursor.getCount();
+ } finally {
+ queryCursor.close();
+ }
+ }
+ return getAdnCount(sub) - count;
+ }
+
+ public static int getSpareAnrCount(int sub) {
+ int anrCount = 0;
+ int[] subId=SubscriptionManager.getSubId(sub);
+ try {
+ IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(ServiceManager
+ .getService(PHONEBOOK));
+ if (iccIpb != null) {
+ if (subId != null
+ && TelephonyManager.getDefault().isMultiSimEnabled()) {
+ anrCount = iccIpb.getSpareAnrCountUsingSubId(subId[0]);
+ } else {
+ anrCount = iccIpb.getSpareAnrCount();
+ }
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ } catch (SecurityException ex) {
+ Log.i(TAG, ex.toString());
+ } catch (Exception ex) {
+ }
+ if (DBG) {
+ Log.d(TAG, "getSpareAnrCount(" + sub + ") = " + anrCount);
+ }
+ return anrCount;
+ }
+
+ public static int getSpareEmailCount(int sub) {
+ int emailCount = 0;
+ int[] subId=SubscriptionManager.getSubId(sub);
+ try {
+ IIccPhoneBook iccIpb = IIccPhoneBook.Stub.asInterface(ServiceManager
+ .getService(PHONEBOOK));
+ if (iccIpb != null) {
+ if (subId != null
+ && TelephonyManager.getDefault().isMultiSimEnabled()) {
+ emailCount = iccIpb.getSpareEmailCountUsingSubId(subId[0]);
+ } else {
+ emailCount = iccIpb.getSpareEmailCount();
+ }
+ }
+ } catch (RemoteException ex) {
+ // ignore it
+ } catch (SecurityException ex) {
+ Log.i(TAG, ex.toString());
+ } catch (Exception ex) {
+ }
+ if (DBG) {
+ Log.d(TAG, "getSpareEmailCount(" + sub + ") = " + emailCount);
+ }
+ return emailCount;
+ }
+
+ private static boolean hasChinese(String name) {
+ return name != null && name.getBytes().length > name.length();
+ }
+
+ /**
+ * Get SIM card aliases name, which defined in Settings
+ */
+ public static String getMultiSimAliasesName(Context context, int subscription) {
+ if (context == null || subscription < 0) {
+ return null;
+ }
+ String name = "";
+ if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+ name = Settings.System.getString(context.getContentResolver(),
+ MULTI_SIM_NAME[subscription]);
+ }
+ if (TextUtils.isEmpty(name)) {
+ name = getSimAccountName(subscription);
+ }
+ return name;
+ }
+
+ /**
+ * Get SIM card icon index by subscription
+ */
+ public static int getCurrentSimIconIndex(Context context, int subscription) {
+ if (context == null || subscription < PhoneConstants.SUB1
+ || subscription >= TelephonyManager.getDefault().getPhoneCount()) {
+ return -1;
+ }
+
+ String simIconIndex = Settings.System.getString(context.getContentResolver(),
+ PREFERRED_SIM_ICON_INDEX);
+ if (TextUtils.isEmpty(simIconIndex)) {
+ return subscription;
+ } else {
+ String[] indexs = simIconIndex.split(",");
+ if (subscription >= indexs.length) {
+ return -1;
+ }
+ return Integer.parseInt(indexs[subscription]);
+ }
+ }
+
+
+ /**
+ * Display IP call setting dialog
+ */
+ public static void showNoIPNumberDialog(final Context mContext, final int subscription) {
+ try {
+ new AlertDialog.Builder(mContext)
+ .setTitle(R.string.no_ip_number)
+ .setMessage(R.string.no_ip_number_on_sim_card)
+ .setPositiveButton(R.string.set_ip_number,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ setIPNumber(mContext, subscription);
+ }
+ }).setNegativeButton(android.R.string.cancel, null).show();
+ } catch (Exception e) {
+ }
+ }
+
+ /**
+ * Setting IP Call number
+ */
+ public static void setIPNumber(final Context mContext, final int subscription) {
+ try {
+ LayoutInflater mInflater = LayoutInflater.from(mContext);
+ View v = mInflater.inflate(R.layout.ip_prefix_dialog, null);
+ final EditText edit = (EditText) v.findViewById(R.id.ip_prefix_dialog_edit);
+ String ip_prefix = Settings.System.getString(mContext.getContentResolver(),
+ IPCALL_PREFIX[subscription]);
+ edit.setText(ip_prefix);
+
+ new AlertDialog.Builder(mContext).setTitle(R.string.ipcall_dialog_title)
+ .setIcon(android.R.drawable.ic_dialog_info).setView(v)
+ .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String ip_prefix = edit.getText().toString();
+ Settings.System.putString(mContext.getContentResolver(),
+ IPCALL_PREFIX[subscription], ip_prefix);
+ }
+ }).setNegativeButton(android.R.string.cancel, null).show();
+ } catch (Exception e) {
+ }
+ }
+
+ /**
+ * Check one SIM card is enabled
+ */
+ public static boolean isMultiSimEnable(Context context, int slotId) {
+ if (Settings.System.getInt(context.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0
+ || TelephonyManager.SIM_STATE_READY != TelephonyManager
+ .getDefault()
+ .getSimState(slotId)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Get IP Call prefix
+ */
+ public static String getIPCallPrefix(Context context, int slot) {
+ String ipCallPrefix = "";
+ if (!TelephonyManager.getDefault().isMultiSimEnabled()) {
+ ipCallPrefix = Settings.System.getString(context.getContentResolver(),
+ "ipcall_prefix");
+ } else {
+ ipCallPrefix = Settings.System.getString(context.getContentResolver(),
+ IPCALL_PREFIX[slot]);
+ }
+ return ipCallPrefix;
+ }
+
+ public static PhoneAccountHandle getAccount(int slot) {
+ ComponentName serviceName = new ComponentName("com.android.phone",
+ "com.android.services.telephony.TelephonyConnectionService");
+ int[] subId = SubscriptionManager.getSubId(slot);
+ return new PhoneAccountHandle(serviceName, String.valueOf(subId[0]));
+ }
}
diff --git a/src/com/android/contacts/common/SimContactsConstants.java b/src/com/android/contacts/common/SimContactsConstants.java
new file mode 100644
index 00000000..9e3510a9
--- /dev/null
+++ b/src/com/android/contacts/common/SimContactsConstants.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015, The Linux Foundation. All Rights Reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+package com.android.contacts.common;
+
+
+public interface SimContactsConstants {
+
+ public static final String SIM_NAME_1 = "SIM1";
+ public static final String SIM_NAME_2 = "SIM2";
+ public static final String SIM_NAME = "SIM";
+ public static final String PHONE_NAME = "PHONE";
+ public static final String ACCOUNT_TYPE_SIM = "com.android.sim";
+ public static final String ACCOUNT_TYPE_PHONE = "com.android.localphone";
+ public static final String ACCOUNT_TYPE = "account_type";
+ public static final String ACCOUNT_NAME = "account_name";
+ public static final String ACCOUNT_DATA = "data_set";
+ public static final String STR_TAG = "tag";
+ public static final String STR_NUMBER = "number";
+ public static final String STR_EMAILS = "emails";
+ public static final String STR_ANRS = "anrs";
+ public static final String STR_NEW_TAG = "newTag";
+ public static final String STR_NEW_NUMBER = "newNumber";
+ public static final String STR_NEW_EMAILS = "newEmails";
+ public static final String STR_NEW_ANRS = "newAnrs";
+ public static final String INTENT_EXPORT_COMPLETE =
+ "com.android.sim.INTENT_EXPORT_COMPLETE";
+ public static final String ANR_SEP = ":";
+ public static final String EMAIL_SEP = ",";
+ public static final String SIM_URI = "content://icc/adn";
+ public static final String SIM_SUB_URI = "content://icc/adn/subId/";
+ public static final String WITHOUT_SIM_FLAG ="no_sim";
+ public static final String IS_CONTACT = "is_contact";
+ public static final String RESULT_KEY = "result";
+ public static final String ACTION_MULTI_PICK =
+ "com.android.contacts.action.MULTI_PICK";
+ public static final String ACTION_MULTI_PICK_EMAIL =
+ "com.android.contacts.action.MULTI_PICK_EMAIL";
+ public static final String ACTION_MULTI_PICK_CALL =
+ "com.android.contacts.action.MULTI_PICK_CALL";
+ public static final String ACTION_MULTI_PICK_SIM =
+ "com.android.contacts.action.MULTI_PICK_SIM";
+}
+
+
diff --git a/src/com/android/contacts/common/SimContactsOperation.java b/src/com/android/contacts/common/SimContactsOperation.java
new file mode 100755
index 00000000..12ce1361
--- /dev/null
+++ b/src/com/android/contacts/common/SimContactsOperation.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2015, The Linux Foundation. All Rights Reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ */
+
+package com.android.contacts.common;
+
+import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.CommonDataKinds;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.RawContacts;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.contacts.common.SimContactsConstants;
+
+public class SimContactsOperation {
+
+ private static final String TAG = "SimContactsOperation";
+ private static final boolean DBG = true;
+ private static final int QUERY_TOKEN = 0;
+ private static final int INSERT_TOKEN = 1;
+ private static final int UPDATE_TOKEN = 2;
+ private static final int DELETE_TOKEN = 3;
+
+ public static final String[] ACCOUNT_PROJECTION = new String[] {
+ RawContacts._ID,
+ RawContacts.CONTACT_ID,
+ RawContacts.ACCOUNT_NAME,
+ RawContacts.ACCOUNT_TYPE,
+ };
+
+
+ private static final int ACCOUNT_COLUMN_RAW_ID = 0;
+ private static final int ACCOUNT_COLUMN_CONTACT_ID = 1;
+ private static final int ACCOUNT_COLUMN_NAME = 2;
+ private static final int ACCOUNT_COLUMN_TYPE = 3;
+ private static final int ACCOUNT_COLUMN_PHONE_NAME = 4;
+
+
+
+ private static Context mContext;
+ private ContentResolver mResolver;
+ private ContentValues mValues = new ContentValues();
+
+
+ public SimContactsOperation(Context context) {
+ this.mContext = context;
+ this.mResolver = context.getContentResolver();
+ }
+
+
+ public Uri insert(ContentValues values, int subscription) {
+
+ Uri uri = getContentUri(subscription);
+ String number = values.getAsString(SimContactsConstants.STR_NUMBER);
+ String anrs = values.getAsString(SimContactsConstants.STR_ANRS);
+ if (!TextUtils.isEmpty(anrs)) {
+ anrs = anrs.replaceAll("[^0123456789PWN\\,\\;\\*\\#\\+\\:]", "");
+ }
+ String emails = values.getAsString(SimContactsConstants.STR_EMAILS);
+ values.put(SimContactsConstants.STR_NUMBER,PhoneNumberUtils.stripSeparators(number));
+ values.put(SimContactsConstants.STR_ANRS,anrs);
+ values.put(SimContactsConstants.STR_EMAILS,emails);
+
+ Uri resultUri;
+ resultUri = mResolver.insert(uri,values);
+ return resultUri;
+ }
+
+ public int update(ContentValues values,int subscription) {
+ Uri uri = getContentUri(subscription);
+
+ int result;
+ String oldNumber = values.getAsString(SimContactsConstants.STR_NUMBER);
+ String newNumber = values.getAsString(SimContactsConstants.STR_NEW_NUMBER);
+ String oldAnrs = values.getAsString(SimContactsConstants.STR_ANRS);
+ String newAnrs = values.getAsString(SimContactsConstants.STR_NEW_ANRS);
+ values.put(SimContactsConstants.STR_NUMBER,PhoneNumberUtils.stripSeparators(oldNumber));
+ values.put(SimContactsConstants.STR_NEW_NUMBER,PhoneNumberUtils.stripSeparators(newNumber));
+ if (!TextUtils.isEmpty(oldAnrs)) {
+ oldAnrs = oldAnrs.replaceAll("[^0123456789PWN\\,\\;\\*\\#\\+\\:]", "");
+ }
+ if (!TextUtils.isEmpty(newAnrs)) {
+ newAnrs = newAnrs.replaceAll("[^0123456789PWN\\,\\;\\*\\#\\+\\:]", "");
+ }
+ values.put(SimContactsConstants.STR_ANRS,oldAnrs);
+ values.put(SimContactsConstants.STR_NEW_ANRS,newAnrs);
+
+ result = mResolver.update(uri,values,null,null);
+ return result;
+
+ }
+
+ public int delete(ContentValues values, int subscription) {
+ int result;
+ StringBuilder buf = new StringBuilder();
+ String num = null;
+ String name = values.getAsString(SimContactsConstants.STR_TAG);
+ String number = values.getAsString(SimContactsConstants.STR_NUMBER);
+ String emails = values.getAsString(SimContactsConstants.STR_EMAILS);
+ String anrs = values.getAsString(SimContactsConstants.STR_ANRS);
+ if (number != null)
+ num = PhoneNumberUtils.stripSeparators(number);
+ if (anrs != null)
+ anrs = anrs.replaceAll("[^0123456789PWN\\,\\;\\*\\#\\+\\:]", "");
+ Uri uri = getContentUri(subscription);
+
+
+ if (!TextUtils.isEmpty(name)) {
+ buf.append("tag='");
+ buf.append(name);
+ buf.append("'");
+ }
+ if (!TextUtils.isEmpty(num)) {
+ buf.append(" AND number='");
+ buf.append(num);
+ buf.append("'");
+ }
+ if (!TextUtils.isEmpty(emails)) {
+ buf.append(" AND emails='");
+ buf.append(emails);
+ buf.append("'");
+ }
+ if (!TextUtils.isEmpty(anrs)) {
+ buf.append(" AND anrs='");
+ buf.append(anrs);
+ buf.append("'");
+ }
+
+ result = mResolver.delete(uri,buf.toString(),null);
+ return result;
+
+ }
+
+ private Uri getContentUri(int subscription) {
+ Uri uri = null;
+ int[] subId = SubscriptionManager.getSubId(subscription);
+
+ if (subId != null && TelephonyManager.from(mContext).isMultiSimEnabled()) {
+ uri = Uri.parse(SimContactsConstants.SIM_SUB_URI + subId[0]);
+ } else {
+ uri = Uri.parse(SimContactsConstants.SIM_URI);
+ }
+ return uri;
+ }
+
+ private static Cursor setupAccountCursor(long contactId) {
+ ContentResolver resolver = mContext.getContentResolver();
+
+ Cursor cursor = null;
+ try {
+ cursor = resolver.query(RawContacts.CONTENT_URI,
+ ACCOUNT_PROJECTION,
+ RawContacts.CONTACT_ID + "="
+ + Long.toString(contactId), null, null);
+ } catch (Exception e) {
+ Log.e(TAG, e.getMessage());
+ } finally {
+ if (cursor != null && cursor.moveToFirst()) {
+ return cursor;
+ }
+ if (cursor != null) {
+ cursor.close();
+ }
+ cursor = null;
+ return null;
+ }
+ }
+
+ public static ContentValues getSimAccountValues(long contactId) {
+ ContentValues mValues = new ContentValues();
+ Cursor cursor = setupAccountCursor(contactId);
+ if (cursor == null || cursor.getCount() == 0) {
+ mValues.clear();
+ return mValues;
+ }
+ long rawContactId = cursor.getLong(cursor.getColumnIndex(RawContacts._ID));
+ String accountName = cursor.getString(cursor.getColumnIndex(RawContacts.ACCOUNT_NAME));
+ String accountType = cursor.getString(cursor.getColumnIndex(RawContacts.ACCOUNT_TYPE));
+ cursor.close();
+ if (SimContactsConstants.ACCOUNT_TYPE_SIM.equals(accountType)) {
+ mValues.clear();
+ String name = getContactItems(rawContactId,StructuredName.CONTENT_ITEM_TYPE,
+ ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
+ mValues.put(SimContactsConstants.STR_TAG,name);
+
+ String number = getContactPhoneNumber(rawContactId,
+ Phone.CONTENT_ITEM_TYPE, String.valueOf(Phone.TYPE_MOBILE),
+ ContactsContract.CommonDataKinds.Phone.DATA);
+ mValues.put(SimContactsConstants.STR_NUMBER,number);
+
+ int sub = getSimSubscription(contactId);
+
+ if (MoreContactUtils.canSaveAnr(sub)) {
+ String anrs = getContactPhoneNumber(rawContactId,
+ Phone.CONTENT_ITEM_TYPE, String.valueOf(Phone.TYPE_HOME),
+ ContactsContract.CommonDataKinds.Phone.DATA);
+ mValues.put(SimContactsConstants.STR_ANRS, anrs);
+ }
+
+ if (MoreContactUtils.canSaveEmail(sub)) {
+ String emails = getContactItems(rawContactId,
+ Email.CONTENT_ITEM_TYPE, ContactsContract.CommonDataKinds.Email.DATA);
+ mValues.put(SimContactsConstants.STR_EMAILS, emails);
+ }
+ }
+ return mValues;
+ }
+
+ public static int getSimSubscription(long contactId) {
+ int subscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ Cursor cursor = setupAccountCursor(contactId);
+ if (cursor == null || cursor.getCount() == 0) {
+ return subscription;
+ }
+
+ String accountName = cursor.getString(cursor.getColumnIndex(RawContacts.ACCOUNT_NAME));
+ String accountType = cursor.getString(cursor.getColumnIndex(RawContacts.ACCOUNT_TYPE));
+ if (accountType == null || accountName == null) {
+ return subscription;
+ }
+ if (SimContactsConstants.ACCOUNT_TYPE_SIM.equals(accountType)) {
+ subscription = MoreContactUtils.getSubscription(accountType, accountName);
+ }
+ cursor.close();
+ return subscription;
+ }
+
+
+ private static String getContactItems(long rawContactId, String selectionArg,
+ String columnName) {
+ StringBuilder retval = new StringBuilder();
+ Uri baseUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
+ Uri dataUri = Uri.withAppendedPath(baseUri, RawContacts.Data.CONTENT_DIRECTORY);
+
+ Cursor c = null;
+ try {
+ c = mContext.getContentResolver().query(dataUri, null,
+ Data.MIMETYPE + "=?", new String[] {selectionArg}, null);
+ if (c == null || c.getCount() == 0) {
+ if(c != null) {
+ c.close();
+ }
+ return null;
+ }
+ c.moveToPosition(-1);
+
+ while (c.moveToNext()) {
+ if (!TextUtils.isEmpty(retval.toString())) {
+ retval.append(SimContactsConstants.EMAIL_SEP);
+ }
+ String value = c.getString(c.getColumnIndex(columnName));
+ if (!TextUtils.isEmpty(value)) {
+ retval.append(value);
+ }
+ }
+
+ } catch (Exception e) {
+ Log.e(TAG, e.getMessage());
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+
+ return retval.toString();
+ }
+
+ private static
+ String getContactPhoneNumber(long rawContactId, String selectionArg1,
+ String selectionArg2, String columnName) {
+ StringBuilder retval = new StringBuilder();
+ Uri baseUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
+ Uri dataUri = Uri.withAppendedPath(baseUri, RawContacts.Data.CONTENT_DIRECTORY);
+
+ Cursor c = null;
+ try {
+ c = mContext.getContentResolver().query(dataUri, null,
+ Data.MIMETYPE + "=? AND " + Phone.TYPE + "=?",
+ new String[] {selectionArg1,selectionArg2}, null);
+ if (c == null || c.getCount() == 0) {
+ if(c != null) {
+ c.close();
+ }
+ return null;
+ }
+ c.moveToPosition(-1);
+
+ while (c.moveToNext()) {
+ if (!TextUtils.isEmpty(retval.toString())) {
+ retval.append(SimContactsConstants.ANR_SEP);
+ }
+ retval.append(c.getString(c.getColumnIndex(columnName)));
+ }
+
+ } catch (Exception e) {
+ Log.e(TAG, e.getMessage());
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+
+ return retval.toString();
+ }
+
+}
diff --git a/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java b/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java
index c2ebbbfa..26fc7712 100644
--- a/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java
+++ b/src/com/android/contacts/common/editor/SelectAccountDialogFragment.java
@@ -65,7 +65,7 @@ public final class SelectAccountDialogFragment extends DialogFragment {
final SelectAccountDialogFragment instance = new SelectAccountDialogFragment();
instance.setArguments(args);
instance.setTargetFragment(targetFragment, 0);
- instance.show(fragmentManager, null);
+ instance.show(fragmentManager, SelectAccountDialogFragment.TAG);
}
@Override
diff --git a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
index 6553627f..d37b93f1 100644..100755
--- a/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/common/interactions/ImportExportDialogFragment.java
@@ -16,20 +16,41 @@
package com.android.contacts.common.interactions;
+import android.accounts.Account;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.FragmentManager;
+import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.ContentProviderOperation;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
+import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Resources;
+import android.content.OperationApplicationException;
import android.database.Cursor;
+import android.text.TextUtils;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.Settings;
import android.telephony.PhoneNumberUtils;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -43,8 +64,13 @@ import android.widget.ArrayAdapter;
import android.widget.TextView;
import android.widget.Toast;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.SimContactsOperation;
+import com.android.contacts.common.SimContactsConstants;
import com.android.contacts.common.R;
import com.android.contacts.common.editor.SelectAccountDialogFragment;
+import com.android.contacts.common.list.AccountFilterActivity;
+import com.android.contacts.common.list.ContactListFilter;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.util.AccountSelectionUtil;
@@ -53,8 +79,11 @@ import com.android.contacts.common.util.ImplicitIntentsUtil;
import com.android.contacts.common.vcard.ExportVCardActivity;
import com.android.contacts.common.vcard.VCardCommonArguments;
import com.android.contacts.commonbind.analytics.AnalyticsUtil;
+import com.android.internal.telephony.PhoneConstants;
import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
/**
* An dialog invoked to import/export contacts.
@@ -67,10 +96,67 @@ public class ImportExportDialogFragment extends DialogFragment
private static final String KEY_SUBSCRIPTION_ID = "subscriptionId";
private static final String ARG_CONTACTS_ARE_AVAILABLE = "CONTACTS_ARE_AVAILABLE";
+ private static final boolean DEBUG = true;
+
+ public static final int SUBACTIVITY_EXPORT_CONTACTS = 100;
+
+ // This values must be consistent with ImportExportDialogFragment.SUBACTIVITY_EXPORT_CONTACTS.
+ // This values is set 101,That is avoid to conflict with other new subactivity.
+ public static final int SUBACTIVITY_SHARE_VISILBLE_CONTACTS = 101;
+ public static final int MAX_COUNT_ALLOW_SHARE_CONTACT = 2000;
+
private final String[] LOOKUP_PROJECTION = new String[] {
Contacts.LOOKUP_KEY
};
+ static final int PHONE_ID_COLUMN_INDEX = 0;
+ static final int PHONE_TYPE_COLUMN_INDEX = 1;
+ static final int PHONE_LABEL_COLUMN_INDEX = 2;
+ static final int PHONE_NUMBER_COLUMN_INDEX = 3;
+ static final int PHONE_DISPLAY_NAME_COLUMN_INDEX = 4;
+ static final int PHONE_CONTACT_ID_COLUMN_INDEX = 5;
+ // This value needs to start at 7. See {@link PeopleActivity}.
+ public static final int SUBACTIVITY_MULTI_PICK_CONTACT = 7;
+ //TODO: we need to refactor the export code in future release.
+ // QRD enhancement: export subscription selected by user
+ public static int mExportSub;
+ //this flag is the same as defined in MultiPickContactActivit
+ private static final String EXT_NOT_SHOW_SIM_FLAG = "not_sim_show";
+ // QRD enhancement: Toast handler for exporting concat to sim card
+ private static final int TOAST_EXPORT_FAILED = 0;
+ private static final int TOAST_EXPORT_FINISHED = 1;
+ // only for sim card is full
+ private static final int TOAST_SIM_CARD_FULL = 2;
+ // only for contact name too long
+ private static final int TOAST_CONTACT_NAME_TOO_LONG = 3;
+ // there is a case export is canceled by user
+ private static final int TOAST_EXPORT_CANCELED = 4;
+ // only for not have phone number or email address
+ private static final int TOAST_EXPORT_NO_PHONE_OR_EMAIL = 5;
+ // only for sim contacts haven't been loaded completely
+ private static final int TOAST_SIM_CARD_NOT_LOAD_COMPLETE = 6;
+ private SimContactsOperation mSimContactsOperation;
+ private ArrayAdapter<AdapterEntry> mAdapter;
+ private Activity mActivity;
+ private static boolean isExportingToSIM = false;
+ public static boolean isExportingToSIM(){
+ return isExportingToSIM;
+ }
+ private static ExportToSimThread mExportThread = null;
+ public ExportToSimThread createExportToSimThread(int subscription,
+ ArrayList<String[]> contactList, Activity mActivity) {
+ if (mExportThread == null)
+ mExportThread = new ExportToSimThread(subscription, contactList, mActivity);
+ return mExportThread;
+ }
+
+ public static void destroyExportToSimThread(){
+ mExportThread = null;
+ }
+ public void showExportToSIMProgressDialog(Activity activity){
+ mExportThread.showExportProgressDialog(activity);
+ }
+
private SubscriptionManager mSubscriptionManager;
/** Preferred way to show this dialog */
@@ -93,6 +179,7 @@ public class ImportExportDialogFragment extends DialogFragment
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Wrap our context to inflate list items using the correct theme
+ mActivity = getActivity();
final Resources res = getActivity().getResources();
final LayoutInflater dialogInflater = (LayoutInflater)getActivity()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -101,7 +188,7 @@ public class ImportExportDialogFragment extends DialogFragment
VCardCommonArguments.ARG_CALLING_ACTIVITY);
// Adapter that shows a list of string resources
- final ArrayAdapter<AdapterEntry> adapter = new ArrayAdapter<AdapterEntry>(getActivity(),
+ mAdapter = new ArrayAdapter<AdapterEntry>(getActivity(),
R.layout.select_dialog_item) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
@@ -113,170 +200,138 @@ public class ImportExportDialogFragment extends DialogFragment
}
};
- final TelephonyManager manager =
- (TelephonyManager) getActivity().getSystemService(Context.TELEPHONY_SERVICE);
-
- mSubscriptionManager = SubscriptionManager.from(getActivity());
-
- if (res.getBoolean(R.bool.config_allow_import_from_vcf_file)) {
- adapter.add(new AdapterEntry(getString(R.string.import_from_vcf_file),
- R.string.import_from_vcf_file));
- }
- if (manager != null && res.getBoolean(R.bool.config_allow_sim_import)) {
- List<SubscriptionInfo> subInfoRecords = null;
- try {
- subInfoRecords = mSubscriptionManager.getActiveSubscriptionInfoList();
- } catch (SecurityException e) {
- Log.w(TAG, "SecurityException thrown, lack permission for"
- + " getActiveSubscriptionInfoList", e);
- }
- if (subInfoRecords != null) {
- if (subInfoRecords.size() == 1) {
- adapter.add(new AdapterEntry(getString(R.string.manage_sim_contacts),
- R.string.manage_sim_contacts,
- subInfoRecords.get(0).getSubscriptionId()));
- adapter.add(new AdapterEntry(getString(R.string.export_to_sim),
- R.string.export_to_sim,
- subInfoRecords.get(0).getSubscriptionId()));
- } else {
- for (SubscriptionInfo record : subInfoRecords) {
- adapter.add(new AdapterEntry(getSubDescription(record, true),
- R.string.manage_sim_contacts, record.getSubscriptionId()));
- adapter.add(new AdapterEntry(getSubDescription(record, false),
- R.string.export_to_sim, record.getSubscriptionId()));
- }
- }
- }
- }
- if (res.getBoolean(R.bool.config_allow_export)) {
- if (contactsAreAvailable) {
- adapter.add(new AdapterEntry(getString(R.string.export_to_vcf_file),
- R.string.export_to_vcf_file));
- }
- }
- if (res.getBoolean(R.bool.config_allow_share_visible_contacts)) {
- if (contactsAreAvailable) {
- adapter.add(new AdapterEntry(getString(R.string.share_visible_contacts),
- R.string.share_visible_contacts));
- }
- }
+ // Manually call notifyDataSetChanged() to refresh the list.
+ mAdapter.setNotifyOnChange(false);
+ loadData(contactsAreAvailable);
final DialogInterface.OnClickListener clickListener =
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- boolean dismissDialog;
- final int resId = adapter.getItem(which).mChoiceResourceId;
+ final int resId = mAdapter.getItem(which).mChoiceResourceId;
switch (resId) {
- case R.string.manage_sim_contacts:
+ case R.string.import_from_sim: {
+ handleImportFromSimRequest(resId);
+ break;
+ }
case R.string.import_from_vcf_file: {
- dismissDialog = handleImportRequest(resId,
- adapter.getItem(which).mSubscriptionId);
+ handleImportRequest(resId);
+ break;
+ }
+ case R.string.export_to_sim: {
+ handleExportToSimRequest(resId);
break;
}
case R.string.export_to_vcf_file: {
- dismissDialog = true;
- Intent exportIntent = new Intent(getActivity(), ExportVCardActivity.class);
- exportIntent.putExtra(VCardCommonArguments.ARG_CALLING_ACTIVITY,
- callingActivity);
- getActivity().startActivity(exportIntent);
+ Intent exportIntent = new Intent(SimContactsConstants.ACTION_MULTI_PICK,
+ Contacts.CONTENT_URI);
+ exportIntent.putExtra(SimContactsConstants.IS_CONTACT, true);
+ getActivity().startActivityForResult(exportIntent,
+ SUBACTIVITY_EXPORT_CONTACTS);
break;
}
case R.string.share_visible_contacts: {
- dismissDialog = true;
doShareVisibleContacts();
break;
}
- case R.string.export_to_sim: {
- dismissDialog = true;
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setClassName("com.android.phone",
- "com.android.phone.ExportContactsToSim");
- intent.putExtra("subscription_id", adapter.getItem(which).mSubscriptionId);
- startActivity(intent);
- break;
- }
default: {
- dismissDialog = true;
Log.e(TAG, "Unexpected resource: "
+ getActivity().getResources().getResourceEntryName(resId));
}
}
- if (dismissDialog) {
- dialog.dismiss();
- }
+ dialog.dismiss();
}
};
return new AlertDialog.Builder(getActivity())
.setTitle(contactsAreAvailable
? R.string.dialog_import_export
: R.string.dialog_import)
- .setSingleChoiceItems(adapter, -1, clickListener)
+ .setSingleChoiceItems(mAdapter, -1, clickListener)
.create();
}
- private void doShareVisibleContacts() {
- try {
- // TODO move the query into a loader and do this in a background thread
- final Cursor cursor = getActivity().getContentResolver().query(Contacts.CONTENT_URI,
- LOOKUP_PROJECTION, Contacts.IN_VISIBLE_GROUP + "!=0", null, null);
- if (cursor != null) {
- try {
- if (!cursor.moveToFirst()) {
- Toast.makeText(getActivity(), R.string.share_error, Toast.LENGTH_SHORT)
- .show();
- return;
- }
+ /**
+ * Loading the menu list data.
+ * @param contactsAreAvailable
+ */
+ private void loadData(boolean contactsAreAvailable) {
+ if (null == mActivity && null == mAdapter) {
+ return;
+ }
- StringBuilder uriListBuilder = new StringBuilder();
- int index = 0;
- do {
- if (index != 0)
- uriListBuilder.append(':');
- uriListBuilder.append(cursor.getString(0));
- index++;
- } while (cursor.moveToNext());
- Uri uri = Uri.withAppendedPath(
- Contacts.CONTENT_MULTI_VCARD_URI,
- Uri.encode(uriListBuilder.toString()));
-
- final Intent intent = new Intent(Intent.ACTION_SEND);
- intent.setType(Contacts.CONTENT_VCARD_TYPE);
- intent.putExtra(Intent.EXTRA_STREAM, uri);
- ImplicitIntentsUtil.startActivityOutsideApp(getActivity(), intent);
- } finally {
- cursor.close();
- }
+ mAdapter.clear();
+ final Resources res = mActivity.getResources();
+ boolean hasIccCard = false;
+ if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+ for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+ hasIccCard = TelephonyManager.getDefault().hasIccCard(i);
+ if (hasIccCard) {
+ break;
+ }
+ }
+ } else {
+ hasIccCard = TelephonyManager.getDefault().hasIccCard();
+ }
+
+ if (hasIccCard
+ && res.getBoolean(R.bool.config_allow_sim_import)) {
+ mAdapter.add(new AdapterEntry(getString(R.string.import_from_sim),
+ R.string.import_from_sim));
+ }
+ if (res.getBoolean(R.bool.config_allow_import_from_vcf_file)) {
+ mAdapter.add(new AdapterEntry(getString(R.string.import_from_vcf_file),
+ R.string.import_from_vcf_file));
+ }
+
+ if (hasIccCard) {
+ mAdapter.add(new AdapterEntry(getString(R.string.export_to_sim),
+ R.string.export_to_sim));
+ }
+ if (res.getBoolean(R.bool.config_allow_export)) {
+ // If contacts are available and there is at least one contact in
+ // database, show "Export to SD card" menu item. Otherwise hide it
+ // because it makes no sense.
+ if (contactsAreAvailable) {
+ mAdapter.add(new AdapterEntry(getString(R.string.export_to_vcf_file),
+ R.string.export_to_vcf_file));
+ }
+ }
+ if (res.getBoolean(R.bool.config_allow_share_visible_contacts)) {
+ if (contactsAreAvailable) {
+ mAdapter.add(new AdapterEntry(getString(R.string.share_visible_contacts),
+ R.string.share_visible_contacts));
}
- } catch (Exception e) {
- Log.e(TAG, "Sharing visible contacts failed", e);
- Toast.makeText(getContext(), R.string.share_visible_contacts_failure,
- Toast.LENGTH_SHORT).show();
}
}
+ private void doShareVisibleContacts() {
+ Intent intent = new Intent(SimContactsConstants.ACTION_MULTI_PICK);
+ intent.setType(Contacts.CONTENT_TYPE);
+ intent.putExtra(SimContactsConstants.IS_CONTACT,true);
+ getActivity().startActivityForResult(intent, SUBACTIVITY_SHARE_VISILBLE_CONTACTS);
+ }
+
/**
* Handle "import from SIM" and "import from SD".
*
* @return {@code true} if the dialog show be closed. {@code false} otherwise.
*/
- private boolean handleImportRequest(int resId, int subscriptionId) {
+ private boolean handleImportRequest(int resId) {
// There are three possibilities:
// - more than one accounts -> ask the user
// - just one account -> use the account without asking the user
// - no account -> use phone-local storage without asking the user
- final AccountTypeManager accountTypes = AccountTypeManager.getInstance(getActivity());
+ final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mActivity);
final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
final int size = accountList.size();
if (size > 1) {
// Send over to the account selector
final Bundle args = new Bundle();
args.putInt(KEY_RES_ID, resId);
- args.putInt(KEY_SUBSCRIPTION_ID, subscriptionId);
- SelectAccountDialogFragment.show(
- getFragmentManager(), this,
- R.string.dialog_new_contact_account,
- AccountListFilter.ACCOUNTS_CONTACT_WRITABLE, args);
+ SelectAccountDialogFragment.show(mActivity.getFragmentManager(),
+ this, R.string.dialog_new_contact_account,
+ AccountListFilter.ACCOUNTS_CONTACT_WRITABLE_WITHOUT_SIM,
+ args);
// In this case, because this DialogFragment is used as a target fragment to
// SelectAccountDialogFragment, we can't close it yet. We close the dialog when
@@ -284,8 +339,8 @@ public class ImportExportDialogFragment extends DialogFragment
return false;
}
- AccountSelectionUtil.doImport(getActivity(), resId,
- (size == 1 ? accountList.get(0) : null), subscriptionId);
+ AccountSelectionUtil.doImport(mActivity, resId,
+ (size == 1 ? accountList.get(0) : null));
return true; // Close the dialog.
}
@@ -294,8 +349,7 @@ public class ImportExportDialogFragment extends DialogFragment
*/
@Override
public void onAccountChosen(AccountWithDataSet account, Bundle extraArgs) {
- AccountSelectionUtil.doImport(getActivity(), extraArgs.getInt(KEY_RES_ID),
- account, extraArgs.getInt(KEY_SUBSCRIPTION_ID));
+ AccountSelectionUtil.doImport(mActivity, extraArgs.getInt(KEY_RES_ID), account);
// At this point the dialog is still showing (which is why we can use getActivity() above)
// So close it.
@@ -308,6 +362,478 @@ public class ImportExportDialogFragment extends DialogFragment
dismiss();
}
+ private class ExportToSimSelectListener implements DialogInterface.OnClickListener {
+ public void onClick(DialogInterface dialog, int which) {
+ if (which >= 0) {
+ mExportSub = which;
+ } else if (which == DialogInterface.BUTTON_POSITIVE) {
+ Intent pickPhoneIntent = new Intent(
+ SimContactsConstants.ACTION_MULTI_PICK, Contacts.CONTENT_URI);
+ // do not show the contacts in SIM card
+ pickPhoneIntent.putExtra(AccountFilterActivity.KEY_EXTRA_CONTACT_LIST_FILTER,
+ ContactListFilter
+ .createFilterWithType(ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS));
+ pickPhoneIntent.putExtra(EXT_NOT_SHOW_SIM_FLAG, true);
+ pickPhoneIntent.putExtra(SimContactsConstants.IS_CONTACT,true);
+ mActivity.startActivityForResult(pickPhoneIntent, SUBACTIVITY_MULTI_PICK_CONTACT);
+ }
+ }
+ }
+
+ public class ImportFromSimSelectListener implements DialogInterface.OnClickListener {
+ public void onClick(DialogInterface dialog, int which) {
+ if (which >= 0) {
+ AccountSelectionUtil.setImportSubscription(which);
+ } else if (which == DialogInterface.BUTTON_POSITIVE) {
+ handleImportRequest(R.string.import_from_sim);
+ }
+ }
+ }
+
+ /**
+ * A thread that export contacts to sim card
+ */
+ public class ExportToSimThread extends Thread {
+ private int subscription;
+ private boolean canceled;
+ private ArrayList<String[]> contactList;
+ private ProgressDialog mExportProgressDlg;
+ private ContentValues mValues = new ContentValues();
+ Activity mPeople;
+ private int freeSimCount = 0;
+
+ public ExportToSimThread(int subscription, ArrayList<String[]> contactList,
+ Activity mActivity) {
+ super();
+ this.subscription = subscription;
+ this.contactList = contactList;
+ canceled = false;
+ mPeople = mActivity;
+ showExportProgressDialog(mPeople);
+ }
+
+ @Override
+ public void run() {
+ isExportingToSIM = true;
+ Account account = MoreContactUtils.getAcount(subscription);
+ boolean isAirplaneMode = false;
+ boolean isSimCardFull = false;
+ boolean isSimCardLoaded = true;
+ // GoogleSource.createMyContactsIfNotExist(account, getActivity());
+ // in case export is stopped, record the count of inserted successfully
+ int insertCount = 0;
+
+ mSimContactsOperation = new SimContactsOperation(mPeople);
+ Cursor cr = null;
+ // call query first, otherwise insert will fail if this insert is called
+ // without any query before
+ try{
+ int[] subId = SubscriptionManager.getSubId(subscription);
+ if (subId != null
+ && TelephonyManager.getDefault().isMultiSimEnabled()) {
+ cr = mPeople.getContentResolver().query(
+ Uri.parse(SimContactsConstants.SIM_SUB_URI
+ + subId[0]), null, null, null, null);
+ } else {
+ cr = mPeople.getContentResolver().query(
+ Uri.parse(SimContactsConstants.SIM_URI), null,
+ null, null, null);
+ }
+ } catch (NullPointerException e) {
+ Log.e(TAG, "Exception:" + e);
+ } finally {
+ if (cr != null) {
+ cr.close();
+ }
+ }
+ freeSimCount = MoreContactUtils.getSimFreeCount(mPeople,subscription);
+ boolean canSaveAnr = MoreContactUtils.canSaveAnr(subscription);
+ boolean canSaveEmail = MoreContactUtils.canSaveEmail(subscription);
+ int emptyAnr = MoreContactUtils.getSpareAnrCount(subscription);
+ int emptyEmail = MoreContactUtils
+ .getSpareEmailCount(subscription);
+ int emptyNumber = freeSimCount + emptyAnr;
+
+ Log.d(TAG, "freeSimCount = " + freeSimCount);
+ String emails = null;
+ if (contactList != null) {
+ Iterator<String[]> iterator = contactList.iterator();
+ while (iterator.hasNext() && !canceled && !isAirplaneMode && isSimCardLoaded) {
+ String[] contactInfo = iterator.next();
+ //contacts name has been existed in contactInfo,so no need query it again
+ String name = contactInfo[4];
+ ArrayList<String> arrayNumber = new ArrayList<String>();
+ ArrayList<String> arrayEmail = new ArrayList<String>();
+
+ Uri dataUri = Uri.withAppendedPath(
+ ContentUris.withAppendedId(Contacts.CONTENT_URI,
+ Long.parseLong(contactInfo[1])),
+ Contacts.Data.CONTENT_DIRECTORY);
+ final String[] projection = new String[] {
+ Contacts._ID, Contacts.Data.MIMETYPE, Contacts.Data.DATA1,
+ };
+ Cursor c = mPeople.getContentResolver().query(dataUri, projection, null,
+ null, null);
+
+ if (c != null && c.moveToFirst()) {
+ do {
+ String mimeType = c.getString(1);
+ if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ String number = c.getString(2);
+ if (!TextUtils.isEmpty(number) && emptyNumber-- >0) {
+ arrayNumber.add(number);
+ }
+ }
+ if (canSaveEmail) {
+ if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
+ String email = c.getString(2);
+ if (!TextUtils.isEmpty(email) && emptyEmail-- > 0) {
+ arrayEmail.add(email);
+ }
+ }
+ }
+ } while (c.moveToNext());
+ }
+ if (c != null) {
+ c.close();
+ }
+
+ if (freeSimCount > 0 && 0 == arrayNumber.size()
+ && 0 == arrayEmail.size()) {
+ mToastHandler.sendMessage(mToastHandler.obtainMessage(
+ TOAST_EXPORT_NO_PHONE_OR_EMAIL, name));
+ continue;
+ }
+
+ int phoneCountInOneSimContact = 1;
+ int emailCountInOneSimContact = 0;
+ if (canSaveAnr) {
+ int num = MoreContactUtils.getOneSimAnrCount(subscription);
+ phoneCountInOneSimContact = num > 1 ? (num + 1) : 2;
+ }
+ if (canSaveEmail) {
+ emailCountInOneSimContact = MoreContactUtils
+ .getOneSimEmailCount(subscription);
+ }
+ int nameCount = (name != null && !name.equals("")) ? 1 : 0;
+ int groupNumCount = (arrayNumber.size() % phoneCountInOneSimContact) != 0 ?
+ (arrayNumber.size() / phoneCountInOneSimContact + 1)
+ : (arrayNumber.size() / phoneCountInOneSimContact);
+ int groupEmailCount = emailCountInOneSimContact == 0 ? 0
+ : ((arrayEmail.size() % emailCountInOneSimContact) != 0 ? (
+ arrayEmail.size() / emailCountInOneSimContact + 1)
+ : (arrayEmail.size() / emailCountInOneSimContact));
+ //recalute the group when spare anr is not enough
+ if (canSaveAnr && emptyAnr >=0 && emptyAnr <= groupNumCount) {
+ groupNumCount = arrayNumber.size() - emptyAnr;
+ }
+ int groupCount = Math.max(groupEmailCount,
+ Math.max(nameCount, groupNumCount));
+
+ Uri result = null;
+ if (DEBUG) {
+ Log.d(TAG, "GroupCount = " + groupCount);
+ }
+ for (int i = 0; i < groupCount; i++) {
+ if (freeSimCount > 0) {
+ String num = arrayNumber.size() > 0 ? arrayNumber.remove(0) : null;
+ StringBuilder anrNum = new StringBuilder();
+ StringBuilder email = new StringBuilder();
+ if (canSaveAnr) {
+ for (int j = 1; j < phoneCountInOneSimContact; j++) {
+ if (arrayNumber.size() > 0 && emptyAnr-- > 0 ) {
+ String s = arrayNumber.remove(0);
+ if (s.length() > MoreContactUtils
+ .MAX_LENGTH_NUMBER_IN_SIM) {
+ s = s.substring(0,
+ MoreContactUtils.MAX_LENGTH_NUMBER_IN_SIM);
+ }
+ anrNum.append(s);
+ anrNum.append(SimContactsConstants.ANR_SEP);
+ }
+ }
+ }
+ if (canSaveEmail) {
+ for (int j = 0; j < emailCountInOneSimContact; j++) {
+ if (arrayEmail.size() > 0) {
+ String s = arrayEmail.remove(0);
+ if (s.length() > MoreContactUtils
+ .MAX_LENGTH_EMAIL_IN_SIM) {
+ s = s.substring(0,
+ MoreContactUtils.MAX_LENGTH_EMAIL_IN_SIM);
+ }
+ email.append(s);
+ email.append(SimContactsConstants.EMAIL_SEP);
+ }
+ }
+ }
+
+ result = MoreContactUtils.insertToCard(mPeople, name, num,
+ email.toString(), anrNum.toString(), subscription);
+
+ if (null == result) {
+ // add toast handler when sim card is full
+ if ((MoreContactUtils.getAdnCount(subscription) > 0)
+ && (MoreContactUtils.getSimFreeCount(mPeople,
+ subscription) == 0)) {
+ isSimCardFull = true;
+ mToastHandler.sendMessage(mToastHandler.obtainMessage(
+ TOAST_SIM_CARD_FULL, insertCount, 0));
+ break;
+ } else {
+ isAirplaneMode = MoreContactUtils
+ .isAPMOnAndSIMPowerDown(mPeople);
+ if (isAirplaneMode) {
+ mToastHandler.sendMessage(mToastHandler.obtainMessage(
+ 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;
+ }
+ }
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Exported contact [" + name + ", "
+ + contactInfo[0] + ", " + contactInfo[1]
+ + "] to sub " + subscription);
+ }
+ insertCount++;
+ freeSimCount--;
+ }
+ } else {
+ if (MoreContactUtils.getAdnCount(subscription) == 0) {
+ isSimCardLoaded = false;
+ mToastHandler.sendEmptyMessage(
+ TOAST_SIM_CARD_NOT_LOAD_COMPLETE);
+ } else {
+ isSimCardFull = true;
+ mToastHandler.sendMessage(mToastHandler.obtainMessage(
+ TOAST_SIM_CARD_FULL, insertCount, 0));
+ }
+ break;
+ }
+ }
+
+ if (isSimCardFull) {
+ break;
+ }
+ }
+ }
+ if (mExportProgressDlg != null) {
+ mExportProgressDlg.dismiss();
+ mExportProgressDlg = null;
+ }
+
+ if (!isAirplaneMode && !isSimCardFull) {
+ // if canceled, show toast indicating export is interrupted.
+ if (canceled) {
+ mToastHandler.sendMessage(mToastHandler.obtainMessage(TOAST_EXPORT_CANCELED,
+ insertCount, 0));
+ } else {
+ mToastHandler.sendEmptyMessage(TOAST_EXPORT_FINISHED);
+ }
+ }
+ isExportingToSIM = false;
+ Intent intent = new Intent(SimContactsConstants.INTENT_EXPORT_COMPLETE);
+ mPeople.sendBroadcast(intent);
+ }
+
+ private Handler mToastHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ int exportCount = 0;
+ switch (msg.what) {
+ case TOAST_EXPORT_FAILED:
+ exportCount = msg.arg1;
+ Toast.makeText(mPeople, mPeople.getString(R.string.export_to_sim_failed,
+ exportCount), Toast.LENGTH_SHORT).show();
+ break;
+ case TOAST_EXPORT_FINISHED:
+ Toast.makeText(mPeople, R.string.export_finished, Toast.LENGTH_SHORT)
+ .show();
+ break;
+
+ // add toast handler when sim card is full
+ case TOAST_SIM_CARD_FULL:
+ exportCount = msg.arg1;
+ Toast.makeText(mPeople, mPeople.getString(R.string.export_sim_card_full,
+ exportCount), Toast.LENGTH_SHORT).show();
+ break;
+
+ //add the max count limit of Chinese code or not
+ case TOAST_CONTACT_NAME_TOO_LONG:
+ Toast.makeText(mPeople, R.string.tag_too_long, Toast.LENGTH_SHORT).show();
+ break;
+
+ // add toast handler when export is canceled
+ case TOAST_EXPORT_CANCELED:
+ exportCount = msg.arg1;
+ Toast.makeText(mPeople,mPeople.getString(R.string.export_cancelled,
+ String.valueOf(exportCount)), Toast.LENGTH_SHORT).show();
+ break;
+
+ // add toast handler when no phone or email
+ case TOAST_EXPORT_NO_PHONE_OR_EMAIL:
+ String name = (String) msg.obj;
+ Toast.makeText(mPeople,
+ mPeople.getString(R.string.export_no_phone_or_email, name),
+ Toast.LENGTH_SHORT).show();
+ break;
+ case TOAST_SIM_CARD_NOT_LOAD_COMPLETE:
+ Toast.makeText(mPeople, R.string.sim_contacts_not_load,
+ Toast.LENGTH_SHORT).show();
+ break;
+ }
+ }
+ };
+
+ public void showExportProgressDialog(Activity activity){
+ mPeople = activity;
+ mExportProgressDlg = new ProgressDialog(mPeople);
+ mExportProgressDlg.setTitle(R.string.export_to_sim);
+ mExportProgressDlg.setOnCancelListener(new OnCancelListener() {
+ public void onCancel(DialogInterface dialog) {
+ Log.d(TAG, "Cancel exporting contacts");
+ canceled = true;
+ }
+ });
+ mExportProgressDlg.setMessage(mPeople.getString(R.string.exporting));
+ mExportProgressDlg.setProgressNumberFormat(mPeople.getString(
+ R.string.reading_vcard_files));
+ mExportProgressDlg.setMax(contactList.size());
+ //mExportProgressDlg.setProgress(insertCount);
+
+ // set cancel dialog by touching outside disabled.
+ mExportProgressDlg.setCanceledOnTouchOutside(false);
+
+ // add a cancel button to let user cancel explicitly.
+ mExportProgressDlg.setButton(DialogInterface.BUTTON_NEGATIVE,
+ mPeople.getString(R.string.progressdialog_cancel),
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (DEBUG) {
+ Log.d(TAG, "Cancel exporting contacts by click button");
+ }
+ canceled = true;
+ }
+ });
+
+ mExportProgressDlg.show();
+ }
+ }
+
+ public ImportFromSimSelectListener listener;
+ /**
+ * Create a {@link Dialog} that allows the user to pick from a bulk import
+ * or bulk export task across all contacts.
+ */
+ private Dialog displayImportExportDialog(int id, Bundle bundle) {
+ Dialog diag;
+ switch (id) {
+ case R.string.import_from_sim_select: {
+ listener = new ImportFromSimSelectListener();
+ showSimSelectDialog();
+ break;
+ }
+ case R.string.export_to_sim: {
+ String[] items = new String[TelephonyManager.getDefault().getPhoneCount()];
+ for (int i = 0; i < items.length; i++) {
+ items[i] = getString(R.string.export_to_sim) + ": "
+ + MoreContactUtils.getMultiSimAliasesName(mActivity, i);
+ }
+ mExportSub = PhoneConstants.SUB1;
+ ExportToSimSelectListener listener = new ExportToSimSelectListener();
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.export_to_sim)
+ .setPositiveButton(android.R.string.ok, listener)
+ .setSingleChoiceItems(items, 0, listener).create();
+ }
+ }
+ return null;
+ }
+
+ public void showSimSelectDialog() {
+ AccountSelectionUtil.setImportSubscription(PhoneConstants.SUB1);
+ // item is for sim account to show
+ String[] items = new String[TelephonyManager.getDefault().getPhoneCount()];
+ for (int i = 0; i < items.length; i++) {
+ items[i] = getString(R.string.import_from_sim) + ": "
+ + MoreContactUtils.getMultiSimAliasesName(mActivity, i);
+ }
+ new AlertDialog.Builder(getActivity())
+ .setTitle(R.string.import_from_sim)
+ .setPositiveButton(android.R.string.ok, listener)
+ .setSingleChoiceItems(items, 0, listener).create().show();
+ }
+
+ private void handleImportFromSimRequest(int Id) {
+ if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+ if (MoreContactUtils.getEnabledSimCount() > 1) {
+ displayImportExportDialog(R.string.import_from_sim_select
+ ,null);
+ } else {
+ AccountSelectionUtil.setImportSubscription(getEnabledIccCard());
+ handleImportRequest(Id);
+ }
+ } else {
+ handleImportRequest(Id);
+ }
+ }
+
+ private void handleExportToSimRequest(int Id) {
+ if (MoreContactUtils.getEnabledSimCount() >1) {
+ //has two enalbed sim cards, prompt dialog to select one
+ displayImportExportDialog(Id, null).show();
+ } else {
+ mExportSub = getEnabledIccCard();
+ Intent pickPhoneIntent = new Intent(
+ SimContactsConstants.ACTION_MULTI_PICK, Contacts.CONTENT_URI);
+ // do not show the contacts in SIM card
+ pickPhoneIntent.putExtra(AccountFilterActivity.KEY_EXTRA_CONTACT_LIST_FILTER,
+ ContactListFilter
+ .createFilterWithType(ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS));
+ pickPhoneIntent.putExtra(EXT_NOT_SHOW_SIM_FLAG, true);
+ pickPhoneIntent.putExtra(SimContactsConstants.IS_CONTACT,true);
+ mActivity.startActivityForResult(pickPhoneIntent, SUBACTIVITY_MULTI_PICK_CONTACT);
+ }
+ }
+
+ private boolean hasEnabledIccCard(int subscription) {
+ return TelephonyManager.getDefault().hasIccCard(subscription)
+ && TelephonyManager.getDefault().getSimState(subscription)
+ == TelephonyManager.SIM_STATE_READY;
+ }
+
+ private int getEnabledIccCard() {
+ for (int i = 0; i < TelephonyManager.getDefault().getPhoneCount(); i++) {
+ if (hasEnabledIccCard(i)) {
+ return i;
+ }
+ }
+ return PhoneConstants.SUB1;
+ }
+
private CharSequence getSubDescription(SubscriptionInfo record, boolean isImport) {
CharSequence name = record.getDisplayName();
if (TextUtils.isEmpty(record.getNumber())) {
diff --git a/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java b/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java
index e62d4218..14548deb 100644
--- a/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java
+++ b/src/com/android/contacts/common/lettertiles/LetterTileDrawable.java
@@ -16,6 +16,8 @@
package com.android.contacts.common.lettertiles;
+import android.accounts.Account;
+import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -28,8 +30,11 @@ import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
+import android.telephony.TelephonyManager;
import android.util.Log;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.model.account.SimAccountType;
import com.android.contacts.common.R;
import com.android.contacts.common.util.BitmapUtil;
@@ -53,6 +58,9 @@ public class LetterTileDrawable extends Drawable {
private static Bitmap DEFAULT_PERSON_AVATAR;
private static Bitmap DEFAULT_BUSINESS_AVATAR;
private static Bitmap DEFAULT_VOICEMAIL_AVATAR;
+ private static Bitmap DEFAULT_SIM_PERSON_AVATAR;
+ private static Bitmap[] DEFAULT_CUSTOMIZE_SIM_PERSON_AVATAR =
+ new Bitmap[MoreContactUtils.IC_SIM_PICTURE.length];
/** Reusable components to avoid new allocations */
private static final Paint sPaint = new Paint();
@@ -70,12 +78,18 @@ public class LetterTileDrawable extends Drawable {
private int mContactType = TYPE_DEFAULT;
private float mScale = 1.0f;
private float mOffset = 0.0f;
+ private Account mAccount;
+ private Context mContext;
private boolean mIsCircle = false;
- public LetterTileDrawable(final Resources res) {
+
+ public LetterTileDrawable(final Context context, final Resources res,
+ final Account account) {
mPaint = new Paint();
mPaint.setFilterBitmap(true);
mPaint.setDither(true);
+ mAccount = account;
+ mContext = context;
if (sColors == null) {
sColors = res.obtainTypedArray(R.array.letter_tile_colors);
@@ -88,6 +102,13 @@ public class LetterTileDrawable extends Drawable {
R.drawable.ic_business_white_120dp);
DEFAULT_VOICEMAIL_AVATAR = BitmapFactory.decodeResource(res,
R.drawable.ic_voicemail_avatar);
+ DEFAULT_SIM_PERSON_AVATAR = BitmapFactory.decodeResource(res,
+ R.drawable.ic_contact_picture_sim);
+ for (int i = 0; i < MoreContactUtils.IC_SIM_PICTURE.length; i++) {
+ DEFAULT_CUSTOMIZE_SIM_PERSON_AVATAR[i] = BitmapFactory
+ .decodeResource(res, MoreContactUtils.IC_SIM_PICTURE[i]);
+ }
+
sPaint.setTypeface(Typeface.create(
res.getString(R.string.letter_tile_letter_font_family), Typeface.NORMAL));
sPaint.setTextAlign(Align.CENTER);
@@ -143,7 +164,10 @@ public class LetterTileDrawable extends Drawable {
}
// Draw letter/digit only if the first character is an english letter
- if (mDisplayName != null && isEnglishLetter(mDisplayName.charAt(0))) {
+ if (mDisplayName != null
+ && isEnglishLetter(mDisplayName.charAt(0))
+ && (mAccount == null || (mAccount != null && !mAccount.type
+ .equals(SimAccountType.ACCOUNT_TYPE)))) {
// Draw letter or digit.
sFirstChar[0] = Character.toUpperCase(mDisplayName.charAt(0));
@@ -160,9 +184,9 @@ public class LetterTileDrawable extends Drawable {
sPaint);
} else {
// Draw the default image if there is no letter/digit to be drawn
- final Bitmap bitmap = getBitmapForContactType(mContactType);
- drawBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(),
- canvas);
+ final Bitmap bitmap = getBitmapForContactType(mContactType,
+ mAccount, mContext);
+ drawBitmap(bitmap, bitmap.getWidth(), bitmap.getHeight(), canvas);
}
}
@@ -184,7 +208,21 @@ public class LetterTileDrawable extends Drawable {
return sColors.getColor(color, sDefaultColor);
}
- private static Bitmap getBitmapForContactType(int contactType) {
+ private static Bitmap getBitmapForContactType(int contactType,
+ Account account, Context context) {
+ if (account != null && SimAccountType.ACCOUNT_TYPE.equals(account.type)) {
+ if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+ final int sub = MoreContactUtils.getSubscription(
+ SimAccountType.ACCOUNT_TYPE, account.name);
+ int index = MoreContactUtils.getCurrentSimIconIndex(context, sub);
+ if (index < 0) {
+ return DEFAULT_PERSON_AVATAR;
+ }
+ return DEFAULT_CUSTOMIZE_SIM_PERSON_AVATAR[index];
+ } else {
+ return DEFAULT_SIM_PERSON_AVATAR;
+ }
+ }
switch (contactType) {
case TYPE_PERSON:
return DEFAULT_PERSON_AVATAR;
diff --git a/src/com/android/contacts/common/list/AccountFilterActivity.java b/src/com/android/contacts/common/list/AccountFilterActivity.java
index 58450c65..9dba5362 100644
--- a/src/com/android/contacts/common/list/AccountFilterActivity.java
+++ b/src/com/android/contacts/common/list/AccountFilterActivity.java
@@ -120,7 +120,8 @@ public class AccountFilterActivity extends Activity implements AdapterView.OnIte
// Hide extensions with no raw_contacts.
continue;
}
- Drawable icon = accountType != null ? accountType.getDisplayIcon(context) : null;
+ Drawable icon = accountType != null ? accountType.getDisplayIcon(
+ context, account.name) : null;
accountFilters.add(ContactListFilter.createAccountFilter(
account.type, account.name, account.dataSet, icon));
}
diff --git a/src/com/android/contacts/common/list/ContactEntry.java b/src/com/android/contacts/common/list/ContactEntry.java
index 43fc19dd..66ae50d1 100644
--- a/src/com/android/contacts/common/list/ContactEntry.java
+++ b/src/com/android/contacts/common/list/ContactEntry.java
@@ -16,6 +16,7 @@
package com.android.contacts.common.list;
+import android.accounts.Account;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.provider.ContactsContract.PinnedPositions;
@@ -36,6 +37,7 @@ public class ContactEntry {
public int pinned = PinnedPositions.UNPINNED;
public boolean isFavorite = false;
public boolean isDefaultNumber = false;
+ public Account account;
public static final ContactEntry BLANK_ENTRY = new ContactEntry();
} \ No newline at end of file
diff --git a/src/com/android/contacts/common/list/ContactEntryListAdapter.java b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
index 8500d816..63b5381d 100644
--- a/src/com/android/contacts/common/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactEntryListAdapter.java
@@ -15,6 +15,7 @@
*/
package com.android.contacts.common.list;
+import android.accounts.Account;
import android.content.Context;
import android.content.CursorLoader;
import android.content.res.Resources;
@@ -711,15 +712,24 @@ public abstract class ContactEntryListAdapter extends IndexerListAdapter {
* @param contactIdColumn Index of the contact id column
* @param lookUpKeyColumn Index of the lookup key column
* @param displayNameColumn Index of the display name column
+ * @param accountTypeColume Index of the account type column
+ * @param accountNameColume Index of the account name column
*/
protected void bindQuickContact(final ContactListItemView view, int partitionIndex,
Cursor cursor, int photoIdColumn, int photoUriColumn, int contactIdColumn,
- int lookUpKeyColumn, int displayNameColumn) {
+ int lookUpKeyColumn,int displayNameColumn, int accountTypeColume,
+ int accountNameColume) {
long photoId = 0;
if (!cursor.isNull(photoIdColumn)) {
photoId = cursor.getLong(photoIdColumn);
}
+ Account account = null;
+ if (!cursor.isNull(accountTypeColume) && !cursor.isNull(accountNameColume)) {
+ final String accountType = cursor.getString(accountTypeColume);
+ final String accountName = cursor.getString(accountNameColume);
+ account = new Account(accountName, accountType);
+ }
QuickContactBadge quickContact = view.getQuickContact();
quickContact.assignContactUri(
getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn));
@@ -729,8 +739,8 @@ public abstract class ContactEntryListAdapter extends IndexerListAdapter {
quickContact.setPrioritizedMimeType(Phone.CONTENT_ITEM_TYPE);
if (photoId != 0 || photoUriColumn == -1) {
- getPhotoLoader().loadThumbnail(quickContact, photoId, mDarkTheme, mCircularPhotos,
- null);
+ getPhotoLoader().loadThumbnail(quickContact, photoId, account,
+ mDarkTheme, mCircularPhotos, null);
} else {
final String photoUriString = cursor.getString(photoUriColumn);
final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
@@ -739,8 +749,8 @@ public abstract class ContactEntryListAdapter extends IndexerListAdapter {
request = getDefaultImageRequestFromCursor(cursor, displayNameColumn,
lookUpKeyColumn);
}
- getPhotoLoader().loadPhoto(quickContact, photoUri, -1, mDarkTheme, mCircularPhotos,
- request);
+ getPhotoLoader().loadPhoto(quickContact, photoUri, account, -1,
+ mDarkTheme, mCircularPhotos, request);
}
}
diff --git a/src/com/android/contacts/common/list/ContactEntryListFragment.java b/src/com/android/contacts/common/list/ContactEntryListFragment.java
index 8d1cedec..b49e57c8 100644
--- a/src/com/android/contacts/common/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/common/list/ContactEntryListFragment.java
@@ -20,9 +20,11 @@ import android.app.Activity;
import android.app.Fragment;
import android.app.LoaderManager;
import android.app.LoaderManager.LoaderCallbacks;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
@@ -50,6 +52,7 @@ import com.android.common.widget.CompositeCursorAdapter.Partition;
import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.preference.ContactsPreferences;
import com.android.contacts.common.util.ContactListViewUtils;
+import com.android.internal.telephony.TelephonyIntents;
import java.util.Locale;
@@ -147,6 +150,13 @@ public abstract class ContactEntryListFragment<T extends ContactEntryListAdapter
private LoaderManager mLoaderManager;
+ private BroadcastReceiver mSIMStateReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context arg0, Intent arg1) {
+ reloadData();
+ }
+ };
+
private Handler mDelayedDirectorySearchHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -262,6 +272,14 @@ public abstract class ContactEntryListFragment<T extends ContactEntryListAdapter
restoreSavedState(savedState);
mAdapter = createListAdapter();
mContactsPrefs = new ContactsPreferences(mContext);
+ restoreSavedState(savedState);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+ if (mContext != null) {
+ mContext.registerReceiver(mSIMStateReceiver, filter);
+ }
}
public void restoreSavedState(Bundle savedState) {
@@ -480,6 +498,14 @@ public abstract class ContactEntryListFragment<T extends ContactEntryListAdapter
mAdapter.clearPartitions();
}
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mContext != null) {
+ mContext.unregisterReceiver(mSIMStateReceiver);
+ }
+ }
+
protected void reloadData() {
removePendingDirectorySearchRequests();
mAdapter.onDataReload();
diff --git a/src/com/android/contacts/common/list/ContactListAdapter.java b/src/com/android/contacts/common/list/ContactListAdapter.java
index 600d731a..4c91f3fb 100644
--- a/src/com/android/contacts/common/list/ContactListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactListAdapter.java
@@ -15,12 +15,14 @@
*/
package com.android.contacts.common.list;
+import android.accounts.Account;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.SearchSnippets;
import android.text.TextUtils;
import android.view.View;
@@ -49,6 +51,8 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter {
Contacts.PHOTO_THUMBNAIL_URI, // 5
Contacts.LOOKUP_KEY, // 6
Contacts.IS_USER_PROFILE, // 7
+ RawContacts.ACCOUNT_TYPE, // 8
+ RawContacts.ACCOUNT_NAME, // 9
};
private static final String[] CONTACT_PROJECTION_ALTERNATIVE = new String[] {
@@ -60,6 +64,8 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter {
Contacts.PHOTO_THUMBNAIL_URI, // 5
Contacts.LOOKUP_KEY, // 6
Contacts.IS_USER_PROFILE, // 7
+ RawContacts.ACCOUNT_TYPE, // 8
+ RawContacts.ACCOUNT_NAME, // 9
};
private static final String[] FILTER_PROJECTION_PRIMARY = new String[] {
@@ -71,7 +77,9 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter {
Contacts.PHOTO_THUMBNAIL_URI, // 5
Contacts.LOOKUP_KEY, // 6
Contacts.IS_USER_PROFILE, // 7
- SearchSnippets.SNIPPET, // 8
+ RawContacts.ACCOUNT_TYPE, // 8
+ RawContacts.ACCOUNT_NAME, // 9
+ SearchSnippets.SNIPPET, // 10
};
private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] {
@@ -83,7 +91,9 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter {
Contacts.PHOTO_THUMBNAIL_URI, // 5
Contacts.LOOKUP_KEY, // 6
Contacts.IS_USER_PROFILE, // 7
- SearchSnippets.SNIPPET, // 8
+ RawContacts.ACCOUNT_TYPE, // 8
+ RawContacts.ACCOUNT_NAME, // 9
+ SearchSnippets.SNIPPET, // 10
};
public static final int CONTACT_ID = 0;
@@ -94,7 +104,9 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter {
public static final int CONTACT_PHOTO_URI = 5;
public static final int CONTACT_LOOKUP_KEY = 6;
public static final int CONTACT_IS_USER_PROFILE = 7;
- public static final int CONTACT_SNIPPET = 8;
+ public static final int CONTACT_ACCOUNT_TYPE = 8;
+ public static final int CONTACT_ACCOUNT_NAME = 9;
+ public static final int CONTACT_SNIPPET = 10;
}
private CharSequence mUnknownNameText;
@@ -230,8 +242,15 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter {
photoId = cursor.getLong(ContactQuery.CONTACT_PHOTO_ID);
}
+ Account account = null;
+ if (!cursor.isNull(ContactQuery.CONTACT_ACCOUNT_TYPE)
+ && !cursor.isNull(ContactQuery.CONTACT_ACCOUNT_NAME)) {
+ final String accountType = cursor.getString(ContactQuery.CONTACT_ACCOUNT_TYPE);
+ final String accountName = cursor.getString(ContactQuery.CONTACT_ACCOUNT_NAME);
+ account = new Account(accountName, accountType);
+ }
if (photoId != 0) {
- getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false,
+ getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, account, false,
getCircularPhotos(), null);
} else {
final String photoUriString = cursor.getString(ContactQuery.CONTACT_PHOTO_URI);
@@ -242,7 +261,7 @@ public abstract class ContactListAdapter extends ContactEntryListAdapter {
ContactQuery.CONTACT_DISPLAY_NAME,
ContactQuery.CONTACT_LOOKUP_KEY);
}
- getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, false,
+ getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, account, false,
getCircularPhotos(), request);
}
}
diff --git a/src/com/android/contacts/common/list/ContactListFilter.java b/src/com/android/contacts/common/list/ContactListFilter.java
index f81ea742..b48efb98 100644
--- a/src/com/android/contacts/common/list/ContactListFilter.java
+++ b/src/com/android/contacts/common/list/ContactListFilter.java
@@ -45,6 +45,7 @@ public final class ContactListFilter implements Comparable<ContactListFilter>, P
* TODO: "group" filter and relevant variables are all obsolete. Remove them.
*/
private static final int FILTER_TYPE_GROUP = 1;
+ public static final int FILTER_TYPE_ALL_WITHOUT_SIM = 2;
private static final String KEY_FILTER_TYPE = "filter.type";
private static final String KEY_ACCOUNT_NAME = "filter.accountName";
diff --git a/src/com/android/contacts/common/list/ContactListFilterView.java b/src/com/android/contacts/common/list/ContactListFilterView.java
index 4cea7558..075f1fb6 100644
--- a/src/com/android/contacts/common/list/ContactListFilterView.java
+++ b/src/com/android/contacts/common/list/ContactListFilterView.java
@@ -28,6 +28,8 @@ import android.widget.TextView;
import com.android.contacts.common.R;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
+import com.android.contacts.common.model.account.PhoneAccountType;
+import com.android.contacts.common.model.account.SimAccountType;
/**
* Contact list filter parameters.
@@ -113,7 +115,13 @@ public class ContactListFilterView extends LinearLayout {
break;
}
case ContactListFilter.FILTER_TYPE_ACCOUNT: {
- mAccountUserName.setVisibility(View.VISIBLE);
+ if (SimAccountType.ACCOUNT_TYPE.equals(mFilter.accountType)
+ || PhoneAccountType.ACCOUNT_TYPE
+ .equals(mFilter.accountType)) {
+ mAccountUserName.setVisibility(View.GONE);
+ } else {
+ mAccountUserName.setVisibility(View.VISIBLE);
+ }
mIcon.setVisibility(View.VISIBLE);
if (mFilter.icon != null) {
mIcon.setImageDrawable(mFilter.icon);
@@ -123,7 +131,7 @@ public class ContactListFilterView extends LinearLayout {
final AccountType accountType =
accountTypes.getAccountType(mFilter.accountType, mFilter.dataSet);
mAccountUserName.setText(mFilter.accountName);
- mAccountType.setText(accountType.getDisplayLabel(getContext()));
+ mAccountType.setText(accountType.getDisplayLabel(getContext(),mFilter.accountName));
break;
}
}
diff --git a/src/com/android/contacts/common/list/ContactTileAdapter.java b/src/com/android/contacts/common/list/ContactTileAdapter.java
index ac10f383..48c6923f 100644
--- a/src/com/android/contacts/common/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/common/list/ContactTileAdapter.java
@@ -15,6 +15,7 @@
*/
package com.android.contacts.common.list;
+import android.accounts.Account;
import android.content.ContentUris;
import android.content.Context;
import android.content.res.Resources;
@@ -67,6 +68,8 @@ public class ContactTileAdapter extends BaseAdapter {
protected int mNameIndex;
protected int mPresenceIndex;
protected int mStatusIndex;
+ private int mAccountTypeIndex;
+ private int mAccountNameIndex;
private boolean mIsQuickContactEnabled = false;
private final int mPaddingInPixels;
@@ -149,6 +152,8 @@ public class ContactTileAdapter extends BaseAdapter {
mStarredIndex = ContactTileLoaderFactory.STARRED;
mPresenceIndex = ContactTileLoaderFactory.CONTACT_PRESENCE;
mStatusIndex = ContactTileLoaderFactory.CONTACT_STATUS;
+ mAccountTypeIndex = ContactTileLoaderFactory.ACCOUNT_TYPE;
+ mAccountNameIndex = ContactTileLoaderFactory.ACCOUNT_NAME;
}
private static boolean cursorIsValid(Cursor cursor) {
@@ -187,6 +192,9 @@ public class ContactTileAdapter extends BaseAdapter {
* Else use {@link ContactTileLoaderFactory}
*/
public void setContactCursor(Cursor cursor) {
+ if (cursor == null || cursor.isClosed()) {
+ return;
+ }
mContactCursor = cursor;
mDividerPosition = getDividerPosition(cursor);
@@ -271,6 +279,13 @@ public class ContactTileAdapter extends BaseAdapter {
}
contact.status = statusMessage;
+ if (!cursor.isNull(mAccountTypeIndex) && !cursor.isNull(mAccountTypeIndex)) {
+ final String accountType = cursor.getString(mAccountTypeIndex);
+ final String accountName = cursor.getString(mAccountNameIndex);
+ contact.account = new Account(accountName, accountType);
+ } else {
+ contact.account = null;
+ }
return contact;
}
diff --git a/src/com/android/contacts/common/list/ContactTileView.java b/src/com/android/contacts/common/list/ContactTileView.java
index 56552bb6..b42ab7bf 100644
--- a/src/com/android/contacts/common/list/ContactTileView.java
+++ b/src/com/android/contacts/common/list/ContactTileView.java
@@ -15,6 +15,7 @@
*/
package com.android.contacts.common.list;
+import android.accounts.Account;
import android.content.Context;
import android.graphics.Rect;
import android.net.Uri;
@@ -128,7 +129,8 @@ public abstract class ContactTileView extends FrameLayout {
DefaultImageRequest request = getDefaultImageRequest(entry.name, entry.lookupKey);
configureViewForImage(entry.photoUri == null);
if (mPhoto != null) {
- mPhotoManager.loadPhoto(mPhoto, entry.photoUri, getApproximateImageSize(),
+ mPhotoManager.loadPhoto(mPhoto, entry.photoUri,
+ entry.account, getApproximateImageSize(),
isDarkTheme(), isContactPhotoCircular(), request);
if (mQuickContact != null) {
@@ -136,7 +138,7 @@ public abstract class ContactTileView extends FrameLayout {
}
} else if (mQuickContact != null) {
mQuickContact.assignContactUri(mLookupUri);
- mPhotoManager.loadPhoto(mQuickContact, entry.photoUri,
+ mPhotoManager.loadPhoto(mQuickContact, entry.photoUri, entry.account,
getApproximateImageSize(), isDarkTheme(), isContactPhotoCircular(),
request);
}
diff --git a/src/com/android/contacts/common/list/CustomContactListFilterActivity.java b/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
index b3253cc3..4066926a 100644
--- a/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
+++ b/src/com/android/contacts/common/list/CustomContactListFilterActivity.java
@@ -39,6 +39,7 @@ import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.Settings;
+import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@@ -54,11 +55,14 @@ import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
import android.widget.TextView;
import com.android.contacts.common.R;
+import com.android.contacts.common.MoreContactUtils;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.model.account.GoogleAccountType;
+import com.android.contacts.common.model.account.PhoneAccountType;
+import com.android.contacts.common.model.account.SimAccountType;
import com.android.contacts.common.util.EmptyService;
import com.android.contacts.common.util.LocalizedNameResolver;
import com.android.contacts.common.util.WeakAsyncTask;
@@ -349,7 +353,11 @@ public class CustomContactListFilterActivity extends Activity
final Integer titleRes = getAsInteger(Groups.TITLE_RES);
if (titleRes != null) {
final String packageName = getAsString(Groups.RES_PACKAGE);
- return context.getPackageManager().getText(packageName, titleRes, null);
+ if (!TextUtils.isEmpty(packageName)) {
+ return context.getPackageManager().getText(packageName, titleRes, null);
+ } else {
+ return getAsString(Groups.TITLE);
+ }
} else {
return getAsString(Groups.TITLE);
}
@@ -584,11 +592,17 @@ public class CustomContactListFilterActivity extends Activity
final AccountType accountType = mAccountTypes.getAccountType(
account.mType, account.mDataSet);
-
- text1.setText(account.mName);
- text1.setVisibility(account.mName == null ? View.GONE : View.VISIBLE);
- text2.setText(accountType.getDisplayLabel(mContext));
-
+ if (SimAccountType.ACCOUNT_TYPE.equals(account.mType)
+ || PhoneAccountType.ACCOUNT_TYPE.equals(account.mType)) {
+ text1.setVisibility(View.VISIBLE);
+ text1.setText(accountType.getDisplayLabel(mContext, account.mName));
+ text2.setVisibility(View.GONE);
+ } else {
+ text1.setText(account.mName);
+ text1.setVisibility(account.mName == null ? View.GONE : View.VISIBLE);
+ text2.setText(accountType.getDisplayLabel(mContext, account.mName));
+ text2.setVisibility(View.VISIBLE);
+ }
return convertView;
}
diff --git a/src/com/android/contacts/common/list/DefaultContactListAdapter.java b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
index 8774777c..f25f5d7f 100644
--- a/src/com/android/contacts/common/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
@@ -26,11 +26,15 @@ import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.SearchSnippets;
import android.text.TextUtils;
import android.view.View;
+import com.android.contacts.common.model.account.SimAccountType;
import com.android.contacts.common.preference.ContactsPreferences;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.SimContactsConstants;
import java.util.ArrayList;
import java.util.List;
@@ -47,6 +51,21 @@ public class DefaultContactListAdapter extends ContactListAdapter {
super(context);
}
+ /** append Uri QueryParameter to filter contacts in SIM card */
+ private void appendUriQueryParameterWithoutSim(CursorLoader loader,
+ String key, String value) {
+ if (null == loader || null == key || null == value) {
+ return;
+ }
+
+ Uri uri = loader.getUri();
+ if (null != uri) {
+ uri = uri.buildUpon().appendQueryParameter(key, value)
+ .appendQueryParameter(SimContactsConstants.WITHOUT_SIM_FLAG, "true").build();
+ loader.setUri(uri);
+ }
+ }
+
@Override
public void configureLoader(CursorLoader loader, long directoryId) {
if (loader instanceof ProfileAndContactsLoader) {
@@ -79,6 +98,21 @@ public class DefaultContactListAdapter extends ContactListAdapter {
loader.setUri(builder.build());
loader.setProjection(getProjection(true));
}
+ boolean isAirMode = MoreContactUtils.isAPMOnAndSIMPowerDown(getContext());
+
+ if (isAirMode
+ || (null != filter && filter.filterType ==
+ ContactListFilter.FILTER_TYPE_ALL_WITHOUT_SIM)) {
+ appendUriQueryParameterWithoutSim(loader,
+ RawContacts.ACCOUNT_TYPE, SimAccountType.ACCOUNT_TYPE);
+ } else {
+ // Do not show contacts when SIM card is disabled
+ String disabledSimFilter = MoreContactUtils.getDisabledSimFilter();
+ if (!TextUtils.isEmpty(disabledSimFilter)) {
+ appendUriQueryParameterWithoutSim(
+ loader, RawContacts.ACCOUNT_NAME, disabledSimFilter);
+ }
+ }
} else {
configureUri(loader, directoryId, filter);
loader.setProjection(getProjection(false));
@@ -139,10 +173,21 @@ public class DefaultContactListAdapter extends ContactListAdapter {
StringBuilder selection = new StringBuilder();
List<String> selectionArgs = new ArrayList<String>();
+ boolean isAirMode = MoreContactUtils.isAPMOnAndSIMPowerDown(getContext());
+ String disabledSimFilter = MoreContactUtils.getDisabledSimFilter();
+
switch (filter.filterType) {
case ContactListFilter.FILTER_TYPE_ALL_ACCOUNTS: {
// We have already added directory=0 to the URI, which takes care of this
// filter
+ // Do not show contacts in SIM card when airplane mode is on
+ if (isAirMode) {
+ appendUriQueryParameterWithoutSim(loader, RawContacts.ACCOUNT_TYPE,
+ SimAccountType.ACCOUNT_TYPE);
+ } else if (!TextUtils.isEmpty(disabledSimFilter)) {
+ appendUriQueryParameterWithoutSim(loader, RawContacts.ACCOUNT_NAME,
+ disabledSimFilter);
+ }
break;
}
case ContactListFilter.FILTER_TYPE_SINGLE_CONTACT: {
@@ -163,12 +208,25 @@ public class DefaultContactListAdapter extends ContactListAdapter {
if (isCustomFilterForPhoneNumbersOnly()) {
selection.append(" AND " + Contacts.HAS_PHONE_NUMBER + "=1");
}
+ // Do not show contacts in SIM card when airplane mode is on
+ if (isAirMode) {
+ appendUriQueryParameterWithoutSim(loader, RawContacts.ACCOUNT_TYPE,
+ SimAccountType.ACCOUNT_TYPE);
+ } else if (!TextUtils.isEmpty(disabledSimFilter)) {
+ appendUriQueryParameterWithoutSim(loader, RawContacts.ACCOUNT_NAME,
+ disabledSimFilter);
+ }
break;
}
case ContactListFilter.FILTER_TYPE_ACCOUNT: {
// We use query parameters for account filter, so no selection to add here.
break;
}
+ case ContactListFilter.FILTER_TYPE_ALL_WITHOUT_SIM: {
+ appendUriQueryParameterWithoutSim(loader, RawContacts.ACCOUNT_TYPE,
+ SimAccountType.ACCOUNT_TYPE);
+ break;
+ }
}
loader.setSelection(selection.toString());
loader.setSelectionArgs(selectionArgs.toArray(new String[0]));
@@ -190,7 +248,8 @@ public class DefaultContactListAdapter extends ContactListAdapter {
if (isQuickContactEnabled()) {
bindQuickContact(view, partition, cursor, ContactQuery.CONTACT_PHOTO_ID,
ContactQuery.CONTACT_PHOTO_URI, ContactQuery.CONTACT_ID,
- ContactQuery.CONTACT_LOOKUP_KEY, ContactQuery.CONTACT_DISPLAY_NAME);
+ ContactQuery.CONTACT_LOOKUP_KEY, ContactQuery.CONTACT_DISPLAY_NAME,
+ ContactQuery.CONTACT_ACCOUNT_TYPE, ContactQuery.CONTACT_ACCOUNT_NAME);
} else {
if (getDisplayPhotos()) {
bindPhoto(view, partition, cursor);
diff --git a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
index fee0a6a1..750f030e 100644
--- a/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
+++ b/src/com/android/contacts/common/list/PhoneNumberListAdapter.java
@@ -15,6 +15,7 @@
*/
package com.android.contacts.common.list;
+import android.accounts.Account;
import android.content.ContentUris;
import android.content.Context;
import android.content.CursorLoader;
@@ -28,6 +29,8 @@ import android.provider.ContactsContract.CommonDataKinds.SipAddress;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Directory;
+import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
import android.util.Log;
@@ -41,6 +44,8 @@ import com.android.contacts.common.extensions.ExtendedPhoneDirectoriesManager;
import com.android.contacts.common.extensions.ExtensionsFactory;
import com.android.contacts.common.preference.ContactsPreferences;
import com.android.contacts.common.util.Constants;
+import com.android.contacts.common.MoreContactUtils;
+import com.android.contacts.common.model.account.SimAccountType;
import java.util.ArrayList;
import java.util.List;
@@ -95,6 +100,8 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
Phone.PHOTO_ID, // 6
Phone.DISPLAY_NAME_PRIMARY, // 7
Phone.PHOTO_THUMBNAIL_URI, // 8
+ RawContacts.ACCOUNT_TYPE, // 9
+ RawContacts.ACCOUNT_NAME, // 10
};
public static final String[] PROJECTION_ALTERNATIVE = new String[] {
@@ -107,6 +114,8 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
Phone.PHOTO_ID, // 6
Phone.DISPLAY_NAME_ALTERNATIVE, // 7
Phone.PHOTO_THUMBNAIL_URI, // 8
+ RawContacts.ACCOUNT_TYPE, // 9
+ RawContacts.ACCOUNT_NAME, // 10
};
public static final int PHONE_ID = 0;
@@ -118,6 +127,8 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
public static final int PHOTO_ID = 6;
public static final int DISPLAY_NAME = 7;
public static final int PHOTO_URI = 8;
+ public static final int PHONE_ACCOUNT_TYPE = 9;
+ public static final int PHONE_ACCOUNT_NAME = 10;
}
private static final String IGNORE_NUMBER_TOO_LONG_CLAUSE =
@@ -212,6 +223,13 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
// Remove duplicates when it is possible.
builder.appendQueryParameter(ContactsContract.REMOVE_DUPLICATE_ENTRIES, "true");
+
+ // Do not show contacts in disabled SIM card
+ String disabledSimFilter = MoreContactUtils.getDisabledSimFilter();
+ if (!TextUtils.isEmpty(disabledSimFilter)) {
+ String disabledSimName = getDisabledSimName(disabledSimFilter);
+ loader.setSelection(RawContacts.ACCOUNT_NAME+ "<>" + disabledSimName);
+ }
loader.setUri(builder.build());
// TODO a projection that includes the search snippet
@@ -396,7 +414,8 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
if (isQuickContactEnabled()) {
bindQuickContact(view, partition, cursor, PhoneQuery.PHOTO_ID,
PhoneQuery.PHOTO_URI, PhoneQuery.CONTACT_ID,
- PhoneQuery.LOOKUP_KEY, PhoneQuery.DISPLAY_NAME);
+ PhoneQuery.LOOKUP_KEY, PhoneQuery.DISPLAY_NAME,
+ PhoneQuery.PHONE_ACCOUNT_TYPE, PhoneQuery.PHONE_ACCOUNT_NAME);
} else {
if (getDisplayPhotos()) {
bindPhoto(view, partition, cursor);
@@ -466,9 +485,15 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
if (!cursor.isNull(PhoneQuery.PHOTO_ID)) {
photoId = cursor.getLong(PhoneQuery.PHOTO_ID);
}
-
+ Account account = null;
+ if (!cursor.isNull(PhoneQuery.PHONE_ACCOUNT_TYPE)
+ && !cursor.isNull(PhoneQuery.PHONE_ACCOUNT_NAME)) {
+ final String accountType = cursor.getString(PhoneQuery.PHONE_ACCOUNT_TYPE);
+ final String accountName = cursor.getString(PhoneQuery.PHONE_ACCOUNT_NAME);
+ account = new Account(accountName, accountType);
+ }
if (photoId != 0) {
- getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false,
+ getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, account, false,
getCircularPhotos(), null);
} else {
final String photoUriString = cursor.getString(PhoneQuery.PHOTO_URI);
@@ -480,7 +505,7 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
final String lookupKey = cursor.getString(PhoneQuery.LOOKUP_KEY);
request = new DefaultImageRequest(displayName, lookupKey, getCircularPhotos());
}
- getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, false,
+ getPhotoLoader().loadDirectoryPhoto(view.getPhotoView(), photoUri, account, false,
getCircularPhotos(), request);
}
}
@@ -571,4 +596,21 @@ public class PhoneNumberListAdapter extends ContactEntryListAdapter {
.encodedFragment(cursor.getString(lookUpKeyColumn))
.build();
}
+
+ private String getDisabledSimName(String disabledSimFilter){
+ String[] disabledSimArray = disabledSimFilter.split(",");//it will never be null
+ String disabledSimName = "";
+ for (int i = 0; i < disabledSimArray.length; i++) {
+ if (i < disabledSimArray.length -1) {
+ //If disabledSimArray[i] is not the last one of the array,
+ //add "or" after every member of the array.
+ disabledSimName = disabledSimName + "'" + disabledSimArray[i] + "'" + "or";
+ } else {
+ //If disabledSimArray[i] is the last one of the array,
+ //should not add anything after it.
+ disabledSimName = disabledSimName + "'" + disabledSimArray[i] + "'";
+ }
+ }
+ return disabledSimName;
+ }
}
diff --git a/src/com/android/contacts/common/list/ShortcutIntentBuilder.java b/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
index 9e6b5e95..35c3ff21 100644
--- a/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
+++ b/src/com/android/contacts/common/list/ShortcutIntentBuilder.java
@@ -15,6 +15,7 @@
*/
package com.android.contacts.common.list;
+import android.accounts.Account;
import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
@@ -39,6 +40,7 @@ import android.provider.ContactsContract.Data;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import android.telecom.PhoneAccount;
+import android.provider.ContactsContract.RawContacts;
import android.text.TextPaint;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
@@ -56,12 +58,16 @@ public class ShortcutIntentBuilder {
private static final String[] CONTACT_COLUMNS = {
Contacts.DISPLAY_NAME,
Contacts.PHOTO_ID,
- Contacts.LOOKUP_KEY
+ Contacts.LOOKUP_KEY,
+ RawContacts.ACCOUNT_TYPE,
+ RawContacts.ACCOUNT_NAME
};
private static final int CONTACT_DISPLAY_NAME_COLUMN_INDEX = 0;
private static final int CONTACT_PHOTO_ID_COLUMN_INDEX = 1;
private static final int CONTACT_LOOKUP_KEY_COLUMN_INDEX = 2;
+ private static final int CONTACT_ACCOUNT_TYPE_COLUMN_INDEX = 3;
+ private static final int CONTACT_ACCOUNT_NAME_COLUMN_INDEX = 4;
private static final String[] PHONE_COLUMNS = {
Phone.DISPLAY_NAME,
@@ -69,7 +75,9 @@ public class ShortcutIntentBuilder {
Phone.NUMBER,
Phone.TYPE,
Phone.LABEL,
- Phone.LOOKUP_KEY
+ Phone.LOOKUP_KEY,
+ RawContacts.ACCOUNT_TYPE,
+ RawContacts.ACCOUNT_NAME
};
private static final int PHONE_DISPLAY_NAME_COLUMN_INDEX = 0;
@@ -78,6 +86,8 @@ public class ShortcutIntentBuilder {
private static final int PHONE_TYPE_COLUMN_INDEX = 3;
private static final int PHONE_LABEL_COLUMN_INDEX = 4;
private static final int PHONE_LOOKUP_KEY_COLUMN_INDEX = 5;
+ private static final int PHONE_ACCOUNT_TYPE_COLUMN_INDEX = 6;
+ private static final int PHONE_ACCOUNT_NAME_COLUMN_INDEX = 7;
private static final String[] PHOTO_COLUMNS = {
Photo.PHOTO,
@@ -187,6 +197,8 @@ public class ShortcutIntentBuilder {
}
private final class ContactLoadingAsyncTask extends LoadingAsyncTask {
+ private Account mAccount;
+
public ContactLoadingAsyncTask(Uri uri) {
super(uri);
}
@@ -200,6 +212,13 @@ public class ShortcutIntentBuilder {
if (cursor.moveToFirst()) {
mDisplayName = cursor.getString(CONTACT_DISPLAY_NAME_COLUMN_INDEX);
mPhotoId = cursor.getLong(CONTACT_PHOTO_ID_COLUMN_INDEX);
+
+ final String accountType = cursor
+ .getString(CONTACT_ACCOUNT_TYPE_COLUMN_INDEX);
+ final String accountName = cursor
+ .getString(CONTACT_ACCOUNT_NAME_COLUMN_INDEX);
+ mAccount = new Account(accountName, accountType);
+
mLookupKey = cursor.getString(CONTACT_LOOKUP_KEY_COLUMN_INDEX);
}
} finally {
@@ -209,7 +228,8 @@ public class ShortcutIntentBuilder {
}
@Override
protected void onPostExecute(Void result) {
- createContactShortcutIntent(mUri, mContentType, mDisplayName, mLookupKey, mBitmapData);
+ createContactShortcutIntent(mUri, mContentType, mDisplayName,
+ mAccount, mLookupKey, mBitmapData);
}
}
@@ -218,6 +238,7 @@ public class ShortcutIntentBuilder {
private String mPhoneNumber;
private int mPhoneType;
private String mPhoneLabel;
+ private Account mAccount;
public PhoneNumberLoadingAsyncTask(Uri uri, String shortcutAction) {
super(uri);
@@ -236,6 +257,13 @@ public class ShortcutIntentBuilder {
mPhoneNumber = cursor.getString(PHONE_NUMBER_COLUMN_INDEX);
mPhoneType = cursor.getInt(PHONE_TYPE_COLUMN_INDEX);
mPhoneLabel = cursor.getString(PHONE_LABEL_COLUMN_INDEX);
+
+ final String accountType = cursor
+ .getString(PHONE_ACCOUNT_TYPE_COLUMN_INDEX);
+ final String accountName = cursor
+ .getString(PHONE_ACCOUNT_NAME_COLUMN_INDEX);
+ mAccount = new Account(accountName, accountType);
+
mLookupKey = cursor.getString(PHONE_LOOKUP_KEY_COLUMN_INDEX);
}
} finally {
@@ -247,23 +275,25 @@ public class ShortcutIntentBuilder {
@Override
protected void onPostExecute(Void result) {
createPhoneNumberShortcutIntent(mUri, mDisplayName, mLookupKey, mBitmapData,
- mPhoneNumber, mPhoneType, mPhoneLabel, mShortcutAction);
+ mPhoneNumber, mPhoneType, mPhoneLabel, mAccount, mShortcutAction);
}
}
- private Drawable getPhotoDrawable(byte[] bitmapData, String displayName, String lookupKey) {
+ private Drawable getPhotoDrawable(byte[] bitmapData, String displayName,
+ String lookupKey, Account account) {
if (bitmapData != null) {
Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length, null);
return new BitmapDrawable(mContext.getResources(), bitmap);
} else {
- return ContactPhotoManager.getDefaultAvatarDrawableForContact(mContext.getResources(),
- false, new DefaultImageRequest(displayName, lookupKey, false));
+ return ContactPhotoManager.getDefaultAvatarDrawableForContact(mContext,
+ mContext.getResources(), false,
+ new DefaultImageRequest(displayName, lookupKey, false), account);
}
}
private void createContactShortcutIntent(Uri contactUri, String contentType, String displayName,
- String lookupKey, byte[] bitmapData) {
- Drawable drawable = getPhotoDrawable(bitmapData, displayName, lookupKey);
+ Account account, String lookupKey, byte[] bitmapData) {
+ Drawable drawable = getPhotoDrawable(bitmapData, displayName, lookupKey, account);
// Use an implicit intent without a package name set. It is reasonable for a disambiguation
// dialog to appear when opening QuickContacts from the launcher. Plus, this will be more
@@ -303,8 +333,8 @@ public class ShortcutIntentBuilder {
private void createPhoneNumberShortcutIntent(Uri uri, String displayName, String lookupKey,
byte[] bitmapData, String phoneNumber, int phoneType, String phoneLabel,
- String shortcutAction) {
- Drawable drawable = getPhotoDrawable(bitmapData, displayName, lookupKey);
+ Account account, String shortcutAction) {
+ Drawable drawable = getPhotoDrawable(bitmapData, displayName, lookupKey, account);
Bitmap bitmap;
Uri phoneUri;
diff --git a/src/com/android/contacts/common/model/AccountTypeManager.java b/src/com/android/contacts/common/model/AccountTypeManager.java
index 33395979..ca144d12 100644
--- a/src/com/android/contacts/common/model/AccountTypeManager.java
+++ b/src/com/android/contacts/common/model/AccountTypeManager.java
@@ -38,6 +38,8 @@ import android.os.Message;
import android.os.SystemClock;
import android.provider.ContactsContract;
import android.text.TextUtils;
+import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
import android.util.Log;
import android.util.TimingLogger;
@@ -51,7 +53,10 @@ import com.android.contacts.common.model.account.ExternalAccountType;
import com.android.contacts.common.model.account.FallbackAccountType;
import com.android.contacts.common.model.account.GoogleAccountType;
import com.android.contacts.common.model.account.SamsungAccountType;
+import com.android.contacts.common.model.account.PhoneAccountType;
+import com.android.contacts.common.model.account.SimAccountType;
import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.contacts.common.SimContactsConstants;
import com.android.contacts.common.testing.NeededForTesting;
import com.android.contacts.common.util.Constants;
import com.google.common.annotations.VisibleForTesting;
@@ -80,6 +85,13 @@ public abstract class AccountTypeManager {
private static final Object mInitializationLock = new Object();
private static AccountTypeManager mAccountTypeManager;
+ public static final int FLAG_ALL_ACCOUNTS = 0;
+ public static final int FLAG_ALL_ACCOUNTS_WITHOUT_SIM = 1;
+ /**
+ * without sim and phone accounts
+ */
+ public static final int FLAG_ALL_ACCOUNTS_WITHOUT_LOCAL = 2;
+
/**
* Requests the singleton instance of {@link AccountTypeManager} with data bound from
* the available authenticators. This method can safely be called from the UI thread.
@@ -113,6 +125,8 @@ public abstract class AccountTypeManager {
* contact writable accounts (if contactWritableOnly is true).
*/
// TODO: Consider splitting this into getContactWritableAccounts() and getAllAccounts()
+ public abstract List<AccountWithDataSet> getAccounts(boolean contactWritableOnly, int flag);
+
public abstract List<AccountWithDataSet> getAccounts(boolean contactWritableOnly);
/**
@@ -417,6 +431,10 @@ class AccountTypeManagerImpl extends AccountTypeManager
} else if (SamsungAccountType.isSamsungAccountType(mContext, type,
auth.packageName)) {
accountType = new SamsungAccountType(mContext, auth.packageName, type);
+ } else if (SimAccountType.ACCOUNT_TYPE.equals(type)) {
+ accountType = new SimAccountType(mContext, auth.packageName);
+ } else if (PhoneAccountType.ACCOUNT_TYPE.equals(type)) {
+ accountType = new PhoneAccountType(mContext, auth.packageName);
} else {
Log.d(TAG, "Registering external account type=" + type
+ ", packageName=" + auth.packageName);
@@ -562,15 +580,86 @@ class AccountTypeManagerImpl extends AccountTypeManager
return null;
}
+ @Override
+ public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
+ return getAccounts(contactWritableOnly, FLAG_ALL_ACCOUNTS);
+ }
+
/**
* Return list of all known, contact writable {@link AccountWithDataSet}'s.
*/
@Override
- public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly) {
+ public List<AccountWithDataSet> getAccounts(boolean contactWritableOnly,
+ int flag) {
ensureAccountsLoaded();
+ boolean isAirMode = MoreContactUtils.isAPMOnAndSIMPowerDown(mContext);
+ switch (flag) {
+ case FLAG_ALL_ACCOUNTS:
+ return trimAccountByType(
+ contactWritableOnly ? mContactWritableAccounts : mAccounts,
+ isAirMode ? SimAccountType.ACCOUNT_TYPE : null);
+ case FLAG_ALL_ACCOUNTS_WITHOUT_LOCAL:
+ return trimAccountByType(
+ contactWritableOnly ? mContactWritableAccounts : mAccounts,
+ SimAccountType.ACCOUNT_TYPE, PhoneAccountType.ACCOUNT_TYPE);
+ case FLAG_ALL_ACCOUNTS_WITHOUT_SIM:
+ return trimAccountByType(
+ contactWritableOnly ? mContactWritableAccounts : mAccounts,
+ SimAccountType.ACCOUNT_TYPE);
+ }
return contactWritableOnly ? mContactWritableAccounts : mAccounts;
}
+ private boolean isSimStateUnknown(AccountWithDataSet account) {
+ int subscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ subscription = MoreContactUtils.getSubscription(account.type, account.name);
+
+ if (subscription > SubscriptionManager.INVALID_SUBSCRIPTION_ID
+ && TelephonyManager.from(mContext).getSimState(subscription)
+ == TelephonyManager.SIM_STATE_UNKNOWN) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private boolean isSimAccountInvalid(AccountWithDataSet account) {
+ if ((SimContactsConstants.ACCOUNT_TYPE_SIM).equals(account.type)) {
+ if (TelephonyManager.from(mContext).isMultiSimEnabled()) {
+ if (account.name.equals(SimContactsConstants.SIM_NAME))
+ return true;
+ } else {
+ if (!account.name.equals(SimContactsConstants.SIM_NAME)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private List<AccountWithDataSet> trimAccountByType(final List<AccountWithDataSet> list,
+ String... trimAccountTypes) {
+ List<AccountWithDataSet> tempList = Lists.newArrayList();
+ outer: for (AccountWithDataSet accountWithDataSet : list) {
+ if (trimAccountTypes != null && trimAccountTypes.length > 0) {
+ for (String type : trimAccountTypes) {
+ if (type != null && type.equals(accountWithDataSet.type)) {
+ continue outer;
+ }
+ }
+ }
+
+ if (isSimStateUnknown(accountWithDataSet)) {
+ continue outer;
+ }
+ if (isSimAccountInvalid(accountWithDataSet)) {
+ continue outer;
+ }
+ tempList.add(accountWithDataSet);
+ }
+ return tempList;
+ }
+
/**
* Return the list of all known, group writable {@link AccountWithDataSet}'s.
*/
diff --git a/src/com/android/contacts/common/model/RawContactDelta.java b/src/com/android/contacts/common/model/RawContactDelta.java
index 7304f023..435e3442 100644
--- a/src/com/android/contacts/common/model/RawContactDelta.java
+++ b/src/com/android/contacts/common/model/RawContactDelta.java
@@ -24,15 +24,20 @@ import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.BaseColumns;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Profile;
import android.provider.ContactsContract.RawContacts;
+import android.text.TextUtils;
import android.util.Log;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.ValuesDelta;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.testing.NeededForTesting;
+import com.android.contacts.common.SimContactsConstants;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -416,6 +421,139 @@ public class RawContactDelta implements Parcelable {
}
}
+ public ContentValues buildSimDiff() {
+ ContentValues values = new ContentValues();
+ ArrayList<ValuesDelta> names = getMimeEntries(StructuredName.CONTENT_ITEM_TYPE);
+ ArrayList<ValuesDelta> phones = getMimeEntries(Phone.CONTENT_ITEM_TYPE);
+ ArrayList<ValuesDelta> emails = getMimeEntries(Email.CONTENT_ITEM_TYPE);
+
+ ValuesDelta nameValuesDelta = null;
+ ValuesDelta emailValuesDelta = null;
+
+ if (getMimeEntriesCount(StructuredName.CONTENT_ITEM_TYPE, true) > 0) {
+ nameValuesDelta = names.get(0);
+ names.get(0).putNull(StructuredName.GIVEN_NAME);
+ names.get(0).putNull(StructuredName.FAMILY_NAME);
+ names.get(0).putNull(StructuredName.PREFIX);
+ names.get(0).putNull(StructuredName.MIDDLE_NAME);
+ names.get(0).putNull(StructuredName.SUFFIX);
+ names.get(0).put(StructuredName.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE);
+ }
+ if (emails != null && emails.size() > 0) {
+ emailValuesDelta = emails.get(0);
+ }
+
+ String name = null;
+ String number = null;
+ String newName = null;
+ String newNumber = null;
+ StringBuilder email = new StringBuilder();
+ StringBuilder anr = new StringBuilder();
+ StringBuilder newEmail = new StringBuilder();
+ StringBuilder newAnr = new StringBuilder();
+
+ if (nameValuesDelta != null) {
+ if (isContactInsert()) {
+ name = nameValuesDelta.getAsString(StructuredName.DISPLAY_NAME);
+ } else {
+ if (nameValuesDelta.getBefore() != null) {
+ name = nameValuesDelta.getBefore()
+ .getAsString(StructuredName.DISPLAY_NAME);
+ }
+ if (nameValuesDelta.getAfter() != null) {
+ newName = nameValuesDelta.getAfter()
+ .getAsString(StructuredName.DISPLAY_NAME);
+ }
+ }
+ }
+
+ if (isContactInsert() && phones != null) {
+ for (ValuesDelta valuesDelta : phones) {
+ if (valuesDelta.getAfter() != null
+ && valuesDelta.getAfter().size() != 0) {
+ if (Phone.TYPE_MOBILE == valuesDelta.getAfter().getAsLong(Phone.TYPE)) {
+ if (TextUtils.isEmpty(number)) {
+ number = valuesDelta.getAfter().getAsString(Phone.NUMBER);
+ } else {
+ // don't supports to save two mobile number,so gives
+ // invalid str here
+ number = SimContactsConstants.STR_ANRS;
+ }
+ } else {
+ anr.append(valuesDelta.getAfter().getAsString(Phone.NUMBER));
+ anr.append(SimContactsConstants.ANR_SEP);
+ }
+ }
+ }
+ } else if(phones != null) {
+ for (ValuesDelta valuesDelta : phones) {
+ if (valuesDelta.getBefore() != null
+ && valuesDelta.getBefore().size() != 0) {
+ if (Phone.TYPE_MOBILE == valuesDelta.getBefore().getAsLong(Phone.TYPE) ) {
+ number = valuesDelta.getBefore().getAsString(Phone.NUMBER);
+ } else {
+ anr.append(valuesDelta.getBefore().getAsString(Phone.NUMBER));
+ anr.append(SimContactsConstants.ANR_SEP);
+ }
+ }
+ if (valuesDelta.getAfter() != null
+ && valuesDelta.getAfter().size() != 0) {
+ if (Phone.TYPE_MOBILE == valuesDelta.getAsLong(Phone.TYPE)) {
+ if (TextUtils.isEmpty(newNumber)) {
+ newNumber = valuesDelta.getAfter().getAsString(Phone.NUMBER);
+ } else {
+ newNumber = SimContactsConstants.STR_ANRS;
+ }
+ } else {
+ newAnr.append(valuesDelta.getAfter().getAsString(Phone.NUMBER));
+ newAnr.append(SimContactsConstants.ANR_SEP);
+ }
+ }
+ }
+ }
+
+ if (isContactInsert() && emails != null) {
+ for (ValuesDelta valuesDelta : emails) {
+ if (valuesDelta.getAfter() != null
+ && valuesDelta.getAfter().size() != 0) {
+ email.append(valuesDelta.getAfter().getAsString(Email.DATA));
+ email.append(SimContactsConstants.EMAIL_SEP);
+ }
+ }
+ } else if (emails != null) {
+ for (ValuesDelta valuesDelta : emails) {
+ if (valuesDelta.getBefore() != null
+ && valuesDelta.getBefore().size() != 0) {
+ email.append(valuesDelta.getBefore().getAsString(Email.DATA));
+ email.append(SimContactsConstants.EMAIL_SEP);
+ }
+ if (valuesDelta.getAfter() != null
+ && valuesDelta.getAfter().size() != 0) {
+ newEmail.append(valuesDelta.getAfter().getAsString(Email.DATA));
+ newEmail.append(SimContactsConstants.EMAIL_SEP);
+ }
+ }
+ }
+
+ if (isContactInsert()) {
+ if (name != null || number != null || anr != null || email != null) {
+ values.put(SimContactsConstants.STR_TAG, name);
+ values.put(SimContactsConstants.STR_NUMBER, number);
+ values.put(SimContactsConstants.STR_EMAILS, email.toString());
+ values.put(SimContactsConstants.STR_ANRS, anr.toString());
+ }
+ } else {
+ values.put(SimContactsConstants.STR_TAG, name);
+ values.put(SimContactsConstants.STR_NUMBER, number);
+ values.put(SimContactsConstants.STR_EMAILS, email.toString());
+ values.put(SimContactsConstants.STR_ANRS, anr.toString());
+ values.put(SimContactsConstants.STR_NEW_TAG, newName);
+ values.put(SimContactsConstants.STR_NEW_NUMBER, newNumber);
+ values.put(SimContactsConstants.STR_NEW_EMAILS, newEmail.toString());
+ values.put(SimContactsConstants.STR_NEW_ANRS, newAnr.toString());
+ }
+ return values;
+ }
/**
* Build a list of {@link ContentProviderOperation} that will transform the
* current "before" {@link Entity} state into the modified state which this
diff --git a/src/com/android/contacts/common/model/ValuesDelta.java b/src/com/android/contacts/common/model/ValuesDelta.java
index 36321d24..5dd95dd9 100644
--- a/src/com/android/contacts/common/model/ValuesDelta.java
+++ b/src/com/android/contacts/common/model/ValuesDelta.java
@@ -23,6 +23,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
+import android.provider.ContactsContract.Data;
import com.android.contacts.common.testing.NeededForTesting;
import com.google.common.collect.Sets;
@@ -61,6 +62,17 @@ public class ValuesDelta implements Parcelable {
final ValuesDelta entry = new ValuesDelta();
entry.mBefore = before;
entry.mAfter = new ContentValues();
+
+ // init data1 to mAfter map. when no operation edittext of
+ // sim phone in the UI, the mAfter init have no data1 value,
+ // it will cause the builddiff data not right.
+ if (before.containsKey(Data.DATA1)) {
+ String contactInfo = before.getAsString(Data.DATA1);
+ if (null != contactInfo && !"".equals(contactInfo)) {
+ entry.mAfter.put(Data.DATA1, contactInfo);
+ }
+ }
+
return entry;
}
@@ -83,6 +95,10 @@ public class ValuesDelta implements Parcelable {
return mAfter;
}
+ public ContentValues getBefore() {
+ return mBefore;
+ }
+
public boolean containsKey(String key) {
return ((mAfter != null && mAfter.containsKey(key)) ||
(mBefore != null && mBefore.containsKey(key)));
diff --git a/src/com/android/contacts/common/model/account/AccountType.java b/src/com/android/contacts/common/model/account/AccountType.java
index 53ab47d9..ae4706ff 100644..100755
--- a/src/com/android/contacts/common/model/account/AccountType.java
+++ b/src/com/android/contacts/common/model/account/AccountType.java
@@ -16,19 +16,26 @@
package com.android.contacts.common.model.account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorDescription;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.RawContacts;
+import android.telephony.TelephonyManager;
+import android.util.Log;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
+import com.android.contacts.common.MoreContactUtils;
import com.android.contacts.common.R;
import com.android.contacts.common.model.dataitem.DataKind;
+import com.android.internal.telephony.PhoneConstants;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -39,6 +46,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Internal structure that represents constraints and styles for a specific data
@@ -96,6 +104,11 @@ public abstract class AccountType {
protected boolean mIsInitialized;
+ private Map<String, AuthenticatorDescription> mTypeToAuthDescription
+ = new HashMap<String, AuthenticatorDescription>();
+
+ private AuthenticatorDescription[] mAuthDescs;
+
protected static class DefinitionException extends Exception {
public DefinitionException(String message) {
super(message);
@@ -196,12 +209,6 @@ public abstract class AccountType {
public String getViewGroupActivity() {
return null;
}
-
- public CharSequence getDisplayLabel(Context context) {
- // Note this resource is defined in the sync adapter package, not resourcePackageName.
- return getResourceText(context, syncAdapterPackageName, titleRes, accountType);
- }
-
/**
* @return resource ID for the "invite contact" action label, or -1 if not defined.
*/
@@ -276,15 +283,89 @@ public abstract class AccountType {
}
}
+ public void updateAuthDescriptions(Context context) {
+ mAuthDescs = AccountManager.get(context).getAuthenticatorTypes();
+ for (int i = 0; i < mAuthDescs.length; i++) {
+ mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]);
+ }
+ }
+ public CharSequence getDisplayLabel(Context context) {
+ CharSequence label = null;
+ updateAuthDescriptions(context);
+ if (mTypeToAuthDescription.containsKey(accountType)) {
+ try {
+ AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
+ Context authContext = context.createPackageContext(desc.packageName, 0);
+ label = authContext.getResources().getText(desc.labelId);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "No label name for account type " + accountType);
+ } catch (Resources.NotFoundException e) {
+ Log.w(TAG, "No label icon for account type " + accountType);
+ }
+ }
+ return label;
+ }
+
+ public CharSequence getDisplayLabel(Context context, String accountName) {
+ if ((SimAccountType.ACCOUNT_TYPE).equals(accountType)) {
+ final int slot = MoreContactUtils.getSubscription(accountType,
+ accountName);
+ return MoreContactUtils.getMultiSimAliasesName(context, slot);
+ }
+ return getDisplayLabel(context);
+ }
+
+ /**
+ * Gets an icon associated with a particular account type. If none found, return null.
+ *
+ * @param accountType the type of account
+ * @return a drawable for the icon or null if one cannot be found.
+ */
public Drawable getDisplayIcon(Context context) {
- if (this.titleRes != -1 && this.syncAdapterPackageName != null) {
- final PackageManager pm = context.getPackageManager();
- return pm.getDrawable(this.syncAdapterPackageName, this.iconRes, null);
- } else if (this.titleRes != -1) {
- return context.getResources().getDrawable(this.iconRes);
- } else {
- return null;
+ Drawable icon = null;
+ updateAuthDescriptions(context);
+ if (PhoneAccountType.ACCOUNT_TYPE.equals(accountType)) {
+ return context.getResources().getDrawable(R.drawable.phone_account);
+ }
+ if (mTypeToAuthDescription.containsKey(accountType)) {
+ try {
+ AuthenticatorDescription desc = mTypeToAuthDescription
+ .get(accountType);
+ Context authContext = context.createPackageContext(
+ desc.packageName, 0);
+ icon = authContext.getResources().getDrawable(desc.iconId);
+ } catch (PackageManager.NameNotFoundException e) {
+ } catch (Resources.NotFoundException e) {
+ }
+ }
+ if (icon == null) {
+ icon = context.getPackageManager().getDefaultActivityIcon();
+ }
+ return icon;
+ }
+
+ public Drawable getDisplayIcon(Context context, String accountName) {
+ if ((SimAccountType.ACCOUNT_TYPE).equals(accountType)) {
+ final int slot = MoreContactUtils.getSubscription(accountType,
+ accountName);
+ if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+ switch (slot) {
+ case PhoneConstants.SUB1:
+ return context.getResources().getDrawable(
+ R.drawable.sim1_account);
+ case PhoneConstants.SUB2:
+ return context.getResources().getDrawable(
+ R.drawable.sim2_account);
+ default:
+ return context.getResources().getDrawable(
+ R.drawable.simcard_account);
+ }
+ } else {
+ return context.getResources().getDrawable(
+ R.drawable.simcard_account);
+ }
}
+ return getDisplayIcon(context);
}
/**
diff --git a/src/com/android/contacts/common/model/account/PhoneAccountType.java b/src/com/android/contacts/common/model/account/PhoneAccountType.java
new file mode 100644
index 00000000..d54216fd
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/PhoneAccountType.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2015, The Linux Foundation. All Rights Reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.android.contacts.common.model.account;
+
+import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.SimContactsConstants;
+import com.android.contacts.common.model.account.AccountType.DefinitionException;
+
+
+public class PhoneAccountType extends BaseAccountType{
+ private static final String TAG = "PhoneAccountType";
+
+ public static final String ACCOUNT_TYPE = SimContactsConstants.ACCOUNT_TYPE_PHONE;
+ public static final int FLAGS_PERSON_NAME = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
+ protected static final int FLAGS_PHONE = EditorInfo.TYPE_CLASS_PHONE;
+
+ public PhoneAccountType(Context context, String resPackageName) {
+ this.accountType = ACCOUNT_TYPE;
+ this.resourcePackageName = null;
+ this.syncAdapterPackageName = resPackageName;
+
+ try {
+
+ addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhoneticName(context);
+ addDataKindNickname(context);
+ addDataKindPhone(context);
+ addDataKindEmail(context);
+ addDataKindStructuredPostal(context);
+ addDataKindIm(context);
+ addDataKindOrganization(context);
+ addDataKindPhoto(context);
+ addDataKindNote(context);
+ addDataKindWebsite(context);
+ addDataKindGroupMembership(context);
+ if (context.getResources().getBoolean(
+ com.android.internal.R.bool.config_built_in_sip_phone)) {
+ addDataKindSipAddress(context);
+ }
+
+ mIsInitialized = true;
+ } catch (DefinitionException e) {
+ Log.e(TAG, "Problem building account type", e);
+ }
+
+ }
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return true;
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return true;
+ }
+
+}
diff --git a/src/com/android/contacts/common/model/account/SimAccountType.java b/src/com/android/contacts/common/model/account/SimAccountType.java
new file mode 100644
index 00000000..ba74be7c
--- /dev/null
+++ b/src/com/android/contacts/common/model/account/SimAccountType.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015, The Linux Foundation. All Rights Reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.android.contacts.common.model.account;
+
+import android.content.Context;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.StructuredName;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.util.Log;
+import android.view.inputmethod.EditorInfo;
+import android.graphics.drawable.Drawable;
+
+import com.android.contacts.common.R;
+import com.android.contacts.common.SimContactsConstants;
+import com.android.contacts.common.model.account.AccountType.DefinitionException;
+import com.android.contacts.common.model.dataitem.DataKind;
+import com.google.android.collect.Lists;
+
+public class SimAccountType extends BaseAccountType{
+ private static final String TAG = "SimContactsType";
+
+ public static final String ACCOUNT_TYPE = SimContactsConstants.ACCOUNT_TYPE_SIM;
+ public static final int FLAGS_PERSON_NAME = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
+ public static final int FLAGS_PHONETIC = EditorInfo.TYPE_CLASS_TEXT
+ | EditorInfo.TYPE_TEXT_VARIATION_PHONETIC;
+ protected static final int FLAGS_PHONE = EditorInfo.TYPE_CLASS_PHONE;
+ private static Context mContext;
+
+ public SimAccountType(Context context, String resPackageName) {
+ this.accountType = ACCOUNT_TYPE;
+ this.resourcePackageName = resPackageName;
+ this.syncAdapterPackageName = resPackageName;
+
+ this.mContext = context;
+
+ try {
+ addDataKindStructuredName(context);
+ addDataKindDisplayName(context);
+ addDataKindPhone(context);
+ addDataKindEmail(context);
+ mIsInitialized = true;
+ } catch (DefinitionException e) {
+ Log.e(TAG, "Problem building account type", e);
+ }
+ }
+
+ @Override
+ protected DataKind addDataKindStructuredName(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindStructuredName(context);
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(StructuredName.DISPLAY_NAME, R.string.nameLabelsGroup,
+ FLAGS_PERSON_NAME));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindPhone(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindPhone(context);
+ kind.typeOverallMax = 2;
+ kind.typeColumn = Phone.TYPE;
+ kind.typeList = Lists.newArrayList();
+ kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
+ kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));// This is used to save ANR records
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Phone.NUMBER, R.string.phoneLabelsGroup, FLAGS_PHONE));
+
+ return kind;
+ }
+
+ @Override
+ protected DataKind addDataKindEmail(Context context) throws DefinitionException {
+ final DataKind kind = super.addDataKindEmail(context);
+
+ kind.typeOverallMax = 1;
+ kind.typeColumn = Email.TYPE;
+ kind.fieldList = Lists.newArrayList();
+ kind.fieldList.add(new EditField(Email.ADDRESS, R.string.emailLabelsGroup, FLAGS_EMAIL));
+ return kind;
+ }
+
+
+ @Override
+ public boolean isGroupMembershipEditable() {
+ return false;
+ }
+
+ @Override
+ public boolean areContactsWritable() {
+ return true;
+ }
+
+}
diff --git a/src/com/android/contacts/common/util/AccountSelectionUtil.java b/src/com/android/contacts/common/util/AccountSelectionUtil.java
index 4302dc43..79eb44a8 100644
--- a/src/com/android/contacts/common/util/AccountSelectionUtil.java
+++ b/src/com/android/contacts/common/util/AccountSelectionUtil.java
@@ -22,6 +22,8 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
@@ -31,11 +33,14 @@ import android.widget.ArrayAdapter;
import android.widget.TextView;
import com.android.contacts.common.R;
+import com.android.contacts.common.SimContactsConstants;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
import com.android.contacts.common.vcard.ImportVCardActivity;
+import com.android.internal.telephony.PhoneConstants;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -48,6 +53,8 @@ public class AccountSelectionUtil {
public static boolean mVCardShare = false;
public static Uri mPath;
+ // QRD enhancement: import subscription selected by user
+ private static int mImportSub = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
public static class AccountSelectedListener
implements DialogInterface.OnClickListener {
@@ -56,7 +63,7 @@ public class AccountSelectionUtil {
final private int mResId;
final private int mSubscriptionId;
- final protected List<AccountWithDataSet> mAccountList;
+ protected List<AccountWithDataSet> mAccountList;
public AccountSelectedListener(Context context, List<AccountWithDataSet> accountList,
int resId, int subscriptionId) {
@@ -78,8 +85,21 @@ public class AccountSelectionUtil {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
- doImport(mContext, mResId, mAccountList.get(which), mSubscriptionId);
+ doImport(mContext, mResId, mAccountList.get(which));
}
+ /**
+ * Reset the account list for this listener, to make sure the selected
+ * items reflect the displayed items.
+ *
+ * @param accountList The reset account list.
+ */
+ void setAccountList(List<AccountWithDataSet> accountList) {
+ mAccountList = accountList;
+ }
+ }
+
+ public static void setImportSubscription(int subscription) {
+ mImportSub = subscription;
}
public static Dialog getSelectAccountDialog(Context context, int resId) {
@@ -91,15 +111,28 @@ public class AccountSelectionUtil {
return getSelectAccountDialog(context, resId, onClickListener, null);
}
+ public static Dialog getSelectAccountDialog(Context context, int resId,
+ DialogInterface.OnClickListener onClickListener,
+ DialogInterface.OnCancelListener onCancelListener) {
+ return getSelectAccountDialog(context, resId, onClickListener,
+ onCancelListener, true);
+ }
+
/**
* When OnClickListener or OnCancelListener is null, uses a default listener.
* The default OnCancelListener just closes itself with {@link Dialog#dismiss()}.
*/
public static Dialog getSelectAccountDialog(Context context, int resId,
DialogInterface.OnClickListener onClickListener,
- DialogInterface.OnCancelListener onCancelListener) {
+ DialogInterface.OnCancelListener onCancelListener, boolean includeSIM) {
final AccountTypeManager accountTypes = AccountTypeManager.getInstance(context);
- final List<AccountWithDataSet> writableAccountList = accountTypes.getAccounts(true);
+ List<AccountWithDataSet> writableAccountList = accountTypes.getAccounts(true);
+ if (includeSIM) {
+ writableAccountList = accountTypes.getAccounts(true);
+ } else {
+ writableAccountList = accountTypes.getAccounts(true,
+ AccountTypeManager.FLAG_ALL_ACCOUNTS_WITHOUT_SIM);
+ }
Log.i(LOG_TAG, "The number of available accounts: " + writableAccountList.size());
@@ -144,6 +177,13 @@ public class AccountSelectionUtil {
AccountSelectedListener accountSelectedListener =
new AccountSelectedListener(context, writableAccountList, resId);
onClickListener = accountSelectedListener;
+ } else if (onClickListener instanceof AccountSelectedListener) {
+ // Because the writableAccountList is different if includeSIM or not, so
+ // should reset the account list for the AccountSelectedListener which
+ // is initialized with FLAG_ALL_ACCOUNTS.
+ // Reset the account list to make sure the selected account is contained
+ // in these display accounts.
+ ((AccountSelectedListener) onClickListener).setAccountList(writableAccountList);
}
if (onCancelListener == null) {
onCancelListener = new DialogInterface.OnCancelListener() {
@@ -159,11 +199,11 @@ public class AccountSelectionUtil {
.create();
}
- public static void doImport(Context context, int resId, AccountWithDataSet account,
- int subscriptionId) {
+ public static void doImport(Context context, int resId,
+ AccountWithDataSet account) {
switch (resId) {
- case R.string.manage_sim_contacts: {
- doImportFromSim(context, account, subscriptionId);
+ case R.string.import_from_sim: {
+ doImportFromSim(context, account);
break;
}
case R.string.import_from_vcf_file: {
@@ -173,17 +213,18 @@ public class AccountSelectionUtil {
}
}
- public static void doImportFromSim(Context context, AccountWithDataSet account,
- int subscriptionId) {
- Intent importIntent = new Intent(Intent.ACTION_VIEW);
- importIntent.setType("vnd.android.cursor.item/sim-contact");
+ public static void doImportFromSim(Context context, AccountWithDataSet account) {
+ Intent importIntent = new Intent(SimContactsConstants.ACTION_MULTI_PICK_SIM);
if (account != null) {
- importIntent.putExtra("account_name", account.name);
- importIntent.putExtra("account_type", account.type);
- importIntent.putExtra("data_set", account.dataSet);
+ importIntent.putExtra(SimContactsConstants.ACCOUNT_NAME, account.name);
+ importIntent.putExtra(SimContactsConstants.ACCOUNT_TYPE, account.type);
+ importIntent.putExtra(SimContactsConstants.ACCOUNT_DATA, account.dataSet);
+ }
+ if (TelephonyManager.getDefault().isMultiSimEnabled()) {
+ importIntent.putExtra(PhoneConstants.SLOT_KEY, mImportSub);
+ } else {
+ importIntent.putExtra(PhoneConstants.SLOT_KEY,PhoneConstants.SUB1);
}
- importIntent.putExtra("subscription_id", (Integer) subscriptionId);
- importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
context.startActivity(importIntent);
}
diff --git a/src/com/android/contacts/common/util/AccountsListAdapter.java b/src/com/android/contacts/common/util/AccountsListAdapter.java
index 84435df8..96a87b5d 100644
--- a/src/com/android/contacts/common/util/AccountsListAdapter.java
+++ b/src/com/android/contacts/common/util/AccountsListAdapter.java
@@ -29,6 +29,8 @@ import com.android.contacts.common.R;
import com.android.contacts.common.model.AccountTypeManager;
import com.android.contacts.common.model.account.AccountType;
import com.android.contacts.common.model.account.AccountWithDataSet;
+import com.android.contacts.common.model.account.PhoneAccountType;
+import com.android.contacts.common.model.account.SimAccountType;
import java.util.ArrayList;
import java.util.List;
@@ -48,7 +50,8 @@ public final class AccountsListAdapter extends BaseAdapter {
public enum AccountListFilter {
ALL_ACCOUNTS, // All read-only and writable accounts
ACCOUNTS_CONTACT_WRITABLE, // Only where the account type is contact writable
- ACCOUNTS_GROUP_WRITABLE // Only accounts where the account type is group writable
+ ACCOUNTS_GROUP_WRITABLE, // Only accounts where the account type is group writable
+ ACCOUNTS_CONTACT_WRITABLE_WITHOUT_SIM
}
public AccountsListAdapter(Context context, AccountListFilter accountListFilter) {
@@ -75,10 +78,22 @@ public final class AccountsListAdapter extends BaseAdapter {
private List<AccountWithDataSet> getAccounts(AccountListFilter accountListFilter) {
if (accountListFilter == AccountListFilter.ACCOUNTS_GROUP_WRITABLE) {
- return new ArrayList<AccountWithDataSet>(mAccountTypes.getGroupWritableAccounts());
+ return new ArrayList<AccountWithDataSet>(mAccountTypes.getAccounts(true,
+ AccountTypeManager.FLAG_ALL_ACCOUNTS_WITHOUT_SIM));
}
- return new ArrayList<AccountWithDataSet>(mAccountTypes.getAccounts(
- accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE));
+ final List<AccountWithDataSet> writableAccountList = mAccountTypes
+ .getAccounts(accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE
+ || accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE_WITHOUT_SIM);
+ List<AccountWithDataSet> deletedList = new ArrayList<AccountWithDataSet>();
+
+ if (accountListFilter == AccountListFilter.ACCOUNTS_CONTACT_WRITABLE_WITHOUT_SIM) {
+ for (AccountWithDataSet account : writableAccountList) {
+ if (SimAccountType.ACCOUNT_TYPE.equals(account.type))
+ deletedList.add(account);
+ }
+ writableAccountList.removeAll(deletedList);
+ }
+ return writableAccountList;
}
@Override
@@ -93,14 +108,20 @@ public final class AccountsListAdapter extends BaseAdapter {
final AccountWithDataSet account = mAccounts.get(position);
final AccountType accountType = mAccountTypes.getAccountType(account.type, account.dataSet);
- text1.setText(accountType.getDisplayLabel(mContext));
+ text1.setText(accountType.getDisplayLabel(mContext, account.name));
// For email addresses, we don't want to truncate at end, which might cut off the domain
// name.
+ if (SimAccountType.ACCOUNT_TYPE.equals(account.type)
+ || PhoneAccountType.ACCOUNT_TYPE.equals(account.type)) {
+ text2.setVisibility(View.GONE);
+ } else {
+ text2.setVisibility(View.VISIBLE);
+ }
text2.setText(account.name);
text2.setEllipsize(TruncateAt.MIDDLE);
- icon.setImageDrawable(accountType.getDisplayIcon(mContext));
+ icon.setImageDrawable(accountType.getDisplayIcon(mContext, account.name));
return resultView;
}
diff --git a/src/com/android/contacts/common/vcard/ExportProcessor.java b/src/com/android/contacts/common/vcard/ExportProcessor.java
index d7b2c0fc..ecf4f8a2 100644
--- a/src/com/android/contacts/common/vcard/ExportProcessor.java
+++ b/src/com/android/contacts/common/vcard/ExportProcessor.java
@@ -56,6 +56,7 @@ public class ExportProcessor extends ProcessorBase {
private volatile boolean mCanceled;
private volatile boolean mDone;
+ private String selExport = "";
public ExportProcessor(VCardService service, ExportRequest exportRequest, int jobId,
String callingActivity) {
@@ -141,7 +142,7 @@ public class ExportProcessor extends ProcessorBase {
final Uri contentUriForRawContactsEntity = RawContactsEntity.CONTENT_URI;
// TODO: should provide better selection.
if (!composer.init(Contacts.CONTENT_URI, new String[] {Contacts._ID},
- null, null,
+ selExport, null,
null, contentUriForRawContactsEntity)) {
final String errorReason = composer.getErrorReason();
Log.e(LOG_TAG, "initialization of vCard composer failed: " + errorReason);
@@ -217,6 +218,10 @@ public class ExportProcessor extends ProcessorBase {
}
}
+ public void setSelExport(String sel) {
+ selExport = sel;
+ }
+
private String translateComposerError(String errorMessage) {
final Resources resources = mService.getResources();
if (VCardComposer.FAILURE_REASON_FAILED_TO_GET_DATABASE_INFO.equals(errorMessage)) {
diff --git a/src/com/android/contacts/common/vcard/ExportVCardActivity.java b/src/com/android/contacts/common/vcard/ExportVCardActivity.java
index 06448ebc..94be8ee1 100644
--- a/src/com/android/contacts/common/vcard/ExportVCardActivity.java
+++ b/src/com/android/contacts/common/vcard/ExportVCardActivity.java
@@ -46,6 +46,7 @@ public class ExportVCardActivity extends Activity implements ServiceConnection,
DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
private static final String LOG_TAG = "VCardExport";
private static final boolean DEBUG = VCardService.DEBUG;
+ private String selExport = "";
private static final int REQUEST_CREATE_DOCUMENT = 100;
/**
@@ -98,6 +99,10 @@ public class ExportVCardActivity extends Activity implements ServiceConnection,
showDialog(R.id.dialog_fail_to_export_with_reason);
}
// Continued to onServiceConnected()
+ Intent selExportIntent = getIntent();
+ if(selExportIntent != null) {
+ selExport = selExportIntent.getStringExtra("SelExport");
+ }
}
@Override
diff --git a/src/com/android/contacts/common/vcard/ImportVCardActivity.java b/src/com/android/contacts/common/vcard/ImportVCardActivity.java
index 85b1417e..642c3da1 100644
--- a/src/com/android/contacts/common/vcard/ImportVCardActivity.java
+++ b/src/com/android/contacts/common/vcard/ImportVCardActivity.java
@@ -36,6 +36,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.provider.OpenableColumns;
+import android.provider.Telephony.Mms.Part;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
@@ -194,6 +195,17 @@ public class ImportVCardActivity extends Activity {
}
}
+ private String getProjection(Uri sourceUri) {
+ String projection = null;
+ if (sourceUri.getAuthority().startsWith("mms")) {
+ // to deal with the vcard received from mms.
+ projection = Part.NAME;
+ } else {
+ projection = OpenableColumns.DISPLAY_NAME;
+ }
+ return projection;
+ }
+
@Override
public void run() {
Log.i(LOG_TAG, "vCard cache thread starts running.");
@@ -270,14 +282,14 @@ public class ImportVCardActivity extends Activity {
// pick up the last part of the Uri.
try {
cursor = resolver.query(sourceUri,
- new String[] { OpenableColumns.DISPLAY_NAME },
+ new String[] { getProjection(sourceUri) },
null, null, null);
if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
if (cursor.getCount() > 1) {
Log.w(LOG_TAG, "Unexpected multiple rows: "
+ cursor.getCount());
}
- int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
+ int index = cursor.getColumnIndex(getProjection(sourceUri));
if (index >= 0) {
displayName = cursor.getString(index);
}
diff --git a/src/com/android/contacts/common/vcard/SelectAccountActivity.java b/src/com/android/contacts/common/vcard/SelectAccountActivity.java
index 66bfbca1..d8596378 100644
--- a/src/com/android/contacts/common/vcard/SelectAccountActivity.java
+++ b/src/com/android/contacts/common/vcard/SelectAccountActivity.java
@@ -58,7 +58,8 @@ public class SelectAccountActivity extends Activity {
// - no account -> use phone-local storage without asking the user
final int resId = R.string.import_from_vcf_file;
final AccountTypeManager accountTypes = AccountTypeManager.getInstance(this);
- final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true);
+ final List<AccountWithDataSet> accountList = accountTypes.getAccounts(true,
+ AccountTypeManager.FLAG_ALL_ACCOUNTS_WITHOUT_SIM);
if (accountList.size() == 0) {
Log.w(LOG_TAG, "Account does not exist");
finish();
@@ -106,7 +107,7 @@ public class SelectAccountActivity extends Activity {
}
return AccountSelectionUtil.getSelectAccountDialog(this, resId,
mAccountSelectionListener,
- new CancelListener());
+ new CancelListener(), false);
}
}
return super.onCreateDialog(resId, bundle);
diff --git a/src/com/android/contacts/common/vcard/VCardService.java b/src/com/android/contacts/common/vcard/VCardService.java
index 1d7837b1..cea79b71 100644
--- a/src/com/android/contacts/common/vcard/VCardService.java
+++ b/src/com/android/contacts/common/vcard/VCardService.java
@@ -67,6 +67,7 @@ public class VCardService extends Service {
/* package */ static final String CACHE_FILE_PREFIX = "import_tmp_";
/* package */ static final String X_VCARD_MIME_TYPE = "text/x-vcard";
+ private String selExport = "";
private class CustomMediaScannerConnectionClient implements MediaScannerConnectionClient {
final MediaScannerConnection mConnection;
@@ -189,7 +190,10 @@ public class VCardService extends Service {
public synchronized void handleExportRequest(ExportRequest request,
VCardImportExportListener listener) {
- if (tryExecute(new ExportProcessor(this, request, mCurrentJobId, mCallingActivity))) {
+ ExportProcessor processor = new ExportProcessor(this, request, mCurrentJobId,
+ mCallingActivity);
+ processor.setSelExport(selExport);
+ if (tryExecute(processor)) {
final String path = request.destUri.getEncodedPath();
if (DEBUG) Log.d(LOG_TAG, "Reserve the path " + path);
if (!mReservedDestination.add(path)) {
@@ -213,6 +217,10 @@ public class VCardService extends Service {
}
}
+ public void setSelExport(String sel) {
+ selExport = sel;
+ }
+
/**
* Tries to call {@link ExecutorService#execute(Runnable)} toward a given processor.
* @return true when successful.