diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2017-10-18 02:50:55 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2017-10-18 02:50:55 +0000 |
commit | ef7a7eb0f103d41df55385267ac52dc3dcf603cb (patch) | |
tree | 8bb6b163a88cf321073913c2b0b7dad5ecbd854e /java/com/android | |
parent | c2590357cf857e714f875f2a7c222d1bd128c2c5 (diff) | |
parent | 6f78d935ff64f178e9fe8891082c18578d4e4b74 (diff) |
Merge changes Ida554313,Ie7187b02,I7a7c23b4
* changes:
Stop showing partially matched numbers that are not global phone numbers.
Display Voicemail Contact Name and Photo in Voicemail Fragment.
Add temporary assisted dialing setting to Dialer.
Diffstat (limited to 'java/com/android')
19 files changed, 718 insertions, 233 deletions
diff --git a/java/com/android/dialer/app/settings/DialerSettingsActivity.java b/java/com/android/dialer/app/settings/DialerSettingsActivity.java index 10ef9ed60..706f0985a 100644 --- a/java/com/android/dialer/app/settings/DialerSettingsActivity.java +++ b/java/com/android/dialer/app/settings/DialerSettingsActivity.java @@ -33,9 +33,12 @@ import android.view.MenuItem; import android.widget.Toast; import com.android.dialer.about.AboutPhoneFragment; import com.android.dialer.app.R; +import com.android.dialer.assisteddialing.ConcreteCreator; +import com.android.dialer.assisteddialing.ui.AssistedDialingSettingFragment; import com.android.dialer.blocking.FilteredNumberCompat; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.telephony.TelephonyManagerCompat; +import com.android.dialer.configprovider.ConfigProviderBindings; import com.android.dialer.proguard.UsedByReflection; import com.android.voicemail.VoicemailClient; import com.android.voicemail.VoicemailComponent; @@ -135,6 +138,21 @@ public class DialerSettingsActivity extends AppCompatPreferenceActivity { target.add(accessibilitySettingsHeader); } + boolean isAssistedDialingEnabled = + ConcreteCreator.isAssistedDialingEnabled( + ConfigProviderBindings.get(getApplicationContext())); + LogUtil.i( + "DialerSettingsActivity.onBuildHeaders", + "showing assisted dialing header: " + isAssistedDialingEnabled); + if (isAssistedDialingEnabled) { + + Header assistedDialingSettingsHeader = new Header(); + assistedDialingSettingsHeader.titleRes = + com.android.dialer.assisteddialing.ui.R.string.assisted_dialing_setting_title; + assistedDialingSettingsHeader.fragment = AssistedDialingSettingFragment.class.getName(); + target.add(assistedDialingSettingsHeader); + } + if (showAbout()) { Header aboutPhoneHeader = new Header(); aboutPhoneHeader.titleRes = R.string.about_phone_label; diff --git a/java/com/android/dialer/assisteddialing/ConcreteCreator.java b/java/com/android/dialer/assisteddialing/ConcreteCreator.java index a8a9d2ab3..1790b8f3f 100644 --- a/java/com/android/dialer/assisteddialing/ConcreteCreator.java +++ b/java/com/android/dialer/assisteddialing/ConcreteCreator.java @@ -20,8 +20,10 @@ import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.os.Build.VERSION_CODES; +import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.telephony.TelephonyManager; +import com.android.dialer.assisteddialing.ui.R; import com.android.dialer.common.LogUtil; import com.android.dialer.configprovider.ConfigProvider; import com.android.dialer.configprovider.ConfigProviderBindings; @@ -63,8 +65,15 @@ public final class ConcreteCreator { throw new NullPointerException("Provided context was null"); } - if ((Build.VERSION.SDK_INT < BUILD_CODE_FLOOR || Build.VERSION.SDK_INT > BUILD_CODE_CEILING) - || !configProvider.getBoolean("assisted_dialing_enabled", false)) { + if (!isAssistedDialingEnabled(configProvider)) { + LogUtil.i("ConcreteCreator.createNewAssistedDialingMediator", "feature not enabled"); + return new AssistedDialingMediatorStub(); + } + + if (!PreferenceManager.getDefaultSharedPreferences(context) + .getBoolean(context.getString(R.string.assisted_dialing_setting_toggle_key), false)) { + LogUtil.i("ConcreteCreator.createNewAssistedDialingMediator", "disabled by local setting"); + return new AssistedDialingMediatorStub(); } @@ -74,4 +83,16 @@ public final class ConcreteCreator { return new AssistedDialingMediatorImpl( new LocationDetector(telephonyManager), new NumberTransformer(constraints)); } + + /** Returns a boolean indicating whether or not the assisted dialing feature is enabled. */ + public static boolean isAssistedDialingEnabled(@NonNull ConfigProvider configProvider) { + if (configProvider == null) { + LogUtil.i("ConcreteCreator.isAssistedDialingEnabled", "provided configProvider was null"); + throw new NullPointerException("Provided configProvider was null"); + } + + return (Build.VERSION.SDK_INT >= BUILD_CODE_FLOOR + && Build.VERSION.SDK_INT <= BUILD_CODE_CEILING) + && configProvider.getBoolean("assisted_dialing_enabled", false); + } } diff --git a/java/com/android/dialer/assisteddialing/ui/AndroidManifest.xml b/java/com/android/dialer/assisteddialing/ui/AndroidManifest.xml new file mode 100644 index 000000000..6625dff07 --- /dev/null +++ b/java/com/android/dialer/assisteddialing/ui/AndroidManifest.xml @@ -0,0 +1,22 @@ +<!-- 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.dialer.assisteddialing"> + + <uses-sdk + android:minSdkVersion="23" + android:targetSdkVersion="24"/> + +</manifest>
\ No newline at end of file diff --git a/java/com/android/dialer/assisteddialing/ui/AssistedDialingSettingFragment.java b/java/com/android/dialer/assisteddialing/ui/AssistedDialingSettingFragment.java new file mode 100644 index 000000000..8847448cd --- /dev/null +++ b/java/com/android/dialer/assisteddialing/ui/AssistedDialingSettingFragment.java @@ -0,0 +1,31 @@ +/* + * 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.assisteddialing.ui; + +import android.os.Bundle; +import android.preference.PreferenceFragment; + +/** The setting for Assisted Dialing */ +public class AssistedDialingSettingFragment extends PreferenceFragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.assisted_dialing_setting); + } +} diff --git a/java/com/android/dialer/assisteddialing/ui/res/values/string.xml b/java/com/android/dialer/assisteddialing/ui/res/values/string.xml new file mode 100644 index 000000000..cd159bfd5 --- /dev/null +++ b/java/com/android/dialer/assisteddialing/ui/res/values/string.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> + +<resources> + <!-- Label for a setting enabling assisted dialing [CHAR LIMIT=40]--> + <string name="assisted_dialing_setting_title">Assisted dialing</string> + + <!-- Label for a setting enabling assisted dialing switch preference--> + <string name="assisted_dialing_setting_summary">Automatically correct the phone number prefix when traveling and calling international numbers</string> + + <!-- Key for the assisted dialing setting toggle--> + <string name="assisted_dialing_setting_toggle_key" translatable="false">assisted_dialing_setting_toggle_key</string> +</resources>
\ No newline at end of file diff --git a/java/com/android/dialer/assisteddialing/ui/res/xml/assisted_dialing_setting.xml b/java/com/android/dialer/assisteddialing/ui/res/xml/assisted_dialing_setting.xml new file mode 100644 index 000000000..8e3c62dde --- /dev/null +++ b/java/com/android/dialer/assisteddialing/ui/res/xml/assisted_dialing_setting.xml @@ -0,0 +1,26 @@ +<!-- + ~ 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. + --> + +<PreferenceScreen + xmlns:android="http://schemas.android.com/apk/res/android"> + + <SwitchPreference + android:defaultValue="false" + android:key="@string/assisted_dialing_setting_toggle_key" + android:title="@string/assisted_dialing_setting_title" + android:summary="@string/assisted_dialing_setting_summary" /> + +</PreferenceScreen>
\ No newline at end of file diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java index a5f1425f8..589fe6384 100644 --- a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java +++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java @@ -60,6 +60,7 @@ class AnnotatedCallLogDatabaseHelper extends SQLiteOpenHelper { .toString(); /** Deletes all but the first maxRows rows (by timestamp) to keep the table a manageable size. */ + // TODO(zachh): Prevent voicemails from being garbage collected. private static final String CREATE_TRIGGER_SQL = "create trigger delete_old_rows after insert on " + AnnotatedCallLog.TABLE @@ -79,12 +80,20 @@ class AnnotatedCallLogDatabaseHelper extends SQLiteOpenHelper { + AnnotatedCallLog.TABLE + " )); end;"; + private static final String CREATE_INDEX_ON_CALL_TYPE_SQL = + "create index call_type_index on " + + AnnotatedCallLog.TABLE + + " (" + + AnnotatedCallLog.CALL_TYPE + + ");"; + @Override public void onCreate(SQLiteDatabase db) { LogUtil.enterBlock("AnnotatedCallLogDatabaseHelper.onCreate"); long startTime = System.currentTimeMillis(); db.execSQL(CREATE_TABLE_SQL); db.execSQL(String.format(Locale.US, CREATE_TRIGGER_SQL, maxRows, maxRows)); + db.execSQL(CREATE_INDEX_ON_CALL_TYPE_SQL); // TODO(zachh): Consider logging impression. LogUtil.i( "AnnotatedCallLogDatabaseHelper.onCreate", diff --git a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java index b680bd57d..f501792f9 100644 --- a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java +++ b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java @@ -337,30 +337,30 @@ public class ContactInfoHelper { return ContactInfo.EMPTY; } - Cursor phoneLookupCursor = null; - try { - String[] projection = PhoneQuery.getPhoneLookupProjection(uri); - phoneLookupCursor = mContext.getContentResolver().query(uri, projection, null, null, null); - } catch (NullPointerException e) { - LogUtil.e("ContactInfoHelper.lookupContactFromUri", "phone lookup", e); - // Trap NPE from pre-N CP2 - return null; - } - if (phoneLookupCursor == null) { - LogUtil.d("ContactInfoHelper.lookupContactFromUri", "phoneLookupCursor is null"); - return null; - } + try (Cursor phoneLookupCursor = + mContext + .getContentResolver() + .query(uri, PhoneQuery.getPhoneLookupProjection(uri), null, null, null)) { + if (phoneLookupCursor == null) { + LogUtil.d("ContactInfoHelper.lookupContactFromUri", "phoneLookupCursor is null"); + return null; + } - try { if (!phoneLookupCursor.moveToFirst()) { return ContactInfo.EMPTY; } - String lookupKey = phoneLookupCursor.getString(PhoneQuery.LOOKUP_KEY); - ContactInfo contactInfo = createPhoneLookupContactInfo(phoneLookupCursor, lookupKey); + + Cursor matchedCursor = + PhoneNumberHelper.getCursorMatchForContactLookupUri( + phoneLookupCursor, PhoneQuery.MATCHED_NUMBER, uri); + if (matchedCursor == null) { + return ContactInfo.EMPTY; + } + + String lookupKey = matchedCursor.getString(PhoneQuery.LOOKUP_KEY); + ContactInfo contactInfo = createPhoneLookupContactInfo(matchedCursor, lookupKey); fillAdditionalContactInfo(mContext, contactInfo); return contactInfo; - } finally { - phoneLookupCursor.close(); } } diff --git a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java index cc9b73081..84cbb6947 100644 --- a/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java +++ b/java/com/android/dialer/phonenumberutil/PhoneNumberHelper.java @@ -17,6 +17,8 @@ package com.android.dialer.phonenumberutil; import android.content.Context; +import android.database.Cursor; +import android.net.Uri; import android.os.Trace; import android.provider.CallLog; import android.support.annotation.Nullable; @@ -24,6 +26,7 @@ import android.telecom.PhoneAccountHandle; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.text.TextUtils; +import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.compat.CompatUtils; import com.android.dialer.compat.telephony.TelephonyManagerCompat; @@ -47,6 +50,78 @@ public class PhoneNumberHelper { } /** + * Find the cursor pointing to a number that matches the number in a contact lookup URI. + * + * <p>When determining whether two phone numbers are identical enough for caller ID purposes, the + * Contacts Provider uses {@link PhoneNumberUtils#compare(String, String)}, which ignores special + * dialable characters such as '#', '*', '+', etc. This makes it possible for the cursor returned + * by the Contacts Provider to have multiple rows even when the URI asks for a specific number. + * + * <p>For example, suppose the user has two contacts whose numbers are "#123" and "123", + * respectively. When the URI asks for number "123", both numbers will be returned. Therefore, the + * following strategy is employed to find a match. + * + * <p>If the cursor points to a global phone number (i.e., a number that can be accepted by {@link + * PhoneNumberUtils#isGlobalPhoneNumber(String)}) and the lookup number in the URI is a PARTIAL + * match, return the cursor. + * + * <p>If the cursor points to a number that is not a global phone number, return the cursor iff + * the lookup number in the URI is an EXACT match. + * + * <p>Return null in all other circumstances. + * + * @param cursor A cursor returned by the Contacts Provider. + * @param columnIndexForNumber The index of the column where phone numbers are stored. It is the + * caller's responsibility to pass the correct column index. + * @param contactLookupUri A URI used to retrieve a contact via the Contacts Provider. It is the + * caller's responsibility to ensure the URI is one that asks for a specific phone number. + * @return The cursor considered as a match by the description above or null if no such cursor can + * be found. + */ + public static Cursor getCursorMatchForContactLookupUri( + Cursor cursor, int columnIndexForNumber, Uri contactLookupUri) { + if (cursor == null || contactLookupUri == null) { + return null; + } + + if (!cursor.moveToFirst()) { + return null; + } + + Assert.checkArgument( + 0 <= columnIndexForNumber && columnIndexForNumber < cursor.getColumnCount()); + + String lookupNumber = contactLookupUri.getLastPathSegment(); + if (lookupNumber == null) { + return null; + } + + boolean isMatchFound; + do { + // All undialable characters should be converted/removed before comparing the lookup number + // and the existing contact number. + String rawExistingContactNumber = + PhoneNumberUtils.stripSeparators( + PhoneNumberUtils.convertKeypadLettersToDigits( + cursor.getString(columnIndexForNumber))); + String rawQueryNumber = + PhoneNumberUtils.stripSeparators( + PhoneNumberUtils.convertKeypadLettersToDigits(lookupNumber)); + + isMatchFound = + PhoneNumberUtils.isGlobalPhoneNumber(rawExistingContactNumber) + ? rawExistingContactNumber.contains(rawQueryNumber) + : rawExistingContactNumber.equals(rawQueryNumber); + + if (isMatchFound) { + return cursor; + } + } while (cursor.moveToNext()); + + return null; + } + + /** * Returns true if the given number is the number of the configured voicemail. To be able to * mock-out this, it is not a static method. */ diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailCallLogAdapter.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java index b40c8630e..71178ceba 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailCallLogAdapter.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java @@ -15,41 +15,40 @@ */ package com.android.dialer.voicemail.listui; +import android.database.Cursor; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.android.dialer.common.LogUtil; -import com.android.dialer.voicemail.datasources.VoicemailData; -import java.util.List; /** {@link RecyclerView.Adapter} for the new voicemail call log fragment. */ -final class NewVoicemailCallLogAdapter extends RecyclerView.Adapter<NewVoicemailCallLogViewHolder> { +final class NewVoicemailAdapter extends RecyclerView.Adapter<NewVoicemailViewHolder> { - private final List<VoicemailData> voicemailData; + private final Cursor cursor; - NewVoicemailCallLogAdapter(List<VoicemailData> dataSet) { - voicemailData = dataSet; + /** @param cursor whose projection is {@link VoicemailCursorLoader.VOICEMAIL_COLUMNS} */ + NewVoicemailAdapter(Cursor cursor) { + this.cursor = cursor; } @Override - public NewVoicemailCallLogViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { - + public NewVoicemailViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext()); - View v = inflater.inflate(R.layout.new_voicemail_call_log_entry, viewGroup, false); - NewVoicemailCallLogViewHolder newVoicemailCallLogViewHolder = - new NewVoicemailCallLogViewHolder(v); - return newVoicemailCallLogViewHolder; + View view = inflater.inflate(R.layout.new_voicemail_call_log_entry, viewGroup, false); + NewVoicemailViewHolder newVoicemailViewHolder = new NewVoicemailViewHolder(view); + return newVoicemailViewHolder; } @Override - public void onBindViewHolder(NewVoicemailCallLogViewHolder viewHolder, int position) { + public void onBindViewHolder(NewVoicemailViewHolder viewHolder, int position) { LogUtil.i("onBindViewHolder", "position" + position); - viewHolder.bind(voicemailData.get(position)); + cursor.moveToPosition(position); + viewHolder.bind(cursor); } @Override public int getItemCount() { - return voicemailData.size(); + return cursor.getCount(); } } diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailCallLogViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailCallLogViewHolder.java deleted file mode 100644 index 9ec768464..000000000 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailCallLogViewHolder.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.voicemail.listui; - -import android.support.v7.widget.RecyclerView; -import android.view.View; -import android.widget.TextView; -import com.android.dialer.voicemail.datasources.VoicemailData; - -/** {@link RecyclerView.ViewHolder} for the new voicemail call log. */ -final class NewVoicemailCallLogViewHolder extends RecyclerView.ViewHolder { - - private final TextView primaryTextView; - private final TextView secondaryTextView; - private final TextView transcriptionTextView; - - NewVoicemailCallLogViewHolder(View view) { - super(view); - primaryTextView = (TextView) view.findViewById(R.id.primary_text); - secondaryTextView = (TextView) view.findViewById(R.id.secondary_text); - transcriptionTextView = (TextView) view.findViewById(R.id.transcription_text); - } - - void bind(VoicemailData voicemailData) { - primaryTextView.setText(voicemailData.name()); - secondaryTextView.setText(getVoicemailLocationDateAndDuration(voicemailData)); - transcriptionTextView.setText(voicemailData.transcription()); - } - - private String getVoicemailLocationDateAndDuration(VoicemailData voicemailData) { - return voicemailData.location() - + " · " - + voicemailData.date() - + " · " - + voicemailData.duration(); - } -} diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java index 3629b7551..1912e1e3f 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java @@ -16,49 +16,50 @@ package com.android.dialer.voicemail.listui; +import android.database.Cursor; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.Loader; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.android.dialer.common.LogUtil; -import com.android.dialer.voicemail.datasources.VoicemailData; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; /** Fragment for Dialer Voicemail Tab. */ -public final class NewVoicemailFragment extends Fragment { +public final class NewVoicemailFragment extends Fragment implements LoaderCallbacks<Cursor> { + + private RecyclerView recyclerView; + @Nullable @Override public View onCreateView( LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.new_voicemail_call_log_fragment, container, false); - RecyclerView recyclerView = - (RecyclerView) view.findViewById(R.id.new_voicemail_call_log_recycler_view); - recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + recyclerView = view.findViewById(R.id.new_voicemail_call_log_recycler_view); + getLoaderManager().restartLoader(0, null, this); + return view; + } - // TODO(uabdullah): To be removed once we hook up the UI to the voicemail backend - List<VoicemailData> voicemailData = new ArrayList<>(); - Random rand = new Random(); - for (int i = 0; i < 50; i++) { - VoicemailData mocked = - VoicemailData.builder() - .setName("Fatima Abdullah " + i) - .setLocation("San Francisco, CA") - .setDate("March " + (rand.nextInt(30) + 1)) - .setDuration("00:" + (rand.nextInt(50) + 10)) - .setTranscription( - "This is a transcription text message that literally means nothing.") - .build(); - voicemailData.add(mocked); - } + @Override + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + LogUtil.enterBlock("NewVoicemailFragment.onCreateLoader"); + return new VoicemailCursorLoader(getContext()); + } - LogUtil.i("onCreateView", "size of input:" + voicemailData.size()); - recyclerView.setAdapter(new NewVoicemailCallLogAdapter(voicemailData)); - return view; + @Override + public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + LogUtil.i("NewVoicemailFragment.onCreateLoader", "cursor size is %d", data.getCount()); + recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + recyclerView.setAdapter(new NewVoicemailAdapter(data)); + } + + @Override + public void onLoaderReset(Loader<Cursor> loader) { + LogUtil.enterBlock("NewVoicemailFragment.onLoaderReset"); + recyclerView.setAdapter(null); } } diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java new file mode 100644 index 000000000..daa24c86c --- /dev/null +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java @@ -0,0 +1,60 @@ +/* + * 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.voicemail.listui; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.support.v7.widget.RecyclerView; +import android.view.View; +import android.widget.QuickContactBadge; +import android.widget.TextView; +import com.android.dialer.contactphoto.ContactPhotoManager; +import com.android.dialer.lettertile.LetterTileDrawable; +import com.android.dialer.voicemail.model.VoicemailEntry; + +/** {@link RecyclerView.ViewHolder} for the new voicemail tab. */ +final class NewVoicemailViewHolder extends RecyclerView.ViewHolder { + + private final Context context; + private final TextView primaryTextView; + private final QuickContactBadge quickContactBadge; + + NewVoicemailViewHolder(View view) { + super(view); + this.context = view.getContext(); + primaryTextView = (TextView) view.findViewById(R.id.primary_text); + quickContactBadge = view.findViewById(R.id.quick_contact_photo); + } + + void bind(Cursor cursor) { + VoicemailEntry voicemailEntry = VoicemailCursorLoader.toVoicemailEntry(cursor); + primaryTextView.setText(VoicemailEntryText.buildPrimaryVoicemailText(context, voicemailEntry)); + setPhoto(voicemailEntry); + } + + // TODO(uabdullah): Consider/Implement TYPE (e.g Spam, TYPE_VOICEMAIL) + private void setPhoto(VoicemailEntry voicemailEntry) { + ContactPhotoManager.getInstance(context) + .loadDialerThumbnailOrPhoto( + quickContactBadge, + voicemailEntry.lookupUri() == null ? null : Uri.parse(voicemailEntry.lookupUri()), + voicemailEntry.photoId(), + voicemailEntry.photoUri() == null ? null : Uri.parse(voicemailEntry.photoUri()), + voicemailEntry.name(), + LetterTileDrawable.TYPE_DEFAULT); + } +} diff --git a/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java b/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java new file mode 100644 index 000000000..5a4176542 --- /dev/null +++ b/java/com/android/dialer/voicemail/listui/VoicemailCursorLoader.java @@ -0,0 +1,91 @@ +/* + * 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.voicemail.listui; + +import android.content.Context; +import android.database.Cursor; +import android.provider.CallLog.Calls; +import android.support.v4.content.CursorLoader; +import com.android.dialer.DialerPhoneNumber; +import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog; +import com.android.dialer.voicemail.model.VoicemailEntry; +import com.google.protobuf.InvalidProtocolBufferException; + +/** CursorLoader for the annotated call log (voicemails only). */ +final class VoicemailCursorLoader extends CursorLoader { + + // When adding columns be sure to update {@link #VoicemailCursorLoader.toVoicemailEntry}. + public static final String[] VOICEMAIL_COLUMNS = + new String[] { + AnnotatedCallLog._ID, + AnnotatedCallLog.TIMESTAMP, + AnnotatedCallLog.NAME, + AnnotatedCallLog.NUMBER, + AnnotatedCallLog.FORMATTED_NUMBER, + AnnotatedCallLog.PHOTO_URI, + AnnotatedCallLog.PHOTO_ID, + AnnotatedCallLog.LOOKUP_URI, + AnnotatedCallLog.GEOCODED_LOCATION, + AnnotatedCallLog.CALL_TYPE + }; + + // Indexes for VOICEMAIL_COLUMNS + private static final int ID = 0; + private static final int TIMESTAMP = 1; + private static final int NAME = 2; + private static final int NUMBER = 3; + private static final int FORMATTED_NUMBER = 4; + private static final int PHOTO_URI = 5; + private static final int PHOTO_ID = 6; + private static final int LOOKUP_URI = 7; + private static final int GEOCODED_LOCATION = 8; + private static final int CALL_TYPE = 9; + + // TODO(zachh): Optimize indexes + VoicemailCursorLoader(Context context) { + super( + context, + AnnotatedCallLog.CONTENT_URI, + VOICEMAIL_COLUMNS, + AnnotatedCallLog.CALL_TYPE + " = ?", + new String[] {Integer.toString(Calls.VOICEMAIL_TYPE)}, + AnnotatedCallLog.TIMESTAMP + " DESC"); + } + + /** Creates a new {@link VoicemailEntry} from the provided cursor using the current position. */ + static VoicemailEntry toVoicemailEntry(Cursor cursor) { + DialerPhoneNumber number; + try { + number = DialerPhoneNumber.parseFrom(cursor.getBlob(NUMBER)); + } catch (InvalidProtocolBufferException e) { + throw new IllegalStateException("Couldn't parse DialerPhoneNumber bytes"); + } + + return VoicemailEntry.builder() + .setId(cursor.getInt(ID)) + .setTimestamp(cursor.getLong(TIMESTAMP)) + .setName(cursor.getString(NAME)) + .setNumber(number) + .setFormattedNumber(cursor.getString(FORMATTED_NUMBER)) + .setPhotoUri(cursor.getString(PHOTO_URI)) + .setPhotoId(cursor.getLong(PHOTO_ID)) + .setLookupUri(cursor.getString(LOOKUP_URI)) + .setGeocodedLocation(cursor.getString(GEOCODED_LOCATION)) + .setCallType(cursor.getInt(CALL_TYPE)) + .build(); + } +} diff --git a/java/com/android/dialer/voicemail/listui/VoicemailEntryText.java b/java/com/android/dialer/voicemail/listui/VoicemailEntryText.java new file mode 100644 index 000000000..cf2fef253 --- /dev/null +++ b/java/com/android/dialer/voicemail/listui/VoicemailEntryText.java @@ -0,0 +1,42 @@ +/* + * 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.voicemail.listui; + +import android.content.Context; +import android.text.TextUtils; +import com.android.dialer.voicemail.model.VoicemailEntry; + +/** + * Computes the primary text for voicemail entries. + * + * <p>These text values are shown in the voicemail tab. + */ +public class VoicemailEntryText { + + public static String buildPrimaryVoicemailText(Context context, VoicemailEntry data) { + StringBuilder primaryText = new StringBuilder(); + if (!TextUtils.isEmpty(data.name())) { + primaryText.append(data.name()); + } else if (!TextUtils.isEmpty(data.formattedNumber())) { + primaryText.append(data.formattedNumber()); + } else { + // TODO(uabdullah): Handle CallLog.Calls.PRESENTATION_*, including Verizon restricted numbers. + primaryText.append(context.getText(R.string.voicemail_entry_unknown)); + } + return primaryText.toString(); + } +} diff --git a/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_call_log_entry.xml b/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_call_log_entry.xml index 01c0ee12e..82ccf88d2 100644 --- a/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_call_log_entry.xml +++ b/java/com/android/dialer/voicemail/listui/res/layout/new_voicemail_call_log_entry.xml @@ -31,7 +31,6 @@ android:layout_height="@dimen/call_log_entry_photo_size" android:layout_centerVertical="true" android:padding="@dimen/call_log_entry_photo_padding" - android:background="@color/dialer_secondary_color" android:focusable="true"/> <LinearLayout @@ -42,6 +41,7 @@ android:layout_toStartOf="@+id/menu_button" android:orientation="vertical"> + <!--TODO(uabdullah): Resolve text clipping on top of primary text --> <TextView android:id="@+id/primary_text" style="@style/PrimaryText" diff --git a/java/com/android/dialer/voicemail/listui/res/values/strings.xml b/java/com/android/dialer/voicemail/listui/res/values/strings.xml new file mode 100644 index 000000000..39c368a5a --- /dev/null +++ b/java/com/android/dialer/voicemail/listui/res/values/strings.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<resources> + <!-- String used to display voicemails from unknown numbers in the voicemail tab. [CHAR LIMIT=30] --> + <string name="voicemail_entry_unknown">Unknown</string> +</resources>
\ No newline at end of file diff --git a/java/com/android/dialer/voicemail/model/VoicemailEntry.java b/java/com/android/dialer/voicemail/model/VoicemailEntry.java new file mode 100644 index 000000000..00e1757dc --- /dev/null +++ b/java/com/android/dialer/voicemail/model/VoicemailEntry.java @@ -0,0 +1,89 @@ +/* + * 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.voicemail.model; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import com.android.dialer.DialerPhoneNumber; +import com.google.auto.value.AutoValue; + +/** Data class containing the contents of a voicemail entry from the AnnotatedCallLog. */ +@AutoValue +public abstract class VoicemailEntry { + + public static Builder builder() { + return new AutoValue_VoicemailEntry.Builder() + .setId(0) + .setTimestamp(0) + .setNumber(DialerPhoneNumber.getDefaultInstance()) + .setPhotoId(0) + .setCallType(0); + } + + public abstract int id(); + + public abstract long timestamp(); + + @NonNull + public abstract DialerPhoneNumber number(); + + @Nullable + public abstract String name(); + + @Nullable + public abstract String formattedNumber(); + + @Nullable + public abstract String photoUri(); + + public abstract long photoId(); + + @Nullable + public abstract String lookupUri(); + + @Nullable + public abstract String geocodedLocation(); + + public abstract int callType(); + + /** Builder for {@link VoicemailEntry}. */ + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder setId(int id); + + public abstract Builder setTimestamp(long timestamp); + + public abstract Builder setNumber(@NonNull DialerPhoneNumber number); + + public abstract Builder setName(@Nullable String name); + + public abstract Builder setFormattedNumber(@Nullable String formattedNumber); + + public abstract Builder setPhotoUri(@Nullable String photoUri); + + public abstract Builder setPhotoId(long photoId); + + public abstract Builder setLookupUri(@Nullable String lookupUri); + + public abstract Builder setGeocodedLocation(@Nullable String geocodedLocation); + + public abstract Builder setCallType(int callType); + + public abstract VoicemailEntry build(); + } +} diff --git a/java/com/android/incallui/CallerInfo.java b/java/com/android/incallui/CallerInfo.java index cc1a60a5b..809ed594c 100644 --- a/java/com/android/incallui/CallerInfo.java +++ b/java/com/android/incallui/CallerInfo.java @@ -192,141 +192,145 @@ public class CallerInfo { * * @param context the context used to retrieve string constants * @param contactRef the URI to attach to this CallerInfo object - * @param cursor the first object in the cursor is used to build the CallerInfo object. + * @param cursor the first matching object in the cursor is used to build the CallerInfo object. * @return the CallerInfo which contains the caller id for the given number. The returned * CallerInfo is null if no number is supplied. */ public static CallerInfo getCallerInfo(Context context, Uri contactRef, Cursor cursor) { CallerInfo info = new CallerInfo(); - info.photoResource = 0; - info.phoneLabel = null; - info.numberType = 0; - info.numberLabel = null; info.cachedPhoto = null; - info.isCachedPhotoCurrent = false; info.contactExists = false; + info.contactRefUri = contactRef; + info.isCachedPhotoCurrent = false; + info.name = null; + info.needUpdate = false; + info.numberLabel = null; + info.numberType = 0; + info.phoneLabel = null; + info.photoResource = 0; info.userType = ContactsUtils.USER_TYPE_CURRENT; Log.v(TAG, "getCallerInfo() based on cursor..."); - if (cursor != null) { - if (cursor.moveToFirst()) { - // TODO: photo_id is always available but not taken - // care of here. Maybe we should store it in the - // CallerInfo object as well. - - long contactId = 0L; - int columnIndex; - - // Look for the name - columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME); - if (columnIndex != -1) { - info.name = cursor.getString(columnIndex); - } - - // Look for the number - columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER); - if (columnIndex != -1) { - info.phoneNumber = cursor.getString(columnIndex); - } - - // Look for the normalized number - columnIndex = cursor.getColumnIndex(PhoneLookup.NORMALIZED_NUMBER); - if (columnIndex != -1) { - info.normalizedNumber = cursor.getString(columnIndex); - } - - // Look for the label/type combo - columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL); - if (columnIndex != -1) { - int typeColumnIndex = cursor.getColumnIndex(PhoneLookup.TYPE); - if (typeColumnIndex != -1) { - info.numberType = cursor.getInt(typeColumnIndex); - info.numberLabel = cursor.getString(columnIndex); - info.phoneLabel = - Phone.getTypeLabel(context.getResources(), info.numberType, info.numberLabel) - .toString(); - } - } - - // cache the lookup key for later use to create lookup URIs - columnIndex = cursor.getColumnIndex(PhoneLookup.LOOKUP_KEY); - if (columnIndex != -1) { - info.lookupKeyOrNull = cursor.getString(columnIndex); - } - - // Look for the person_id. - columnIndex = getColumnIndexForPersonId(contactRef, cursor); - if (columnIndex != -1) { - contactId = cursor.getLong(columnIndex); - // QuickContacts in M doesn't support enterprise contact id - if (contactId != 0 - && (VERSION.SDK_INT >= VERSION_CODES.N - || !Contacts.isEnterpriseContactId(contactId))) { - info.contactIdOrZero = contactId; - Log.v(TAG, "==> got info.contactIdOrZero: " + info.contactIdOrZero); - } - } else { - // No valid columnIndex, so we can't look up person_id. - Log.v(TAG, "Couldn't find contactId column for " + contactRef); - // Watch out: this means that anything that depends on - // person_id will be broken (like contact photo lookups in - // the in-call UI, for example.) - } - - // Display photo URI. - columnIndex = cursor.getColumnIndex(PhoneLookup.PHOTO_URI); - if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) { - info.contactDisplayPhotoUri = Uri.parse(cursor.getString(columnIndex)); - } else { - info.contactDisplayPhotoUri = null; - } - - // look for the custom ringtone, create from the string stored - // in the database. - columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE); - if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) { - if (TextUtils.isEmpty(cursor.getString(columnIndex))) { - // make it consistent with frameworks/base/.../CallerInfo.java - info.contactRingtoneUri = Uri.EMPTY; - } else { - info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex)); - } - } else { - info.contactRingtoneUri = null; - } - - // look for the send to voicemail flag, set it to true only - // under certain circumstances. - columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL); - info.shouldSendToVoicemail = (columnIndex != -1) && ((cursor.getInt(columnIndex)) == 1); - info.contactExists = true; - - // Determine userType by directoryId and contactId - final String directory = - contactRef == null - ? null - : contactRef.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY); - Long directoryId = null; - if (directory != null) { - try { - directoryId = Long.parseLong(directory); - } catch (NumberFormatException e) { - // do nothing - } - } - info.userType = ContactsUtils.determineUserType(directoryId, contactId); - - info.nameAlternative = - ContactInfoHelper.lookUpDisplayNameAlternative( - context, info.lookupKeyOrNull, info.userType, directoryId); + if (cursor == null || !cursor.moveToFirst()) { + return info; + } + + // TODO: photo_id is always available but not taken + // care of here. Maybe we should store it in the + // CallerInfo object as well. + + long contactId = 0L; + int columnIndex; + + // If the cursor has the phone number column, find the one that matches the lookup number in the + // URI. + columnIndex = cursor.getColumnIndex(PhoneLookup.NUMBER); + if (columnIndex != -1 && contactRef != null) { + cursor = PhoneNumberHelper.getCursorMatchForContactLookupUri(cursor, columnIndex, contactRef); + if (cursor != null) { + info.phoneNumber = cursor.getString(columnIndex); + } else { + return info; } - cursor.close(); } - info.needUpdate = false; - info.name = normalize(info.name); - info.contactRefUri = contactRef; + // Look for the name + columnIndex = cursor.getColumnIndex(PhoneLookup.DISPLAY_NAME); + if (columnIndex != -1) { + info.name = normalize(cursor.getString(columnIndex)); + } + + // Look for the normalized number + columnIndex = cursor.getColumnIndex(PhoneLookup.NORMALIZED_NUMBER); + if (columnIndex != -1) { + info.normalizedNumber = cursor.getString(columnIndex); + } + + // Look for the label/type combo + columnIndex = cursor.getColumnIndex(PhoneLookup.LABEL); + if (columnIndex != -1) { + int typeColumnIndex = cursor.getColumnIndex(PhoneLookup.TYPE); + if (typeColumnIndex != -1) { + info.numberType = cursor.getInt(typeColumnIndex); + info.numberLabel = cursor.getString(columnIndex); + info.phoneLabel = + Phone.getTypeLabel(context.getResources(), info.numberType, info.numberLabel) + .toString(); + } + } + + // cache the lookup key for later use to create lookup URIs + columnIndex = cursor.getColumnIndex(PhoneLookup.LOOKUP_KEY); + if (columnIndex != -1) { + info.lookupKeyOrNull = cursor.getString(columnIndex); + } + + // Look for the person_id. + columnIndex = getColumnIndexForPersonId(contactRef, cursor); + if (columnIndex != -1) { + contactId = cursor.getLong(columnIndex); + // QuickContacts in M doesn't support enterprise contact id + if (contactId != 0 + && (VERSION.SDK_INT >= VERSION_CODES.N || !Contacts.isEnterpriseContactId(contactId))) { + info.contactIdOrZero = contactId; + Log.v(TAG, "==> got info.contactIdOrZero: " + info.contactIdOrZero); + } + } else { + // No valid columnIndex, so we can't look up person_id. + Log.v(TAG, "Couldn't find contactId column for " + contactRef); + // Watch out: this means that anything that depends on + // person_id will be broken (like contact photo lookups in + // the in-call UI, for example.) + } + + // Display photo URI. + columnIndex = cursor.getColumnIndex(PhoneLookup.PHOTO_URI); + if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) { + info.contactDisplayPhotoUri = Uri.parse(cursor.getString(columnIndex)); + } else { + info.contactDisplayPhotoUri = null; + } + + // look for the custom ringtone, create from the string stored + // in the database. + columnIndex = cursor.getColumnIndex(PhoneLookup.CUSTOM_RINGTONE); + if ((columnIndex != -1) && (cursor.getString(columnIndex) != null)) { + if (TextUtils.isEmpty(cursor.getString(columnIndex))) { + // make it consistent with frameworks/base/.../CallerInfo.java + info.contactRingtoneUri = Uri.EMPTY; + } else { + info.contactRingtoneUri = Uri.parse(cursor.getString(columnIndex)); + } + } else { + info.contactRingtoneUri = null; + } + + // look for the send to voicemail flag, set it to true only + // under certain circumstances. + columnIndex = cursor.getColumnIndex(PhoneLookup.SEND_TO_VOICEMAIL); + info.shouldSendToVoicemail = (columnIndex != -1) && ((cursor.getInt(columnIndex)) == 1); + info.contactExists = true; + + // Determine userType by directoryId and contactId + final String directory = + contactRef == null + ? null + : contactRef.getQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY); + Long directoryId = null; + if (directory != null) { + try { + directoryId = Long.parseLong(directory); + } catch (NumberFormatException e) { + // do nothing + } + } + info.userType = ContactsUtils.determineUserType(directoryId, contactId); + + info.nameAlternative = + ContactInfoHelper.lookUpDisplayNameAlternative( + context, info.lookupKeyOrNull, info.userType, directoryId); + cursor.close(); return info; } |