Log conversation id in notification history
So we can clean up the history when a conversation is deleted
and link to the correct notification settings screen
Test: atest
Bug: 149505730
Change-Id: I0784ae80b0fd0a1c00e9b63dfce1104b274df6ce
Exempt-From-Owner-Approval: impatience
diff --git a/core/java/android/app/NotificationHistory.java b/core/java/android/app/NotificationHistory.java
index f26e628..d16120d 100644
--- a/core/java/android/app/NotificationHistory.java
+++ b/core/java/android/app/NotificationHistory.java
@@ -21,6 +21,7 @@
import android.graphics.drawable.Icon;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Arrays;
@@ -51,6 +52,7 @@
private String mTitle;
private String mText;
private Icon mIcon;
+ private String mConversationId;
private HistoricalNotification() {}
@@ -94,6 +96,10 @@
return mPackage + "|" + mUid + "|" + mPostedTimeMs;
}
+ public String getConversationId() {
+ return mConversationId;
+ }
+
@Override
public String toString() {
return "HistoricalNotification{" +
@@ -104,6 +110,7 @@
", mTitle='" + mTitle + '\'' +
", mText='" + mText + '\'' +
", mIcon=" + mIcon +
+ ", mConversationId=" + mConversationId +
'}';
}
@@ -123,6 +130,7 @@
Objects.equals(getChannelId(), that.getChannelId()) &&
Objects.equals(getTitle(), that.getTitle()) &&
Objects.equals(getText(), that.getText()) &&
+ Objects.equals(getConversationId(), that.getConversationId()) &&
iconsAreSame;
}
@@ -130,7 +138,7 @@
public int hashCode() {
return Objects.hash(getPackage(), getChannelName(), getChannelId(), getUid(),
getUserId(),
- getPostedTimeMs(), getTitle(), getText(), getIcon());
+ getPostedTimeMs(), getTitle(), getText(), getIcon(), getConversationId());
}
public static final class Builder {
@@ -143,6 +151,7 @@
private String mTitle;
private String mText;
private Icon mIcon;
+ private String mConversationId;
public Builder() {}
@@ -191,6 +200,11 @@
return this;
}
+ public Builder setConversationId(String conversationId) {
+ mConversationId = conversationId;
+ return this;
+ }
+
public HistoricalNotification build() {
HistoricalNotification n = new HistoricalNotification();
n.mPackage = mPackage;
@@ -202,6 +216,7 @@
n.mTitle = mTitle;
n.mText = mText;
n.mIcon = mIcon;
+ n.mConversationId = mConversationId;
return n;
}
}
@@ -299,6 +314,9 @@
mStringsToWrite.add(notification.getPackage());
mStringsToWrite.add(notification.getChannelName());
mStringsToWrite.add(notification.getChannelId());
+ if (!TextUtils.isEmpty(notification.getConversationId())) {
+ mStringsToWrite.add(notification.getConversationId());
+ }
}
}
@@ -423,9 +441,17 @@
channelIdIndex = -1;
}
+ final int conversationIdIndex;
+ if (!TextUtils.isEmpty(notification.getConversationId())) {
+ conversationIdIndex = findStringIndex(notification.getConversationId());
+ } else {
+ conversationIdIndex = -1;
+ }
+
p.writeInt(packageIndex);
p.writeInt(channelNameIndex);
p.writeInt(channelIdIndex);
+ p.writeInt(conversationIdIndex);
p.writeInt(notification.getUid());
p.writeInt(notification.getUserId());
p.writeLong(notification.getPostedTimeMs());
@@ -461,6 +487,13 @@
notificationOut.setChannelId(null);
}
+ final int conversationIdIndex = p.readInt();
+ if (conversationIdIndex >= 0) {
+ notificationOut.setConversationId(mStringPool[conversationIdIndex]);
+ } else {
+ notificationOut.setConversationId(null);
+ }
+
notificationOut.setUid(p.readInt());
notificationOut.setUserId(p.readInt());
notificationOut.setPostedTimeMs(p.readLong());
diff --git a/core/proto/android/server/notificationhistory.proto b/core/proto/android/server/notificationhistory.proto
index 6749719..15f4abb 100644
--- a/core/proto/android/server/notificationhistory.proto
+++ b/core/proto/android/server/notificationhistory.proto
@@ -55,6 +55,11 @@
// The small icon of the notification
optional Icon icon = 12;
+ // The conversation id, if any, that this notification belongs to
+ optional string conversation_id = 13;
+ // conversation_id_index contains the index + 1 of the conversation id in the string pool
+ optional int32 conversation_id_index = 14;
+
// Matches the constants of android.graphics.drawable.Icon
enum ImageTypeEnum {
TYPE_UNKNOWN = 0;
diff --git a/core/tests/coretests/src/android/app/NotificationHistoryTest.java b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
index d1608d0..8d8acb7 100644
--- a/core/tests/coretests/src/android/app/NotificationHistoryTest.java
+++ b/core/tests/coretests/src/android/app/NotificationHistoryTest.java
@@ -21,6 +21,7 @@
import android.app.NotificationHistory.HistoricalNotification;
import android.graphics.drawable.Icon;
import android.os.Parcel;
+import android.util.Slog;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -48,6 +49,10 @@
String expectedText = "text" + index;
Icon expectedIcon = Icon.createWithResource(InstrumentationRegistry.getContext(),
index);
+ String conversationId = null;
+ if (index % 2 == 0) {
+ conversationId = "convo" + index;
+ }
return new HistoricalNotification.Builder()
.setPackage(packageName)
@@ -59,6 +64,7 @@
.setTitle(expectedTitle)
.setText(expectedText)
.setIcon(expectedIcon)
+ .setConversationId(conversationId)
.build();
}
@@ -74,6 +80,7 @@
String expectedText = "text";
Icon expectedIcon = Icon.createWithResource(InstrumentationRegistry.getContext(),
android.R.drawable.btn_star);
+ String expectedConversationId = "convo";
HistoricalNotification n = new HistoricalNotification.Builder()
.setPackage(expectedPackage)
@@ -85,6 +92,7 @@
.setTitle(expectedTitle)
.setText(expectedText)
.setIcon(expectedIcon)
+ .setConversationId(expectedConversationId)
.build();
assertThat(n.getPackage()).isEqualTo(expectedPackage);
@@ -96,6 +104,7 @@
assertThat(n.getTitle()).isEqualTo(expectedTitle);
assertThat(n.getText()).isEqualTo(expectedText);
assertThat(expectedIcon.sameAs(n.getIcon())).isTrue();
+ assertThat(n.getConversationId()).isEqualTo(expectedConversationId);
}
@Test
@@ -153,6 +162,9 @@
expectedStrings.add(n.getPackage());
expectedStrings.add(n.getChannelName());
expectedStrings.add(n.getChannelId());
+ if (n.getConversationId() != null) {
+ expectedStrings.add(n.getConversationId());
+ }
history.addNotificationToWrite(n);
}
@@ -180,6 +192,9 @@
expectedStrings.add(n.getPackage());
expectedStrings.add(n.getChannelName());
expectedStrings.add(n.getChannelId());
+ if (n.getConversationId() != null) {
+ expectedStrings.add(n.getConversationId());
+ }
history.addNotificationToWrite(n);
}
@@ -212,6 +227,9 @@
postRemoveExpectedStrings.add(n.getPackage());
postRemoveExpectedStrings.add(n.getChannelName());
postRemoveExpectedStrings.add(n.getChannelId());
+ if (n.getConversationId() != null) {
+ postRemoveExpectedStrings.add(n.getConversationId());
+ }
postRemoveExpectedEntries.add(n);
}
@@ -221,14 +239,14 @@
history.poolStringsFromNotifications();
assertThat(history.getNotificationsToWrite().size()).isEqualTo(10);
- // 2 package names and 10 * 2 unique channel names and ids
- assertThat(history.getPooledStringsToWrite().length).isEqualTo(22);
+ // 2 package names and 10 * 2 unique channel names and ids and 5 conversation ids
+ assertThat(history.getPooledStringsToWrite().length).isEqualTo(27);
history.removeNotificationsFromWrite("pkgOdd");
- // 1 package names and 5 * 2 unique channel names and ids
- assertThat(history.getPooledStringsToWrite().length).isEqualTo(11);
+ // 1 package names and 5 * 2 unique channel names and ids and 5 conversation ids
+ assertThat(history.getPooledStringsToWrite().length).isEqualTo(16);
assertThat(history.getNotificationsToWrite())
.containsExactlyElementsIn(postRemoveExpectedEntries);
}
@@ -246,6 +264,9 @@
postRemoveExpectedStrings.add(n.getPackage());
postRemoveExpectedStrings.add(n.getChannelName());
postRemoveExpectedStrings.add(n.getChannelId());
+ if (n.getConversationId() != null) {
+ postRemoveExpectedStrings.add(n.getConversationId());
+ }
postRemoveExpectedEntries.add(n);
}
@@ -255,14 +276,14 @@
history.poolStringsFromNotifications();
assertThat(history.getNotificationsToWrite().size()).isEqualTo(10);
- // 1 package name and 10 unique channel names and ids
- assertThat(history.getPooledStringsToWrite().length).isEqualTo(21);
+ // 1 package name and 20 unique channel names and ids and 5 conversation ids
+ assertThat(history.getPooledStringsToWrite().length).isEqualTo(26);
history.removeNotificationFromWrite("pkg", 987654323);
- // 1 package names and 9 * 2 unique channel names and ids
- assertThat(history.getPooledStringsToWrite().length).isEqualTo(19);
+ // 1 package names and 9 * 2 unique channel names and ids and 4 conversation ids
+ assertThat(history.getPooledStringsToWrite().length).isEqualTo(23);
assertThat(history.getNotificationsToWrite())
.containsExactlyElementsIn(postRemoveExpectedEntries);
}
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryProtoHelper.java b/services/core/java/com/android/server/notification/NotificationHistoryProtoHelper.java
index 2831d37..7ba993b 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryProtoHelper.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryProtoHelper.java
@@ -19,6 +19,7 @@
import android.app.NotificationHistory.HistoricalNotification;
import android.content.res.Resources;
import android.graphics.drawable.Icon;
+import android.text.TextUtils;
import android.util.Slog;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
@@ -141,6 +142,16 @@
loadIcon(parser, notification, pkg);
parser.end(iconToken);
break;
+ case (int) Notification.CONVERSATION_ID_INDEX:
+ String conversationId =
+ stringPool.get(parser.readInt(Notification.CONVERSATION_ID_INDEX) - 1);
+ notification.setConversationId(conversationId);
+ break;
+ case (int) Notification.CONVERSATION_ID:
+ conversationId = parser.readString(Notification.CONVERSATION_ID);
+ notification.setConversationId(conversationId);
+ stringPool.add(conversationId);
+ break;
case ProtoInputStream.NO_MORE_FIELDS:
return notification.build();
}
@@ -271,6 +282,17 @@
+ ") not found in string cache");
proto.write(Notification.CHANNEL_ID, notification.getChannelId());
}
+ if (!TextUtils.isEmpty(notification.getConversationId())) {
+ final int conversationIdIndex = Arrays.binarySearch(
+ stringPool, notification.getConversationId());
+ if (conversationIdIndex >= 0) {
+ proto.write(Notification.CONVERSATION_ID_INDEX, conversationIdIndex + 1);
+ } else {
+ Slog.w(TAG, "notification conversation id (" + notification.getConversationId()
+ + ") not found in string cache");
+ proto.write(Notification.CONVERSATION_ID, notification.getConversationId());
+ }
+ }
proto.write(Notification.UID, notification.getUid());
proto.write(Notification.USER_ID, notification.getUserId());
proto.write(Notification.POSTED_TIME_MS, notification.getPostedTimeMs());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java
index 458117d..6eaf546 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryProtoHelperTest.java
@@ -21,6 +21,7 @@
import android.app.NotificationHistory.HistoricalNotification;
import android.graphics.drawable.Icon;
import android.test.suitebuilder.annotation.SmallTest;
+import android.text.TextUtils;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -57,6 +58,10 @@
String expectedText = "text" + index;
Icon expectedIcon = Icon.createWithResource(InstrumentationRegistry.getContext(),
index);
+ String conversationId = null;
+ if (index % 2 == 0) {
+ conversationId = "convo" + index;
+ }
return new HistoricalNotification.Builder()
.setPackage(packageName)
@@ -68,6 +73,7 @@
.setTitle(expectedTitle)
.setText(expectedText)
.setIcon(expectedIcon)
+ .setConversationId(conversationId)
.build();
}
@@ -139,6 +145,9 @@
expectedStrings.add(n.getPackage());
expectedStrings.add(n.getChannelName());
expectedStrings.add(n.getChannelId());
+ if (!TextUtils.isEmpty(n.getConversationId())) {
+ expectedStrings.add(n.getConversationId());
+ }
expectedEntries.add(n);
}
history.addNotificationToWrite(n);
@@ -178,6 +187,9 @@
expectedStrings.add(n.getPackage());
expectedStrings.add(n.getChannelName());
expectedStrings.add(n.getChannelId());
+ if (!TextUtils.isEmpty(n.getConversationId())) {
+ expectedStrings.add(n.getConversationId());
+ }
expectedEntries.add(n);
}
history.addNotificationToWrite(n);
@@ -227,6 +239,9 @@
expectedStrings.add(n.getPackage());
expectedStrings.add(n.getChannelName());
expectedStrings.add(n.getChannelId());
+ if (n.getConversationId() != null) {
+ expectedStrings.add(n.getConversationId());
+ }
expectedEntries.add(n);
}
history.addNotificationToWrite(n);
@@ -264,6 +279,9 @@
expectedStrings.add(n.getPackage());
expectedStrings.add(n.getChannelName());
expectedStrings.add(n.getChannelId());
+ if (n.getConversationId() != null) {
+ expectedStrings.add(n.getConversationId());
+ }
history.addNotificationToWrite(n);
}
history.poolStringsFromNotifications();
@@ -279,6 +297,9 @@
expectedStrings.add(n.getPackage());
expectedStrings.add(n.getChannelName());
expectedStrings.add(n.getChannelId());
+ if (n.getConversationId() != null) {
+ expectedStrings.add(n.getConversationId());
+ }
actualHistory.addNotificationToWrite(n);
}
actualHistory.poolStringsFromNotifications();