From 21b13e2975180744020b0fb8c150e4a74c45e30c Mon Sep 17 00:00:00 2001 From: linyuh Date: Thu, 8 Feb 2018 10:44:50 -0800 Subject: Show icon and label for a spam number in the new call log. Bug: 73077158 Test: CallLogEntryTextTest, GlidePhotoManagerImplTest, PhoneLookupInfoConsolidatorTest PiperOrigin-RevId: 185017362 Change-Id: I113472482da2213d17a847054272a22249edc578 --- .../binary/aosp/AospDialerRootComponent.java | 2 + .../basecomponent/BaseDialerRootComponent.java | 2 + .../google/GoogleStubDialerRootComponent.java | 2 + .../database/contract/number_attributes.proto | 6 +- .../phonelookup/PhoneLookupDataSource.java | 1 + .../dialer/calllog/ui/NewCallLogAdapter.java | 7 +- .../dialer/calllog/ui/NewCallLogViewHolder.java | 38 +++---- .../dialer/calllog/ui/RealtimeRowProcessor.java | 1 + .../dialer/calllog/ui/menu/NewCallLogMenu.java | 9 +- .../dialer/calllog/ui/menu/PrimaryAction.java | 12 +-- .../dialer/calllogutils/CallLogEntryText.java | 37 ++++++- .../calllogutils/NumberAttributesConverter.java | 37 +++++++ .../dialer/calllogutils/res/values/strings.xml | 3 + .../contactactions/ContactActionBottomSheet.java | 25 ++--- .../contactactions/ContactPrimaryActionInfo.java | 47 +------- .../contactphoto/NumberAttributeConverter.java | 66 ------------ .../res/drawable-xxxhdpi/ic_block_black_48dp.png | Bin 2532 -> 0 bytes .../res/drawable/ic_block_grey_48dp.xml | 17 --- .../android/dialer/glide/DialerGlideModule.java | 27 +++++ .../glidephotomanager/GlidePhotoManager.java | 33 ++++++ .../GlidePhotoManagerComponent.java | 38 +++++++ .../glidephotomanager/GlidePhotoManagerModule.java | 30 ++++++ .../dialer/glidephotomanager/PhotoInfo.java | 110 +++++++++++++++++++ .../glidephotomanager/impl/AndroidManifest.xml | 18 ++++ .../impl/GlidePhotoManagerImpl.java | 119 +++++++++++++++++++++ .../res/drawable-xxxhdpi/ic_block_black_48dp.png | Bin 0 -> 2532 bytes .../impl/res/drawable/ic_block_grey_48dp.xml | 17 +++ .../impl/res/drawable/ic_report_red_48dp.xml | 36 +++++++ .../consolidator/PhoneLookupInfoConsolidator.java | 8 ++ .../voicemail/listui/NewVoicemailAdapter.java | 11 +- .../voicemail/listui/NewVoicemailFragment.java | 6 +- .../voicemail/listui/NewVoicemailViewHolder.java | 34 +++--- .../voicemail/listui/menu/NewVoicemailMenu.java | 6 +- .../voicemail/listui/menu/PrimaryAction.java | 15 +-- 34 files changed, 601 insertions(+), 219 deletions(-) create mode 100644 java/com/android/dialer/calllogutils/NumberAttributesConverter.java delete mode 100644 java/com/android/dialer/contactphoto/NumberAttributeConverter.java delete mode 100644 java/com/android/dialer/contactphoto/res/drawable-xxxhdpi/ic_block_black_48dp.png delete mode 100644 java/com/android/dialer/contactphoto/res/drawable/ic_block_grey_48dp.xml create mode 100644 java/com/android/dialer/glide/DialerGlideModule.java create mode 100644 java/com/android/dialer/glidephotomanager/GlidePhotoManager.java create mode 100644 java/com/android/dialer/glidephotomanager/GlidePhotoManagerComponent.java create mode 100644 java/com/android/dialer/glidephotomanager/GlidePhotoManagerModule.java create mode 100644 java/com/android/dialer/glidephotomanager/PhotoInfo.java create mode 100644 java/com/android/dialer/glidephotomanager/impl/AndroidManifest.xml create mode 100644 java/com/android/dialer/glidephotomanager/impl/GlidePhotoManagerImpl.java create mode 100644 java/com/android/dialer/glidephotomanager/impl/res/drawable-xxxhdpi/ic_block_black_48dp.png create mode 100644 java/com/android/dialer/glidephotomanager/impl/res/drawable/ic_block_grey_48dp.xml create mode 100644 java/com/android/dialer/glidephotomanager/impl/res/drawable/ic_report_red_48dp.xml (limited to 'java/com/android') diff --git a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java index 3f90e6a9e..0f00a5d82 100644 --- a/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java +++ b/java/com/android/dialer/binary/aosp/AospDialerRootComponent.java @@ -24,6 +24,7 @@ import com.android.dialer.configprovider.SharedPrefConfigProviderModule; import com.android.dialer.duo.stub.StubDuoModule; import com.android.dialer.enrichedcall.stub.StubEnrichedCallModule; import com.android.dialer.feedback.stub.StubFeedbackModule; +import com.android.dialer.glidephotomanager.GlidePhotoManagerModule; import com.android.dialer.inject.ContextModule; import com.android.dialer.phonelookup.PhoneLookupModule; import com.android.dialer.phonenumbergeoutil.impl.PhoneNumberGeoUtilModule; @@ -50,6 +51,7 @@ import javax.inject.Singleton; CommandLineModule.class, ContextModule.class, DialerExecutorModule.class, + GlidePhotoManagerModule.class, PhoneLookupModule.class, PhoneNumberGeoUtilModule.class, PreCallModule.class, diff --git a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java index d8efd0a07..3e7db9d8a 100644 --- a/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java +++ b/java/com/android/dialer/binary/basecomponent/BaseDialerRootComponent.java @@ -25,6 +25,7 @@ import com.android.dialer.configprovider.ConfigProviderComponent; import com.android.dialer.duo.DuoComponent; import com.android.dialer.enrichedcall.EnrichedCallComponent; import com.android.dialer.feedback.FeedbackComponent; +import com.android.dialer.glidephotomanager.GlidePhotoManagerComponent; import com.android.dialer.main.MainComponent; import com.android.dialer.phonelookup.PhoneLookupComponent; import com.android.dialer.phonenumbergeoutil.PhoneNumberGeoUtilComponent; @@ -55,6 +56,7 @@ public interface BaseDialerRootComponent DuoComponent.HasComponent, EnrichedCallComponent.HasComponent, FeedbackComponent.HasComponent, + GlidePhotoManagerComponent.HasComponent, MainComponent.HasComponent, MapsComponent.HasComponent, NewBubbleComponent.HasComponent, diff --git a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java index 4da0f92f4..d4520f33e 100644 --- a/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java +++ b/java/com/android/dialer/binary/google/GoogleStubDialerRootComponent.java @@ -24,6 +24,7 @@ import com.android.dialer.configprovider.SharedPrefConfigProviderModule; import com.android.dialer.duo.stub.StubDuoModule; import com.android.dialer.enrichedcall.stub.StubEnrichedCallModule; import com.android.dialer.feedback.stub.StubFeedbackModule; +import com.android.dialer.glidephotomanager.GlidePhotoManagerModule; import com.android.dialer.inject.ContextModule; import com.android.dialer.phonelookup.PhoneLookupModule; import com.android.dialer.phonenumbergeoutil.impl.PhoneNumberGeoUtilModule; @@ -54,6 +55,7 @@ import javax.inject.Singleton; CommandLineModule.class, ContextModule.class, DialerExecutorModule.class, + GlidePhotoManagerModule.class, MapsModule.class, PhoneLookupModule.class, // TODO(zachh): Module which uses APDL? PhoneNumberGeoUtilModule.class, 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 b1a756650..594e6764c 100644 --- a/java/com/android/dialer/calllog/database/contract/number_attributes.proto +++ b/java/com/android/dialer/calllog/database/contract/number_attributes.proto @@ -22,6 +22,7 @@ option optimize_for = LITE_RUNTIME; package com.android.dialer; // Information related to the phone number of the call. +// 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 @@ -59,6 +60,9 @@ message NumberAttributes { // display time. optional bool is_cp2_info_incomplete = 9; - // The number is blocked. + // Whether the number is blocked. optional bool is_blocked = 10; + + // Whether the number is spam. + optional bool is_spam = 11; } \ No newline at end of file diff --git a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java index 8fa6b67cc..52570c05e 100644 --- a/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java +++ b/java/com/android/dialer/calllog/datasources/phonelookup/PhoneLookupDataSource.java @@ -586,6 +586,7 @@ public final class PhoneLookupDataSource .setIsBusiness(phoneLookupInfoConsolidator.isBusiness()) .setIsVoicemail(phoneLookupInfoConsolidator.isVoicemail()) .setIsBlocked(phoneLookupInfoConsolidator.isBlocked()) + .setIsSpam(phoneLookupInfoConsolidator.isSpam()) .setCanReportAsInvalidNumber(phoneLookupInfoConsolidator.canReportAsInvalidNumber()) .setIsCp2InfoIncomplete(phoneLookupInfoConsolidator.isCp2LocalInfoIncomplete()) .build() diff --git a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java index 05a339978..f7ba9efde 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogAdapter.java @@ -25,6 +25,8 @@ import android.view.LayoutInflater; import android.view.ViewGroup; import com.android.dialer.calllogutils.CallLogDates; import com.android.dialer.common.Assert; +import com.android.dialer.glidephotomanager.GlidePhotoManager; +import com.android.dialer.glidephotomanager.GlidePhotoManagerComponent; import com.android.dialer.time.Clock; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -53,6 +55,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter { private final Clock clock; private final RealtimeRowProcessor realtimeRowProcessor; + private final GlidePhotoManager glidePhotoManager; private Cursor cursor; @@ -69,6 +72,7 @@ final class NewCallLogAdapter extends RecyclerView.Adapter { this.cursor = cursor; this.clock = clock; this.realtimeRowProcessor = CallLogUiComponent.get(context).realtimeRowProcessor(); + this.glidePhotoManager = GlidePhotoManagerComponent.get(context).glidePhotoManager(); setHeaderPositions(); } @@ -138,7 +142,8 @@ final class NewCallLogAdapter extends RecyclerView.Adapter { LayoutInflater.from(viewGroup.getContext()) .inflate(R.layout.new_call_log_entry, viewGroup, false), clock, - realtimeRowProcessor); + realtimeRowProcessor, + glidePhotoManager); default: throw Assert.createUnsupportedOperationFailException("Unsupported view type: " + viewType); } diff --git a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java index ee114b5f9..cf016083f 100644 --- a/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java +++ b/java/com/android/dialer/calllog/ui/NewCallLogViewHolder.java @@ -19,26 +19,22 @@ import android.content.Context; import android.content.Intent; import android.content.res.ColorStateList; import android.database.Cursor; -import android.net.Uri; import android.provider.CallLog.Calls; import android.support.annotation.DrawableRes; -import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; -import android.text.TextUtils; import android.view.View; import android.widget.ImageView; import android.widget.QuickContactBadge; import android.widget.TextView; import com.android.dialer.calllog.model.CoalescedRow; import com.android.dialer.calllog.ui.menu.NewCallLogMenu; -import com.android.dialer.calllogutils.CallLogContactTypes; import com.android.dialer.calllogutils.CallLogEntryText; import com.android.dialer.calllogutils.CallLogIntents; +import com.android.dialer.calllogutils.NumberAttributesConverter; import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.compat.AppCompatConstants; import com.android.dialer.compat.telephony.TelephonyManagerCompat; -import com.android.dialer.contactphoto.ContactPhotoManager; -import com.android.dialer.contactphoto.NumberAttributeConverter; +import com.android.dialer.glidephotomanager.GlidePhotoManager; import com.android.dialer.oem.MotorolaUtils; import com.android.dialer.time.Clock; import com.google.common.util.concurrent.FutureCallback; @@ -65,9 +61,15 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { private final RealtimeRowProcessor realtimeRowProcessor; private final ExecutorService uiExecutorService; + private final GlidePhotoManager glidePhotoManager; + private int currentRowId; - NewCallLogViewHolder(View view, Clock clock, RealtimeRowProcessor realtimeRowProcessor) { + NewCallLogViewHolder( + View view, + Clock clock, + RealtimeRowProcessor realtimeRowProcessor, + GlidePhotoManager glidePhotoManager) { super(view); this.context = view.getContext(); primaryTextView = view.findViewById(R.id.primary_text); @@ -83,6 +85,7 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { this.clock = clock; this.realtimeRowProcessor = realtimeRowProcessor; + this.glidePhotoManager = glidePhotoManager; uiExecutorService = DialerExecutorComponent.get(context).uiExecutor(); } @@ -147,19 +150,11 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { } private void setPhoto(CoalescedRow row) { - ContactPhotoManager.getInstance(context) - .loadDialerThumbnailOrPhoto( - quickContactBadge, - parseUri(row.numberAttributes().getLookupUri()), - row.numberAttributes().getPhotoId(), - NumberAttributeConverter.getPhotoUri(context, row.numberAttributes()), - CallLogEntryText.buildPrimaryText(context, row).toString(), - CallLogContactTypes.getContactType(row)); - } - - @Nullable - private static Uri parseUri(@Nullable String uri) { - return TextUtils.isEmpty(uri) ? null : Uri.parse(uri); + glidePhotoManager.loadQuickContactBadge( + quickContactBadge, + NumberAttributesConverter.toPhotoInfoBuilder(row.numberAttributes()) + .setFormattedNumber(row.formattedNumber()) + .build()); } private void setFeatureIcons(CoalescedRow row) { @@ -254,7 +249,8 @@ final class NewCallLogViewHolder extends RecyclerView.ViewHolder { } private void setOnClickListenerForMenuButon(CoalescedRow row) { - menuButton.setOnClickListener(NewCallLogMenu.createOnClickListener(context, row)); + menuButton.setOnClickListener( + NewCallLogMenu.createOnClickListener(context, row, glidePhotoManager)); } private class RealtimeRowFutureCallback implements FutureCallback { diff --git a/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java b/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java index 421c35f55..5083a95c5 100644 --- a/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java +++ b/java/com/android/dialer/calllog/ui/RealtimeRowProcessor.java @@ -212,6 +212,7 @@ public final class RealtimeRowProcessor { .setIsBusiness(phoneLookupInfoConsolidator.isBusiness()) .setIsVoicemail(phoneLookupInfoConsolidator.isVoicemail()) .setIsBlocked(phoneLookupInfoConsolidator.isBlocked()) + .setIsSpam(phoneLookupInfoConsolidator.isSpam()) .setCanReportAsInvalidNumber(phoneLookupInfoConsolidator.canReportAsInvalidNumber()) .build()) .build(); diff --git a/java/com/android/dialer/calllog/ui/menu/NewCallLogMenu.java b/java/com/android/dialer/calllog/ui/menu/NewCallLogMenu.java index 2ae823e7f..81c05135f 100644 --- a/java/com/android/dialer/calllog/ui/menu/NewCallLogMenu.java +++ b/java/com/android/dialer/calllog/ui/menu/NewCallLogMenu.java @@ -20,14 +20,19 @@ import android.content.Context; import android.view.View; import com.android.dialer.calllog.model.CoalescedRow; import com.android.dialer.contactactions.ContactActionBottomSheet; +import com.android.dialer.glidephotomanager.GlidePhotoManager; /** Handles configuration of the bottom sheet menus for call log entries. */ public final class NewCallLogMenu { /** Creates and returns the OnClickListener which opens the menu for the provided row. */ - public static View.OnClickListener createOnClickListener(Context context, CoalescedRow row) { + public static View.OnClickListener createOnClickListener( + Context context, CoalescedRow row, GlidePhotoManager glidePhotoManager) { return (view) -> ContactActionBottomSheet.show( - context, PrimaryAction.fromRow(context, row), Modules.fromRow(context, row)); + context, + PrimaryAction.fromRow(context, row), + Modules.fromRow(context, row), + glidePhotoManager); } } diff --git a/java/com/android/dialer/calllog/ui/menu/PrimaryAction.java b/java/com/android/dialer/calllog/ui/menu/PrimaryAction.java index 2a43a3ca5..92a8453f4 100644 --- a/java/com/android/dialer/calllog/ui/menu/PrimaryAction.java +++ b/java/com/android/dialer/calllog/ui/menu/PrimaryAction.java @@ -19,12 +19,10 @@ package com.android.dialer.calllog.ui.menu; import android.content.Context; import android.provider.CallLog.Calls; import com.android.dialer.calllog.model.CoalescedRow; -import com.android.dialer.calllogutils.CallLogContactTypes; import com.android.dialer.calllogutils.CallLogEntryText; import com.android.dialer.calllogutils.CallLogIntents; +import com.android.dialer.calllogutils.NumberAttributesConverter; import com.android.dialer.contactactions.ContactPrimaryActionInfo; -import com.android.dialer.contactactions.ContactPrimaryActionInfo.PhotoInfo; -import com.android.dialer.contactphoto.NumberAttributeConverter; /** Configures the primary action row (top row) for the bottom sheet. */ final class PrimaryAction { @@ -34,13 +32,9 @@ final class PrimaryAction { return ContactPrimaryActionInfo.builder() .setNumber(row.number()) .setPhotoInfo( - PhotoInfo.builder() - .setPhotoId(row.numberAttributes().getPhotoId()) - .setPhotoUri(NumberAttributeConverter.getPhotoUri(context, row.numberAttributes())) - .setLookupUri(row.numberAttributes().getLookupUri()) + NumberAttributesConverter.toPhotoInfoBuilder(row.numberAttributes()) + .setFormattedNumber(row.formattedNumber()) .setIsVideo((row.features() & Calls.FEATURES_VIDEO) == Calls.FEATURES_VIDEO) - .setContactType(CallLogContactTypes.getContactType(row)) - .setDisplayName(primaryText.toString()) .build()) .setPrimaryText(primaryText) .setSecondaryText(CallLogEntryText.buildSecondaryTextForBottomSheet(context, row)) diff --git a/java/com/android/dialer/calllogutils/CallLogEntryText.java b/java/com/android/dialer/calllogutils/CallLogEntryText.java index 49f5e42ca..737b1d30f 100644 --- a/java/com/android/dialer/calllogutils/CallLogEntryText.java +++ b/java/com/android/dialer/calllogutils/CallLogEntryText.java @@ -65,7 +65,13 @@ public final class CallLogEntryText { /** * The secondary text to show in the main call log entry list. * - *

Rules: (Blocked • )?(Duo video, )?$Label|$Location • Date + *

Rules: + * + *

    + *
  • For numbers that are not spam or blocked: (Duo video, )?$Label|$Location • Date + *
  • For blocked non-spam numbers: Blocked • (Duo video, )?$Label|$Location • Date + *
  • For spam numbers: Spam • (Duo video, )?$Label • Date + *
* *

Examples: * @@ -74,6 +80,10 @@ public final class CallLogEntryText { *

  • Duo Video • 10 min ago *
  • Mobile • 11:45 PM *
  • Mobile • Sun + *
  • Blocked • Duo Video, Mobile • Now + *
  • Blocked • Brooklyn, NJ • 10 min ago + *
  • Spam • Mobile • Now + *
  • Spam • Now *
  • Brooklyn, NJ • Jan 15 * * @@ -82,7 +92,11 @@ public final class CallLogEntryText { public static CharSequence buildSecondaryTextForEntries( Context context, Clock clock, CoalescedRow row) { List components = new ArrayList<>(); - if (row.numberAttributes().getIsBlocked()) { + + // If a number is both spam and blocked, only show "Spam". + if (row.numberAttributes().getIsSpam()) { + components.add(context.getText(R.string.new_call_log_secondary_spam)); + } else if (row.numberAttributes().getIsBlocked()) { components.add(context.getText(R.string.new_call_log_secondary_blocked)); } @@ -102,7 +116,13 @@ public final class CallLogEntryText { */ public static CharSequence buildSecondaryTextForBottomSheet(Context context, CoalescedRow row) { /* - * Rules: (Blocked • )(Duo video, )?$Label|$Location [• NumberIfNoName]? + * Rules: + * For numbers that are not spam or blocked: + * (Duo video, )?$Label|$Location [• NumberIfNoName]? + * For blocked non-spam numbers: + * Blocked • (Duo video, )?$Label|$Location [• NumberIfNoName]? + * For spam numbers: + * Spam • (Duo video, )?$Label [• NumberIfNoName]? * * The number is shown at the end if there is no name for the entry. (It is shown in primary * text otherwise.) @@ -112,11 +132,17 @@ public final class CallLogEntryText { * Duo Video • 555-1234 * Mobile • 555-1234 * Blocked • Mobile • 555-1234 + * Blocked • Brooklyn, NJ • 555-1234 + * Spam • Mobile • 555-1234 * Mobile • 555-1234 * Brooklyn, NJ */ List components = new ArrayList<>(); - if (row.numberAttributes().getIsBlocked()) { + + // If a number is both spam and blocked, only show "Spam". + if (row.numberAttributes().getIsSpam()) { + components.add(context.getText(R.string.new_call_log_secondary_spam)); + } else if (row.numberAttributes().getIsBlocked()) { components.add(context.getText(R.string.new_call_log_secondary_blocked)); } @@ -162,7 +188,8 @@ public final class CallLogEntryText { secondaryText.append(", "); } secondaryText.append(numberTypeLabel); - } else { // If there's a number type label, don't show the location. + } else if (!row.numberAttributes().getIsSpam()) { + // Don't show the location if there's a number type label or the number is spam. String location = row.geocodedLocation(); if (!TextUtils.isEmpty(location)) { if (secondaryText.length() > 0) { diff --git a/java/com/android/dialer/calllogutils/NumberAttributesConverter.java b/java/com/android/dialer/calllogutils/NumberAttributesConverter.java new file mode 100644 index 000000000..bed1edd06 --- /dev/null +++ b/java/com/android/dialer/calllogutils/NumberAttributesConverter.java @@ -0,0 +1,37 @@ +/* + * 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.calllogutils; + +import com.android.dialer.NumberAttributes; +import com.android.dialer.glidephotomanager.PhotoInfo; + +/** Converts {@link NumberAttributes} to {@link PhotoInfo} */ +public final class NumberAttributesConverter { + + /** Converts to {@link PhotoInfo.Builder} */ + public static PhotoInfo.Builder toPhotoInfoBuilder(NumberAttributes numberAttributes) { + return PhotoInfo.builder() + .setName(numberAttributes.getName()) + .setPhotoUri(numberAttributes.getPhotoUri()) + .setPhotoId(numberAttributes.getPhotoId()) + .setLookupUri(numberAttributes.getLookupUri()) + .setIsBusiness(numberAttributes.getIsBusiness()) + .setIsSpam(numberAttributes.getIsSpam()) + .setIsVoicemail(numberAttributes.getIsVoicemail()) + .setIsBlocked(numberAttributes.getIsBlocked()); + } +} diff --git a/java/com/android/dialer/calllogutils/res/values/strings.xml b/java/com/android/dialer/calllogutils/res/values/strings.xml index 4622e509c..f536ca66d 100644 --- a/java/com/android/dialer/calllogutils/res/values/strings.xml +++ b/java/com/android/dialer/calllogutils/res/values/strings.xml @@ -139,4 +139,7 @@ Blocked + + + Spam \ No newline at end of file diff --git a/java/com/android/dialer/contactactions/ContactActionBottomSheet.java b/java/com/android/dialer/contactactions/ContactActionBottomSheet.java index 27e318786..98a5dd115 100644 --- a/java/com/android/dialer/contactactions/ContactActionBottomSheet.java +++ b/java/com/android/dialer/contactactions/ContactActionBottomSheet.java @@ -17,7 +17,6 @@ package com.android.dialer.contactactions; import android.content.Context; -import android.net.Uri; import android.os.Bundle; import android.support.design.widget.BottomSheetDialog; import android.text.TextUtils; @@ -29,8 +28,7 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import com.android.dialer.common.Assert; -import com.android.dialer.contactactions.ContactPrimaryActionInfo.PhotoInfo; -import com.android.dialer.contactphoto.ContactPhotoManager; +import com.android.dialer.glidephotomanager.GlidePhotoManager; import java.util.List; /** @@ -44,23 +42,27 @@ public class ContactActionBottomSheet extends BottomSheetDialog implements OnCli private final List modules; private final ContactPrimaryActionInfo contactPrimaryActionInfo; + private final GlidePhotoManager glidePhotoManager; private ContactActionBottomSheet( Context context, ContactPrimaryActionInfo contactPrimaryActionInfo, - List modules) { + List modules, + GlidePhotoManager glidePhotoManager) { super(context); this.modules = modules; this.contactPrimaryActionInfo = contactPrimaryActionInfo; + this.glidePhotoManager = glidePhotoManager; setContentView(LayoutInflater.from(context).inflate(R.layout.sheet_layout, null)); } public static ContactActionBottomSheet show( Context context, ContactPrimaryActionInfo contactPrimaryActionInfo, - List modules) { + List modules, + GlidePhotoManager glidePhotoManager) { ContactActionBottomSheet sheet = - new ContactActionBottomSheet(context, contactPrimaryActionInfo, modules); + new ContactActionBottomSheet(context, contactPrimaryActionInfo, modules, glidePhotoManager); sheet.show(); return sheet; } @@ -85,15 +87,8 @@ public class ContactActionBottomSheet extends BottomSheetDialog implements OnCli View contactView = inflater.inflate(R.layout.contact_layout, container, false); // TODO(zachh): The contact image should be badged with a video icon if it is for a video call. - PhotoInfo photoInfo = contactPrimaryActionInfo.photoInfo(); - ContactPhotoManager.getInstance(getContext()) - .loadDialerThumbnailOrPhoto( - contactView.findViewById(R.id.quick_contact_photo), - !TextUtils.isEmpty(photoInfo.lookupUri()) ? Uri.parse(photoInfo.lookupUri()) : null, - photoInfo.photoId(), - photoInfo.photoUri(), - photoInfo.displayName(), - photoInfo.contactType()); + glidePhotoManager.loadQuickContactBadge( + contactView.findViewById(R.id.quick_contact_photo), contactPrimaryActionInfo.photoInfo()); TextView primaryTextView = contactView.findViewById(R.id.primary_text); TextView secondaryTextView = contactView.findViewById(R.id.secondary_text); diff --git a/java/com/android/dialer/contactactions/ContactPrimaryActionInfo.java b/java/com/android/dialer/contactactions/ContactPrimaryActionInfo.java index f19fd282c..5017d83b9 100644 --- a/java/com/android/dialer/contactactions/ContactPrimaryActionInfo.java +++ b/java/com/android/dialer/contactactions/ContactPrimaryActionInfo.java @@ -16,11 +16,10 @@ package com.android.dialer.contactactions; import android.content.Intent; -import android.net.Uri; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import com.android.dialer.DialerPhoneNumber; -import com.android.dialer.lettertile.LetterTileDrawable; +import com.android.dialer.glidephotomanager.PhotoInfo; import com.google.auto.value.AutoValue; /** @@ -35,50 +34,6 @@ public abstract class ContactPrimaryActionInfo { @Nullable public abstract DialerPhoneNumber number(); - /** Information used to construct the photo for the contact. */ - @AutoValue - public abstract static class PhotoInfo { - public abstract long photoId(); - - @Nullable - public abstract Uri photoUri(); - - @Nullable - public abstract String lookupUri(); - - /** Badges the photo with a video icon if true. */ - public abstract boolean isVideo(); - - @LetterTileDrawable.ContactType - public abstract int contactType(); - - /** Used to generate letter tile if there is no photo. */ - @Nullable - public abstract String displayName(); - - /** Builder for {@link PhotoInfo}. */ - @AutoValue.Builder - public abstract static class Builder { - public abstract Builder setPhotoId(long photoId); - - public abstract Builder setPhotoUri(@Nullable Uri photoUri); - - public abstract Builder setLookupUri(@Nullable String lookupUri); - - public abstract Builder setIsVideo(boolean isVideo); - - public abstract Builder setContactType(@LetterTileDrawable.ContactType int contactType); - - public abstract Builder setDisplayName(@Nullable String displayName); - - public abstract PhotoInfo build(); - } - - public static Builder builder() { - return new AutoValue_ContactPrimaryActionInfo_PhotoInfo.Builder(); - } - } - @NonNull public abstract PhotoInfo photoInfo(); diff --git a/java/com/android/dialer/contactphoto/NumberAttributeConverter.java b/java/com/android/dialer/contactphoto/NumberAttributeConverter.java deleted file mode 100644 index d7bf9bda7..000000000 --- a/java/com/android/dialer/contactphoto/NumberAttributeConverter.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.contactphoto; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Resources; -import android.net.Uri; -import android.support.annotation.DrawableRes; -import android.support.annotation.Nullable; -import android.text.TextUtils; -import com.android.dialer.NumberAttributes; - -/** - * Convert photo information in {@link NumberAttributes} to an URI suitable for {@link - * ContactPhotoManager}. - * - *

    This class is temporary. The new photo manager should take NumberAttributes directly. - */ -public final class NumberAttributeConverter { - - /** - * Computes the photo URI from NumberAttributes. - * - *

    The photo URI is shown in the quick contact badge in the main call log list or in the top - * item of the bottom sheet menu. - */ - @Nullable - public static Uri getPhotoUri(Context context, NumberAttributes numberAttributes) { - if (numberAttributes.getIsBlocked()) { - return getResourceUri(context.getResources(), R.drawable.ic_block_grey_48dp); - } else { - return parseUri(numberAttributes.getPhotoUri()); - } - } - - @Nullable - private static Uri parseUri(@Nullable String uri) { - return TextUtils.isEmpty(uri) ? null : Uri.parse(uri); - } - - private static Uri getResourceUri(Resources resources, @DrawableRes int drawable) { - return Uri.parse( - ContentResolver.SCHEME_ANDROID_RESOURCE - + "://" - + resources.getResourcePackageName(drawable) - + "/" - + resources.getResourceTypeName(drawable) - + "/" - + resources.getResourceEntryName(drawable)); - } -} diff --git a/java/com/android/dialer/contactphoto/res/drawable-xxxhdpi/ic_block_black_48dp.png b/java/com/android/dialer/contactphoto/res/drawable-xxxhdpi/ic_block_black_48dp.png deleted file mode 100644 index 1168bd8d5..000000000 Binary files a/java/com/android/dialer/contactphoto/res/drawable-xxxhdpi/ic_block_black_48dp.png and /dev/null differ diff --git a/java/com/android/dialer/contactphoto/res/drawable/ic_block_grey_48dp.xml b/java/com/android/dialer/contactphoto/res/drawable/ic_block_grey_48dp.xml deleted file mode 100644 index 42cfa99bd..000000000 --- a/java/com/android/dialer/contactphoto/res/drawable/ic_block_grey_48dp.xml +++ /dev/null @@ -1,17 +0,0 @@ - - \ No newline at end of file diff --git a/java/com/android/dialer/glide/DialerGlideModule.java b/java/com/android/dialer/glide/DialerGlideModule.java new file mode 100644 index 000000000..c74c7cfd4 --- /dev/null +++ b/java/com/android/dialer/glide/DialerGlideModule.java @@ -0,0 +1,27 @@ +/* + * 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.glide; + +import com.bumptech.glide.annotation.GlideModule; +import com.bumptech.glide.module.AppGlideModule; + +/** + * Generates {@link GlideApp}. This class is required for glide annotation processor to generate + * generated API, which most documentations are based on. + */ +@GlideModule +public class DialerGlideModule extends AppGlideModule {} diff --git a/java/com/android/dialer/glidephotomanager/GlidePhotoManager.java b/java/com/android/dialer/glidephotomanager/GlidePhotoManager.java new file mode 100644 index 000000000..519a39481 --- /dev/null +++ b/java/com/android/dialer/glidephotomanager/GlidePhotoManager.java @@ -0,0 +1,33 @@ +/* + * 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.glidephotomanager; + +import android.support.annotation.MainThread; +import android.widget.QuickContactBadge; + +/** Class to load photo for call/contacts */ +public interface GlidePhotoManager { + + /** + * Load {@code photoInfo} into the {@code badge}. The loading is performed in the background and a + * placeholder will be used appropriately. {@code badge} must be already attached to an + * activity/fragment, and the load will be automatically canceled if the lifecycle of the activity + * ends. + */ + @MainThread + void loadQuickContactBadge(QuickContactBadge badge, PhotoInfo photoInfo); +} diff --git a/java/com/android/dialer/glidephotomanager/GlidePhotoManagerComponent.java b/java/com/android/dialer/glidephotomanager/GlidePhotoManagerComponent.java new file mode 100644 index 000000000..b4699be54 --- /dev/null +++ b/java/com/android/dialer/glidephotomanager/GlidePhotoManagerComponent.java @@ -0,0 +1,38 @@ +/* + * 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.glidephotomanager; + +import android.content.Context; +import com.android.dialer.inject.HasRootComponent; +import dagger.Subcomponent; + +/** Entry point for {@link GlidePhotoManager} */ +@Subcomponent +public abstract class GlidePhotoManagerComponent { + + public abstract GlidePhotoManager glidePhotoManager(); + + public static GlidePhotoManagerComponent get(Context context) { + return ((HasComponent) ((HasRootComponent) context.getApplicationContext()).component()) + .glidePhotoManagerComponent(); + } + + /** Used to refer to the root application component. */ + public interface HasComponent { + GlidePhotoManagerComponent glidePhotoManagerComponent(); + } +} diff --git a/java/com/android/dialer/glidephotomanager/GlidePhotoManagerModule.java b/java/com/android/dialer/glidephotomanager/GlidePhotoManagerModule.java new file mode 100644 index 000000000..79629d69e --- /dev/null +++ b/java/com/android/dialer/glidephotomanager/GlidePhotoManagerModule.java @@ -0,0 +1,30 @@ +/* + * 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.glidephotomanager; + +import com.android.dialer.glidephotomanager.impl.GlidePhotoManagerImpl; +import dagger.Binds; +import dagger.Module; +import javax.inject.Singleton; + +/** Module for {@link GlidePhotoManagerComponent} */ +@Module +public abstract class GlidePhotoManagerModule { + @Binds + @Singleton + public abstract GlidePhotoManager bindGlidePhotoManager(GlidePhotoManagerImpl glidePhotoManager); +} diff --git a/java/com/android/dialer/glidephotomanager/PhotoInfo.java b/java/com/android/dialer/glidephotomanager/PhotoInfo.java new file mode 100644 index 000000000..e4dd87152 --- /dev/null +++ b/java/com/android/dialer/glidephotomanager/PhotoInfo.java @@ -0,0 +1,110 @@ +/* + * 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.glidephotomanager; + +import android.support.annotation.Nullable; +import com.google.auto.value.AutoValue; + +/** The number information used to create the photo.. */ +@AutoValue +public abstract class PhotoInfo { + + /** The display name of the number */ + @Nullable + public abstract String name(); + + /** The number displayed to the user. */ + @Nullable + public abstract String formattedNumber(); + + /** The URI to the photo */ + @Nullable + public abstract String photoUri(); + + /** Value of {@link android.provider.ContactsContract.CommonDataKinds.Photo#_ID} */ + public abstract long photoId(); + + /** The contacts provider lookup URI for the contact associated with the number */ + @Nullable + public abstract String lookupUri(); + + /** Should a business icon be displayed */ + public abstract boolean isBusiness(); + + /** Should a voicemail icon be displayed */ + public abstract boolean isVoicemail(); + + /** Should a blocked icon be displayed */ + public abstract boolean isBlocked(); + + /** Should a spam icon be displayed */ + public abstract boolean isSpam(); + + /** + * Should the photo be badged as video call. + * + *

    Defaults to false. + */ + public abstract boolean isVideo(); + + /** + * Should the result be circularized. + * + *

    Defaults to true. + */ + public abstract boolean isCircular(); + + /** Builder for {@link PhotoInfo} */ + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder setName(@Nullable String name); + + public abstract Builder setFormattedNumber(@Nullable String formattedNumber); + + public abstract Builder setPhotoUri(@Nullable String uri); + + public abstract Builder setPhotoId(long id); + + public abstract Builder setLookupUri(@Nullable String uri); + + public abstract Builder setIsBusiness(boolean isBusiness); + + public abstract Builder setIsVoicemail(boolean isVoicemail); + + public abstract Builder setIsBlocked(boolean isBlocked); + + public abstract Builder setIsSpam(boolean isSpam); + + public abstract Builder setIsVideo(boolean isVideo); + + public abstract Builder setIsCircular(boolean isCircular); + + public abstract PhotoInfo build(); + } + + public static PhotoInfo.Builder builder() { + return new AutoValue_PhotoInfo.Builder() + .setPhotoId(0) + .setIsBusiness(false) + .setIsVoicemail(false) + .setIsBlocked(false) + .setIsSpam(false) + .setIsCircular(true) + .setIsVideo(false); + } +} diff --git a/java/com/android/dialer/glidephotomanager/impl/AndroidManifest.xml b/java/com/android/dialer/glidephotomanager/impl/AndroidManifest.xml new file mode 100644 index 000000000..065c10365 --- /dev/null +++ b/java/com/android/dialer/glidephotomanager/impl/AndroidManifest.xml @@ -0,0 +1,18 @@ + + + \ No newline at end of file diff --git a/java/com/android/dialer/glidephotomanager/impl/GlidePhotoManagerImpl.java b/java/com/android/dialer/glidephotomanager/impl/GlidePhotoManagerImpl.java new file mode 100644 index 000000000..20d379c48 --- /dev/null +++ b/java/com/android/dialer/glidephotomanager/impl/GlidePhotoManagerImpl.java @@ -0,0 +1,119 @@ +/* + * 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.glidephotomanager.impl; + +import android.content.ContentUris; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.provider.ContactsContract.Data; +import android.support.annotation.MainThread; +import android.support.annotation.Nullable; +import android.telecom.TelecomManager; +import android.text.TextUtils; +import android.widget.QuickContactBadge; +import com.android.dialer.common.Assert; +import com.android.dialer.glide.GlideApp; +import com.android.dialer.glide.GlideRequest; +import com.android.dialer.glide.GlideRequests; +import com.android.dialer.glidephotomanager.GlidePhotoManager; +import com.android.dialer.glidephotomanager.PhotoInfo; +import com.android.dialer.inject.ApplicationContext; +import com.android.dialer.lettertile.LetterTileDrawable; +import javax.inject.Inject; + +/** Implementation of {@link GlidePhotoManager} */ +public class GlidePhotoManagerImpl implements GlidePhotoManager { + private final Context appContext; + + @Inject + public GlidePhotoManagerImpl(@ApplicationContext Context appContext) { + this.appContext = appContext; + } + + @MainThread + @Override + public void loadQuickContactBadge(QuickContactBadge badge, PhotoInfo photoInfo) { + Assert.isMainThread(); + badge.assignContactUri(parseUri(photoInfo.lookupUri())); + badge.setOverlay(null); + LetterTileDrawable defaultDrawable = getDefaultDrawable(photoInfo); + GlideRequest request = + buildRequest(GlideApp.with(badge), photoInfo) + .placeholder(defaultDrawable) // when the photo is still loading. + .fallback(defaultDrawable); // when there's nothing to load. + + if (photoInfo.isCircular()) { + request.circleCrop(); + } + + request.into(badge); + } + + private GlideRequest buildRequest(GlideRequests requestManager, PhotoInfo photoInfo) { + // The spam status takes precedence over whether the number is blocked. + if (photoInfo.isSpam()) { + return requestManager.load(R.drawable.ic_report_red_48dp); + } + if (photoInfo.isBlocked()) { + return requestManager.load(R.drawable.ic_block_grey_48dp); + } + if (!TextUtils.isEmpty(photoInfo.photoUri())) { + return requestManager.load(parseUri(photoInfo.photoUri())); + } + if (photoInfo.photoId() != 0) { + return requestManager.load(ContentUris.withAppendedId(Data.CONTENT_URI, photoInfo.photoId())); + } + // load null to indicate fallback should be used. + return requestManager.load((Object) null); + } + + /** + * Generate the default drawable when photos are not available. Used when the photo is loading or + * no photo is available. + */ + private LetterTileDrawable getDefaultDrawable(PhotoInfo photoInfo) { + LetterTileDrawable letterTileDrawable = new LetterTileDrawable(appContext.getResources()); + String displayName; + String identifier; + if (TextUtils.isEmpty(photoInfo.lookupUri())) { + // Use generic avatar instead of letter for non-contacts. + displayName = null; + identifier = + TextUtils.isEmpty(photoInfo.name()) ? photoInfo.formattedNumber() : photoInfo.name(); + } else { + displayName = photoInfo.name(); + identifier = photoInfo.lookupUri(); + } + letterTileDrawable.setCanonicalDialerLetterTileDetails( + displayName, + identifier, + LetterTileDrawable.SHAPE_CIRCLE, + LetterTileDrawable.getContactTypeFromPrimitives( + photoInfo.isVoicemail(), + false, // TODO(twyen):implement + photoInfo.isBusiness(), + TelecomManager.PRESENTATION_ALLOWED, // TODO(twyen):implement + false)); // TODO(twyen):implement + return letterTileDrawable; + } + + @Nullable + private static Uri parseUri(@Nullable String uri) { + return TextUtils.isEmpty(uri) ? null : Uri.parse(uri); + } +} diff --git a/java/com/android/dialer/glidephotomanager/impl/res/drawable-xxxhdpi/ic_block_black_48dp.png b/java/com/android/dialer/glidephotomanager/impl/res/drawable-xxxhdpi/ic_block_black_48dp.png new file mode 100644 index 000000000..1168bd8d5 Binary files /dev/null and b/java/com/android/dialer/glidephotomanager/impl/res/drawable-xxxhdpi/ic_block_black_48dp.png differ diff --git a/java/com/android/dialer/glidephotomanager/impl/res/drawable/ic_block_grey_48dp.xml b/java/com/android/dialer/glidephotomanager/impl/res/drawable/ic_block_grey_48dp.xml new file mode 100644 index 000000000..42cfa99bd --- /dev/null +++ b/java/com/android/dialer/glidephotomanager/impl/res/drawable/ic_block_grey_48dp.xml @@ -0,0 +1,17 @@ + + \ No newline at end of file diff --git a/java/com/android/dialer/glidephotomanager/impl/res/drawable/ic_report_red_48dp.xml b/java/com/android/dialer/glidephotomanager/impl/res/drawable/ic_report_red_48dp.xml new file mode 100644 index 000000000..8a1ddcd99 --- /dev/null +++ b/java/com/android/dialer/glidephotomanager/impl/res/drawable/ic_report_red_48dp.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java index 0373cfe4e..874bdbc5b 100644 --- a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java +++ b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java @@ -227,6 +227,14 @@ public final class PhoneLookupInfoConsolidator { .equals(BlockedState.BLOCKED); } + /** + * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method + * returns whether the number is spam. + */ + public boolean isSpam() { + return phoneLookupInfo.getSpamInfo().getIsSpam(); + } + /** * Returns true if the {@link PhoneLookupInfo} passed to the constructor has incomplete CP2 local * info. diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java index 318f79783..05a3bc951 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailAdapter.java @@ -42,6 +42,7 @@ import com.android.dialer.common.concurrent.DialerExecutor.SuccessListener; import com.android.dialer.common.concurrent.DialerExecutor.Worker; import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.common.concurrent.ThreadUtil; +import com.android.dialer.glidephotomanager.GlidePhotoManager; import com.android.dialer.time.Clock; import com.android.dialer.voicemail.listui.NewVoicemailViewHolder.NewVoicemailViewHolderListener; import com.android.dialer.voicemail.listui.error.VoicemailErrorMessage; @@ -75,6 +76,7 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter private Cursor cursor; private Cursor voicemailStatusCursor; private final Clock clock; + private final GlidePhotoManager glidePhotoManager; /** {@link Integer#MAX_VALUE} when the "Today" header should not be displayed. */ private int todayHeaderPosition = Integer.MAX_VALUE; @@ -117,11 +119,16 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter new NewVoicemailMediaPlayer(new MediaPlayer()); /** @param cursor whose projection is {@link VoicemailCursorLoader#VOICEMAIL_COLUMNS} */ - NewVoicemailAdapter(Cursor cursor, Clock clock, FragmentManager fragmentManager) { + NewVoicemailAdapter( + Cursor cursor, + Clock clock, + FragmentManager fragmentManager, + GlidePhotoManager glidePhotoManager) { LogUtil.enterBlock("NewVoicemailAdapter"); this.cursor = cursor; this.clock = clock; this.fragmentManager = fragmentManager; + this.glidePhotoManager = glidePhotoManager; initializeMediaPlayerListeners(); updateHeaderPositions(); } @@ -223,7 +230,7 @@ final class NewVoicemailAdapter extends RecyclerView.Adapter case NewVoicemailAdapter.RowType.VOICEMAIL_ENTRY: view = inflater.inflate(R.layout.new_voicemail_entry, viewGroup, false); NewVoicemailViewHolder newVoicemailViewHolder = - new NewVoicemailViewHolder(view, clock, this); + new NewVoicemailViewHolder(view, clock, this, glidePhotoManager); newVoicemailViewHolderSet.add(newVoicemailViewHolder); return newVoicemailViewHolder; default: diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java index 8812bcc2f..45a544323 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailFragment.java @@ -37,6 +37,7 @@ import com.android.dialer.common.concurrent.ThreadUtil; import com.android.dialer.common.concurrent.UiListener; import com.android.dialer.database.CallLogQueryHandler; import com.android.dialer.database.CallLogQueryHandler.Listener; +import com.android.dialer.glidephotomanager.GlidePhotoManagerComponent; import com.google.common.util.concurrent.ListenableFuture; // TODO(uabdullah): Register content observer for VoicemailContract.Status.CONTENT_URI in onStart @@ -175,7 +176,10 @@ public final class NewVoicemailFragment extends Fragment // TODO(uabdullah): Replace getActivity().getFragmentManager() with getChildFragment() recyclerView.setAdapter( new NewVoicemailAdapter( - data, System::currentTimeMillis, getActivity().getFragmentManager())); + data, + System::currentTimeMillis, + getActivity().getFragmentManager(), + GlidePhotoManagerComponent.get(getContext()).glidePhotoManager())); } else { // This would only be called in cases such as when voicemail has been fetched from the server // or a changed occurred in the annotated table changed (e.g deletes). To check if the change diff --git a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java index b0c07df66..5328dd33e 100644 --- a/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java +++ b/java/com/android/dialer/voicemail/listui/NewVoicemailViewHolder.java @@ -27,7 +27,6 @@ import android.graphics.Typeface; import android.net.Uri; import android.provider.VoicemailContract.Voicemails; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.annotation.WorkerThread; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; @@ -38,15 +37,14 @@ import android.widget.ImageView; import android.widget.QuickContactBadge; import android.widget.TextView; import com.android.dialer.calllog.database.contract.AnnotatedCallLogContract.AnnotatedCallLog; +import com.android.dialer.calllogutils.NumberAttributesConverter; import com.android.dialer.common.Assert; import com.android.dialer.common.LogUtil; import com.android.dialer.common.concurrent.DialerExecutor.SuccessListener; import com.android.dialer.common.concurrent.DialerExecutor.Worker; import com.android.dialer.common.concurrent.DialerExecutorComponent; import com.android.dialer.compat.android.provider.VoicemailCompat; -import com.android.dialer.contactphoto.ContactPhotoManager; -import com.android.dialer.contactphoto.NumberAttributeConverter; -import com.android.dialer.lettertile.LetterTileDrawable; +import com.android.dialer.glidephotomanager.GlidePhotoManager; import com.android.dialer.time.Clock; import com.android.dialer.voicemail.listui.menu.NewVoicemailMenu; import com.android.dialer.voicemail.model.VoicemailEntry; @@ -69,9 +67,13 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On private VoicemailEntry voicemailEntryOfViewHolder; @NonNull private Uri viewHolderVoicemailUri; private final NewVoicemailViewHolderListener voicemailViewHolderListener; + private final GlidePhotoManager glidePhotoManager; NewVoicemailViewHolder( - View view, Clock clock, NewVoicemailViewHolderListener newVoicemailViewHolderListener) { + View view, + Clock clock, + NewVoicemailViewHolderListener newVoicemailViewHolderListener, + GlidePhotoManager glidePhotoManager) { super(view); LogUtil.enterBlock("NewVoicemailViewHolder"); this.context = view.getContext(); @@ -84,6 +86,7 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On menuButton = view.findViewById(R.id.menu_button); this.clock = clock; voicemailViewHolderListener = newVoicemailViewHolderListener; + this.glidePhotoManager = glidePhotoManager; viewHolderId = -1; isViewHolderExpanded = false; @@ -144,7 +147,8 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On itemView.setOnClickListener(this); menuButton.setOnClickListener( - NewVoicemailMenu.createOnClickListener(context, voicemailEntryOfViewHolder)); + NewVoicemailMenu.createOnClickListener( + context, voicemailEntryOfViewHolder, glidePhotoManager)); setPhoto(voicemailEntryOfViewHolder); @@ -206,19 +210,11 @@ final class NewVoicemailViewHolder extends RecyclerView.ViewHolder implements On } private void setPhoto(VoicemailEntry voicemailEntry) { - ContactPhotoManager.getInstance(context) - .loadDialerThumbnailOrPhoto( - quickContactBadge, - parseUri(voicemailEntry.numberAttributes().getLookupUri()), - voicemailEntry.numberAttributes().getPhotoId(), - NumberAttributeConverter.getPhotoUri(context, voicemailEntry.numberAttributes()), - VoicemailEntryText.buildPrimaryVoicemailText(context, voicemailEntry), - LetterTileDrawable.TYPE_DEFAULT); - } - - @Nullable - private static Uri parseUri(@Nullable String string) { - return TextUtils.isEmpty(string) ? null : Uri.parse(string); + glidePhotoManager.loadQuickContactBadge( + quickContactBadge, + NumberAttributesConverter.toPhotoInfoBuilder(voicemailEntry.numberAttributes()) + .setFormattedNumber(voicemailEntry.formattedNumber()) + .build()); } void collapseViewHolder() { diff --git a/java/com/android/dialer/voicemail/listui/menu/NewVoicemailMenu.java b/java/com/android/dialer/voicemail/listui/menu/NewVoicemailMenu.java index 9af8de6f5..fbd7fe854 100644 --- a/java/com/android/dialer/voicemail/listui/menu/NewVoicemailMenu.java +++ b/java/com/android/dialer/voicemail/listui/menu/NewVoicemailMenu.java @@ -19,6 +19,7 @@ package com.android.dialer.voicemail.listui.menu; import android.content.Context; import android.view.View; import com.android.dialer.contactactions.ContactActionBottomSheet; +import com.android.dialer.glidephotomanager.GlidePhotoManager; import com.android.dialer.voicemail.model.VoicemailEntry; /** Handles configuration of the bottom sheet menus for voicemail entries. */ @@ -26,11 +27,12 @@ public final class NewVoicemailMenu { /** Creates and returns the OnClickListener which opens the menu for the provided row. */ public static View.OnClickListener createOnClickListener( - Context context, VoicemailEntry voicemailEntry) { + Context context, VoicemailEntry voicemailEntry, GlidePhotoManager glidePhotoManager) { return (view) -> ContactActionBottomSheet.show( context, PrimaryAction.fromVoicemailEntry(context, voicemailEntry), - Modules.fromVoicemailEntry(context, voicemailEntry)); + Modules.fromVoicemailEntry(context, voicemailEntry), + glidePhotoManager); } } diff --git a/java/com/android/dialer/voicemail/listui/menu/PrimaryAction.java b/java/com/android/dialer/voicemail/listui/menu/PrimaryAction.java index ffc53e779..91f505cb0 100644 --- a/java/com/android/dialer/voicemail/listui/menu/PrimaryAction.java +++ b/java/com/android/dialer/voicemail/listui/menu/PrimaryAction.java @@ -18,10 +18,8 @@ package com.android.dialer.voicemail.listui.menu; import android.content.Context; import android.text.TextUtils; +import com.android.dialer.calllogutils.NumberAttributesConverter; import com.android.dialer.contactactions.ContactPrimaryActionInfo; -import com.android.dialer.contactactions.ContactPrimaryActionInfo.PhotoInfo; -import com.android.dialer.contactphoto.NumberAttributeConverter; -import com.android.dialer.lettertile.LetterTileDrawable; import com.android.dialer.voicemail.model.VoicemailEntry; /** Configures the primary action row (top row) for theottom sheet for the Voicemail Tab */ @@ -38,15 +36,8 @@ final class PrimaryAction { return ContactPrimaryActionInfo.builder() .setNumber(voicemailEntry.number()) .setPhotoInfo( - PhotoInfo.builder() - .setPhotoId(voicemailEntry.numberAttributes().getPhotoId()) - .setPhotoUri( - NumberAttributeConverter.getPhotoUri( - context, voicemailEntry.numberAttributes())) - .setIsVideo(false) - .setContactType( - LetterTileDrawable.TYPE_DEFAULT) // TODO(uabdullah): Use proper type. - .setDisplayName(voicemailEntry.numberAttributes().getName()) + NumberAttributesConverter.toPhotoInfoBuilder(voicemailEntry.numberAttributes()) + .setFormattedNumber(voicemailEntry.formattedNumber()) .build()) .setPrimaryText(buildPrimaryVoicemailText(context, voicemailEntry)) .setSecondaryText(buildSecondaryVoicemailText(voicemailEntry)) -- cgit v1.2.3