Add option to make sign-in notification ongoing

Add an overlay boolean that allows setting the SIGN_IN notification as
an ongoing notification.

This can be useful to make sure users can always easily find the
notification to sign in to a captive portal, as studies have found that
some users have a tendency to dismiss notifications before reading them.
At the same time the notification shade is generally too crowded, which
is what causes such behaviors in the first place, so this option is not
enabled by default and should generally not be enabled without proper
user studies or metrics.

Bug: 173171709
Test: atest NetworkNotificationManagerTest
Change-Id: Ic187d2a2b7e49ad152ea2aa35bb784864b97473c
This commit is contained in:
Remi NGUYEN VAN
2021-03-31 17:07:45 +09:00
parent 92a0b5130f
commit f672f1b055
4 changed files with 51 additions and 6 deletions

View File

@@ -123,4 +123,8 @@
<string-array translatable="false" name="config_networkNotifySwitches">
</string-array>
<!-- Whether to use an ongoing notification for signing in to captive portals, instead of a
notification that can be dismissed. -->
<bool name="config_ongoingSignInNotification">false</bool>
</resources>

View File

@@ -32,6 +32,7 @@
<item type="integer" name="config_networkWakeupPacketMask"/>
<item type="integer" name="config_networkNotifySwitchType"/>
<item type="array" name="config_networkNotifySwitches"/>
<item type="bool" name="config_ongoingSignInNotification"/>
</policy>
</overlayable>

View File

@@ -280,7 +280,11 @@ public class NetworkNotificationManager {
.setContentTitle(title)
.setContentIntent(intent)
.setLocalOnly(true)
.setOnlyAlertOnce(true);
.setOnlyAlertOnce(true)
// TODO: consider having action buttons to disconnect on the sign-in notification
// especially if it is ongoing
.setOngoing(notifyType == NotificationType.SIGN_IN
&& r.getBoolean(R.bool.config_ongoingSignInNotification));
if (notifyType == NotificationType.NETWORK_SWITCH) {
builder.setStyle(new Notification.BigTextStyle().bigText(details));

View File

@@ -16,8 +16,16 @@
package com.android.server.connectivity;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.*;
import static android.app.Notification.FLAG_ONGOING_EVENT;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.LOST_INTERNET;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.NETWORK_SWITCH;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.NO_INTERNET;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.PARTIAL_CONNECTIVITY;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.PRIVATE_DNS_BROKEN;
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.SIGN_IN;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.clearInvocations;
@@ -230,19 +238,47 @@ public class NetworkNotificationManagerTest {
verify(mNotificationManager, never()).notify(any(), anyInt(), any());
}
private void assertNotification(NotificationType type, boolean ongoing) {
final int id = 101;
final String tag = NetworkNotificationManager.tagFor(id);
final ArgumentCaptor<Notification> noteCaptor = ArgumentCaptor.forClass(Notification.class);
mManager.showNotification(id, type, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, times(1)).notify(eq(tag), eq(type.eventId),
noteCaptor.capture());
assertEquals("Notification ongoing flag should be " + (ongoing ? "set" : "unset"),
ongoing, (noteCaptor.getValue().flags & FLAG_ONGOING_EVENT) != 0);
}
@Test
public void testDuplicatedNotificationsNoInternetThenSignIn() {
final int id = 101;
final String tag = NetworkNotificationManager.tagFor(id);
// Show first NO_INTERNET
mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
verify(mNotificationManager, times(1)).notify(eq(tag), eq(NO_INTERNET.eventId), any());
assertNotification(NO_INTERNET, false /* ongoing */);
// Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
assertNotification(SIGN_IN, false /* ongoing */);
verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
// Network disconnects
mManager.clearNotification(id);
verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
}
@Test
public void testOngoingSignInNotification() {
doReturn(true).when(mResources).getBoolean(R.bool.config_ongoingSignInNotification);
final int id = 101;
final String tag = NetworkNotificationManager.tagFor(id);
// Show first NO_INTERNET
assertNotification(NO_INTERNET, false /* ongoing */);
// Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
assertNotification(SIGN_IN, true /* ongoing */);
verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
// Network disconnects
mManager.clearNotification(id);