resolve merge conflicts of 88c651eab1 to oc-dr1-dev
Bug: 119041698 Test: atest SystemUITests Change-Id: I9d1547f98cc19111ce2dc8ab2f4e2bf2d3cb0baa Merged-In: I0680034ed9315aa2c05282524d48faaed066ebd0
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.systemui.statusbar;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Notification;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.systemui.statusbar.NotificationData;
|
||||
|
||||
/**
|
||||
* Extends the lifetime of foreground notification services such that they show for at least
|
||||
* five seconds
|
||||
*/
|
||||
public class ForegroundServiceLifetimeExtender implements NotificationLifetimeExtender {
|
||||
private static final String TAG = "FGSLifetimeExtender";
|
||||
|
||||
@VisibleForTesting
|
||||
public static final int MIN_FGS_TIME_MS = 5000;
|
||||
|
||||
private NotificationSafeToRemoveCallback mNotificationSafeToRemoveCallback;
|
||||
private ArraySet<NotificationData.Entry> mManagedEntries = new ArraySet<>();
|
||||
private Handler mHandler = new Handler(Looper.getMainLooper());
|
||||
|
||||
public ForegroundServiceLifetimeExtender() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(@NonNull NotificationSafeToRemoveCallback callback) {
|
||||
mNotificationSafeToRemoveCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry) {
|
||||
if ((entry.notification.getNotification().flags
|
||||
& Notification.FLAG_FOREGROUND_SERVICE) == 0) {
|
||||
return false;
|
||||
}
|
||||
long currentTime = System.currentTimeMillis();
|
||||
return currentTime - entry.notification.getPostTime() < MIN_FGS_TIME_MS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldExtendLifetimeForPendingNotification(
|
||||
@NonNull NotificationData.Entry entry) {
|
||||
return shouldExtendLifetime(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShouldManageLifetime(
|
||||
@NonNull NotificationData.Entry entry, boolean shouldManage) {
|
||||
android.util.Log.d("FGSExtender", "setShouldManageLifetime " + shouldManage);
|
||||
if (!shouldManage) {
|
||||
mManagedEntries.remove(entry);
|
||||
return;
|
||||
}
|
||||
mManagedEntries.add(entry);
|
||||
Runnable r = () -> {
|
||||
if (mManagedEntries.contains(entry)) {
|
||||
mManagedEntries.remove(entry);
|
||||
if (mNotificationSafeToRemoveCallback != null) {
|
||||
mNotificationSafeToRemoveCallback.onSafeToRemove(entry.key);
|
||||
}
|
||||
}
|
||||
};
|
||||
long delayAmt = MIN_FGS_TIME_MS
|
||||
- (System.currentTimeMillis() - entry.notification.getPostTime());
|
||||
mHandler.postDelayed(r, delayAmt);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.systemui.statusbar;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import com.android.systemui.statusbar.NotificationData;
|
||||
|
||||
/**
|
||||
* Interface for anything that may need to keep notifications managed even after
|
||||
* {@link NotificationListener} removes it. The lifetime extender is in charge of performing the
|
||||
* callback when the notification is then safe to remove.
|
||||
*/
|
||||
public interface NotificationLifetimeExtender {
|
||||
|
||||
/**
|
||||
* Set the handler to callback to when the notification is safe to remove.
|
||||
*
|
||||
* @param callback the handler to callback
|
||||
*/
|
||||
void setCallback(@NonNull NotificationSafeToRemoveCallback callback);
|
||||
|
||||
/**
|
||||
* Determines whether or not the extender needs the notification kept after removal.
|
||||
*
|
||||
* @param entry the entry containing the notification to check
|
||||
* @return true if the notification lifetime should be extended
|
||||
*/
|
||||
boolean shouldExtendLifetime(@NonNull NotificationData.Entry entry);
|
||||
|
||||
/**
|
||||
* It's possible that a notification was canceled before it ever became visible. This callback
|
||||
* gives lifetime extenders a chance to make sure it shows up. For example if a foreground
|
||||
* service is canceled too quickly but we still want to make sure a FGS notification shows.
|
||||
* @param pendingEntry the canceled (but pending) entry
|
||||
* @return true if the notification lifetime should be extended
|
||||
*/
|
||||
default boolean shouldExtendLifetimeForPendingNotification(
|
||||
@NonNull NotificationData.Entry pendingEntry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not the lifetime should be managed by the extender. In practice, if
|
||||
* shouldManage is true, this is where the extender starts managing the entry internally and is
|
||||
* now responsible for calling {@link NotificationSafeToRemoveCallback#onSafeToRemove(String)}
|
||||
* when the entry is safe to remove. If shouldManage is false, the extender no longer needs to
|
||||
* worry about it (either because we will be removing it anyway or the entry is no longer
|
||||
* removed due to an update).
|
||||
*
|
||||
* @param entry the entry that needs an extended lifetime
|
||||
* @param shouldManage true if the extender should manage the entry now, false otherwise
|
||||
*/
|
||||
void setShouldManageLifetime(@NonNull NotificationData.Entry entry, boolean shouldManage);
|
||||
|
||||
/**
|
||||
* The callback for when the notification is now safe to remove (i.e. its lifetime has ended).
|
||||
*/
|
||||
interface NotificationSafeToRemoveCallback {
|
||||
/**
|
||||
* Called when the lifetime extender determines it's safe to remove.
|
||||
*
|
||||
* @param key key of the entry that is now safe to remove
|
||||
*/
|
||||
void onSafeToRemove(String key);
|
||||
}
|
||||
}
|
||||
@@ -112,6 +112,7 @@ import android.service.vr.IVrManager;
|
||||
import android.service.vr.IVrStateCallbacks;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
@@ -206,6 +207,7 @@ import com.android.systemui.statusbar.DismissView;
|
||||
import com.android.systemui.statusbar.DragDownHelper;
|
||||
import com.android.systemui.statusbar.EmptyShadeView;
|
||||
import com.android.systemui.statusbar.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.ForegroundServiceLifetimeExtender;
|
||||
import com.android.systemui.statusbar.GestureRecorder;
|
||||
import com.android.systemui.statusbar.KeyboardShortcuts;
|
||||
import com.android.systemui.statusbar.KeyguardIndicationController;
|
||||
@@ -213,6 +215,7 @@ import com.android.systemui.statusbar.NotificationData;
|
||||
import com.android.systemui.statusbar.NotificationData.Entry;
|
||||
import com.android.systemui.statusbar.NotificationGuts;
|
||||
import com.android.systemui.statusbar.NotificationInfo;
|
||||
import com.android.systemui.statusbar.NotificationLifetimeExtender;
|
||||
import com.android.systemui.statusbar.NotificationShelf;
|
||||
import com.android.systemui.statusbar.NotificationSnooze;
|
||||
import com.android.systemui.statusbar.RemoteInputController;
|
||||
@@ -745,10 +748,11 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
@Nullable private View mAmbientIndicationContainer;
|
||||
private String mKeyToRemoveOnGutsClosed;
|
||||
private SysuiColorExtractor mColorExtractor;
|
||||
private ForegroundServiceController mForegroundServiceController;
|
||||
private ScreenLifecycle mScreenLifecycle;
|
||||
@VisibleForTesting WakefulnessLifecycle mWakefulnessLifecycle;
|
||||
|
||||
protected ForegroundServiceController mForegroundServiceController;
|
||||
|
||||
private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
|
||||
final int N = array.size();
|
||||
for (int i = 0 ; i < N; i++) {
|
||||
@@ -803,6 +807,9 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
|
||||
|
||||
mForegroundServiceController = Dependency.get(ForegroundServiceController.class);
|
||||
mFGSExtender = new ForegroundServiceLifetimeExtender();
|
||||
mFGSExtender.setCallback(key -> removeNotification(key, mLatestRankingMap));
|
||||
|
||||
|
||||
mDisplay = mWindowManager.getDefaultDisplay();
|
||||
updateDisplaySize();
|
||||
@@ -1803,6 +1810,11 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
}
|
||||
Entry entry = mNotificationData.get(key);
|
||||
|
||||
if (entry != null && mFGSExtender.shouldExtendLifetime(entry)) {
|
||||
extendLifetime(entry, mFGSExtender);
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry != null && mRemoteInputController.isRemoteInputActive(entry)
|
||||
&& (entry.row != null && !entry.row.isDismissed())) {
|
||||
mLatestRankingMap = ranking;
|
||||
@@ -1841,9 +1853,35 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
}
|
||||
}
|
||||
}
|
||||
// Make sure no lifetime extension is happening anymore
|
||||
cancelLifetimeExtension(entry);
|
||||
setAreThereNotifications();
|
||||
}
|
||||
|
||||
/** Lifetime extension keeps entries around after they would've otherwise been canceled */
|
||||
private void extendLifetime(Entry entry, NotificationLifetimeExtender extender) {
|
||||
// Cancel any other extender which might be holding on to this notification entry
|
||||
NotificationLifetimeExtender activeExtender = mRetainedNotifications.get(entry);
|
||||
if (activeExtender != null && activeExtender != extender) {
|
||||
activeExtender.setShouldManageLifetime(entry, false);
|
||||
}
|
||||
mRetainedNotifications.put(entry, extender);
|
||||
extender.setShouldManageLifetime(entry, true);
|
||||
}
|
||||
|
||||
/** Tells the current extender (if any) to stop extending the entry's lifetime */
|
||||
private void cancelLifetimeExtension(NotificationData.Entry entry) {
|
||||
NotificationLifetimeExtender activeExtender = mRetainedNotifications.remove(entry);
|
||||
if (activeExtender != null) {
|
||||
activeExtender.setShouldManageLifetime(entry, false);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public Map<Entry, NotificationLifetimeExtender> getRetainedNotificationMap() {
|
||||
return mRetainedNotifications;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the group children are cancelled immediately when the group summary is cancelled
|
||||
* instead of waiting for the notification manager to send all cancels. Otherwise this could
|
||||
@@ -3479,6 +3517,17 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
}
|
||||
}
|
||||
|
||||
pw.println(" Lifetime-extended notifications:");
|
||||
if (mRetainedNotifications.isEmpty()) {
|
||||
pw.println(" None");
|
||||
} else {
|
||||
for (Map.Entry<NotificationData.Entry, NotificationLifetimeExtender> entry
|
||||
: mRetainedNotifications.entrySet()) {
|
||||
pw.println(" " + entry.getKey().notification + " retained by "
|
||||
+ entry.getValue().getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
pw.print(" mInteractingWindows="); pw.println(mInteractingWindows);
|
||||
pw.print(" mStatusBarWindowState=");
|
||||
pw.println(windowStateToString(mStatusBarWindowState));
|
||||
@@ -5622,6 +5671,11 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
|
||||
protected RemoteInputController mRemoteInputController;
|
||||
|
||||
// A lifetime extender that watches for foreground service notifications
|
||||
@VisibleForTesting protected NotificationLifetimeExtender mFGSExtender;
|
||||
private final Map<Entry, NotificationLifetimeExtender> mRetainedNotifications =
|
||||
new ArrayMap<>();
|
||||
|
||||
// for heads up notifications
|
||||
protected HeadsUpManager mHeadsUpManager;
|
||||
|
||||
@@ -7288,6 +7342,9 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
Log.w(TAG, "Notification that was kept for guts was updated. " + key);
|
||||
}
|
||||
|
||||
// No need to keep the lifetime extension around if an update comes in for it
|
||||
cancelLifetimeExtension(entry);
|
||||
|
||||
Notification n = notification.getNotification();
|
||||
mNotificationData.updateRanking(ranking);
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.systemui.statusbar;
|
||||
|
||||
import static com.android.systemui.statusbar.ForegroundServiceLifetimeExtender.MIN_FGS_TIME_MS;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.service.notification.NotificationListenerService.Ranking;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.statusbar.NotificationData.Entry;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@SmallTest
|
||||
public class ForegroundServiceLifetimeExtenderTest extends SysuiTestCase {
|
||||
private ForegroundServiceLifetimeExtender mExtender = new ForegroundServiceLifetimeExtender();
|
||||
private StatusBarNotification mSbn;
|
||||
private NotificationData.Entry mEntry;
|
||||
private Notification mNotif;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mNotif = new Notification.Builder(mContext, "")
|
||||
.setSmallIcon(R.drawable.ic_person)
|
||||
.setContentTitle("Title")
|
||||
.setContentText("Text")
|
||||
.build();
|
||||
mSbn = mock(StatusBarNotification.class);
|
||||
when(mSbn.getNotification()).thenReturn(mNotif);
|
||||
mEntry = new NotificationData.Entry(mSbn);
|
||||
}
|
||||
|
||||
/**
|
||||
* ForegroundServiceLifetimeExtenderTest
|
||||
*/
|
||||
@Test
|
||||
public void testShouldExtendLifetime_should_foreground() {
|
||||
// Extend the lifetime of a FGS notification iff it has not been visible
|
||||
// for the minimum time
|
||||
mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
|
||||
when(mSbn.getPostTime()).thenReturn(System.currentTimeMillis());
|
||||
assertTrue(mExtender.shouldExtendLifetime(mEntry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldExtendLifetime_shouldNot_foreground() {
|
||||
mNotif.flags |= Notification.FLAG_FOREGROUND_SERVICE;
|
||||
when(mSbn.getPostTime()).thenReturn(System.currentTimeMillis() - MIN_FGS_TIME_MS - 1);
|
||||
assertFalse(mExtender.shouldExtendLifetime(mEntry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testShouldExtendLifetime_shouldNot_notForeground() {
|
||||
mNotif.flags = 0;
|
||||
when(mSbn.getPostTime()).thenReturn(System.currentTimeMillis() - MIN_FGS_TIME_MS - 1);
|
||||
assertFalse(mExtender.shouldExtendLifetime(mEntry));
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,8 @@ package com.android.systemui.statusbar.phone;
|
||||
|
||||
import static android.app.NotificationManager.IMPORTANCE_HIGH;
|
||||
|
||||
import static com.android.systemui.statusbar.ForegroundServiceLifetimeExtender.MIN_FGS_TIME_MS;
|
||||
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.TestCase.fail;
|
||||
@@ -37,6 +39,7 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Notification;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.hardware.fingerprint.FingerprintManager;
|
||||
@@ -49,6 +52,7 @@ import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.service.notification.NotificationListenerService.RankingMap;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.metricshelper.MetricsAsserts;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
@@ -64,6 +68,11 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.logging.testing.FakeMetricsLogger;
|
||||
import com.android.internal.statusbar.IStatusBarService;
|
||||
import com.android.keyguard.KeyguardHostView.OnDismissAction;
|
||||
import com.android.systemui.ForegroundServiceController;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.ForegroundServiceLifetimeExtender;
|
||||
import com.android.systemui.statusbar.NotificationLifetimeExtender;
|
||||
import com.android.systemui.statusbar.RemoteInputController;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.keyguard.WakefulnessLifecycle;
|
||||
import com.android.systemui.recents.misc.SystemServicesProxy;
|
||||
@@ -83,12 +92,18 @@ import org.junit.runner.RunWith;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@RunWithLooper
|
||||
public class StatusBarTest extends SysuiTestCase {
|
||||
|
||||
private static final String TEST_PACKAGE_NAME = "test";
|
||||
private static final int TEST_UID = 123;
|
||||
|
||||
StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
|
||||
UnlockMethodCache mUnlockMethodCache;
|
||||
KeyguardIndicationController mKeyguardIndicationController;
|
||||
@@ -101,8 +116,12 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
SystemServicesProxy mSystemServicesProxy;
|
||||
NotificationPanelView mNotificationPanelView;
|
||||
IStatusBarService mBarService;
|
||||
RemoteInputController mRemoteInputController;
|
||||
ForegroundServiceController mForegroundServiceController;
|
||||
ArrayList<Entry> mNotificationList;
|
||||
private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
|
||||
private ForegroundServiceLifetimeExtender mFGSExtender =
|
||||
new ForegroundServiceLifetimeExtender();
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
@@ -120,6 +139,8 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
when(mNotificationPanelView.getLayoutParams()).thenReturn(new LayoutParams(0, 0));
|
||||
mNotificationList = mock(ArrayList.class);
|
||||
IPowerManager powerManagerService = mock(IPowerManager.class);
|
||||
mRemoteInputController = mock(RemoteInputController.class);
|
||||
mForegroundServiceController = mock(ForegroundServiceController.class);
|
||||
HandlerThread handlerThread = new HandlerThread("TestThread");
|
||||
handlerThread.start();
|
||||
mPowerManager = new PowerManager(mContext, powerManagerService,
|
||||
@@ -128,11 +149,12 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
mBarService = mock(IStatusBarService.class);
|
||||
|
||||
mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger);
|
||||
mFGSExtender.setCallback(key -> mStatusBar.removeNotification(key, mock(RankingMap.class)));
|
||||
mStatusBar = new TestableStatusBar(mStatusBarKeyguardViewManager, mUnlockMethodCache,
|
||||
mKeyguardIndicationController, mStackScroller, mHeadsUpManager,
|
||||
mNotificationData, mPowerManager, mSystemServicesProxy, mNotificationPanelView,
|
||||
mBarService);
|
||||
mStatusBar.mContext = mContext;
|
||||
mBarService, mFGSExtender, mRemoteInputController, mForegroundServiceController);
|
||||
|
||||
doAnswer(invocation -> {
|
||||
OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0];
|
||||
onDismissAction.onDismiss();
|
||||
@@ -410,6 +432,53 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
assertTrue(mStatusBar.shouldPeek(entry, sbn));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForegroundServiceNotificationKeptForFiveSeconds() throws Exception {
|
||||
RankingMap rm = mock(RankingMap.class);
|
||||
|
||||
// sbn posted "just now"
|
||||
Notification n = new Notification.Builder(mContext, "")
|
||||
.setSmallIcon(R.drawable.ic_person)
|
||||
.setContentTitle("Title")
|
||||
.setContentText("Text")
|
||||
.build();
|
||||
n.flags |= Notification.FLAG_FOREGROUND_SERVICE;
|
||||
StatusBarNotification sbn =
|
||||
new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
|
||||
0, n, new UserHandle(ActivityManager.getCurrentUser()), null,
|
||||
System.currentTimeMillis());
|
||||
NotificationData.Entry entry = new NotificationData.Entry(sbn);
|
||||
when(mNotificationData.get(any())).thenReturn(entry);
|
||||
mStatusBar.removeNotification(sbn.getKey(), rm);
|
||||
Map<NotificationData.Entry, NotificationLifetimeExtender> map =
|
||||
mStatusBar.getRetainedNotificationMap();
|
||||
Assert.assertTrue(map.containsKey(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForegroundServiceNotification_notRetainedIfShownForFiveSeconds()
|
||||
throws Exception {
|
||||
|
||||
RankingMap rm = mock(RankingMap.class);
|
||||
|
||||
// sbn posted "more than 5 seconds ago"
|
||||
Notification n = new Notification.Builder(mContext, "")
|
||||
.setSmallIcon(R.drawable.ic_person)
|
||||
.setContentTitle("Title")
|
||||
.setContentText("Text")
|
||||
.build();
|
||||
n.flags |= Notification.FLAG_FOREGROUND_SERVICE;
|
||||
StatusBarNotification sbn =
|
||||
new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID,
|
||||
0, n, new UserHandle(ActivityManager.getCurrentUser()), null,
|
||||
System.currentTimeMillis() - MIN_FGS_TIME_MS - 1);
|
||||
NotificationData.Entry entry = new NotificationData.Entry(sbn);
|
||||
when(mNotificationData.get(any())).thenReturn(entry);
|
||||
mStatusBar.removeNotification(sbn.getKey(), rm);
|
||||
Map<NotificationData.Entry, NotificationLifetimeExtender> map =
|
||||
mStatusBar.getRetainedNotificationMap();
|
||||
Assert.assertFalse(map.containsKey(entry));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLogHidden() {
|
||||
@@ -489,7 +558,8 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
UnlockMethodCache unlock, KeyguardIndicationController key,
|
||||
NotificationStackScrollLayout stack, HeadsUpManager hum, NotificationData nd,
|
||||
PowerManager pm, SystemServicesProxy ssp, NotificationPanelView panelView,
|
||||
IStatusBarService barService) {
|
||||
IStatusBarService barService, ForegroundServiceLifetimeExtender fgsExtender,
|
||||
RemoteInputController ric, ForegroundServiceController fsc) {
|
||||
mStatusBarKeyguardViewManager = man;
|
||||
mUnlockMethodCache = unlock;
|
||||
mKeyguardIndicationController = key;
|
||||
@@ -501,6 +571,9 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
mSystemServicesProxy = ssp;
|
||||
mNotificationPanel = panelView;
|
||||
mBarService = barService;
|
||||
mFGSExtender = fgsExtender;
|
||||
mRemoteInputController = ric;
|
||||
mForegroundServiceController = fsc;
|
||||
mWakefulnessLifecycle = createAwakeWakefulnessLifecycle();
|
||||
}
|
||||
|
||||
@@ -511,8 +584,9 @@ public class StatusBarTest extends SysuiTestCase {
|
||||
return wakefulnessLifecycle;
|
||||
}
|
||||
|
||||
|
||||
public void setBarStateForTest(int state) {
|
||||
mState = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4442,8 +4442,15 @@ public class NotificationManagerService extends SystemService {
|
||||
userId, mustHaveFlags, mustNotHaveFlags, reason, listenerName);
|
||||
|
||||
synchronized (mNotificationLock) {
|
||||
// Look for the notification, searching both the posted and enqueued lists.
|
||||
NotificationRecord r = findNotificationLocked(pkg, tag, id, userId);
|
||||
// If the notification is currently enqueued, repost this runnable so it has a
|
||||
// chance to notify listeners
|
||||
if ((findNotificationByListLocked(
|
||||
mEnqueuedNotifications, pkg, tag, id, userId)) != null) {
|
||||
mHandler.post(this);
|
||||
}
|
||||
// Look for the notification in the posted list, since we already checked enq
|
||||
NotificationRecord r = findNotificationByListLocked(
|
||||
mNotificationList, pkg, tag, id, userId);
|
||||
if (r != null) {
|
||||
// The notification was found, check if it should be removed.
|
||||
|
||||
|
||||
@@ -336,6 +336,21 @@ public class NotificationManagerServiceTest extends NotificationTestCase {
|
||||
assertEquals(0, mNotificationManagerService.getNotificationRecordCount());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCancelImmediatelyAfterEnqueueNotifiesListeners_ForegroundServiceFlag()
|
||||
throws Exception {
|
||||
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
|
||||
sbn.getNotification().flags =
|
||||
Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE;
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
|
||||
sbn.getId(), sbn.getNotification(), sbn.getUserId());
|
||||
mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId());
|
||||
waitForIdle();
|
||||
verify(mNotificationListeners, times(1)).notifyPostedLocked(any(), any());
|
||||
verify(mNotificationListeners, times(1)).notifyRemovedLocked(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
|
||||
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
|
||||
|
||||
Reference in New Issue
Block a user