Merge "Track NotificationEntry creation time" into rvc-dev am: 2214685d42

Change-Id: Id53763057974702084e82b86688c59fda2f0640e
This commit is contained in:
Evan Laird
2020-04-09 16:23:43 +00:00
committed by Automerger Merge Worker
9 changed files with 83 additions and 27 deletions

View File

@@ -25,6 +25,7 @@ import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.statusbar.NotificationLifetimeExtender; import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.util.time.SystemClock;
/** /**
* Extends the lifetime of foreground notification services such that they show for at least * Extends the lifetime of foreground notification services such that they show for at least
@@ -39,8 +40,10 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx
private NotificationSafeToRemoveCallback mNotificationSafeToRemoveCallback; private NotificationSafeToRemoveCallback mNotificationSafeToRemoveCallback;
private ArraySet<NotificationEntry> mManagedEntries = new ArraySet<>(); private ArraySet<NotificationEntry> mManagedEntries = new ArraySet<>();
private Handler mHandler = new Handler(Looper.getMainLooper()); private Handler mHandler = new Handler(Looper.getMainLooper());
private final SystemClock mSystemClock;
public ForegroundServiceLifetimeExtender() { public ForegroundServiceLifetimeExtender(SystemClock systemClock) {
mSystemClock = systemClock;
} }
@Override @Override
@@ -55,8 +58,8 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx
return false; return false;
} }
long currentTime = System.currentTimeMillis(); long currentTime = mSystemClock.uptimeMillis();
return currentTime - entry.getSbn().getPostTime() < MIN_FGS_TIME_MS; return currentTime - entry.getCreationTime() < MIN_FGS_TIME_MS;
} }
@Override @Override
@@ -84,7 +87,7 @@ public class ForegroundServiceLifetimeExtender implements NotificationLifetimeEx
} }
}; };
long delayAmt = MIN_FGS_TIME_MS long delayAmt = MIN_FGS_TIME_MS
- (System.currentTimeMillis() - entry.getSbn().getPostTime()); - (mSystemClock.uptimeMillis() - entry.getCreationTime());
mHandler.postDelayed(r, delayAmt); mHandler.postDelayed(r, delayAmt);
} }
} }

View File

@@ -30,6 +30,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.util.time.SystemClock;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@@ -49,7 +50,8 @@ public class ForegroundServiceNotificationListener {
public ForegroundServiceNotificationListener(Context context, public ForegroundServiceNotificationListener(Context context,
ForegroundServiceController foregroundServiceController, ForegroundServiceController foregroundServiceController,
NotificationEntryManager notificationEntryManager, NotificationEntryManager notificationEntryManager,
NotifPipeline notifPipeline) { NotifPipeline notifPipeline,
SystemClock systemClock) {
mContext = context; mContext = context;
mForegroundServiceController = foregroundServiceController; mForegroundServiceController = foregroundServiceController;
@@ -76,7 +78,8 @@ public class ForegroundServiceNotificationListener {
removeNotification(entry.getSbn()); removeNotification(entry.getSbn());
} }
}); });
mEntryManager.addNotificationLifetimeExtender(new ForegroundServiceLifetimeExtender()); mEntryManager.addNotificationLifetimeExtender(
new ForegroundServiceLifetimeExtender(systemClock));
notifPipeline.addCollectionListener(new NotifCollectionListener() { notifPipeline.addCollectionListener(new NotifCollectionListener() {
@Override @Override

View File

@@ -24,6 +24,7 @@ import static com.android.systemui.statusbar.notification.row.NotificationRowCon
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.Notification; import android.app.Notification;
import android.os.SystemClock;
import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.Ranking;
import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.NotificationListenerService.RankingMap;
@@ -555,8 +556,8 @@ public class NotificationEntryManager implements
NotificationEntry entry = new NotificationEntry( NotificationEntry entry = new NotificationEntry(
notification, notification,
ranking, ranking,
mFgsFeatureController.isForegroundServiceDismissalEnabled()); mFgsFeatureController.isForegroundServiceDismissalEnabled(),
mAllNotifications.add(entry); SystemClock.uptimeMillis());
mLeakDetector.trackInstance(entry); mLeakDetector.trackInstance(entry);

View File

@@ -47,6 +47,7 @@ import android.annotation.Nullable;
import android.annotation.UserIdInt; import android.annotation.UserIdInt;
import android.app.Notification; import android.app.Notification;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle; import android.os.UserHandle;
import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService;
import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.Ranking;
@@ -387,7 +388,7 @@ public class NotifCollection implements Dumpable {
if (entry == null) { if (entry == null) {
// A new notification! // A new notification!
entry = new NotificationEntry(sbn, ranking); entry = new NotificationEntry(sbn, ranking, SystemClock.uptimeMillis());
mNotificationSet.put(sbn.getKey(), entry); mNotificationSet.put(sbn.getKey(), entry);
mLogger.logNotifPosted(sbn.getKey()); mLogger.logNotifPosted(sbn.getKey());

View File

@@ -35,6 +35,7 @@ import static com.android.systemui.statusbar.notification.stack.NotificationSect
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import android.annotation.CurrentTimeMillisLong;
import android.app.Notification; import android.app.Notification;
import android.app.Notification.MessagingStyle.Message; import android.app.Notification.MessagingStyle.Message;
import android.app.NotificationChannel; import android.app.NotificationChannel;
@@ -93,6 +94,7 @@ public final class NotificationEntry extends ListEntry {
private final String mKey; private final String mKey;
private StatusBarNotification mSbn; private StatusBarNotification mSbn;
private Ranking mRanking; private Ranking mRanking;
private long mCreationTime;
/* /*
* Bookkeeping members * Bookkeeping members
@@ -171,21 +173,29 @@ public final class NotificationEntry extends ListEntry {
private boolean mAllowFgsDismissal; private boolean mAllowFgsDismissal;
private int mBucket = BUCKET_ALERTING; private int mBucket = BUCKET_ALERTING;
/**
* @param sbn the StatusBarNotification from system server
* @param ranking also from system server
* @param creationTime SystemClock.uptimeMillis of when we were created
*/
public NotificationEntry( public NotificationEntry(
@NonNull StatusBarNotification sbn, @NonNull StatusBarNotification sbn,
@NonNull Ranking ranking) { @NonNull Ranking ranking,
this(sbn, ranking, false); long creationTime) {
this(sbn, ranking, false, creationTime);
} }
public NotificationEntry( public NotificationEntry(
@NonNull StatusBarNotification sbn, @NonNull StatusBarNotification sbn,
@NonNull Ranking ranking, @NonNull Ranking ranking,
boolean allowFgsDismissal boolean allowFgsDismissal,
long creationTime
) { ) {
super(requireNonNull(Objects.requireNonNull(sbn).getKey())); super(requireNonNull(Objects.requireNonNull(sbn).getKey()));
requireNonNull(ranking); requireNonNull(ranking);
mCreationTime = creationTime;
mKey = sbn.getKey(); mKey = sbn.getKey();
setSbn(sbn); setSbn(sbn);
setRanking(ranking); setRanking(ranking);
@@ -237,6 +247,21 @@ public final class NotificationEntry extends ListEntry {
return mRanking; return mRanking;
} }
/**
* A timestamp of SystemClock.uptimeMillis() of when this entry was first created, regardless
* of any changes to the data presented. It is set once on creation and will never change, and
* allows us to know exactly how long this notification has been alive for in our listener
* service. It is entirely unrelated to the information inside of the notification.
*
* This is different to Notification#when because it persists throughout updates, whereas
* system server treats every single call to notify() as a new notification and we handle
* updates to NotificationEntry locally.
*/
@CurrentTimeMillisLong
public long getCreationTime() {
return mCreationTime;
}
/** /**
* Should only be called by NotificationEntryManager and friends. * Should only be called by NotificationEntryManager and friends.
* TODO: Make this package-private * TODO: Make this package-private

View File

@@ -52,6 +52,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.util.time.FakeSystemClock;
import junit.framework.Assert; import junit.framework.Assert;
@@ -69,6 +70,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
private ForegroundServiceController mFsc; private ForegroundServiceController mFsc;
private ForegroundServiceNotificationListener mListener; private ForegroundServiceNotificationListener mListener;
private NotificationEntryListener mEntryListener; private NotificationEntryListener mEntryListener;
private final FakeSystemClock mClock = new FakeSystemClock();
@Mock private NotificationEntryManager mEntryManager; @Mock private NotificationEntryManager mEntryManager;
@Mock private AppOpsController mAppOpsController; @Mock private AppOpsController mAppOpsController;
@Mock private Handler mMainHandler; @Mock private Handler mMainHandler;
@@ -80,9 +82,10 @@ public class ForegroundServiceControllerTest extends SysuiTestCase {
allowTestableLooperAsMainThread(); allowTestableLooperAsMainThread();
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mFsc = new ForegroundServiceController(mEntryManager, mAppOpsController, mMainHandler); mFsc = new ForegroundServiceController(
mEntryManager, mAppOpsController, mMainHandler);
mListener = new ForegroundServiceNotificationListener( mListener = new ForegroundServiceNotificationListener(
mContext, mFsc, mEntryManager, mNotifPipeline); mContext, mFsc, mEntryManager, mNotifPipeline, mClock);
ArgumentCaptor<NotificationEntryListener> entryListenerCaptor = ArgumentCaptor<NotificationEntryListener> entryListenerCaptor =
ArgumentCaptor.forClass(NotificationEntryListener.class); ArgumentCaptor.forClass(NotificationEntryListener.class);
verify(mEntryManager).addNotificationEntryListener( verify(mEntryManager).addNotificationEntryListener(

View File

@@ -17,7 +17,6 @@
package com.android.systemui; package com.android.systemui;
import static com.android.systemui.ForegroundServiceLifetimeExtender.MIN_FGS_TIME_MS; import static com.android.systemui.ForegroundServiceLifetimeExtender.MIN_FGS_TIME_MS;
import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@@ -29,6 +28,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -37,12 +37,15 @@ import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
@SmallTest @SmallTest
public class ForegroundServiceNotificationListenerTest extends SysuiTestCase { public class ForegroundServiceNotificationListenerTest extends SysuiTestCase {
private ForegroundServiceLifetimeExtender mExtender = new ForegroundServiceLifetimeExtender(); private ForegroundServiceLifetimeExtender mExtender;
private NotificationEntry mEntry; private NotificationEntry mEntry;
private Notification mNotif; private Notification mNotif;
private final FakeSystemClock mClock = new FakeSystemClock();
@Before @Before
public void setup() { public void setup() {
mExtender = new ForegroundServiceLifetimeExtender(mClock);
mNotif = new Notification.Builder(mContext, "") mNotif = new Notification.Builder(mContext, "")
.setSmallIcon(R.drawable.ic_person) .setSmallIcon(R.drawable.ic_person)
.setContentTitle("Title") .setContentTitle("Title")
@@ -50,6 +53,7 @@ public class ForegroundServiceNotificationListenerTest extends SysuiTestCase {
.build(); .build();
mEntry = new NotificationEntryBuilder() mEntry = new NotificationEntryBuilder()
.setCreationTime(mClock.uptimeMillis())
.setNotification(mNotif) .setNotification(mNotif)
.build(); .build();
} }
@@ -62,27 +66,26 @@ public class ForegroundServiceNotificationListenerTest extends SysuiTestCase {
// Extend the lifetime of a FGS notification iff it has not been visible // Extend the lifetime of a FGS notification iff it has not been visible
// for the minimum time // for the minimum time
mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE; mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
modifySbn(mEntry)
.setPostTime(System.currentTimeMillis()) // No time has elapsed, keep showing
.build();
assertTrue(mExtender.shouldExtendLifetime(mEntry)); assertTrue(mExtender.shouldExtendLifetime(mEntry));
} }
@Test @Test
public void testShouldExtendLifetime_shouldNot_foreground() { public void testShouldExtendLifetime_shouldNot_foreground() {
mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE; mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
modifySbn(mEntry)
.setPostTime(System.currentTimeMillis() - MIN_FGS_TIME_MS - 1) // Entry was created at mClock.uptimeMillis(), advance it MIN_FGS_TIME_MS + 1
.build(); mClock.advanceTime(MIN_FGS_TIME_MS + 1);
assertFalse(mExtender.shouldExtendLifetime(mEntry)); assertFalse(mExtender.shouldExtendLifetime(mEntry));
} }
@Test @Test
public void testShouldExtendLifetime_shouldNot_notForeground() { public void testShouldExtendLifetime_shouldNot_notForeground() {
mNotif.flags = 0; mNotif.flags = 0;
modifySbn(mEntry)
.setPostTime(System.currentTimeMillis() - MIN_FGS_TIME_MS - 1) // Entry was created at mClock.uptimeMillis(), advance it MIN_FGS_TIME_MS + 1
.build(); mClock.advanceTime(MIN_FGS_TIME_MS + 1);
assertFalse(mExtender.shouldExtendLifetime(mEntry)); assertFalse(mExtender.shouldExtendLifetime(mEntry));
} }
} }

View File

@@ -29,6 +29,7 @@ import android.service.notification.StatusBarNotification;
import com.android.internal.logging.InstanceId; import com.android.internal.logging.InstanceId;
import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder; import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.util.time.FakeSystemClock;
import java.util.ArrayList; import java.util.ArrayList;
@@ -44,16 +45,22 @@ import java.util.ArrayList;
public class NotificationEntryBuilder { public class NotificationEntryBuilder {
private final SbnBuilder mSbnBuilder = new SbnBuilder(); private final SbnBuilder mSbnBuilder = new SbnBuilder();
private final RankingBuilder mRankingBuilder = new RankingBuilder(); private final RankingBuilder mRankingBuilder = new RankingBuilder();
private final FakeSystemClock mClock = new FakeSystemClock();
private StatusBarNotification mSbn = null; private StatusBarNotification mSbn = null;
/* ListEntry properties */ /* ListEntry properties */
private GroupEntry mParent; private GroupEntry mParent;
private int mSection = -1; private int mSection = -1;
/* If set, use this creation time instead of mClock.uptimeMillis */
private long mCreationTime = -1;
public NotificationEntry build() { public NotificationEntry build() {
StatusBarNotification sbn = mSbn != null ? mSbn : mSbnBuilder.build(); StatusBarNotification sbn = mSbn != null ? mSbn : mSbnBuilder.build();
mRankingBuilder.setKey(sbn.getKey()); mRankingBuilder.setKey(sbn.getKey());
final NotificationEntry entry = new NotificationEntry(sbn, mRankingBuilder.build()); long creationTime = mCreationTime != -1 ? mCreationTime : mClock.uptimeMillis();
final NotificationEntry entry = new NotificationEntry(
sbn, mRankingBuilder.build(), mClock.uptimeMillis());
/* ListEntry properties */ /* ListEntry properties */
entry.setParent(mParent); entry.setParent(mParent);
@@ -86,6 +93,14 @@ public class NotificationEntryBuilder {
return this; return this;
} }
/**
* Set the creation time
*/
public NotificationEntryBuilder setCreationTime(long creationTime) {
mCreationTime = creationTime;
return this;
}
/* Delegated to SbnBuilder */ /* Delegated to SbnBuilder */
public NotificationEntryBuilder setPkg(String pkg) { public NotificationEntryBuilder setPkg(String pkg) {

View File

@@ -52,6 +52,7 @@ import com.android.systemui.R;
import com.android.systemui.SysuiTestCase; import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder; import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -71,6 +72,7 @@ public class NotificationEntryTest extends SysuiTestCase {
private int mId; private int mId;
private NotificationEntry mEntry; private NotificationEntry mEntry;
private final FakeSystemClock mClock = new FakeSystemClock();
@Before @Before
public void setup() { public void setup() {
@@ -187,7 +189,7 @@ public class NotificationEntryTest extends SysuiTestCase {
.build(); .build();
NotificationEntry entry = NotificationEntry entry =
new NotificationEntry(sbn, ranking); new NotificationEntry(sbn, ranking, mClock.uptimeMillis());
assertEquals(systemGeneratedSmartActions, entry.getSmartActions()); assertEquals(systemGeneratedSmartActions, entry.getSmartActions());
assertEquals(NOTIFICATION_CHANNEL, entry.getChannel()); assertEquals(NOTIFICATION_CHANNEL, entry.getChannel());