Merge "Show messages count in People Tile" into sc-dev

This commit is contained in:
Flavio Fiszman
2021-03-23 16:42:53 +00:00
committed by Android (Google) Code Review
11 changed files with 157 additions and 16 deletions

View File

@@ -56,6 +56,7 @@ public class PeopleSpaceTile implements Parcelable {
private CharSequence mNotificationContent;
private String mNotificationCategory;
private Uri mNotificationDataUri;
private int mMessagesCount;
private Intent mIntent;
private long mNotificationTimestamp;
private List<ConversationStatus> mStatuses;
@@ -74,6 +75,7 @@ public class PeopleSpaceTile implements Parcelable {
mNotificationContent = b.mNotificationContent;
mNotificationCategory = b.mNotificationCategory;
mNotificationDataUri = b.mNotificationDataUri;
mMessagesCount = b.mMessagesCount;
mIntent = b.mIntent;
mNotificationTimestamp = b.mNotificationTimestamp;
mStatuses = b.mStatuses;
@@ -140,6 +142,10 @@ public class PeopleSpaceTile implements Parcelable {
return mNotificationDataUri;
}
public int getMessagesCount() {
return mMessagesCount;
}
/**
* Provides an intent to launch. If present, we should manually launch the intent on tile
* click, rather than calling {@link android.content.pm.LauncherApps} to launch the shortcut ID.
@@ -175,6 +181,7 @@ public class PeopleSpaceTile implements Parcelable {
builder.setNotificationContent(mNotificationContent);
builder.setNotificationCategory(mNotificationCategory);
builder.setNotificationDataUri(mNotificationDataUri);
builder.setMessagesCount(mMessagesCount);
builder.setIntent(mIntent);
builder.setNotificationTimestamp(mNotificationTimestamp);
builder.setStatuses(mStatuses);
@@ -196,6 +203,7 @@ public class PeopleSpaceTile implements Parcelable {
private CharSequence mNotificationContent;
private String mNotificationCategory;
private Uri mNotificationDataUri;
private int mMessagesCount;
private Intent mIntent;
private long mNotificationTimestamp;
private List<ConversationStatus> mStatuses;
@@ -320,6 +328,12 @@ public class PeopleSpaceTile implements Parcelable {
return this;
}
/** Sets the number of messages associated with the Tile. */
public Builder setMessagesCount(int messagesCount) {
mMessagesCount = messagesCount;
return this;
}
/** Sets an intent to launch on click. */
public Builder setIntent(Intent intent) {
mIntent = intent;
@@ -359,6 +373,7 @@ public class PeopleSpaceTile implements Parcelable {
mNotificationContent = in.readCharSequence();
mNotificationCategory = in.readString();
mNotificationDataUri = in.readParcelable(Uri.class.getClassLoader());
mMessagesCount = in.readInt();
mIntent = in.readParcelable(Intent.class.getClassLoader());
mNotificationTimestamp = in.readLong();
mStatuses = new ArrayList<>();
@@ -385,6 +400,7 @@ public class PeopleSpaceTile implements Parcelable {
dest.writeCharSequence(mNotificationContent);
dest.writeString(mNotificationCategory);
dest.writeParcelable(mNotificationDataUri, flags);
dest.writeInt(mMessagesCount);
dest.writeParcelable(mIntent, flags);
dest.writeLong(mNotificationTimestamp);
dest.writeParcelableList(mStatuses, flags);

View File

@@ -235,6 +235,7 @@ public class PeopleSpaceTileTest {
.setStatuses(statusList).setNotificationKey("key")
.setNotificationContent("content")
.setNotificationDataUri(Uri.parse("data"))
.setMessagesCount(2)
.setIntent(new Intent())
.build();
@@ -256,6 +257,7 @@ public class PeopleSpaceTileTest {
assertThat(readTile.getNotificationKey()).isEqualTo(tile.getNotificationKey());
assertThat(readTile.getNotificationContent()).isEqualTo(tile.getNotificationContent());
assertThat(readTile.getNotificationDataUri()).isEqualTo(tile.getNotificationDataUri());
assertThat(readTile.getMessagesCount()).isEqualTo(tile.getMessagesCount());
assertThat(readTile.getIntent().toString()).isEqualTo(tile.getIntent().toString());
}
@@ -290,6 +292,17 @@ public class PeopleSpaceTileTest {
assertThat(tile.getNotificationDataUri()).isEqualTo(Uri.parse("test"));
}
@Test
public void testMessagesCount() {
PeopleSpaceTile tile =
new PeopleSpaceTile.Builder(new ShortcutInfo.Builder(mContext, "123").build(),
mLauncherApps)
.setMessagesCount(2)
.build();
assertThat(tile.getMessagesCount()).isEqualTo(2);
}
@Test
public void testIntent() {
PeopleSpaceTile tile = new PeopleSpaceTile.Builder(

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android" >
<solid android:color="#9ED582" />
<corners android:radius="@dimen/people_space_messages_count_radius" />
</shape>

View File

@@ -98,8 +98,8 @@
android:orientation="horizontal"
android:paddingTop="4dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:clipToOutline="true">
<TextView
android:id="@+id/name"
android:gravity="center_vertical"
@@ -112,7 +112,21 @@
android:ellipsize="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/messages_count"
android:gravity="end"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
android:textColor="?android:attr/textColorPrimary"
android:background="@drawable/people_space_messages_count_background"
android:textSize="14sp"
android:maxLines="1"
android:ellipsize="end"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
/>
<ImageView
android:id="@+id/predefined_icon"
android:gravity="end|center_vertical"

View File

@@ -1353,6 +1353,7 @@
<dimen name="people_space_widget_radius">28dp</dimen>
<dimen name="people_space_image_radius">20dp</dimen>
<dimen name="people_space_messages_count_radius">12dp</dimen>
<dimen name="people_space_widget_background_padding">6dp</dimen>
<dimen name="required_width_for_medium">146dp</dimen>
<dimen name="required_width_for_large">138dp</dimen>

View File

@@ -2865,6 +2865,8 @@
<string name="empty_status">Let’s chat tonight!</string>
<!-- Default text for missed call notifications on their Conversation widget [CHAR LIMIT=20] -->
<string name="missed_call">Missed call</string>
<!-- Text when a Notification may have more messages than the number indicated [CHAR LIMIT=5] -->
<string name="messages_count_overflow_indicator"><xliff:g id="number" example="7">%d</xliff:g>+</string>
<!-- Description text for adding a Conversation widget [CHAR LIMIT=100] -->
<string name="people_tile_description">See recent messages, missed calls, and status updates</string>
<!-- Title text displayed for the Conversation widget [CHAR LIMIT=50] -->

View File

@@ -274,13 +274,17 @@ public class PeopleSpaceUtils {
return tile;
}
boolean isMissedCall = Objects.equals(notification.category, CATEGORY_MISSED_CALL);
Notification.MessagingStyle.Message message = getLastMessagingStyleMessage(notification);
List<Notification.MessagingStyle.Message> messages =
getMessagingStyleMessages(notification);
if (!isMissedCall && message == null) {
if (!isMissedCall && ArrayUtils.isEmpty(messages)) {
if (DEBUG) Log.d(TAG, "Notification has no content");
return tile;
}
// messages are in chronological order from most recent to least.
Notification.MessagingStyle.Message message = messages != null ? messages.get(0) : null;
int messagesCount = messages != null ? messages.size() : 0;
// If it's a missed call notification and it doesn't include content, use fallback value,
// otherwise, use notification content.
boolean hasMessageText = message != null && !TextUtils.isEmpty(message.getText());
@@ -294,12 +298,16 @@ public class PeopleSpaceUtils {
.setNotificationCategory(notification.category)
.setNotificationContent(content)
.setNotificationDataUri(dataUri)
.setMessagesCount(messagesCount)
.build();
}
/** Gets the most recent {@link Notification.MessagingStyle.Message} from the notification. */
/**
* Returns {@link Notification.MessagingStyle.Message}s from the Notification in chronological
* order from most recent to least.
*/
@VisibleForTesting
public static Notification.MessagingStyle.Message getLastMessagingStyleMessage(
public static List<Notification.MessagingStyle.Message> getMessagingStyleMessages(
Notification notification) {
if (notification == null) {
return null;
@@ -312,7 +320,7 @@ public class PeopleSpaceUtils {
Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
sortedMessages.sort(Collections.reverseOrder(
Comparator.comparing(Notification.MessagingStyle.Message::getTimestamp)));
return sortedMessages.get(0);
return sortedMessages;
}
}
return null;

View File

@@ -58,8 +58,10 @@ import com.android.systemui.R;
import com.android.systemui.people.widget.LaunchConversationActivity;
import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Matcher;
@@ -82,6 +84,8 @@ class PeopleTileViewHelper {
private static final int FIXED_HEIGHT_DIMENS_FOR_SMALL = 6 + 4 + 8;
private static final int FIXED_WIDTH_DIMENS_FOR_SMALL = 4 + 4;
private static final int MESSAGES_COUNT_OVERFLOW = 7;
private static final Pattern DOUBLE_EXCLAMATION_PATTERN = Pattern.compile("[!][!]+");
private static final Pattern DOUBLE_QUESTION_PATTERN = Pattern.compile("[?][?]+");
private static final Pattern ANY_DOUBLE_MARK_PATTERN = Pattern.compile("[!?][!?]+");
@@ -97,6 +101,9 @@ class PeopleTileViewHelper {
private int mHeight;
private int mLayoutSize;
private Locale mLocale;
private NumberFormat mIntegerFormat;
PeopleTileViewHelper(Context context, PeopleSpaceTile tile,
int appWidgetId, Bundle options) {
mContext = context;
@@ -354,12 +361,35 @@ class PeopleTileViewHelper {
views.setViewVisibility(R.id.image, View.GONE);
views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_message);
}
if (mTile.getMessagesCount() > 1 && mLayoutSize == LAYOUT_MEDIUM) {
views.setViewVisibility(R.id.messages_count, View.VISIBLE);
views.setTextViewText(R.id.messages_count,
getMessagesCountText(mTile.getMessagesCount()));
}
// TODO: Set subtext as Group Sender name once storing the name in PeopleSpaceTile and
// subtract 1 from maxLines when present.
views.setViewVisibility(R.id.subtext, View.GONE);
return views;
}
// Some messaging apps only include up to 7 messages in their notifications.
private String getMessagesCountText(int count) {
if (count >= MESSAGES_COUNT_OVERFLOW) {
return mContext.getResources().getString(
R.string.messages_count_overflow_indicator, MESSAGES_COUNT_OVERFLOW);
}
// Cache the locale-appropriate NumberFormat. Configuration locale is guaranteed
// non-null, so the first time this is called we will always get the appropriate
// NumberFormat, then never regenerate it unless the locale changes on the fly.
final Locale curLocale = mContext.getResources().getConfiguration().getLocales().get(0);
if (!curLocale.equals(mLocale)) {
mLocale = curLocale;
mIntegerFormat = NumberFormat.getIntegerInstance(curLocale);
}
return mIntegerFormat.format(count);
}
private RemoteViews createStatusRemoteViews(ConversationStatus status) {
RemoteViews views = getViewForContentLayout();
CharSequence statusText = status.getDescription();

View File

@@ -328,6 +328,7 @@ public class PeopleSpaceWidgetManager {
.setNotificationKey(null)
.setNotificationContent(null)
.setNotificationDataUri(null)
.setMessagesCount(0)
// Reset missed calls category.
.setNotificationCategory(null)
.build();

View File

@@ -65,6 +65,7 @@ import android.util.DisplayMetrics;
import androidx.test.filters.SmallTest;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.util.ArrayUtils;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.people.widget.PeopleTileKey;
@@ -119,6 +120,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
.setNotificationKey(NOTIFICATION_KEY)
.setNotificationContent(NOTIFICATION_CONTENT)
.setNotificationDataUri(URI)
.setMessagesCount(1)
.build();
private final ShortcutInfo mShortcutInfo = new ShortcutInfo.Builder(mContext,
@@ -318,7 +320,7 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
}
@Test
public void testGetLastMessagingStyleMessageNoMessage() {
public void testGetMessagingStyleMessagesNoMessage() {
Notification notification = new Notification.Builder(mContext, "test")
.setContentTitle("TEST_TITLE")
.setContentText("TEST_TEXT")
@@ -328,22 +330,23 @@ public class PeopleSpaceUtilsTest extends SysuiTestCase {
.setNotification(notification)
.build();
Notification.MessagingStyle.Message lastMessage =
PeopleSpaceUtils.getLastMessagingStyleMessage(sbn.getNotification());
List<Notification.MessagingStyle.Message> messages =
PeopleSpaceUtils.getMessagingStyleMessages(sbn.getNotification());
assertThat(lastMessage).isNull();
assertThat(ArrayUtils.isEmpty(messages)).isTrue();
}
@Test
public void testGetLastMessagingStyleMessage() {
public void testGetMessagingStyleMessages() {
StatusBarNotification sbn = new SbnBuilder()
.setNotification(mNotification1)
.build();
Notification.MessagingStyle.Message lastMessage =
PeopleSpaceUtils.getLastMessagingStyleMessage(sbn.getNotification());
List<Notification.MessagingStyle.Message> messages =
PeopleSpaceUtils.getMessagingStyleMessages(sbn.getNotification());
assertThat(lastMessage.getText().toString()).isEqualTo(NOTIFICATION_TEXT_2);
assertThat(messages.size()).isEqualTo(3);
assertThat(messages.get(0).getText().toString()).isEqualTo(NOTIFICATION_TEXT_2);
}
@Test

View File

@@ -467,6 +467,9 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {
assertEquals(View.VISIBLE,
smallResult.findViewById(R.id.person_icon).getVisibility());
// Has a single message, no count shown.
assertEquals(View.GONE, result.findViewById(R.id.messages_count).getVisibility());
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
getSizeInDp(R.dimen.required_width_for_large));
mOptions.putInt(OPTION_APPWIDGET_MIN_WIDTH,
@@ -491,6 +494,36 @@ public class PeopleTileViewHelperTest extends SysuiTestCase {
assertThat(statusContent.getMaxLines()).isEqualTo(3);
}
@Test
public void testCreateRemoteViewsWithNotificationTemplateTwoMessages() {
PeopleSpaceTile tileWithStatusAndNotification = PERSON_TILE.toBuilder()
.setNotificationDataUri(null)
.setStatuses(Arrays.asList(GAME_STATUS,
NEW_STORY_WITH_AVAILABILITY))
.setMessagesCount(2).build();
RemoteViews views = new PeopleTileViewHelper(mContext,
tileWithStatusAndNotification, 0, mOptions).getViews();
View result = views.apply(mContext, null);
TextView name = (TextView) result.findViewById(R.id.name);
assertEquals(name.getText(), NAME);
TextView subtext = (TextView) result.findViewById(R.id.subtext);
assertEquals(View.GONE, subtext.getVisibility());
// Has availability.
View availability = result.findViewById(R.id.availability);
assertEquals(View.VISIBLE, availability.getVisibility());
// Has person icon.
View personIcon = result.findViewById(R.id.person_icon);
assertEquals(View.VISIBLE, personIcon.getVisibility());
// Has notification content.
TextView statusContent = (TextView) result.findViewById(R.id.text_content);
assertEquals(statusContent.getText(), NOTIFICATION_CONTENT);
// Has 2 messages, show count.
assertEquals(View.VISIBLE, result.findViewById(R.id.messages_count).getVisibility());
}
@Test
public void testGetBackgroundTextFromMessageNoPunctuation() {
String backgroundText = mPeopleTileViewHelper.getBackgroundTextFromMessage("test");