summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2019-12-12 02:08:07 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2019-12-12 02:08:07 +0000
commit9bb03ebce29e157ca3d69914281fae019f87d4a3 (patch)
treea5953b40cfc157bb6397db088247d44bce509f78
parenta8f419b5d60f89949997f3469dd97cc2ad380555 (diff)
parente1358b52a2df4d8606c3c3dd172c25169df5a15c (diff)
downloadMessenger-9bb03ebce29e157ca3d69914281fae019f87d4a3.tar.gz
Snap for 6066667 from e1358b52a2df4d8606c3c3dd172c25169df5a15c to qt-d4-release
Change-Id: I3233095a9dfb46850d463ed698773b39505c50cb
-rw-r--r--Android.mk4
-rw-r--r--res/values/dimens.xml1
-rw-r--r--src/com/android/car/messenger/MessengerDelegate.java160
-rw-r--r--src/com/android/car/messenger/SmsDatabaseHandler.java25
4 files changed, 116 insertions, 74 deletions
diff --git a/Android.mk b/Android.mk
index 2c2372f..623b5ea 100644
--- a/Android.mk
+++ b/Android.mk
@@ -40,10 +40,12 @@ LOCAL_USE_AAPT2 := true
LOCAL_STATIC_ANDROID_LIBRARIES += \
car-apps-common \
+ car-telephony-common \
# Including the resources for the static android libraries allows to pick up their static overlays.
LOCAL_RESOURCE_DIR += \
- $(LOCAL_PATH)/../libs/car-apps-common/res
+ $(LOCAL_PATH)/../libs/car-apps-common/res \
+ $(LOCAL_PATH)/../libs/car-telephony-common/res \
LOCAL_STATIC_JAVA_LIBRARIES += \
androidx.annotation_annotation \
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 7308708..1f9b6af 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -16,4 +16,5 @@
-->
<resources>
<dimen name="notification_contact_photo_size">300dp</dimen>
+ <dimen name="contact_avatar_corner_radius_percent" format="float">0.5</dimen>
</resources>
diff --git a/src/com/android/car/messenger/MessengerDelegate.java b/src/com/android/car/messenger/MessengerDelegate.java
index 33615fb..58193d4 100644
--- a/src/com/android/car/messenger/MessengerDelegate.java
+++ b/src/com/android/car/messenger/MessengerDelegate.java
@@ -7,20 +7,15 @@ import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothMapClient;
-import android.bluetooth.BluetoothProfile;
-import android.content.ContentResolver;
-import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources.NotFoundException;
-import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.net.Uri;
-import android.provider.ContactsContract;
-import android.text.TextUtils;
+import android.util.Log;
import android.widget.Toast;
-
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.app.NotificationCompat;
@@ -28,23 +23,24 @@ import androidx.core.app.NotificationCompat.Action;
import androidx.core.app.NotificationCompat.MessagingStyle;
import androidx.core.app.Person;
import androidx.core.app.RemoteInput;
-
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import com.android.car.apps.common.LetterTileDrawable;
import com.android.car.messenger.bluetooth.BluetoothHelper;
import com.android.car.messenger.bluetooth.BluetoothMonitor;
import com.android.car.messenger.log.L;
+import com.android.car.telephony.common.TelecomUtils;
import com.android.internal.annotations.GuardedBy;
-
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.SimpleTarget;
import com.bumptech.glide.request.transition.Transition;
-
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
/** Delegate class responsible for handling messaging service actions */
@@ -57,7 +53,10 @@ public class MessengerDelegate implements BluetoothMonitor.OnBluetoothEventListe
private BluetoothMapClient mBluetoothMapClient;
private final NotificationManager mNotificationManager;
private final SmsDatabaseHandler mSmsDatabaseHandler;
+ private final int mBitmapSize;
+ private final float mCornerRadiusPercent;
private boolean mShouldLoadExistingMessages;
+ private CompletableFuture<Void> mPhoneNumberInfoFuture;
@VisibleForTesting
final Map<MessageKey, MapMessage> mMessages = new HashMap<>();
@@ -67,6 +66,7 @@ public class MessengerDelegate implements BluetoothMonitor.OnBluetoothEventListe
// Notifications for messages received before this time.
@VisibleForTesting
final Map<String, Long> mBTDeviceAddressToConnectionTimestamp = new HashMap<>();
+ final Map<SenderKey, Bitmap> mSenderToLargeIconBitmap = new HashMap<>();
public MessengerDelegate(Context context) {
mContext = context;
@@ -75,6 +75,11 @@ public class MessengerDelegate implements BluetoothMonitor.OnBluetoothEventListe
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
mSmsDatabaseHandler = new SmsDatabaseHandler(mContext);
+ mBitmapSize =
+ mContext.getResources()
+ .getDimensionPixelSize(R.dimen.notification_contact_photo_size);
+ mCornerRadiusPercent = mContext.getResources()
+ .getFloat(R.dimen.contact_avatar_corner_radius_percent);
try {
mShouldLoadExistingMessages =
mContext.getResources().getBoolean(R.bool.config_loadExistingMessages);
@@ -216,6 +221,14 @@ public class MessengerDelegate implements BluetoothMonitor.OnBluetoothEventListe
}
}
+ protected void onDestroy() {
+ cleanupMessagesAndNotifications(key -> true);
+
+ if (mPhoneNumberInfoFuture != null) {
+ mPhoneNumberInfoFuture.cancel(true);
+ }
+ }
+
/**
* Clears all notifications matching the {@param predicate}. Example method calls are when user
* wants to clear (a) message notification(s), or when the Bluetooth device that received the
@@ -240,6 +253,7 @@ public class MessengerDelegate implements BluetoothMonitor.OnBluetoothEventListe
messageKeyMapMessageEntry -> predicate.test(messageKeyMapMessageEntry.getKey()));
clearNotifications(predicate);
mNotificationInfos.entrySet().removeIf(entry -> predicate.test(entry.getKey()));
+ mSenderToLargeIconBitmap.entrySet().removeIf(entry -> predicate.test(entry.getKey()));
}
private void updateNotification(MessageKey messageKey, MapMessage mapMessage) {
@@ -258,72 +272,75 @@ public class MessengerDelegate implements BluetoothMonitor.OnBluetoothEventListe
NotificationInfo notificationInfo = mNotificationInfos.get(senderKey);
notificationInfo.mMessageKeys.add(messageKey);
- updateNotification(senderKey, notificationInfo);
- }
-
- private void updateNotification(SenderKey senderKey, NotificationInfo notificationInfo) {
- final Uri photoUri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,
- getContactId(mContext.getContentResolver(), notificationInfo.mSenderContactUri));
-
- Glide.with(mContext)
- .asBitmap()
- .load(photoUri)
- .apply(RequestOptions.circleCropTransform())
- .into(new SimpleTarget<Bitmap>() {
- @Override
- public void onResourceReady(Bitmap bitmap,
- Transition<? super Bitmap> transition) {
- sendNotification(bitmap);
- }
-
- @Override
- public void onLoadFailed(@Nullable Drawable fallback) {
- sendNotification(null);
- }
-
- private void sendNotification(Bitmap bitmap) {
- mNotificationManager.notify(
- notificationInfo.mNotificationId,
- createNotification(senderKey, notificationInfo, bitmap));
- }
- });
+ updateNotificationWithIcon(senderKey, notificationInfo);
}
- // TODO: move out to a shared library.
- protected static int getContactId(ContentResolver cr, String contactUri) {
- if (TextUtils.isEmpty(contactUri)) {
- return 0;
+ private void updateNotificationWithIcon(SenderKey senderKey,
+ NotificationInfo notificationInfo) {
+ String phoneNumber = getPhoneNumber(notificationInfo.mSenderContactUri);
+ if (mSenderToLargeIconBitmap.get(senderKey) != null || phoneNumber == null) {
+ postNotification(senderKey, notificationInfo);
}
- Uri lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
- Uri.encode(contactUri));
- String[] projection = new String[]{ContactsContract.PhoneLookup._ID};
-
- try (Cursor cursor = cr.query(lookupUri, projection, null, null, null)) {
- if (cursor != null && cursor.moveToFirst() && cursor.isLast()) {
- return cursor.getInt(cursor.getColumnIndex(ContactsContract.PhoneLookup._ID));
- } else {
- L.w(TAG, "Unable to find contact id from phone number.");
- }
+ if (mPhoneNumberInfoFuture != null) {
+ mPhoneNumberInfoFuture.cancel(/* mayInterruptRunning= */ true);
}
- return 0;
+ LetterTileDrawable errorDrawable = TelecomUtils.createLetterTile(mContext,
+ notificationInfo.mSenderName, notificationInfo.mSenderName);
+
+ mPhoneNumberInfoFuture = TelecomUtils.getPhoneNumberInfo(mContext, phoneNumber)
+ .thenAcceptAsync(phoneNumberInfo -> {
+ if (phoneNumberInfo == null) {
+ postNotification(senderKey, notificationInfo);
+ }
+ Glide.with(mContext)
+ .asBitmap()
+ .load(phoneNumberInfo.getAvatarUri())
+ .apply(new RequestOptions().override(mBitmapSize).error(errorDrawable))
+ .into(new SimpleTarget<Bitmap>() {
+ @Override
+ public void onResourceReady(Bitmap bitmap,
+ Transition<? super Bitmap> transition) {
+ RoundedBitmapDrawable roundedBitmapDrawable =
+ RoundedBitmapDrawableFactory
+ .create(mContext.getResources(), bitmap);
+ Icon avatarIcon = TelecomUtils
+ .createFromRoundedBitmapDrawable(roundedBitmapDrawable, mBitmapSize,
+ mCornerRadiusPercent);
+ mSenderToLargeIconBitmap.put(senderKey, avatarIcon.getBitmap());
+ postNotification(senderKey, notificationInfo);
+ }
+
+ @Override
+ public void onLoadFailed(@Nullable Drawable fallback) {
+ postNotification(senderKey, notificationInfo);
+ }
+
+ });
+ }, mContext.getMainExecutor());
}
- protected void onDestroy() {
- cleanupMessagesAndNotifications(key -> true);
+ private void postNotification(SenderKey senderKey, NotificationInfo notificationInfo) {
+ mNotificationManager.notify(
+ notificationInfo.mNotificationId,
+ createNotification(senderKey, notificationInfo));
}
private Notification createNotification(
- SenderKey senderKey, NotificationInfo notificationInfo, Bitmap bitmap) {
+ SenderKey senderKey, NotificationInfo notificationInfo) {
String contentText = mContext.getResources().getQuantityString(
R.plurals.notification_new_message, notificationInfo.mMessageKeys.size(),
notificationInfo.mMessageKeys.size());
long lastReceiveTime = mMessages.get(notificationInfo.mMessageKeys.getLast())
.getReceiveTime();
- if (bitmap == null) {
- bitmap = letterTileBitmap(notificationInfo.mSenderName);
+ Bitmap largeIcon = mSenderToLargeIconBitmap.get(senderKey);
+ if (largeIcon == null) {
+ largeIcon =
+ TelecomUtils.createLetterTile(mContext,
+ TelecomUtils.getInitials(notificationInfo.mSenderName, ""),
+ notificationInfo.mSenderName, mBitmapSize, mCornerRadiusPercent).getBitmap();
}
final String senderName = notificationInfo.mSenderName;
@@ -358,7 +375,7 @@ public class MessengerDelegate implements BluetoothMonitor.OnBluetoothEventListe
.setContentText(contentText)
.setStyle(messagingStyle)
.setCategory(Notification.CATEGORY_MESSAGE)
- .setLargeIcon(bitmap)
+ .setLargeIcon(largeIcon)
.setSmallIcon(R.drawable.ic_message)
.setWhen(lastReceiveTime)
.setShowWhen(true)
@@ -371,17 +388,6 @@ public class MessengerDelegate implements BluetoothMonitor.OnBluetoothEventListe
return builder.build();
}
- private Bitmap letterTileBitmap(String senderName) {
- LetterTileDrawable letterTileDrawable = new LetterTileDrawable(mContext.getResources());
- letterTileDrawable.setContactDetails(senderName, senderName);
- letterTileDrawable.setIsCircular(true);
-
- int bitmapSize = mContext.getResources()
- .getDimensionPixelSize(R.dimen.notification_contact_photo_size);
-
- return letterTileDrawable.toBitmap(bitmapSize);
- }
-
private PendingIntent createServiceIntent(SenderKey senderKey, int notificationId,
String action) {
Intent intent = new Intent(mContext, MessengerService.class)
@@ -449,6 +455,18 @@ public class MessengerDelegate implements BluetoothMonitor.OnBluetoothEventListe
}
/**
+ * Extracts the phone number from the {@link BluetoothMapClient} formatted URI.
+ **/
+ @Nullable
+ private String getPhoneNumber(String senderContactUri) {
+ if (senderContactUri == null || !senderContactUri.matches("tel:(.+)")) {
+ return null;
+ }
+
+ return senderContactUri.substring(4);
+ }
+
+ /**
* Contains information about a single notification that is displayed, with grouped messages.
*/
@VisibleForTesting
diff --git a/src/com/android/car/messenger/SmsDatabaseHandler.java b/src/com/android/car/messenger/SmsDatabaseHandler.java
index 333d8d7..77d8e29 100644
--- a/src/com/android/car/messenger/SmsDatabaseHandler.java
+++ b/src/com/android/car/messenger/SmsDatabaseHandler.java
@@ -1,8 +1,6 @@
package com.android.car.messenger;
-import static com.android.car.messenger.MessengerDelegate.getContactId;
-
import android.Manifest;
import android.app.AppOpsManager;
import android.content.ContentResolver;
@@ -13,7 +11,9 @@ import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
import android.provider.BaseColumns;
+import android.provider.ContactsContract;
import android.provider.Telephony;
+import android.text.TextUtils;
import android.util.Log;
import androidx.core.content.ContextCompat;
@@ -194,4 +194,25 @@ class SmsDatabaseHandler {
return granted;
}
+
+ // TODO: move out to a shared library.
+ private static int getContactId(ContentResolver cr, String contactUri) {
+ if (TextUtils.isEmpty(contactUri)) {
+ return 0;
+ }
+
+ Uri lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
+ Uri.encode(contactUri));
+ String[] projection = new String[]{ContactsContract.PhoneLookup._ID};
+
+ try (Cursor cursor = cr.query(lookupUri, projection, null, null, null)) {
+ if (cursor != null && cursor.moveToFirst() && cursor.isLast()) {
+ return cursor.getInt(cursor.getColumnIndex(ContactsContract.PhoneLookup._ID));
+ } else {
+ L.w(TAG, "Unable to find contact id from phone number.");
+ }
+ }
+
+ return 0;
+ }
}