diff options
12 files changed, 168 insertions, 26 deletions
diff --git a/java/com/android/dialer/calllog/CallLogModule.java b/java/com/android/dialer/calllog/CallLogModule.java index 6c85fd631..9dd9a794d 100644 --- a/java/com/android/dialer/calllog/CallLogModule.java +++ b/java/com/android/dialer/calllog/CallLogModule.java @@ -20,6 +20,7 @@ import com.android.dialer.calllog.datasources.CallLogDataSource; import com.android.dialer.calllog.datasources.DataSources; import com.android.dialer.calllog.datasources.phonelookup.PhoneLookupDataSource; import com.android.dialer.calllog.datasources.systemcalllog.SystemCallLogDataSource; +import com.android.dialer.calllog.datasources.voicemail.VoicemailDataSource; import com.google.common.collect.ImmutableList; import dagger.Module; import dagger.Provides; @@ -31,10 +32,11 @@ public abstract class CallLogModule { @Provides static DataSources provideCallLogDataSources( SystemCallLogDataSource systemCallLogDataSource, - PhoneLookupDataSource phoneLookupDataSource) { + PhoneLookupDataSource phoneLookupDataSource, + VoicemailDataSource voicemailDataSource) { // System call log must be first, see getDataSourcesExcludingSystemCallLog below. ImmutableList<CallLogDataSource> allDataSources = - ImmutableList.of(systemCallLogDataSource, phoneLookupDataSource); + ImmutableList.of(systemCallLogDataSource, phoneLookupDataSource, voicemailDataSource); return new DataSources() { @Override public SystemCallLogDataSource getSystemCallLogDataSource() { diff --git a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java index c8387377b..3b67ff2d7 100644 --- a/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java +++ b/java/com/android/dialer/calllog/database/AnnotatedCallLogDatabaseHelper.java @@ -56,6 +56,8 @@ class AnnotatedCallLogDatabaseHelper extends SQLiteOpenHelper { + (AnnotatedCallLog.VOICEMAIL_URI + " text, ") + (AnnotatedCallLog.CALL_TYPE + " integer not null, ") + (AnnotatedCallLog.NUMBER_ATTRIBUTES + " blob, ") + + (AnnotatedCallLog.IS_VOICEMAIL_CALL + " integer, ") + + (AnnotatedCallLog.VOICEMAIL_CALL_TAG + " text, ") + (AnnotatedCallLog.TRANSCRIPTION_STATE + " integer") + ");"; diff --git a/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java b/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java index c181d7573..b1cf6e495 100644 --- a/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java +++ b/java/com/android/dialer/calllog/database/contract/AnnotatedCallLogContract.java @@ -133,6 +133,25 @@ public class AnnotatedCallLogContract { String NUMBER_ATTRIBUTES = "number_attributes"; /** + * Whether the call is to the voicemail inbox. + * + * <p>TYPE: INTEGER (boolean) + * + * @see android.telecom.TelecomManager#isVoiceMailNumber(android.telecom.PhoneAccountHandle, + * String) + */ + String IS_VOICEMAIL_CALL = "is_voicemail_call"; + + /** + * The "name" of the voicemail inbox. This is provided by the SIM to show as the caller ID + * + * <p>TYPE: TEXT + * + * @see android.telephony.TelephonyManager#getVoiceMailAlphaTag() + */ + String VOICEMAIL_CALL_TAG = "voicemail_call_tag"; + + /** * Copied from {@link android.provider.CallLog.Calls#TYPE}. * * <p>Type: INTEGER (int) @@ -155,6 +174,8 @@ public class AnnotatedCallLogContract { PHONE_ACCOUNT_COLOR, FEATURES, NUMBER_ATTRIBUTES, + IS_VOICEMAIL_CALL, + VOICEMAIL_CALL_TAG, CALL_TYPE }; } diff --git a/java/com/android/dialer/calllog/database/contract/number_attributes.proto b/java/com/android/dialer/calllog/database/contract/number_attributes.proto index e24f393f7..2e93291ab 100644 --- a/java/com/android/dialer/calllog/database/contract/number_attributes.proto +++ b/java/com/android/dialer/calllog/database/contract/number_attributes.proto @@ -24,7 +24,7 @@ package com.android.dialer; import "java/com/android/dialer/logging/contact_source.proto"; // Information related to the phone number of the call. -// Next ID: 13 +// Next ID: 12 message NumberAttributes { // The name (which may be a person's name or business name, but not a number) // formatted exactly as it should appear to the user. If the user's locale or @@ -52,22 +52,19 @@ message NumberAttributes { // The number is a call to a business from nearby places lookup. optional bool is_business = 6; - // The number is a call to the voicemail inbox. - optional bool is_voicemail = 7; - // Can the number be reported as invalid through People API - optional bool can_report_as_invalid_number = 8; + optional bool can_report_as_invalid_number = 7; // True if the CP2 information is incomplete and needs to be queried at // display time. - optional bool is_cp2_info_incomplete = 9; + optional bool is_cp2_info_incomplete = 8; // Whether the number is blocked. - optional bool is_blocked = 10; + optional bool is_blocked = 9; // Whether the number is spam. - optional bool is_spam = 11; + optional bool is_spam = 10; // Source of the contact associated with the number. - optional com.android.dialer.logging.ContactSource.Type contact_source = 12; + optional com.android.dialer.logging.ContactSource.Type contact_source = 11; }
\ No newline at end of file diff --git a/java/com/android/dialer/calllog/datasources/voicemail/VoicemailDataSource.java b/java/com/android/dialer/calllog/datasources/voicemail/VoicemailDataSource.java new file mode 100644 index 000000000..e8dc3e1eb --- /dev/null +++ b/java/com/android/dialer/calllog/datasources/voicemail/VoicemailDataSource.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2018 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.calllog.datasources.voicemail; + +import android.content.ContentValues; +import android.content.Context; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; +import android.telephony.TelephonyManager; +import com.android.dialer.DialerPhoneNumber; +import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog; +import com.android.dialer.calllog.datasources.CallLogDataSource; +import com.android.dialer.calllog.datasources.CallLogMutations; +import com.android.dialer.calllog.datasources.util.RowCombiner; +import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor; +import com.android.dialer.compat.telephony.TelephonyManagerCompat; +import com.android.dialer.telecom.TelecomUtil; +import com.android.dialer.util.PermissionsUtil; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.protobuf.InvalidProtocolBufferException; +import java.util.List; +import java.util.Map.Entry; +import javax.inject.Inject; + +/** Provide information for whether the call is a call to the voicemail inbox. */ +public class VoicemailDataSource implements CallLogDataSource { + + private final ListeningExecutorService backgroundExecutor; + + @Inject + VoicemailDataSource(@BackgroundExecutor ListeningExecutorService backgroundExecutor) { + this.backgroundExecutor = backgroundExecutor; + } + + @Override + public ListenableFuture<Boolean> isDirty(Context appContext) { + // The isVoicemail status is immutable and permanent. The call will always show as "Voicemail" + // even if the SIM is swapped. Dialing the row will result in some unexpected number after a SIM + // swap but this is deemed acceptable. + return Futures.immediateFuture(false); + } + + @Override + @SuppressWarnings("missingPermission") + public ListenableFuture<Void> fill(Context appContext, CallLogMutations mutations) { + if (!PermissionsUtil.hasReadPhoneStatePermissions(appContext)) { + return Futures.immediateFuture(null); + } + return backgroundExecutor.submit( + () -> { + TelecomManager telecomManager = appContext.getSystemService(TelecomManager.class); + for (Entry<Long, ContentValues> insert : mutations.getInserts().entrySet()) { + ContentValues values = insert.getValue(); + PhoneAccountHandle phoneAccountHandle = + TelecomUtil.composePhoneAccountHandle( + values.getAsString(AnnotatedCallLog.PHONE_ACCOUNT_COMPONENT_NAME), + values.getAsString(AnnotatedCallLog.PHONE_ACCOUNT_ID)); + DialerPhoneNumber dialerPhoneNumber; + try { + dialerPhoneNumber = + DialerPhoneNumber.parseFrom(values.getAsByteArray(AnnotatedCallLog.NUMBER)); + } catch (InvalidProtocolBufferException e) { + throw new IllegalStateException(e); + } + + if (telecomManager.isVoiceMailNumber( + phoneAccountHandle, dialerPhoneNumber.getNormalizedNumber())) { + values.put(AnnotatedCallLog.IS_VOICEMAIL_CALL, 1); + TelephonyManager telephonyManager = + TelephonyManagerCompat.getTelephonyManagerForPhoneAccountHandle( + appContext, phoneAccountHandle); + values.put( + AnnotatedCallLog.VOICEMAIL_CALL_TAG, telephonyManager.getVoiceMailAlphaTag()); + } + } + return null; + }); + } + + @Override + public ListenableFuture<Void> onSuccessfulFill(Context appContext) { + return Futures.immediateFuture(null); + } + + @Override + public ContentValues coalesce(List<ContentValues> individualRowsSortedByTimestampDesc) { + return new RowCombiner(individualRowsSortedByTimestampDesc) + .useMostRecentInt(AnnotatedCallLog.IS_VOICEMAIL_CALL) + .useMostRecentString(AnnotatedCallLog.VOICEMAIL_CALL_TAG) + .combine(); + } + + @Override + public void registerContentObservers(Context appContext) {} +} diff --git a/java/com/android/dialer/calllog/model/CoalescedRow.java b/java/com/android/dialer/calllog/model/CoalescedRow.java index 2b6db97a2..737e736d6 100644 --- a/java/com/android/dialer/calllog/model/CoalescedRow.java +++ b/java/com/android/dialer/calllog/model/CoalescedRow.java @@ -39,6 +39,7 @@ public abstract class CoalescedRow { .setFeatures(0) .setCallType(0) .setNumberAttributes(NumberAttributes.getDefaultInstance()) + .setIsVoicemailCall(false) .setCoalescedIds(CoalescedIds.getDefaultInstance()); } @@ -80,6 +81,11 @@ public abstract class CoalescedRow { public abstract NumberAttributes numberAttributes(); + public abstract boolean isVoicemailCall(); + + @Nullable + public abstract String voicemailCallTag(); + public abstract CoalescedIds coalescedIds(); /** Builder for {@link CoalescedRow}. */ @@ -117,6 +123,10 @@ public abstract class CoalescedRow { public abstract Builder setNumberAttributes(NumberAttributes numberAttributes); + public abstract Builder setIsVoicemailCall(boolean isVoicemail); + + public abstract Builder setVoicemailCallTag(@Nullable String tag); + public abstract Builder setCoalescedIds(CoalescedIds coalescedIds); public abstract CoalescedRow build(); diff --git a/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java b/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java index 0b1c6c990..a5cfd3f59 100644 --- a/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java +++ b/java/com/android/dialer/calllog/ui/CoalescedAnnotatedCallLogCursorLoader.java @@ -44,8 +44,10 @@ final class CoalescedAnnotatedCallLogCursorLoader extends CursorLoader { private static final int PHONE_ACCOUNT_COLOR = 11; private static final int FEATURES = 12; private static final int NUMBER_ATTRIBUTES = 13; - private static final int CALL_TYPE = 14; - private static final int COALESCED_IDS = 15; + private static final int IS_VOICEMAIL_CALL = 14; + private static final int VOICEMAIL_CALL_TAG = 15; + private static final int CALL_TYPE = 16; + private static final int COALESCED_IDS = 17; CoalescedAnnotatedCallLogCursorLoader(Context context) { // CoalescedAnnotatedCallLog requires that PROJECTION be ALL_COLUMNS and the following params be @@ -98,6 +100,8 @@ final class CoalescedAnnotatedCallLogCursorLoader extends CursorLoader { .setFeatures(cursor.getInt(FEATURES)) .setCallType(cursor.getInt(CALL_TYPE)) .setNumberAttributes(numberAttributes) + .setIsVoicemailCall(cursor.getInt(IS_VOICEMAIL_CALL) == 1) + .setVoicemailCallTag(cursor.getString(VOICEMAIL_CALL_TAG)) .setCoalescedIds(coalescedIds) .build(); } diff --git a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java index 4c2d124d7..74be21b0c 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java @@ -153,7 +153,8 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { private void setPhoto(CoalescedRow row) { PhotoInfo.Builder photoInfoBuilder = - NumberAttributesConverter.toPhotoInfoBuilder(row.numberAttributes()); + NumberAttributesConverter.toPhotoInfoBuilder(row.numberAttributes()) + .setIsVoicemail(row.isVoicemailCall()); if (!TextUtils.isEmpty(row.formattedNumber())) { photoInfoBuilder.setFormattedNumber(row.formattedNumber()); } diff --git a/java/com/android/dialer/calllog/ui/menu/Modules.java b/java/com/android/dialer/calllog/ui/menu/Modules.java index fd5f6a348..69b42e304 100644 --- a/java/com/android/dialer/calllog/ui/menu/Modules.java +++ b/java/com/android/dialer/calllog/ui/menu/Modules.java @@ -176,7 +176,8 @@ final class Modules { private static PhotoInfo createPhotoInfoFromRow(CoalescedRow row) { PhotoInfo.Builder photoInfoBuilder = NumberAttributesConverter.toPhotoInfoBuilder(row.numberAttributes()) - .setIsVideo((row.features() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO); + .setIsVideo((row.features() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) + .setIsVoicemail(row.isVoicemailCall()); if (!TextUtils.isEmpty(row.formattedNumber())) { photoInfoBuilder.setFormattedNumber(row.formattedNumber()); } diff --git a/java/com/android/dialer/calllogutils/CallLogEntryText.java b/java/com/android/dialer/calllogutils/CallLogEntryText.java index ab851cbbd..6f1047cb7 100644 --- a/java/com/android/dialer/calllogutils/CallLogEntryText.java +++ b/java/com/android/dialer/calllogutils/CallLogEntryText.java @@ -48,6 +48,10 @@ public final class CallLogEntryText { return presentationName.get(); } + if (row.isVoicemailCall() && !TextUtils.isEmpty(row.voicemailCallTag())) { + return row.voicemailCallTag(); + } + // Otherwise prefer the name. if (!TextUtils.isEmpty(row.numberAttributes().getName())) { return row.numberAttributes().getName(); diff --git a/java/com/android/dialer/calllogutils/NumberAttributesConverter.java b/java/com/android/dialer/calllogutils/NumberAttributesConverter.java index df6b680db..24567e027 100644 --- a/java/com/android/dialer/calllogutils/NumberAttributesConverter.java +++ b/java/com/android/dialer/calllogutils/NumberAttributesConverter.java @@ -34,7 +34,6 @@ public final class NumberAttributesConverter { .setLookupUri(numberAttributes.getLookupUri()) .setIsBusiness(numberAttributes.getIsBusiness()) .setIsSpam(numberAttributes.getIsSpam()) - .setIsVoicemail(numberAttributes.getIsVoicemail()) .setIsBlocked(numberAttributes.getIsBlocked()); } @@ -52,7 +51,6 @@ public final class NumberAttributesConverter { .setLookupUri(phoneLookupInfoConsolidator.getLookupUri()) .setNumberTypeLabel(phoneLookupInfoConsolidator.getNumberLabel()) .setIsBusiness(phoneLookupInfoConsolidator.isBusiness()) - .setIsVoicemail(phoneLookupInfoConsolidator.isVoicemail()) .setIsBlocked(phoneLookupInfoConsolidator.isBlocked()) .setIsSpam(phoneLookupInfoConsolidator.isSpam()) .setCanReportAsInvalidNumber(phoneLookupInfoConsolidator.canReportAsInvalidNumber()) diff --git a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java index 6e867560d..f9ffd0404 100644 --- a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java +++ b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java @@ -267,15 +267,6 @@ public final class PhoneLookupInfoConsolidator { /** * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method - * returns whether the number is a voicemail number. - */ - public boolean isVoicemail() { - // TODO(twyen): implement - return false; - } - - /** - * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method * returns whether the number is blocked. */ public boolean isBlocked() { |