summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java64
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java127
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java2
3 files changed, 180 insertions, 13 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f3eed7d22bec..837003f87598 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -27,6 +27,7 @@ import static android.app.AppOpsManager.OP_RECEIVE_SENSITIVE_NOTIFICATIONS;
import static android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR;
import static android.app.Flags.lifetimeExtensionRefactor;
import static android.app.Flags.notificationClassificationUi;
+import static android.app.Flags.redactSensitiveContentNotificationsOnLockscreen;
import static android.app.Flags.sortSectionByTime;
import static android.app.Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION;
import static android.app.Notification.EXTRA_BUILDER_APPLICATION_INFO;
@@ -254,6 +255,10 @@ import android.content.pm.VersionedPackage;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.metrics.LogMaker;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -656,6 +661,7 @@ public class NotificationManagerService extends SystemService {
private UsageStatsManagerInternal mUsageStatsManagerInternal;
private TelecomManager mTelecomManager;
private PowerManager mPowerManager;
+ private ConnectivityManager mConnectivityManager;
private PostNotificationTrackerFactory mPostNotificationTrackerFactory;
private LockPatternUtils mLockUtils;
@@ -777,6 +783,8 @@ public class NotificationManagerService extends SystemService {
private ModuleInfo mAdservicesModuleInfo;
+ private boolean mConnectedToWifi;
+
static class Archive {
final SparseArray<Boolean> mEnabled;
final int mBufferSize;
@@ -2573,6 +2581,7 @@ public class NotificationManagerService extends SystemService {
TelecomManager telecomManager, NotificationChannelLogger channelLogger,
SystemUiSystemPropertiesFlags.FlagResolver flagResolver,
PermissionManager permissionManager, PowerManager powerManager,
+ ConnectivityManager connectivityManager,
PostNotificationTrackerFactory postNotificationTrackerFactory) {
mHandler = handler;
Resources resources = getContext().getResources();
@@ -2605,6 +2614,8 @@ public class NotificationManagerService extends SystemService {
mUm = userManager;
mTelecomManager = telecomManager;
mPowerManager = powerManager;
+ mConnectivityManager = connectivityManager;
+ registerNetworkCallback();
mPostNotificationTrackerFactory = postNotificationTrackerFactory;
mPlatformCompat = IPlatformCompat.Stub.asInterface(
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
@@ -2820,6 +2831,36 @@ public class NotificationManagerService extends SystemService {
mAppOps.startWatchingMode(AppOpsManager.OP_POST_NOTIFICATION, null, mAppOpsListener);
}
+ private void registerNetworkCallback() {
+ NetworkRequest request = new NetworkRequest.Builder().addTransportType(
+ NetworkCapabilities.TRANSPORT_WIFI).build();
+ mConnectivityManager.registerNetworkCallback(request,
+ new ConnectivityManager.NetworkCallback() {
+ // Need to post to another thread, as we can't call synchronous ConnectivityManager
+ // methods from the callback itself, due to potential race conditions.
+ @Override
+ public void onAvailable(@NonNull Network network) {
+ mHandler.post(() -> updateWifiConnectionState());
+ }
+ @Override
+ public void onLost(@NonNull Network network) {
+ mHandler.post(() -> updateWifiConnectionState());
+ }
+ });
+ updateWifiConnectionState();
+ }
+
+ @VisibleForTesting()
+ void updateWifiConnectionState() {
+ Network current = mConnectivityManager.getActiveNetwork();
+ NetworkCapabilities capabilities = mConnectivityManager.getNetworkCapabilities(current);
+ if (current == null || capabilities == null) {
+ mConnectedToWifi = false;
+ return;
+ }
+ mConnectedToWifi = capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);
+ }
+
/**
* Cleanup broadcast receivers change listeners.
*/
@@ -2930,6 +2971,7 @@ public class NotificationManagerService extends SystemService {
new NotificationChannelLoggerImpl(), SystemUiSystemPropertiesFlags.getResolver(),
getContext().getSystemService(PermissionManager.class),
getContext().getSystemService(PowerManager.class),
+ getContext().getSystemService(ConnectivityManager.class),
new PostNotificationTrackerFactory() {});
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
@@ -11645,12 +11687,20 @@ public class NotificationManagerService extends SystemService {
new NotificationListenerService.Ranking();
ArrayList<Notification.Action> smartActions = record.getSystemGeneratedSmartActions();
ArrayList<CharSequence> smartReplies = record.getSmartReplies();
- if (redactSensitiveNotificationsFromUntrustedListeners()
- && info != null
- && !mListeners.isUidTrusted(info.uid)
- && mListeners.hasSensitiveContent(record)) {
- smartActions = null;
- smartReplies = null;
+ boolean hasSensitiveContent = record.hasSensitiveContent();
+ if (redactSensitiveNotificationsFromUntrustedListeners()) {
+ if (!mListeners.isUidTrusted(info.uid) && mListeners.hasSensitiveContent(record)) {
+ smartActions = null;
+ smartReplies = null;
+ }
+ if (redactSensitiveContentNotificationsOnLockscreen()) {
+ if (mListeners.hasSensitiveContent(record) && mConnectedToWifi
+ && info.isSystemUi) {
+ // We don't inform systemUI of sensitive content if
+ // connected to wifi, though we do still redact from untrusted listeners.
+ hasSensitiveContent = false;
+ }
+ }
}
ranking.populate(
key,
@@ -11680,7 +11730,7 @@ public class NotificationManagerService extends SystemService {
: (record.getRankingScore() > 0 ? RANKING_PROMOTED : RANKING_DEMOTED),
record.getNotification().isBubbleNotification(),
record.getProposedImportance(),
- record.hasSensitiveContent()
+ hasSensitiveContent
);
rankings.add(ranking);
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index e43b28bb9404..fdb6a6802b7e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -24,6 +24,7 @@ import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_
import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS;
+import static android.app.Flags.FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN;
import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME;
import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP;
import static android.app.Notification.EXTRA_PICTURE;
@@ -251,6 +252,9 @@ import android.graphics.drawable.Icon;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.session.MediaSession;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -475,6 +479,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Mock
private PowerManager mPowerManager;
@Mock
+ private ConnectivityManager mConnectivityManager;
+ @Mock
private LightsManager mLightsManager;
private final ArrayList<WakeLock> mAcquiredWakeLocks = new ArrayList<>();
private final TestPostNotificationTrackerFactory mPostNotificationTrackerFactory =
@@ -765,6 +771,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mActivityIntentImmutable = spy(PendingIntent.getActivity(mContext, 0,
new Intent().setPackage(mPkg), FLAG_IMMUTABLE));
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(null);
+
initNMS();
}
@@ -798,7 +806,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mAppOpsManager, mUm, mHistoryManager, mStatsManager,
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager,
- mPowerManager, mPostNotificationTrackerFactory);
+ mPowerManager, mConnectivityManager, mPostNotificationTrackerFactory);
mService.setAttentionHelper(mAttentionHelper);
mService.setLockPatternUtils(mock(LockPatternUtils.class));
@@ -14314,7 +14322,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mService.addNotification(pkgB);
mService.setIsVisibleToListenerReturnValue(true);
- NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(null);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
// when only user 0 entering the lockdown mode, its notification will be suppressed.
@@ -14324,7 +14333,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertTrue(mStrongAuthTracker.isInLockDownMode(0));
assertFalse(mStrongAuthTracker.isInLockDownMode(1));
- nru = mService.makeRankingUpdateLocked(null);
+ nru = mService.makeRankingUpdateLocked(info);
assertEquals(1, nru.getRankingMap().getOrderedKeys().length);
// User 0 exits lockdown mode. Its notification will be resumed.
@@ -14333,7 +14342,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertFalse(mStrongAuthTracker.isInLockDownMode(0));
assertFalse(mStrongAuthTracker.isInLockDownMode(1));
- nru = mService.makeRankingUpdateLocked(null);
+ nru = mService.makeRankingUpdateLocked(info);
assertEquals(2, nru.getRankingMap().getOrderedKeys().length);
}
@@ -14365,13 +14374,119 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(0, ranking2.getSmartReplies().size());
}
+ private NotificationRecord getSensitiveNotificationRecord() {
+ NotificationRecord record = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ Bundle signals = new Bundle();
+ signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, true);
+ Adjustment adjustment = new Adjustment("a", record.getKey(), signals, "", 0);
+ record.addAdjustment(adjustment);
+ record.applyAdjustments();
+ return record;
+ }
+
+ @Test
+ public void testMakeRankingUpdate_clearsHasSensitiveContentIfConnectedToWifi() {
+ mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS,
+ FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class));
+ when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build()
+ );
+ mService.updateWifiConnectionState();
+ when(mListeners.hasSensitiveContent(any())).thenReturn(true);
+ NotificationRecord pkgA = new NotificationRecord(mContext,
+ generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ mService.addNotification(pkgA);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ info.isSystemUi = true;
+ when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
+ NotificationListenerService.Ranking ranking =
+ nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey());
+ assertFalse(ranking.hasSensitiveContent());
+ }
+
+ @Test
+ public void testMakeRankingUpdate_doesntClearHasSensitiveContentIfNotConnectedToWifi() {
+ mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS,
+ FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class));
+ when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build()
+ );
+ mService.updateWifiConnectionState();
+ when(mListeners.hasSensitiveContent(any())).thenReturn(true);
+ NotificationRecord record = getSensitiveNotificationRecord();
+ mService.addNotification(record);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ info.isSystemUi = true;
+ when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
+ NotificationListenerService.Ranking ranking =
+ nru.getRankingMap().getRawRankingObject(record.getSbn().getKey());
+ assertTrue(ranking.hasSensitiveContent());
+ }
+
+ @Test
+ public void testMakeRankingUpdate_doesntClearHasSensitiveContentIfNotSysUi() {
+ mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
+ mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class));
+ when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build()
+ );
+ mService.updateWifiConnectionState();
+ when(mListeners.hasSensitiveContent(any())).thenReturn(true);
+ NotificationRecord record = getSensitiveNotificationRecord();
+ mService.addNotification(record);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
+ NotificationListenerService.Ranking ranking =
+ nru.getRankingMap().getRawRankingObject(record.getSbn().getKey());
+ assertTrue(ranking.hasSensitiveContent());
+ }
+
+ @Test
+ public void testMakeRankingUpdate_doesntClearHasSensitiveContentIfFlagDisabled() {
+ mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
+ mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_CONTENT_NOTIFICATIONS_ON_LOCKSCREEN);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(mock(Network.class));
+ when(mConnectivityManager.getNetworkCapabilities(any())).thenReturn(
+ new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build()
+ );
+ mService.updateWifiConnectionState();
+ when(mListeners.hasSensitiveContent(any())).thenReturn(true);
+ NotificationRecord record = getSensitiveNotificationRecord();
+ mService.addNotification(record);
+ ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class);
+ info.isSystemUi = true;
+ when(info.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(info.isSameUser(anyInt())).thenReturn(true);
+ NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info);
+ NotificationListenerService.Ranking ranking =
+ nru.getRankingMap().getRawRankingObject(record.getSbn().getKey());
+ assertTrue(ranking.hasSensitiveContent());
+ }
+
@Test
public void testMakeRankingUpdate_doestntRedactIfFlagDisabled() {
mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS);
when(mListeners.isUidTrusted(anyInt())).thenReturn(false);
when(mListeners.hasSensitiveContent(any())).thenReturn(true);
- NotificationRecord pkgA = new NotificationRecord(mContext,
- generateSbn("a", 1000, 9, 0), mTestNotificationChannel);
+ NotificationRecord pkgA = getSensitiveNotificationRecord();
addSmartActionsAndReplies(pkgA);
mService.addNotification(pkgA);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index c1bb3e7408fc..82d87d40031a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -47,6 +47,7 @@ import android.companion.ICompanionDeviceManager;
import android.content.Context;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
import android.os.Looper;
import android.os.PowerManager;
import android.os.UserHandle;
@@ -171,6 +172,7 @@ public class RoleObserverTest extends UiServiceTestCase {
mock(NotificationChannelLogger.class), new TestableFlagResolver(),
mock(PermissionManager.class),
mock(PowerManager.class),
+ mock(ConnectivityManager.class),
new NotificationManagerService.PostNotificationTrackerFactory() {});
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {