summaryrefslogtreecommitdiff
path: root/java
diff options
context:
space:
mode:
Diffstat (limited to 'java')
-rw-r--r--java/com/android/dialer/app/calllog/BlockReportSpamListener.java27
-rw-r--r--java/com/android/dialer/app/calllog/CallLogFragment.java2
-rw-r--r--java/com/android/dialer/callintent/CallIntentBuilder.java1
-rw-r--r--java/com/android/dialer/calllog/database/contract/number_attributes.proto6
-rw-r--r--java/com/android/dialer/calllogutils/CallLogEntryText.java7
-rw-r--r--java/com/android/dialer/calllogutils/NumberAttributesConverter.java3
-rw-r--r--java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java8
-rw-r--r--java/com/android/dialer/historyitemactions/HistoryItemActionModule.java5
-rw-r--r--java/com/android/dialer/historyitemactions/res/layout/module_layout.xml1
-rw-r--r--java/com/android/dialer/oem/CequintCallerIdManager.java113
-rw-r--r--java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java90
-rw-r--r--java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java45
-rw-r--r--java/com/android/dialer/phonenumbercache/ContactInfoHelper.java2
-rw-r--r--java/com/android/dialer/spam/promo/SpamBlockingPromoHelper.java28
-rw-r--r--java/com/android/dialer/speeddial/SpeedDialFragment.java114
-rw-r--r--java/com/android/dialer/speeddial/SuggestionViewHolder.java35
-rw-r--r--java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java12
-rw-r--r--java/com/android/dialer/speeddial/res/layout/suggestion_row_layout.xml5
-rw-r--r--java/com/android/incallui/ContactInfoCache.java2
-rw-r--r--java/com/android/incallui/rtt/impl/AdvisoryViewHolder.java29
-rw-r--r--java/com/android/incallui/rtt/impl/RttChatAdapter.java107
-rw-r--r--java/com/android/incallui/rtt/impl/RttChatFragment.java1
-rw-r--r--java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml2
-rw-r--r--java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml33
-rw-r--r--java/com/android/incallui/rtt/impl/res/layout/rtt_transcript_advisory.xml41
-rw-r--r--java/com/android/incallui/rtt/impl/res/values/dimens.xml3
-rw-r--r--java/com/android/incallui/rtt/impl/res/values/strings.xml3
-rw-r--r--java/com/android/incallui/spam/SpamNotificationActivity.java45
28 files changed, 615 insertions, 155 deletions
diff --git a/java/com/android/dialer/app/calllog/BlockReportSpamListener.java b/java/com/android/dialer/app/calllog/BlockReportSpamListener.java
index 551791850..987615f5f 100644
--- a/java/com/android/dialer/app/calllog/BlockReportSpamListener.java
+++ b/java/com/android/dialer/app/calllog/BlockReportSpamListener.java
@@ -206,11 +206,28 @@ public class BlockReportSpamListener implements CallLogListItemViewHolder.OnClic
}
private void showSpamBlockingPromoDialog() {
- if (spamBlockingPromoHelper.shouldShowSpamBlockingPromo()) {
- spamBlockingPromoHelper.showSpamBlockingPromoDialog(
- fragmentManager,
- success -> spamBlockingPromoHelper.showModifySettingOnCompleteSnackbar(rootView, success),
- null /* onDissmissListener */);
+ if (!spamBlockingPromoHelper.shouldShowSpamBlockingPromo()) {
+ return;
}
+
+ Logger.get(context).logImpression(DialerImpression.Type.SPAM_BLOCKING_CALL_LOG_PROMO_SHOWN);
+ spamBlockingPromoHelper.showSpamBlockingPromoDialog(
+ fragmentManager,
+ () -> {
+ Logger.get(context)
+ .logImpression(DialerImpression.Type.SPAM_BLOCKING_ENABLED_THROUGH_CALL_LOG_PROMO);
+ spamSettings.modifySpamBlockingSetting(
+ true,
+ success -> {
+ if (!success) {
+ Logger.get(context)
+ .logImpression(
+ DialerImpression.Type
+ .SPAM_BLOCKING_MODIFY_FAILURE_THROUGH_CALL_LOG_PROMO);
+ }
+ spamBlockingPromoHelper.showModifySettingOnCompleteSnackbar(rootView, success);
+ });
+ },
+ null /* onDismissListener */);
}
}
diff --git a/java/com/android/dialer/app/calllog/CallLogFragment.java b/java/com/android/dialer/app/calllog/CallLogFragment.java
index 4e968f095..1e55c6358 100644
--- a/java/com/android/dialer/app/calllog/CallLogFragment.java
+++ b/java/com/android/dialer/app/calllog/CallLogFragment.java
@@ -449,7 +449,7 @@ public class CallLogFragment extends Fragment
super.onStart();
CequintCallerIdManager cequintCallerIdManager = null;
if (CequintCallerIdManager.isCequintCallerIdEnabled(getContext())) {
- cequintCallerIdManager = CequintCallerIdManager.createInstanceForCallLog();
+ cequintCallerIdManager = new CequintCallerIdManager();
}
contactInfoCache.setCequintCallerIdManager(cequintCallerIdManager);
}
diff --git a/java/com/android/dialer/callintent/CallIntentBuilder.java b/java/com/android/dialer/callintent/CallIntentBuilder.java
index 0f9f8905d..92efd392b 100644
--- a/java/com/android/dialer/callintent/CallIntentBuilder.java
+++ b/java/com/android/dialer/callintent/CallIntentBuilder.java
@@ -152,6 +152,7 @@ public class CallIntentBuilder implements Parcelable {
return isVideoCall;
}
+ /** Default false. Should only be set to true if the number has a lookup URI. */
public CallIntentBuilder setAllowAssistedDial(boolean allowAssistedDial) {
this.allowAssistedDial = allowAssistedDial;
return this;
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 f99693d4e..f42974d36 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: 14
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
@@ -70,4 +70,8 @@ message NumberAttributes {
// Whether the number can be reached via a carrier video call.
optional bool can_support_carrier_video_call = 12;
+
+ // Description of the number's geolocation (e.g., "Mountain View, CA").
+ // This string is for display purpose only.
+ optional string geolocation = 13;
} \ No newline at end of file
diff --git a/java/com/android/dialer/calllogutils/CallLogEntryText.java b/java/com/android/dialer/calllogutils/CallLogEntryText.java
index e346de011..a1a2a3b48 100644
--- a/java/com/android/dialer/calllogutils/CallLogEntryText.java
+++ b/java/com/android/dialer/calllogutils/CallLogEntryText.java
@@ -214,7 +214,12 @@ public final class CallLogEntryText {
// (1) there is no number type label, and
// (2) the number is not spam.
if (TextUtils.isEmpty(numberTypeLabel) && !row.getNumberAttributes().getIsSpam()) {
- String location = row.getGeocodedLocation();
+ // If number attributes contain a location (obtained from a PhoneLookup), use it instead
+ // of the one from the annotated call log.
+ String location =
+ !TextUtils.isEmpty(row.getNumberAttributes().getGeolocation())
+ ? row.getNumberAttributes().getGeolocation()
+ : row.getGeocodedLocation();
if (!TextUtils.isEmpty(location)) {
if (secondaryText.length() > 0) {
secondaryText.append(", ");
diff --git a/java/com/android/dialer/calllogutils/NumberAttributesConverter.java b/java/com/android/dialer/calllogutils/NumberAttributesConverter.java
index f4fab8405..9f07fdac5 100644
--- a/java/com/android/dialer/calllogutils/NumberAttributesConverter.java
+++ b/java/com/android/dialer/calllogutils/NumberAttributesConverter.java
@@ -56,6 +56,7 @@ public final class NumberAttributesConverter {
.setCanReportAsInvalidNumber(phoneLookupInfoConsolidator.canReportAsInvalidNumber())
.setIsCp2InfoIncomplete(phoneLookupInfoConsolidator.isDefaultCp2InfoIncomplete())
.setContactSource(phoneLookupInfoConsolidator.getContactSource())
- .setCanSupportCarrierVideoCall(phoneLookupInfoConsolidator.canSupportCarrierVideoCall());
+ .setCanSupportCarrierVideoCall(phoneLookupInfoConsolidator.canSupportCarrierVideoCall())
+ .setGeolocation(phoneLookupInfoConsolidator.getGeolocation());
}
}
diff --git a/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java b/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java
index 79205a7d9..28663c17d 100644
--- a/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java
+++ b/java/com/android/dialer/historyitemactions/HistoryItemActionBottomSheet.java
@@ -17,8 +17,10 @@
package com.android.dialer.historyitemactions;
import android.content.Context;
+import android.content.res.ColorStateList;
import android.os.Bundle;
import android.support.design.widget.BottomSheetDialog;
+import android.support.v4.content.ContextCompat;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -109,6 +111,12 @@ public class HistoryItemActionBottomSheet extends BottomSheetDialog implements O
((TextView) moduleView.findViewById(R.id.module_text)).setText(module.getStringId());
((ImageView) moduleView.findViewById(R.id.module_image))
.setImageResource(module.getDrawableId());
+ if (module.tintDrawable()) {
+ ((ImageView) moduleView.findViewById(R.id.module_image))
+ .setImageTintList(
+ ColorStateList.valueOf(
+ ContextCompat.getColor(getContext(), R.color.secondary_text_color)));
+ }
moduleView.setOnClickListener(this);
moduleView.setTag(module);
return moduleView;
diff --git a/java/com/android/dialer/historyitemactions/HistoryItemActionModule.java b/java/com/android/dialer/historyitemactions/HistoryItemActionModule.java
index d64cbca53..e948924d7 100644
--- a/java/com/android/dialer/historyitemactions/HistoryItemActionModule.java
+++ b/java/com/android/dialer/historyitemactions/HistoryItemActionModule.java
@@ -32,6 +32,11 @@ public interface HistoryItemActionModule {
@DrawableRes
int getDrawableId();
+ /** Returns true if tint can be applied to the drawable. */
+ default boolean tintDrawable() {
+ return true;
+ }
+
/** @return true if the bottom sheet should close, false otherwise */
boolean onClick();
}
diff --git a/java/com/android/dialer/historyitemactions/res/layout/module_layout.xml b/java/com/android/dialer/historyitemactions/res/layout/module_layout.xml
index 9aee67937..063051947 100644
--- a/java/com/android/dialer/historyitemactions/res/layout/module_layout.xml
+++ b/java/com/android/dialer/historyitemactions/res/layout/module_layout.xml
@@ -28,7 +28,6 @@
android:layout_height="@dimen/contact_actions_image_size"
android:layout_marginStart="@dimen/contact_actions_image_margin"
android:layout_marginEnd="@dimen/contact_actions_image_margin"
- android:tint="@color/dialer_secondary_text_color"
android:scaleType="center"/>
<TextView
diff --git a/java/com/android/dialer/oem/CequintCallerIdManager.java b/java/com/android/dialer/oem/CequintCallerIdManager.java
index 55cafc15e..53f5352b2 100644
--- a/java/com/android/dialer/oem/CequintCallerIdManager.java
+++ b/java/com/android/dialer/oem/CequintCallerIdManager.java
@@ -24,6 +24,7 @@ import android.os.Build.VERSION_CODES;
import android.support.annotation.AnyThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
@@ -45,7 +46,8 @@ import java.util.concurrent.ConcurrentHashMap;
@TargetApi(VERSION_CODES.N)
public class CequintCallerIdManager {
- private static final String CONFIG_CALLER_ID_ENABLED = "config_caller_id_enabled";
+ @VisibleForTesting
+ public static final String CONFIG_CALLER_ID_ENABLED = "config_caller_id_enabled";
private static final int CALLER_ID_LOOKUP_USER_PROVIDED_CID = 0x0001;
private static final int CALLER_ID_LOOKUP_SYSTEM_PROVIDED_CID = 0x0002;
@@ -53,36 +55,43 @@ public class CequintCallerIdManager {
private static final String[] EMPTY_PROJECTION = new String[] {};
- // Column names in Cequint provider.
- private static final String CITY_NAME = "cid_pCityName";
- private static final String STATE_NAME = "cid_pStateName";
- private static final String STATE_ABBR = "cid_pStateAbbr";
- private static final String COUNTRY_NAME = "cid_pCountryName";
- private static final String COMPANY = "cid_pCompany";
- private static final String NAME = "cid_pName";
- private static final String FIRST_NAME = "cid_pFirstName";
- private static final String LAST_NAME = "cid_pLastName";
- private static final String IMAGE = "cid_pLogo";
- private static final String DISPLAY_NAME = "cid_pDisplayName";
+ /** Column names in Cequint content provider. */
+ @VisibleForTesting
+ public static final class CequintColumnNames {
+ public static final String CITY_NAME = "cid_pCityName";
+ public static final String STATE_NAME = "cid_pStateName";
+ public static final String STATE_ABBR = "cid_pStateAbbr";
+ public static final String COUNTRY_NAME = "cid_pCountryName";
+ public static final String COMPANY = "cid_pCompany";
+ public static final String NAME = "cid_pName";
+ public static final String FIRST_NAME = "cid_pFirstName";
+ public static final String LAST_NAME = "cid_pLastName";
+ public static final String PHOTO_URI = "cid_pLogo";
+ public static final String DISPLAY_NAME = "cid_pDisplayName";
+ }
private static boolean hasAlreadyCheckedCequintCallerIdPackage;
private static String cequintProviderAuthority;
- // TODO(wangqi): Revisit it and maybe remove it if it's not necessary.
- private final ConcurrentHashMap<String, CequintCallerIdContact> callLogCache;
+ // TODO(a bug): Revisit it and maybe remove it if it's not necessary.
+ private final ConcurrentHashMap<String, CequintCallerIdContact> callLogCache =
+ new ConcurrentHashMap<>();
/** Cequint caller ID contact information. */
@AutoValue
public abstract static class CequintCallerIdContact {
+ @Nullable
public abstract String name();
/**
* Description of the geolocation (e.g., "Mountain View, CA"), which is for display purpose
* only.
*/
+ @Nullable
public abstract String geolocation();
+ @Nullable
public abstract String photoUri();
static Builder builder() {
@@ -91,11 +100,11 @@ public class CequintCallerIdManager {
@AutoValue.Builder
abstract static class Builder {
- abstract Builder setName(String name);
+ abstract Builder setName(@Nullable String name);
- abstract Builder setGeolocation(String geolocation);
+ abstract Builder setGeolocation(@Nullable String geolocation);
- abstract Builder setPhotoUri(String photoUri);
+ abstract Builder setPhotoUri(@Nullable String photoUri);
abstract CequintCallerIdContact build();
}
@@ -125,17 +134,14 @@ public class CequintCallerIdManager {
return cequintProviderAuthority != null;
}
- public static CequintCallerIdManager createInstanceForCallLog() {
- return new CequintCallerIdManager();
- }
-
+ /** Returns a {@link CequintCallerIdContact} for a call. */
@WorkerThread
@Nullable
- public static CequintCallerIdContact getCequintCallerIdContactForInCall(
+ public static CequintCallerIdContact getCequintCallerIdContactForCall(
Context context, String number, String cnapName, boolean isIncoming) {
Assert.isWorkerThread();
LogUtil.d(
- "CequintCallerIdManager.getCequintCallerIdContactForInCall",
+ "CequintCallerIdManager.getCequintCallerIdContactForCall",
"number: %s, cnapName: %s, isIncoming: %b",
LogUtil.sanitizePhoneNumber(number),
LogUtil.sanitizePii(cnapName),
@@ -151,29 +157,51 @@ public class CequintCallerIdManager {
return lookup(context, getIncallLookupUri(), number, flags);
}
+ /**
+ * Returns a cached {@link CequintCallerIdContact} associated with the provided number. If no
+ * contact can be found in the cache, look up the number using the Cequint content provider.
+ *
+ * @deprecated This method is for the old call log only. New code should use {@link
+ * #getCequintCallerIdContactForNumber(Context, String)}.
+ */
+ @Deprecated
@WorkerThread
@Nullable
- public CequintCallerIdContact getCequintCallerIdContact(Context context, String number) {
+ public CequintCallerIdContact getCachedCequintCallerIdContact(Context context, String number) {
Assert.isWorkerThread();
LogUtil.d(
- "CequintCallerIdManager.getCequintCallerIdContact",
+ "CequintCallerIdManager.getCachedCequintCallerIdContact",
"number: %s",
LogUtil.sanitizePhoneNumber(number));
if (callLogCache.containsKey(number)) {
return callLogCache.get(number);
}
CequintCallerIdContact cequintCallerIdContact =
- lookup(
- context,
- getLookupUri(),
- PhoneNumberUtils.stripSeparators(number),
- new String[] {"system"});
+ getCequintCallerIdContactForNumber(context, number);
if (cequintCallerIdContact != null) {
callLogCache.put(number, cequintCallerIdContact);
}
return cequintCallerIdContact;
}
+ /**
+ * Returns a {@link CequintCallerIdContact} associated with the provided number by looking it up
+ * using the Cequint content provider.
+ */
+ @WorkerThread
+ @Nullable
+ public static CequintCallerIdContact getCequintCallerIdContactForNumber(
+ Context context, String number) {
+ Assert.isWorkerThread();
+ LogUtil.d(
+ "CequintCallerIdManager.getCequintCallerIdContactForNumber",
+ "number: %s",
+ LogUtil.sanitizePhoneNumber(number));
+
+ return lookup(
+ context, getLookupUri(), PhoneNumberUtils.stripSeparators(number), new String[] {"system"});
+ }
+
@WorkerThread
@Nullable
private static CequintCallerIdContact lookup(
@@ -185,16 +213,17 @@ public class CequintCallerIdManager {
try (Cursor cursor =
context.getContentResolver().query(uri, EMPTY_PROJECTION, number, flags, null)) {
if (cursor != null && cursor.moveToFirst()) {
- String city = getString(cursor, cursor.getColumnIndex(CITY_NAME));
- String state = getString(cursor, cursor.getColumnIndex(STATE_NAME));
- String stateAbbr = getString(cursor, cursor.getColumnIndex(STATE_ABBR));
- String country = getString(cursor, cursor.getColumnIndex(COUNTRY_NAME));
- String company = getString(cursor, cursor.getColumnIndex(COMPANY));
- String name = getString(cursor, cursor.getColumnIndex(NAME));
- String firstName = getString(cursor, cursor.getColumnIndex(FIRST_NAME));
- String lastName = getString(cursor, cursor.getColumnIndex(LAST_NAME));
- String photoUri = getString(cursor, cursor.getColumnIndex(IMAGE));
- String displayName = getString(cursor, cursor.getColumnIndex(DISPLAY_NAME));
+ String city = getString(cursor, cursor.getColumnIndex(CequintColumnNames.CITY_NAME));
+ String state = getString(cursor, cursor.getColumnIndex(CequintColumnNames.STATE_NAME));
+ String stateAbbr = getString(cursor, cursor.getColumnIndex(CequintColumnNames.STATE_ABBR));
+ String country = getString(cursor, cursor.getColumnIndex(CequintColumnNames.COUNTRY_NAME));
+ String company = getString(cursor, cursor.getColumnIndex(CequintColumnNames.COMPANY));
+ String name = getString(cursor, cursor.getColumnIndex(CequintColumnNames.NAME));
+ String firstName = getString(cursor, cursor.getColumnIndex(CequintColumnNames.FIRST_NAME));
+ String lastName = getString(cursor, cursor.getColumnIndex(CequintColumnNames.LAST_NAME));
+ String photoUri = getString(cursor, cursor.getColumnIndex(CequintColumnNames.PHOTO_URI));
+ String displayName =
+ getString(cursor, cursor.getColumnIndex(CequintColumnNames.DISPLAY_NAME));
String contactName =
TextUtils.isEmpty(displayName)
@@ -293,8 +322,4 @@ public class CequintCallerIdManager {
private static Uri getIncallLookupUri() {
return Uri.parse("content://" + cequintProviderAuthority + "/incalllookup");
}
-
- private CequintCallerIdManager() {
- callLogCache = new ConcurrentHashMap<>();
- }
}
diff --git a/java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java b/java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java
index ce2cd18ad..36d0be40f 100644
--- a/java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java
+++ b/java/com/android/dialer/phonelookup/cequint/CequintPhoneLookup.java
@@ -18,33 +18,85 @@ package com.android.dialer.phonelookup.cequint;
import android.content.Context;
import android.telecom.Call;
+import android.text.TextUtils;
import com.android.dialer.DialerPhoneNumber;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.concurrent.Annotations.BackgroundExecutor;
+import com.android.dialer.common.concurrent.Annotations.LightweightExecutor;
+import com.android.dialer.inject.ApplicationContext;
+import com.android.dialer.location.GeoUtil;
+import com.android.dialer.oem.CequintCallerIdManager;
+import com.android.dialer.oem.CequintCallerIdManager.CequintCallerIdContact;
import com.android.dialer.phonelookup.PhoneLookup;
import com.android.dialer.phonelookup.PhoneLookupInfo;
import com.android.dialer.phonelookup.PhoneLookupInfo.CequintInfo;
+import com.android.dialer.phonenumberproto.DialerPhoneNumberUtil;
+import com.android.dialer.telecom.TelecomCallUtil;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
import javax.inject.Inject;
/** PhoneLookup implementation for Cequint. */
public class CequintPhoneLookup implements PhoneLookup<CequintInfo> {
+ private final Context appContext;
+ private final ListeningExecutorService backgroundExecutorService;
+ private final ListeningExecutorService lightweightExecutorService;
+
@Inject
- CequintPhoneLookup() {}
+ CequintPhoneLookup(
+ @ApplicationContext Context appContext,
+ @BackgroundExecutor ListeningExecutorService backgroundExecutorService,
+ @LightweightExecutor ListeningExecutorService lightweightExecutorService) {
+ this.appContext = appContext;
+ this.backgroundExecutorService = backgroundExecutorService;
+ this.lightweightExecutorService = lightweightExecutorService;
+ }
@Override
public ListenableFuture<CequintInfo> lookup(Context appContext, Call call) {
- // TODO(a bug): Override the default implementation in the PhoneLookup interface
- // as a Cequint lookup requires info in the provided call.
- return Futures.immediateFuture(CequintInfo.getDefaultInstance());
+ if (!CequintCallerIdManager.isCequintCallerIdEnabled(appContext)) {
+ return Futures.immediateFuture(CequintInfo.getDefaultInstance());
+ }
+
+ ListenableFuture<DialerPhoneNumber> dialerPhoneNumberFuture =
+ backgroundExecutorService.submit(
+ () -> {
+ DialerPhoneNumberUtil dialerPhoneNumberUtil = new DialerPhoneNumberUtil();
+ return dialerPhoneNumberUtil.parse(
+ TelecomCallUtil.getNumber(call), GeoUtil.getCurrentCountryIso(appContext));
+ });
+ String callerDisplayName = call.getDetails().getCallerDisplayName();
+ boolean isIncomingCall = (call.getState() == Call.STATE_RINGING);
+
+ return Futures.transformAsync(
+ dialerPhoneNumberFuture,
+ dialerPhoneNumber ->
+ backgroundExecutorService.submit(
+ () ->
+ buildCequintInfo(
+ CequintCallerIdManager.getCequintCallerIdContactForCall(
+ appContext,
+ Assert.isNotNull(dialerPhoneNumber).getNormalizedNumber(),
+ callerDisplayName,
+ isIncomingCall))),
+ lightweightExecutorService);
}
@Override
public ListenableFuture<CequintInfo> lookup(DialerPhoneNumber dialerPhoneNumber) {
- // TODO(a bug): Implement this method.
- return Futures.immediateFuture(CequintInfo.getDefaultInstance());
+ if (!CequintCallerIdManager.isCequintCallerIdEnabled(appContext)) {
+ return Futures.immediateFuture(CequintInfo.getDefaultInstance());
+ }
+
+ return backgroundExecutorService.submit(
+ () ->
+ buildCequintInfo(
+ CequintCallerIdManager.getCequintCallerIdContactForNumber(
+ appContext, dialerPhoneNumber.getNormalizedNumber())));
}
@Override
@@ -75,16 +127,38 @@ public class CequintPhoneLookup implements PhoneLookup<CequintInfo> {
@Override
public void registerContentObservers() {
- // No content observers for Cequint info.
+ // No need to register a content observer as the Cequint content provider doesn't support batch
+ // queries.
}
@Override
public void unregisterContentObservers() {
- // No content observers for Cequint info.
+ // Nothing to be done as no content observer is registered.
}
@Override
public ListenableFuture<Void> clearData() {
return Futures.immediateFuture(null);
}
+
+ /**
+ * Builds a {@link CequintInfo} proto based on the given {@link CequintCallerIdContact} returned
+ * by {@link CequintCallerIdManager}.
+ */
+ private static CequintInfo buildCequintInfo(CequintCallerIdContact cequintCallerIdContact) {
+ CequintInfo.Builder cequintInfoBuilder = CequintInfo.newBuilder();
+
+ // Every field in CequintCallerIdContact can be null.
+ if (!TextUtils.isEmpty(cequintCallerIdContact.name())) {
+ cequintInfoBuilder.setName(cequintCallerIdContact.name());
+ }
+ if (!TextUtils.isEmpty(cequintCallerIdContact.geolocation())) {
+ cequintInfoBuilder.setGeolocation(cequintCallerIdContact.geolocation());
+ }
+ if (!TextUtils.isEmpty(cequintCallerIdContact.photoUri())) {
+ cequintInfoBuilder.setPhotoUri(cequintCallerIdContact.photoUri());
+ }
+
+ return cequintInfoBuilder.build();
+ }
}
diff --git a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java
index 07aea749d..23ecc8301 100644
--- a/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java
+++ b/java/com/android/dialer/phonelookup/consolidator/PhoneLookupInfoConsolidator.java
@@ -46,6 +46,7 @@ public final class PhoneLookupInfoConsolidator {
NameSource.CP2_DEFAULT_DIRECTORY,
NameSource.CP2_EXTENDED_DIRECTORY,
NameSource.PEOPLE_API,
+ NameSource.CEQUINT,
NameSource.CNAP
})
@interface NameSource {
@@ -53,7 +54,8 @@ public final class PhoneLookupInfoConsolidator {
int CP2_DEFAULT_DIRECTORY = 1;
int CP2_EXTENDED_DIRECTORY = 2;
int PEOPLE_API = 3;
- int CNAP = 4;
+ int CEQUINT = 4;
+ int CNAP = 5;
}
/**
@@ -78,6 +80,7 @@ public final class PhoneLookupInfoConsolidator {
NameSource.CP2_DEFAULT_DIRECTORY,
NameSource.CP2_EXTENDED_DIRECTORY,
NameSource.PEOPLE_API,
+ NameSource.CEQUINT,
NameSource.CNAP);
private final @NameSource int nameSource;
@@ -106,6 +109,8 @@ public final class PhoneLookupInfoConsolidator {
return ContactSource.Type.SOURCE_TYPE_EXTENDED;
case NameSource.PEOPLE_API:
return getRefinedPeopleApiSource();
+ case NameSource.CEQUINT:
+ return ContactSource.Type.SOURCE_TYPE_CEQUINT_CALLER_ID;
case NameSource.CNAP:
return ContactSource.Type.SOURCE_TYPE_CNAP;
case NameSource.NONE:
@@ -146,6 +151,8 @@ public final class PhoneLookupInfoConsolidator {
return Assert.isNotNull(firstExtendedCp2Contact).getName();
case NameSource.PEOPLE_API:
return phoneLookupInfo.getPeopleApiInfo().getDisplayName();
+ case NameSource.CEQUINT:
+ return phoneLookupInfo.getCequintInfo().getName();
case NameSource.CNAP:
return phoneLookupInfo.getCnapInfo().getName();
case NameSource.NONE:
@@ -170,6 +177,7 @@ public final class PhoneLookupInfoConsolidator {
case NameSource.CP2_EXTENDED_DIRECTORY:
return Assert.isNotNull(firstExtendedCp2Contact).getPhotoThumbnailUri();
case NameSource.PEOPLE_API:
+ case NameSource.CEQUINT:
case NameSource.CNAP:
case NameSource.NONE:
return "";
@@ -192,6 +200,8 @@ public final class PhoneLookupInfoConsolidator {
return Assert.isNotNull(firstDefaultCp2Contact).getPhotoUri();
case NameSource.CP2_EXTENDED_DIRECTORY:
return Assert.isNotNull(firstExtendedCp2Contact).getPhotoUri();
+ case NameSource.CEQUINT:
+ return phoneLookupInfo.getCequintInfo().getPhotoUri();
case NameSource.PEOPLE_API:
case NameSource.CNAP:
case NameSource.NONE:
@@ -213,6 +223,7 @@ public final class PhoneLookupInfoConsolidator {
case NameSource.CP2_EXTENDED_DIRECTORY:
return Math.max(Assert.isNotNull(firstExtendedCp2Contact).getPhotoId(), 0);
case NameSource.PEOPLE_API:
+ case NameSource.CEQUINT:
case NameSource.CNAP:
case NameSource.NONE:
return 0;
@@ -235,6 +246,7 @@ public final class PhoneLookupInfoConsolidator {
return Assert.isNotNull(firstExtendedCp2Contact).getLookupUri();
case NameSource.PEOPLE_API:
return Assert.isNotNull(phoneLookupInfo.getPeopleApiInfo().getLookupUri());
+ case NameSource.CEQUINT:
case NameSource.CNAP:
case NameSource.NONE:
return "";
@@ -259,6 +271,30 @@ public final class PhoneLookupInfoConsolidator {
case NameSource.CP2_EXTENDED_DIRECTORY:
return Assert.isNotNull(firstExtendedCp2Contact).getLabel();
case NameSource.PEOPLE_API:
+ case NameSource.CEQUINT:
+ case NameSource.CNAP:
+ case NameSource.NONE:
+ return "";
+ default:
+ throw Assert.createUnsupportedOperationFailException(
+ String.format("Unsupported name source: %s", nameSource));
+ }
+ }
+
+ /**
+ * The {@link PhoneLookupInfo} passed to the constructor is associated with a number. This method
+ * returns the number's geolocation (which is for display purpose only).
+ *
+ * <p>If no geolocation can be obtained from the {@link PhoneLookupInfo}, an empty string will be
+ * returned.
+ */
+ public String getGeolocation() {
+ switch (nameSource) {
+ case NameSource.CEQUINT:
+ return phoneLookupInfo.getCequintInfo().getGeolocation();
+ case NameSource.CP2_DEFAULT_DIRECTORY:
+ case NameSource.CP2_EXTENDED_DIRECTORY:
+ case NameSource.PEOPLE_API:
case NameSource.CNAP:
case NameSource.NONE:
return "";
@@ -320,6 +356,7 @@ public final class PhoneLookupInfoConsolidator {
switch (nameSource) {
case NameSource.CP2_DEFAULT_DIRECTORY:
case NameSource.CP2_EXTENDED_DIRECTORY:
+ case NameSource.CEQUINT:
case NameSource.CNAP:
case NameSource.NONE:
return false;
@@ -343,6 +380,7 @@ public final class PhoneLookupInfoConsolidator {
return Assert.isNotNull(firstDefaultCp2Contact).getCanSupportCarrierVideoCall();
case NameSource.CP2_EXTENDED_DIRECTORY:
case NameSource.PEOPLE_API:
+ case NameSource.CEQUINT:
case NameSource.CNAP:
case NameSource.NONE:
return false;
@@ -396,6 +434,11 @@ public final class PhoneLookupInfoConsolidator {
return NameSource.PEOPLE_API;
}
break;
+ case NameSource.CEQUINT:
+ if (!phoneLookupInfo.getCequintInfo().getName().isEmpty()) {
+ return NameSource.CEQUINT;
+ }
+ break;
case NameSource.CNAP:
if (!phoneLookupInfo.getCnapInfo().getName().isEmpty()) {
return NameSource.CNAP;
diff --git a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
index 4302436a7..6179b5dcf 100644
--- a/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
+++ b/java/com/android/dialer/phonenumbercache/ContactInfoHelper.java
@@ -621,7 +621,7 @@ public class ContactInfoHelper {
return;
}
CequintCallerIdContact cequintCallerIdContact =
- cequintCallerIdManager.getCequintCallerIdContact(context, number);
+ cequintCallerIdManager.getCachedCequintCallerIdContact(context, number);
if (cequintCallerIdContact == null) {
return;
}
diff --git a/java/com/android/dialer/spam/promo/SpamBlockingPromoHelper.java b/java/com/android/dialer/spam/promo/SpamBlockingPromoHelper.java
index 891ac44ad..6a8cde864 100644
--- a/java/com/android/dialer/spam/promo/SpamBlockingPromoHelper.java
+++ b/java/com/android/dialer/spam/promo/SpamBlockingPromoHelper.java
@@ -34,14 +34,14 @@ import com.android.dialer.logging.Logger;
import com.android.dialer.notification.DialerNotificationManager;
import com.android.dialer.notification.NotificationChannelId;
import com.android.dialer.spam.SpamSettings;
-import com.android.dialer.spam.SpamSettings.ModifySettingListener;
+import com.android.dialer.spam.promo.SpamBlockingPromoDialogFragment.OnEnableListener;
/** Helper class for showing spam blocking on-boarding promotions. */
public class SpamBlockingPromoHelper {
static final String SPAM_BLOCKING_PROMO_PERIOD_MILLIS = "spam_blocking_promo_period_millis";
static final String SPAM_BLOCKING_PROMO_LAST_SHOW_MILLIS = "spam_blocking_promo_last_show_millis";
- static final String ENABLE_SPAM_BLOCKING_PROMO = "enable_spam_blocking_promo";
+ public static final String ENABLE_SPAM_BLOCKING_PROMO = "enable_spam_blocking_promo";
private final Context context;
private final SpamSettings spamSettings;
@@ -81,33 +81,15 @@ public class SpamBlockingPromoHelper {
* Shows a spam blocking promo dialog.
*
* @param fragmentManager the fragment manager to show the dialog.
- * @param modifySettingListener the listener called after spam blocking setting is modified.
+ * @param onEnableListener the listener called when enable button is clicked.
* @param onDismissListener the listener called when the dialog is dismissed.
*/
public void showSpamBlockingPromoDialog(
FragmentManager fragmentManager,
- ModifySettingListener modifySettingListener,
+ OnEnableListener onEnableListener,
OnDismissListener onDismissListener) {
updateLastShowSpamTimestamp();
- Logger.get(context).logImpression(DialerImpression.Type.SPAM_BLOCKING_CALL_LOG_PROMO_SHOWN);
- SpamBlockingPromoDialogFragment.newInstance(
- () -> {
- Logger.get(context)
- .logImpression(
- DialerImpression.Type.SPAM_BLOCKING_ENABLED_THROUGH_CALL_LOG_PROMO);
- spamSettings.modifySpamBlockingSetting(
- true,
- success -> {
- if (!success) {
- Logger.get(context)
- .logImpression(
- DialerImpression.Type
- .SPAM_BLOCKING_MODIFY_FAILURE_THROUGH_CALL_LOG_PROMO);
- }
- modifySettingListener.onComplete(success);
- });
- },
- onDismissListener)
+ SpamBlockingPromoDialogFragment.newInstance(onEnableListener, onDismissListener)
.show(fragmentManager, SpamBlockingPromoDialogFragment.SPAM_BLOCKING_PROMO_DIALOG_TAG);
}
diff --git a/java/com/android/dialer/speeddial/SpeedDialFragment.java b/java/com/android/dialer/speeddial/SpeedDialFragment.java
index b76db1cf3..018f97888 100644
--- a/java/com/android/dialer/speeddial/SpeedDialFragment.java
+++ b/java/com/android/dialer/speeddial/SpeedDialFragment.java
@@ -16,6 +16,7 @@
package com.android.dialer.speeddial;
+import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@@ -41,6 +42,12 @@ import com.android.dialer.common.concurrent.DialerExecutorComponent;
import com.android.dialer.common.concurrent.SupportUiListener;
import com.android.dialer.constants.ActivityRequestCodes;
import com.android.dialer.duo.DuoComponent;
+import com.android.dialer.historyitemactions.DividerModule;
+import com.android.dialer.historyitemactions.HistoryItemActionBottomSheet;
+import com.android.dialer.historyitemactions.HistoryItemActionModule;
+import com.android.dialer.historyitemactions.HistoryItemBottomSheetHeaderInfo;
+import com.android.dialer.historyitemactions.IntentModule;
+import com.android.dialer.historyitemactions.SharedModules;
import com.android.dialer.logging.DialerImpression;
import com.android.dialer.logging.Logger;
import com.android.dialer.precall.PreCall;
@@ -54,8 +61,11 @@ import com.android.dialer.speeddial.draghelper.SpeedDialLayoutManager;
import com.android.dialer.speeddial.loader.SpeedDialUiItem;
import com.android.dialer.speeddial.loader.UiItemLoaderComponent;
import com.android.dialer.util.IntentUtil;
+import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.util.concurrent.Futures;
+import java.util.ArrayList;
+import java.util.List;
/**
* Fragment for displaying:
@@ -301,8 +311,61 @@ public class SpeedDialFragment extends Fragment {
private final class SpeedDialSuggestedListener implements SuggestedContactsListener {
@Override
- public void onOverFlowMenuClicked(SpeedDialUiItem speedDialUiItem) {
- // TODO(calderwoodra) show overflow menu for suggested contacts
+ public void onOverFlowMenuClicked(
+ SpeedDialUiItem speedDialUiItem, HistoryItemBottomSheetHeaderInfo headerInfo) {
+ List<HistoryItemActionModule> modules = new ArrayList<>();
+ Channel defaultChannel = speedDialUiItem.defaultChannel();
+
+ // Add voice call module
+ Channel voiceChannel = speedDialUiItem.getDeterministicVoiceChannel();
+ if (voiceChannel != null) {
+ modules.add(
+ IntentModule.newCallModule(
+ getContext(),
+ new CallIntentBuilder(voiceChannel.number(), CallInitiationType.Type.SPEED_DIAL)
+ .setAllowAssistedDial(true)));
+ } else {
+ modules.add(new DisambigDialogModule(speedDialUiItem, /* isVideo = */ false));
+ }
+
+ // Add video if we can determine the correct channel
+ Channel videoChannel = speedDialUiItem.getDeterministicVideoChannel();
+ if (videoChannel != null) {
+ modules.add(
+ IntentModule.newCallModule(
+ getContext(),
+ new CallIntentBuilder(videoChannel.number(), CallInitiationType.Type.SPEED_DIAL)
+ .setIsVideoCall(true)
+ .setAllowAssistedDial(true)));
+ } else if (speedDialUiItem.hasVideoChannels()) {
+ modules.add(new DisambigDialogModule(speedDialUiItem, /* isVideo = */ true));
+ }
+
+ // Add sms module
+ Optional<HistoryItemActionModule> smsModule =
+ SharedModules.createModuleForSendingTextMessage(
+ getContext(), defaultChannel.number(), false);
+ if (smsModule.isPresent()) {
+ modules.add(smsModule.get());
+ }
+
+ modules.add(new DividerModule());
+
+ // TODO(calderwoodra): add to favorites module
+ // TODO(calderwoodra): remove from strequent module
+
+ // Contact info module
+ modules.add(
+ new ContactInfoModule(
+ getContext(),
+ new Intent(
+ Intent.ACTION_VIEW,
+ Uri.withAppendedPath(
+ Contacts.CONTENT_URI, String.valueOf(speedDialUiItem.contactId()))),
+ R.string.contact_menu_contact_info,
+ R.drawable.context_menu_contact_icon));
+
+ HistoryItemActionBottomSheet.show(getContext(), headerInfo, modules);
}
@Override
@@ -321,6 +384,53 @@ public class SpeedDialFragment extends Fragment {
new CallIntentBuilder(channel.number(), CallInitiationType.Type.SPEED_DIAL)
.setIsVideoCall(channel.isVideoTechnology()));
}
+
+ private final class ContactInfoModule extends IntentModule {
+
+ public ContactInfoModule(Context context, Intent intent, int text, int image) {
+ super(context, intent, text, image);
+ }
+
+ @Override
+ public boolean tintDrawable() {
+ return false;
+ }
+ }
+
+ private final class DisambigDialogModule implements HistoryItemActionModule {
+
+ private final SpeedDialUiItem speedDialUiItem;
+ private final boolean isVideo;
+
+ DisambigDialogModule(SpeedDialUiItem speedDialUiItem, boolean isVideo) {
+ this.speedDialUiItem = speedDialUiItem;
+ this.isVideo = isVideo;
+ }
+
+ @Override
+ public int getStringId() {
+ if (isVideo) {
+ return R.string.contact_menu_video_call;
+ } else {
+ return R.string.contact_menu_voice_call;
+ }
+ }
+
+ @Override
+ public int getDrawableId() {
+ if (isVideo) {
+ return R.drawable.quantum_ic_videocam_vd_theme_24;
+ } else {
+ return R.drawable.quantum_ic_phone_vd_theme_24;
+ }
+ }
+
+ @Override
+ public boolean onClick() {
+ DisambigDialog.show(speedDialUiItem, getChildFragmentManager());
+ return true;
+ }
+ }
}
private static final class SpeedDialContextMenuItemListener implements ContextMenuItemListener {
diff --git a/java/com/android/dialer/speeddial/SuggestionViewHolder.java b/java/com/android/dialer/speeddial/SuggestionViewHolder.java
index 546ffbdff..578e0b328 100644
--- a/java/com/android/dialer/speeddial/SuggestionViewHolder.java
+++ b/java/com/android/dialer/speeddial/SuggestionViewHolder.java
@@ -17,27 +17,25 @@
package com.android.dialer.speeddial;
import android.content.Context;
-import android.provider.ContactsContract.Contacts;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
-import android.widget.QuickContactBadge;
import android.widget.TextView;
import com.android.dialer.common.Assert;
-import com.android.dialer.glidephotomanager.GlidePhotoManagerComponent;
-import com.android.dialer.glidephotomanager.PhotoInfo;
+import com.android.dialer.historyitemactions.HistoryItemBottomSheetHeaderInfo;
import com.android.dialer.location.GeoUtil;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
import com.android.dialer.speeddial.database.SpeedDialEntry.Channel;
import com.android.dialer.speeddial.loader.SpeedDialUiItem;
+import com.android.dialer.widget.ContactPhotoView;
/** ViewHolder for displaying suggested contacts in {@link SpeedDialFragment}. */
public class SuggestionViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
private final SuggestedContactsListener listener;
- private final QuickContactBadge photoView;
+ private final ContactPhotoView photoView;
private final TextView nameOrNumberView;
private final TextView numberView;
@@ -71,34 +69,31 @@ public class SuggestionViewHolder extends RecyclerView.ViewHolder implements OnC
nameOrNumberView.setText(speedDialUiItem.name());
numberView.setText(secondaryInfo);
- GlidePhotoManagerComponent.get(context)
- .glidePhotoManager()
- .loadQuickContactBadge(
- photoView,
- PhotoInfo.newBuilder()
- .setPhotoId(speedDialUiItem.photoId())
- .setPhotoUri(speedDialUiItem.photoUri())
- .setName(speedDialUiItem.name())
- .setIsVideo(speedDialUiItem.defaultChannel().isVideoTechnology())
- .setLookupUri(
- Contacts.getLookupUri(speedDialUiItem.contactId(), speedDialUiItem.lookupKey())
- .toString())
- .build());
+ photoView.setPhoto(speedDialUiItem.getPhotoInfo());
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.overflow) {
- listener.onOverFlowMenuClicked(speedDialUiItem);
+ listener.onOverFlowMenuClicked(speedDialUiItem, getHeaderInfo());
} else {
listener.onRowClicked(speedDialUiItem.defaultChannel());
}
}
+ private HistoryItemBottomSheetHeaderInfo getHeaderInfo() {
+ return HistoryItemBottomSheetHeaderInfo.newBuilder()
+ .setPhotoInfo(speedDialUiItem.getPhotoInfo())
+ .setPrimaryText(nameOrNumberView.getText().toString())
+ .setSecondaryText(numberView.getText().toString())
+ .build();
+ }
+
/** Listener/Callback for {@link SuggestionViewHolder} parents. */
public interface SuggestedContactsListener {
- void onOverFlowMenuClicked(SpeedDialUiItem speedDialUiItem);
+ void onOverFlowMenuClicked(
+ SpeedDialUiItem speedDialUiItem, HistoryItemBottomSheetHeaderInfo headerInfo);
/** Called when a suggested contact is clicked. */
void onRowClicked(Channel channel);
diff --git a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
index a2bdfb89a..c5a3ea3ed 100644
--- a/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
+++ b/java/com/android/dialer/speeddial/loader/SpeedDialUiItem.java
@@ -18,10 +18,12 @@ package com.android.dialer.speeddial.loader;
import android.database.Cursor;
import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.android.dialer.common.Assert;
+import com.android.dialer.glidephotomanager.PhotoInfo;
import com.android.dialer.speeddial.database.SpeedDialEntry;
import com.android.dialer.speeddial.database.SpeedDialEntry.Channel;
import com.google.auto.value.AutoValue;
@@ -139,6 +141,16 @@ public abstract class SpeedDialUiItem {
return builder.build();
}
+ public PhotoInfo getPhotoInfo() {
+ return PhotoInfo.newBuilder()
+ .setPhotoId(photoId())
+ .setPhotoUri(photoUri())
+ .setName(name())
+ .setIsVideo(defaultChannel() != null && defaultChannel().isVideoTechnology())
+ .setLookupUri(Contacts.getLookupUri(contactId(), lookupKey()).toString())
+ .build();
+ }
+
public SpeedDialEntry buildSpeedDialEntry() {
return SpeedDialEntry.builder()
.setId(speedDialEntryId())
diff --git a/java/com/android/dialer/speeddial/res/layout/suggestion_row_layout.xml b/java/com/android/dialer/speeddial/res/layout/suggestion_row_layout.xml
index ff95b5906..868606065 100644
--- a/java/com/android/dialer/speeddial/res/layout/suggestion_row_layout.xml
+++ b/java/com/android/dialer/speeddial/res/layout/suggestion_row_layout.xml
@@ -21,7 +21,7 @@
android:minHeight="72dp"
android:background="?android:attr/selectableItemBackground">
- <QuickContactBadge
+ <com.android.dialer.widget.ContactPhotoView
android:id="@+id/avatar"
android:layout_width="48dp"
android:layout_height="48dp"
@@ -59,5 +59,6 @@
android:scaleType="center"
android:tint="@color/secondary_text_color"
android:src="@drawable/quantum_ic_more_vert_white_24"
- android:background="?android:selectableItemBackgroundBorderless"/>
+ android:background="?android:selectableItemBackgroundBorderless"
+ android:contentDescription="@string/content_description_overflow"/>
</RelativeLayout> \ No newline at end of file
diff --git a/java/com/android/incallui/ContactInfoCache.java b/java/com/android/incallui/ContactInfoCache.java
index eefd4833c..81c7b724d 100644
--- a/java/com/android/incallui/ContactInfoCache.java
+++ b/java/com/android/incallui/ContactInfoCache.java
@@ -514,7 +514,7 @@ public class ContactInfoCache implements OnImageLoadCompleteListener {
return;
}
CequintCallerIdContact cequintCallerIdContact =
- CequintCallerIdManager.getCequintCallerIdContactForInCall(
+ CequintCallerIdManager.getCequintCallerIdContactForCall(
context, callerInfo.phoneNumber, cnapName, isIncoming);
if (cequintCallerIdContact == null) {
diff --git a/java/com/android/incallui/rtt/impl/AdvisoryViewHolder.java b/java/com/android/incallui/rtt/impl/AdvisoryViewHolder.java
new file mode 100644
index 000000000..8f081bebf
--- /dev/null
+++ b/java/com/android/incallui/rtt/impl/AdvisoryViewHolder.java
@@ -0,0 +1,29 @@
+/*
+ * 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.incallui.rtt.impl;
+
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.view.View;
+
+/** ViewHolder class for RTT advisory text. */
+public class AdvisoryViewHolder extends ViewHolder {
+
+ public AdvisoryViewHolder(@NonNull View itemView) {
+ super(itemView);
+ }
+}
diff --git a/java/com/android/incallui/rtt/impl/RttChatAdapter.java b/java/com/android/incallui/rtt/impl/RttChatAdapter.java
index 692266335..f1cde759c 100644
--- a/java/com/android/incallui/rtt/impl/RttChatAdapter.java
+++ b/java/com/android/incallui/rtt/impl/RttChatAdapter.java
@@ -18,8 +18,10 @@ package com.android.incallui.rtt.impl;
import android.content.Context;
import android.graphics.drawable.Drawable;
+import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -27,11 +29,29 @@ import android.view.ViewGroup;
import com.android.dialer.common.LogUtil;
import com.android.dialer.rtt.RttTranscript;
import com.android.dialer.rtt.RttTranscriptMessage;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
/** Adapter class for holding RTT chat data. */
-public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolder> {
+public class RttChatAdapter extends RecyclerView.Adapter<ViewHolder> {
+
+ /** IntDef for the different types of rows that can be shown in the call log. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ RowType.ADVISORY,
+ RowType.MESSAGE,
+ })
+ @interface RowType {
+ /** The transcript advisory message. */
+ int ADVISORY = 1;
+
+ /** RTT chat message. */
+ int MESSAGE = 2;
+ }
+
+ private static final int POSITION_ADVISORY = 0;
private Drawable avatarDrawable;
@@ -45,6 +65,7 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
private List<RttChatMessage> rttMessages = new ArrayList<>();
private int lastIndexOfLocalMessage = -1;
private final MessageListener messageListener;
+ private boolean shouldShowAdvisory;
RttChatAdapter(Context context, MessageListener listener) {
this.context = context;
@@ -52,29 +73,54 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
}
@Override
- public RttChatMessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ public ViewHolder onCreateViewHolder(ViewGroup parent, @RowType int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(context);
- View view = layoutInflater.inflate(R.layout.rtt_chat_list_item, parent, false);
- return new RttChatMessageViewHolder(view);
+ switch (viewType) {
+ case RowType.ADVISORY:
+ View view = layoutInflater.inflate(R.layout.rtt_transcript_advisory, parent, false);
+ return new AdvisoryViewHolder(view);
+ case RowType.MESSAGE:
+ view = layoutInflater.inflate(R.layout.rtt_chat_list_item, parent, false);
+ return new RttChatMessageViewHolder(view);
+ default:
+ throw new RuntimeException("Unknown row type.");
+ }
}
@Override
public int getItemViewType(int position) {
- return super.getItemViewType(position);
+ if (shouldShowAdvisory && position == POSITION_ADVISORY) {
+ return RowType.ADVISORY;
+ } else {
+ return RowType.MESSAGE;
+ }
}
@Override
- public void onBindViewHolder(RttChatMessageViewHolder rttChatMessageViewHolder, int i) {
- boolean isSameGroup = false;
- if (i > 0) {
- isSameGroup = rttMessages.get(i).isRemote == rttMessages.get(i - 1).isRemote;
+ public void onBindViewHolder(ViewHolder viewHolder, int itemPosition) {
+ switch (getItemViewType(itemPosition)) {
+ case RowType.ADVISORY:
+ return;
+ case RowType.MESSAGE:
+ RttChatMessageViewHolder rttChatMessageViewHolder = (RttChatMessageViewHolder) viewHolder;
+ int messagePosition = toMessagePosition(itemPosition);
+ boolean isSameGroup = false;
+ if (messagePosition > 0) {
+ isSameGroup =
+ rttMessages.get(messagePosition).isRemote
+ == rttMessages.get(messagePosition - 1).isRemote;
+ }
+ rttChatMessageViewHolder.setMessage(
+ rttMessages.get(messagePosition), isSameGroup, avatarDrawable);
+ return;
+ default:
+ throw new RuntimeException("Unknown row type.");
}
- rttChatMessageViewHolder.setMessage(rttMessages.get(i), isSameGroup, avatarDrawable);
}
@Override
public int getItemCount() {
- return rttMessages.size();
+ return shouldShowAdvisory ? rttMessages.size() + 1 : rttMessages.size();
}
private void updateCurrentLocalMessage(String newMessage) {
@@ -96,11 +142,31 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
notifyItemRemoved(lastIndexOfLocalMessage);
lastIndexOfLocalMessage = -1;
} else {
- notifyItemChanged(lastIndexOfLocalMessage);
+ notifyItemChanged(toItemPosition(lastIndexOfLocalMessage));
}
}
}
+ private int toMessagePosition(int itemPosition) {
+ if (shouldShowAdvisory) {
+ return itemPosition - 1;
+ } else {
+ return itemPosition;
+ }
+ }
+
+ // Converts position in message list into item position in adapter.
+ private int toItemPosition(int messagePosition) {
+ if (messagePosition < 0) {
+ return messagePosition;
+ }
+ if (shouldShowAdvisory) {
+ return messagePosition + 1;
+ } else {
+ return messagePosition;
+ }
+ }
+
private void updateCurrentRemoteMessage(String newMessage) {
RttChatMessage.updateRemoteRttChatMessage(rttMessages, newMessage);
lastIndexOfLocalMessage = RttChatMessage.getLastIndexLocalMessage(rttMessages);
@@ -110,14 +176,14 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
void addLocalMessage(String message) {
updateCurrentLocalMessage(message);
if (messageListener != null) {
- messageListener.onUpdateLocalMessage(lastIndexOfLocalMessage);
+ messageListener.onUpdateLocalMessage(toItemPosition(lastIndexOfLocalMessage));
}
}
void submitLocalMessage() {
LogUtil.enterBlock("RttChatAdapater.submitLocalMessage");
rttMessages.get(lastIndexOfLocalMessage).finish();
- notifyItemChanged(lastIndexOfLocalMessage);
+ notifyItemChanged(toItemPosition(lastIndexOfLocalMessage));
lastIndexOfLocalMessage = -1;
}
@@ -139,10 +205,21 @@ public class RttChatAdapter extends RecyclerView.Adapter<RttChatMessageViewHolde
}
updateCurrentRemoteMessage(message);
if (messageListener != null) {
- messageListener.onUpdateRemoteMessage(RttChatMessage.getLastIndexRemoteMessage(rttMessages));
+ messageListener.onUpdateRemoteMessage(
+ toItemPosition(RttChatMessage.getLastIndexRemoteMessage(rttMessages)));
}
}
+ void hideAdvisory() {
+ shouldShowAdvisory = false;
+ notifyItemRemoved(POSITION_ADVISORY);
+ }
+
+ void showAdvisory() {
+ shouldShowAdvisory = true;
+ notifyItemInserted(POSITION_ADVISORY);
+ }
+
/**
* Retrieve last local message and update the index. This is used when deleting to previous
* message bubble.
diff --git a/java/com/android/incallui/rtt/impl/RttChatFragment.java b/java/com/android/incallui/rtt/impl/RttChatFragment.java
index 47036cd43..13e013fd3 100644
--- a/java/com/android/incallui/rtt/impl/RttChatFragment.java
+++ b/java/com/android/incallui/rtt/impl/RttChatFragment.java
@@ -467,6 +467,7 @@ public class RttChatFragment extends Fragment
if (editText.requestFocus()) {
UiUtil.openKeyboardFrom(getContext(), editText);
}
+ adapter.showAdvisory();
}
if (primaryCallState.state() == State.DIALING) {
showWaitingForJoinBanner();
diff --git a/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml b/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml
index f995185b1..cff2b3f38 100644
--- a/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml
+++ b/java/com/android/incallui/rtt/impl/res/layout/frag_rtt_chat.xml
@@ -23,7 +23,7 @@
android:id="@+id/rtt_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:paddingTop="70dp"
+ android:paddingTop="56dp"
android:paddingBottom="70dp"
android:clipToPadding="false"/>
diff --git a/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml b/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml
index 4b03ad8d5..8a5bba28d 100644
--- a/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml
+++ b/java/com/android/incallui/rtt/impl/res/layout/rtt_banner.xml
@@ -19,30 +19,30 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
- <RelativeLayout
+ <LinearLayout
android:layout_width="match_parent"
- android:layout_height="?android:attr/actionBarSize"
+ android:layout_height="@dimen/rtt_banner_height"
android:background="#F305228F"
- android:elevation="3dp">
+ android:elevation="3dp"
+ android:orientation="horizontal">
<ImageButton
android:id="@+id/rtt_end_call_button"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_marginStart="16dp"
- android:layout_alignParentStart="true"
- android:layout_centerVertical="true"
+ android:layout_width="@dimen/rtt_banner_height"
+ android:layout_height="@dimen/rtt_banner_height"
+ android:layout_marginStart="4dp"
+ android:layout_marginEnd="4dp"
+ android:padding="@dimen/rtt_banner_button_padding"
android:background="@android:color/transparent"
android:contentDescription="@string/incall_content_description_end_call"
android:scaleType="fitXY"
android:src="@drawable/quantum_ic_call_end_vd_theme_24"
android:tint="#FFDF0000"/>
<LinearLayout
- android:layout_width="260dp"
+ android:layout_width="0dp"
android:layout_height="match_parent"
+ android:layout_weight="1"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
- android:layout_marginStart="32dp"
- android:layout_toEndOf="@id/rtt_end_call_button"
android:orientation="vertical">
<TextView
android:id="@+id/rtt_name_or_number"
@@ -67,18 +67,17 @@
</LinearLayout>
<ImageButton
android:id="@+id/rtt_overflow_button"
- android:layout_width="32dp"
- android:layout_height="32dp"
- android:layout_marginEnd="12dp"
- android:layout_alignParentEnd="true"
- android:layout_centerVertical="true"
+ android:layout_width="@dimen/rtt_banner_height"
+ android:layout_height="@dimen/rtt_banner_height"
+ android:layout_marginStart="8dp"
+ android:padding="@dimen/rtt_banner_button_padding"
android:background="@android:color/transparent"
android:contentDescription="@string/content_description_overflow"
android:scaleType="fitXY"
android:src="@drawable/quantum_ic_more_vert_vd_theme_24"
android:tint="#FFFFFF"/>
- </RelativeLayout>
+ </LinearLayout>
<FrameLayout
android:id="@id/rtt_on_hold_banner"
android:layout_width="match_parent"
diff --git a/java/com/android/incallui/rtt/impl/res/layout/rtt_transcript_advisory.xml b/java/com/android/incallui/rtt/impl/res/layout/rtt_transcript_advisory.xml
new file mode 100644
index 000000000..a2cf3e74f
--- /dev/null
+++ b/java/com/android/incallui/rtt/impl/res/layout/rtt_transcript_advisory.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="24dp"
+ android:paddingBottom="16dp"
+ android:orientation="vertical">
+ <ImageView
+ android:layout_width="16dp"
+ android:layout_height="16dp"
+ android:layout_gravity="center_horizontal"
+ android:src="@drawable/quantum_ic_question_answer_vd_theme_24"
+ android:tint="#DEFFFFFF"
+ android:tintMode="src_in"/>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="4dp"
+ android:paddingBottom="9dp"
+ android:paddingStart="64dp"
+ android:paddingEnd="64dp"
+ android:gravity="center_horizontal"
+ android:text="@string/rtt_transcript_advisory"
+ android:textColor="#FFFFFF"
+ android:textSize="12sp"/>
+</LinearLayout> \ No newline at end of file
diff --git a/java/com/android/incallui/rtt/impl/res/values/dimens.xml b/java/com/android/incallui/rtt/impl/res/values/dimens.xml
index c3d28da77..cab9da00c 100644
--- a/java/com/android/incallui/rtt/impl/res/values/dimens.xml
+++ b/java/com/android/incallui/rtt/impl/res/values/dimens.xml
@@ -20,4 +20,7 @@
<dimen name="rtt_overflow_menu_width">180dp</dimen>
<dimen name="rtt_overflow_menu_elevation">8dp</dimen>
<dimen name="rtt_avatar_size">40dp</dimen>
+ <dimen name="rtt_banner_height">56dp</dimen>
+ <!-- This is used to control image size inside the button. -->
+ <dimen name="rtt_banner_button_padding">12dp</dimen>
</resources>
diff --git a/java/com/android/incallui/rtt/impl/res/values/strings.xml b/java/com/android/incallui/rtt/impl/res/values/strings.xml
index 1d09f5446..462eea563 100644
--- a/java/com/android/incallui/rtt/impl/res/values/strings.xml
+++ b/java/com/android/incallui/rtt/impl/res/values/strings.xml
@@ -30,4 +30,7 @@
<!-- Text for status banner. [CHAR LIMIT=100] -->
<string name="rtt_status_banner_text">Waiting for <xliff:g id="name">%s</xliff:g> to join RTT call&#8230;</string>
+ <!-- Text for RTT transcript advisory. [CHAR LIMIT=NONE] -->
+ <string name="rtt_transcript_advisory">The other party can see you typing. Transcripts stored on your device in the call history.</string>
+
</resources> \ No newline at end of file
diff --git a/java/com/android/incallui/spam/SpamNotificationActivity.java b/java/com/android/incallui/spam/SpamNotificationActivity.java
index c04a071a1..e10dea381 100644
--- a/java/com/android/incallui/spam/SpamNotificationActivity.java
+++ b/java/com/android/incallui/spam/SpamNotificationActivity.java
@@ -43,6 +43,7 @@ import com.android.dialer.logging.ReportingLocation;
import com.android.dialer.notification.DialerNotificationManager;
import com.android.dialer.phonenumberutil.PhoneNumberHelper;
import com.android.dialer.spam.SpamComponent;
+import com.android.dialer.spam.SpamSettings;
import com.android.dialer.spam.promo.SpamBlockingPromoHelper;
import com.android.incallui.call.DialerCall;
@@ -86,6 +87,8 @@ public class SpamNotificationActivity extends FragmentActivity {
}
};
private FilteredNumberAsyncQueryHandler filteredNumberAsyncQueryHandler;
+ private SpamSettings spamSettings;
+ private SpamBlockingPromoHelper spamBlockingPromoHelper;
/**
* Creates an intent to start this activity.
@@ -160,6 +163,8 @@ public class SpamNotificationActivity extends FragmentActivity {
super.onCreate(savedInstanceState);
setFinishOnTouchOutside(true);
filteredNumberAsyncQueryHandler = new FilteredNumberAsyncQueryHandler(this);
+ spamSettings = SpamComponent.get(this).spamSettings();
+ spamBlockingPromoHelper = new SpamBlockingPromoHelper(getApplicationContext(), spamSettings);
cancelNotification();
}
@@ -417,7 +422,7 @@ public class SpamNotificationActivity extends FragmentActivity {
dismiss();
spamNotificationActivity.maybeShowBlockReportSpamDialog(
number, contactLookupResultType);
- spamNotificationActivity.showSpamBlockingPromoDialog();
+ spamNotificationActivity.maybeShowSpamBlockingPromoAndFinish();
}
})
.setNegativeButton(
@@ -515,23 +520,43 @@ public class SpamNotificationActivity extends FragmentActivity {
dismiss();
spamNotificationActivity.maybeShowBlockReportSpamDialog(
number, contactLookupResultType);
+ spamNotificationActivity.maybeShowSpamBlockingPromoAndFinish();
}
})
.create();
}
}
- private void showSpamBlockingPromoDialog() {
- SpamBlockingPromoHelper spamBlockingPromoHelper =
- new SpamBlockingPromoHelper(
- getApplicationContext(), SpamComponent.get(this).spamSettings());
+ private void maybeShowSpamBlockingPromoAndFinish() {
if (!spamBlockingPromoHelper.shouldShowSpamBlockingPromo()) {
finish();
- } else {
- spamBlockingPromoHelper.showSpamBlockingPromoDialog(
- getFragmentManager(),
- success -> spamBlockingPromoHelper.showModifySettingOnCompleteToast(success),
- dialog -> finish());
+ return;
}
+ Logger.get(this)
+ .logImpression(DialerImpression.Type.SPAM_BLOCKING_AFTER_CALL_NOTIFICATION_PROMO_SHOWN);
+ showSpamBlockingPromoDialog();
+ }
+
+ private void showSpamBlockingPromoDialog() {
+ spamBlockingPromoHelper.showSpamBlockingPromoDialog(
+ getFragmentManager(),
+ () -> {
+ Logger.get(this)
+ .logImpression(
+ DialerImpression.Type
+ .SPAM_BLOCKING_ENABLED_THROUGH_AFTER_CALL_NOTIFICATION_PROMO);
+ spamSettings.modifySpamBlockingSetting(
+ true,
+ success -> {
+ if (!success) {
+ Logger.get(this)
+ .logImpression(
+ DialerImpression.Type
+ .SPAM_BLOCKING_MODIFY_FAILURE_THROUGH_AFTER_CALL_NOTIFICATION_PROMO);
+ }
+ spamBlockingPromoHelper.showModifySettingOnCompleteToast(success);
+ });
+ },
+ dialog -> finish());
}
}