diff options
author | wangqi <wangqi@google.com> | 2017-11-20 20:45:05 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2017-11-20 20:45:05 +0000 |
commit | bfb1dbf27746a8838a7ae4bff243161ad3259273 (patch) | |
tree | 0109c9bda4395c5384ceb330b078a9e6cf846c46 /java | |
parent | 94df7e455565845de8fe09e8d68e9e6fe4258a3a (diff) | |
parent | f58635425b633a010c70ca2c1947d2282a0ee668 (diff) |
Merge changes Ie8759ae5,I5bb23420,I5b2b0f3f
am: f58635425b
Change-Id: Ic51239b61d8fa561cc67f706f74513d913470118
Diffstat (limited to 'java')
8 files changed, 370 insertions, 28 deletions
diff --git a/java/com/android/contacts/common/ContactsUtils.java b/java/com/android/contacts/common/ContactsUtils.java index 66ccc90e7..bc0e42300 100644 --- a/java/com/android/contacts/common/ContactsUtils.java +++ b/java/com/android/contacts/common/ContactsUtils.java @@ -79,6 +79,7 @@ public class ContactsUtils { * running inside Work Profile. */ @Retention(RetentionPolicy.SOURCE) - @IntDef({USER_TYPE_CURRENT, USER_TYPE_WORK}) + // TODO: Switch to @LongDef when @LongDef is available in the support library + @IntDef({(int) USER_TYPE_CURRENT, (int) USER_TYPE_WORK}) public @interface UserType {} } diff --git a/java/com/android/dialer/oem/CequintCallerIdManager.java b/java/com/android/dialer/oem/CequintCallerIdManager.java index df624e06a..48a5985ce 100644 --- a/java/com/android/dialer/oem/CequintCallerIdManager.java +++ b/java/com/android/dialer/oem/CequintCallerIdManager.java @@ -46,17 +46,10 @@ public class CequintCallerIdManager { private static final String CONFIG_CALLER_ID_ENABLED = "config_caller_id_enabled"; - private static final String PROVIDER_NAME = "com.cequint.ecid"; - - private static final Uri CONTENT_URI = Uri.parse("content://" + PROVIDER_NAME + "/lookup"); - private static final int CALLER_ID_LOOKUP_USER_PROVIDED_CID = 0x0001; private static final int CALLER_ID_LOOKUP_SYSTEM_PROVIDED_CID = 0x0002; private static final int CALLER_ID_LOOKUP_INCOMING_CALL = 0x0020; - private static final Uri CONTENT_URI_FOR_INCALL = - Uri.parse("content://" + PROVIDER_NAME + "/incalllookup"); - private static final String[] EMPTY_PROJECTION = new String[] {}; // Column names in Cequint provider. @@ -72,7 +65,7 @@ public class CequintCallerIdManager { private static final String DISPLAY_NAME = "cid_pDisplayName"; private static boolean hasAlreadyCheckedCequintCallerIdPackage; - private static boolean isCequintCallerIdEnabled; + private static String cequintProviderAuthority; // TODO(wangqi): Revisit it and maybe remove it if it's not necessary. private final ConcurrentHashMap<String, CequintCallerIdContact> callLogCache; @@ -98,16 +91,20 @@ public class CequintCallerIdManager { } if (!hasAlreadyCheckedCequintCallerIdPackage) { hasAlreadyCheckedCequintCallerIdPackage = true; - isCequintCallerIdEnabled = false; - try { - context.getPackageManager().getPackageInfo(PROVIDER_NAME, 0); - isCequintCallerIdEnabled = true; - } catch (PackageManager.NameNotFoundException e) { - isCequintCallerIdEnabled = false; + String[] providerNames = context.getResources().getStringArray(R.array.cequint_providers); + PackageManager packageManager = context.getPackageManager(); + for (String provider : providerNames) { + if (CequintPackageUtils.isCallerIdInstalled(packageManager, provider)) { + cequintProviderAuthority = provider; + LogUtil.i( + "CequintCallerIdManager.isCequintCallerIdEnabled", "found provider: %s", provider); + return true; + } } + LogUtil.d("CequintCallerIdManager.isCequintCallerIdEnabled", "no provider found"); } - return isCequintCallerIdEnabled; + return cequintProviderAuthority != null; } public static CequintCallerIdManager createInstanceForCallLog() { @@ -133,7 +130,7 @@ public class CequintCallerIdManager { flag |= CALLER_ID_LOOKUP_USER_PROVIDED_CID; } String[] flags = {cnapName, String.valueOf(flag)}; - return lookup(context, CONTENT_URI_FOR_INCALL, number, flags); + return lookup(context, getIncallLookupUri(), number, flags); } @WorkerThread @@ -150,7 +147,7 @@ public class CequintCallerIdManager { CequintCallerIdContact cequintCallerIdContact = lookup( context, - CONTENT_URI, + getLookupUri(), PhoneNumberUtils.stripSeparators(number), new String[] {"system"}); if (cequintCallerIdContact != null) { @@ -267,6 +264,14 @@ public class CequintCallerIdManager { return geoDescription; } + private static Uri getLookupUri() { + return Uri.parse("content://" + cequintProviderAuthority + "/lookup"); + } + + private static Uri getIncallLookupUri() { + return Uri.parse("content://" + cequintProviderAuthority + "/incalllookup"); + } + private CequintCallerIdManager() { callLogCache = new ConcurrentHashMap<>(); } diff --git a/java/com/android/dialer/oem/CequintPackageUtils.java b/java/com/android/dialer/oem/CequintPackageUtils.java new file mode 100644 index 000000000..66c900e8b --- /dev/null +++ b/java/com/android/dialer/oem/CequintPackageUtils.java @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.dialer.oem; + +import android.annotation.SuppressLint; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ProviderInfo; +import android.content.pm.Signature; +import android.support.annotation.Nullable; +import com.android.dialer.common.LogUtil; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** Utility class to verify Cequint package information. */ +final class CequintPackageUtils { + + private static final int SIGNED_1024 = 0; + private static final int SIGNED_2048 = 1; + private static final int SIGNED_VZW = 2; + private static final int SIGNED_SPRINT = 3; + + // Known Caller Name ID fingerprints + private static final List<byte[]> callerIdFingerprints = new ArrayList<>(); + + static { + // 1024 signed + callerIdFingerprints.add( + SIGNED_1024, + new byte[] { + 0x1A, + 0x0C, + (byte) 0xF8, + (byte) 0x8D, + 0x5B, + (byte) 0xE2, + 0x6A, + (byte) 0xED, + 0x50, + (byte) 0x85, + (byte) 0xFE, + (byte) 0x88, + (byte) 0xA0, + (byte) 0x9E, + (byte) 0xEC, + 0x25, + 0x1E, + (byte) 0xCA, + 0x16, + (byte) 0x97, + 0x50, + (byte) 0xDA, + 0x21, + (byte) 0xCC, + 0x18, + (byte) 0xC9, + (byte) 0x98, + (byte) 0xAF, + 0x26, + (byte) 0xCD, + 0x06, + 0x71 + }); + // 2048 signed + callerIdFingerprints.add( + SIGNED_2048, + new byte[] { + (byte) 0xCA, + 0x2F, + (byte) 0xAE, + (byte) 0xF4, + 0x09, + (byte) 0xEF, + 0x4C, + 0x79, + (byte) 0xF8, + 0x4C, + (byte) 0xD8, + (byte) 0x97, + (byte) 0xBF, + 0x1A, + 0x15, + 0x0F, + (byte) 0xF0, + 0x5E, + 0x54, + 0x74, + (byte) 0xB6, + 0x4A, + (byte) 0xCA, + (byte) 0xCD, + 0x05, + 0x7E, + 0x1E, + (byte) 0x98, + (byte) 0xC6, + 0x1F, + 0x5C, + 0x45 + }); + // VZW Package + callerIdFingerprints.add( + SIGNED_VZW, + new byte[] { + (byte) 0xE6, + 0x7A, + 0x0E, + (byte) 0xB0, + 0x76, + 0x4E, + (byte) 0xC3, + 0x28, + (byte) 0xB7, + (byte) 0xC1, + 0x1B, + 0x1B, + (byte) 0xD0, + (byte) 0x84, + 0x28, + (byte) 0xA6, + 0x16, + (byte) 0xD9, + (byte) 0xF3, + (byte) 0xEB, + (byte) 0xB0, + 0x20, + (byte) 0xA7, + (byte) 0xD8, + (byte) 0xDF, + 0x14, + 0x72, + (byte) 0x81, + 0x4C, + 0x13, + (byte) 0xF3, + (byte) 0xC9 + }); + + // Sprint Package + callerIdFingerprints.add( + SIGNED_SPRINT, + new byte[] { + 0x1A, + (byte) 0xBA, + (byte) 0xA2, + (byte) 0x84, + 0x0C, + 0x61, + (byte) 0x96, + 0x09, + (byte) 0x91, + 0x5E, + (byte) 0x91, + (byte) 0x95, + 0x3D, + 0x29, + 0x3C, + (byte) 0x90, + (byte) 0xEC, + (byte) 0xB4, + (byte) 0x89, + 0x1D, + (byte) 0xC0, + (byte) 0xB1, + 0x23, + 0x58, + (byte) 0x98, + (byte) 0xEB, + (byte) 0xE6, + (byte) 0xD4, + 0x09, + (byte) 0xE5, + (byte) 0x8E, + (byte) 0x9D + }); + } + + @SuppressLint("PackageManagerGetSignatures") + static boolean isCallerIdInstalled( + @Nullable PackageManager packageManager, @Nullable String authority) { + if (packageManager == null) { + LogUtil.i("CequintPackageUtils.isCallerIdInstalled", "failed to get PackageManager!"); + return false; + } + + ProviderInfo providerInfo = + packageManager.resolveContentProvider(authority, PackageManager.GET_META_DATA); + if (providerInfo == null) { + LogUtil.d( + "CequintPackageUtils.isCallerIdInstalled", + "no content provider with '%s' authority", + authority); + return false; + } + + String packageName = providerInfo.packageName; + if (packageName == null) { + LogUtil.w("CequintPackageUtils.isCallerIdInstalled", "can't get valid package name."); + return false; + } + + LogUtil.i( + "CequintPackageUtils.isCallerIdInstalled", + "content provider package name : " + packageName); + + try { + PackageInfo packageInfo = + packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + + Signature[] signatures = packageInfo.signatures; + if (signatures.length > 1) { + LogUtil.w( + "CequintPackageUtils.isCallerIdInstalled", "package has more than one signature."); + return false; + } + byte[] sha256Bytes = getSHA256(signatures[0].toByteArray()); + + for (int i = 0; i < callerIdFingerprints.size(); i++) { + if (Arrays.equals(callerIdFingerprints.get(i), sha256Bytes)) { + LogUtil.i( + "CequintPackageUtils.isCallerIdInstalled", + "this is %s Caller Name ID APK.", + getApkTypeString(i)); + return true; + } + } + } catch (PackageManager.NameNotFoundException e) { + LogUtil.e( + "CequintPackageUtils.isCallerIdInstalled", + "couldn't find package info for the package: %s", + packageName, + e); + } + LogUtil.w( + "CequintPackageUtils.isCallerIdInstalled", + "signature check failed for package: %s", + packageName); + return false; + } + + // Returns sha256 hash of the signature + @Nullable + private static byte[] getSHA256(byte[] sig) { + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA256", "BC"); + } catch (NoSuchAlgorithmException | NoSuchProviderException e) { + LogUtil.e("CequintPackageUtils.getSHA256", "", e); + return null; + } + + digest.update(sig); + return digest.digest(); + } + + private static String getApkTypeString(int index) { + switch (index) { + case SIGNED_1024: + return "1024-signed"; + case SIGNED_2048: + return "2048-signed"; + case SIGNED_VZW: + return "VZWPackage"; + case SIGNED_SPRINT: + default: + return "SprintPackage"; + } + } +} diff --git a/java/com/android/dialer/oem/res/values/motorola_config.xml b/java/com/android/dialer/oem/res/values/motorola_config.xml index 46e7a16b6..ba451e715 100644 --- a/java/com/android/dialer/oem/res/values/motorola_config.xml +++ b/java/com/android/dialer/oem/res/values/motorola_config.xml @@ -74,4 +74,10 @@ <string-array name="motorola_hidden_menu_key_pattern_intents"> <item>@string/motorola_hidden_menu_intent</item> </string-array> + + <!-- This defines the provider names for cequint callerid applications + used for different carriers--> + <string-array name="cequint_providers"> + <item>com.cequint.ecid</item> + </string-array> </resources>
\ No newline at end of file diff --git a/java/com/android/dialer/searchfragment/common/Projections.java b/java/com/android/dialer/searchfragment/common/Projections.java index 63fac4ca0..cebe5c9a9 100644 --- a/java/com/android/dialer/searchfragment/common/Projections.java +++ b/java/com/android/dialer/searchfragment/common/Projections.java @@ -39,8 +39,10 @@ public class Projections { @SuppressWarnings("unused") public static final int SORT_KEY = 11; - public static final int COMPANY_NAME = 12; - public static final int NICKNAME = 13; + public static final int SORT_ALTERNATIVE = 12; + + public static final int COMPANY_NAME = 13; + public static final int NICKNAME = 14; public static final String[] CP2_PROJECTION = new String[] { @@ -56,8 +58,29 @@ public class Projections { Data.CONTACT_ID, // 9 Data.MIMETYPE, // 10 Data.SORT_KEY_PRIMARY, // 11 - Organization.COMPANY, // 12 - Nickname.NAME // 13 + Data.SORT_KEY_ALTERNATIVE, // 12 + Organization.COMPANY, // 13 + Nickname.NAME // 14 + }; + + // Uses alternative display names (i.e. "Bob Dylan" becomes "Dylan, Bob"). + public static final String[] CP2_PROJECTION_ALTERNATIVE = + new String[] { + Data._ID, // 0 + Phone.TYPE, // 1 + Phone.LABEL, // 2 + Phone.NUMBER, // 3 + Data.DISPLAY_NAME_ALTERNATIVE, // 4 + Data.PHOTO_ID, // 5 + Data.PHOTO_THUMBNAIL_URI, // 6 + Data.LOOKUP_KEY, // 7 + Data.CARRIER_PRESENCE, // 8 + Data.CONTACT_ID, // 9 + Data.MIMETYPE, // 10 + Data.SORT_KEY_PRIMARY, // 11 + Data.SORT_KEY_ALTERNATIVE, // 12 + Organization.COMPANY, // 13 + Nickname.NAME // 14 }; public static final String[] DATA_PROJECTION = diff --git a/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java b/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java index dc16f9dd0..23c0d6e6d 100644 --- a/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java +++ b/java/com/android/dialer/searchfragment/cp2/ContactFilterCursor.java @@ -32,6 +32,7 @@ import android.support.annotation.IntDef; import android.support.annotation.Nullable; import android.support.v4.util.ArraySet; import android.text.TextUtils; +import android.util.ArrayMap; import com.android.dialer.searchfragment.common.Projections; import com.android.dialer.searchfragment.common.QueryFilteringUtil; import java.lang.annotation.Retention; @@ -40,6 +41,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Set; /** @@ -108,25 +110,24 @@ final class ContactFilterCursor implements Cursor { private static Cursor createCursor(Cursor cursor) { // Convert cursor rows into Cp2Contacts List<Cp2Contact> cp2Contacts = new ArrayList<>(); - Set<Integer> contactIds = new ArraySet<>(); + Map<Integer, Integer> contactIdsToPosition = new ArrayMap<>(); cursor.moveToPosition(-1); while (cursor.moveToNext()) { Cp2Contact contact = Cp2Contact.fromCursor(cursor); cp2Contacts.add(contact); - contactIds.add(contact.contactId()); + contactIdsToPosition.put(contact.contactId(), cursor.getPosition()); } cursor.close(); // Group then combine contact data List<Cp2Contact> coalescedContacts = new ArrayList<>(); - for (Integer contactId : contactIds) { + for (Integer contactId : contactIdsToPosition.keySet()) { List<Cp2Contact> duplicateContacts = getAllContactsWithContactId(contactId, cp2Contacts); coalescedContacts.addAll(coalesceContacts(duplicateContacts)); } - // Sort by display name, then build new cursor from coalesced contacts. - // We sort the contacts so that they are displayed to the user in lexicographic order. - Collections.sort(coalescedContacts, (o1, o2) -> o1.displayName().compareTo(o2.displayName())); + // Sort the contacts back into the exact same order they were inside of {@code cursor} + Collections.sort(coalescedContacts, (o1, o2) -> compare(contactIdsToPosition, o1, o2)); MatrixCursor newCursor = new MatrixCursor(Projections.CP2_PROJECTION, coalescedContacts.size()); for (Cp2Contact contact : coalescedContacts) { newCursor.addRow(contact.toCursorRow()); @@ -166,6 +167,13 @@ final class ContactFilterCursor implements Cursor { return coalescedContacts; } + private static int compare( + Map<Integer, Integer> contactIdsToPosition, Cp2Contact o1, Cp2Contact o2) { + int position1 = contactIdsToPosition.get(o1.contactId()); + int position2 = contactIdsToPosition.get(o2.contactId()); + return Integer.compare(position1, position2); + } + private static void removeDuplicatePhoneNumbers(List<Cp2Contact> phoneContacts) { for (int i = 0; i < phoneContacts.size(); i++) { Cp2Contact contact1 = phoneContacts.get(i); diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java b/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java index 386ab3a6b..e36df4bf7 100644 --- a/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java +++ b/java/com/android/dialer/searchfragment/cp2/SearchContactViewHolder.java @@ -171,6 +171,8 @@ public final class SearchContactViewHolder extends ViewHolder implements OnClick callToActionView.setVisibility(View.VISIBLE); callToActionView.setImageDrawable( context.getDrawable(com.android.contacts.common.R.drawable.ic_phone_attach)); + callToActionView.setContentDescription( + context.getString(R.string.description_search_call_and_share)); callToActionView.setOnClickListener(this); break; case CallToAction.DUO_CALL: @@ -178,6 +180,8 @@ public final class SearchContactViewHolder extends ViewHolder implements OnClick callToActionView.setVisibility(View.VISIBLE); callToActionView.setImageDrawable( context.getDrawable(R.drawable.quantum_ic_videocam_white_24)); + callToActionView.setContentDescription( + context.getString(R.string.description_search_video_call)); callToActionView.setOnClickListener(this); break; default: diff --git a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java index 2b7af1131..7624bc712 100644 --- a/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java +++ b/java/com/android/dialer/searchfragment/cp2/SearchContactsCursorLoader.java @@ -24,6 +24,7 @@ import android.provider.ContactsContract.CommonDataKinds.Organization; import android.provider.ContactsContract.CommonDataKinds.Phone; import android.provider.ContactsContract.Data; import android.support.annotation.Nullable; +import com.android.contacts.common.preference.ContactsPreferences; import com.android.dialer.searchfragment.common.Projections; /** Cursor Loader for CP2 contacts. */ @@ -41,6 +42,14 @@ public final class SearchContactsCursorLoader extends CursorLoader { null, Phone.SORT_KEY_PRIMARY + " ASC"); this.query = query; + + ContactsPreferences preferences = new ContactsPreferences(getContext()); + if (preferences.getSortOrder() == ContactsPreferences.SORT_ORDER_ALTERNATIVE) { + setSortOrder(Phone.SORT_KEY_ALTERNATIVE + " ASC"); + } + if (preferences.getDisplayOrder() == ContactsPreferences.DISPLAY_ORDER_ALTERNATIVE) { + setProjection(Projections.CP2_PROJECTION_ALTERNATIVE); + } } /** |