Merge "Add overlay options for no internet notifications"

This commit is contained in:
Remi NGUYEN VAN
2021-08-04 07:50:36 +00:00
committed by Gerrit Code Review
6 changed files with 158 additions and 1 deletions

View File

@@ -114,4 +114,15 @@
<!-- Whether to cancel network notifications automatically when tapped -->
<bool name="config_autoCancelNetworkNotifications">true</bool>
<!-- When no internet or partial connectivity is detected on a network, and a high priority
(heads up) notification would be shown due to the network being explicitly selected,
directly show the dialog that would normally be shown when tapping the notification
instead of showing the notification. -->
<bool name="config_notifyNoInternetAsDialogWhenHighPriority">false</bool>
<!-- When showing notifications indicating partial connectivity, display the same notifications
as no connectivity instead. This may be easier to understand for users but offers less
details on what is happening. -->
<bool name="config_partialConnectivityNotifiedAsNoInternet">false</bool>
</resources>

View File

@@ -32,6 +32,8 @@
<item type="array" name="config_networkNotifySwitches"/>
<item type="bool" name="config_ongoingSignInNotification"/>
<item type="bool" name="config_autoCancelNetworkNotifications"/>
<item type="bool" name="config_notifyNoInternetAsDialogWhenHighPriority"/>
<item type="bool" name="config_partialConnectivityNotifiedAsNoInternet"/>
<item type="drawable" name="stat_notify_wifi_in_range"/>
<item type="drawable" name="stat_notify_rssi_in_range"/>
</policy>

View File

@@ -198,11 +198,22 @@ public class NetworkNotificationManager {
}
final Resources r = mResources.get();
if (highPriority && maybeNotifyViaDialog(r, notifyType, intent)) {
Log.d(TAG, "Notified via dialog for event " + nameOf(eventId));
return;
}
final CharSequence title;
final CharSequence details;
Icon icon = Icon.createWithResource(
mResources.getResourcesContext(), getIcon(transportType));
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
final boolean showAsNoInternet = notifyType == NotificationType.PARTIAL_CONNECTIVITY
&& r.getBoolean(R.bool.config_partialConnectivityNotifiedAsNoInternet);
if (showAsNoInternet) {
Log.d(TAG, "Showing partial connectivity as NO_INTERNET");
}
if ((notifyType == NotificationType.NO_INTERNET || showAsNoInternet)
&& transportType == TRANSPORT_WIFI) {
title = r.getString(R.string.wifi_no_internet, name);
details = r.getString(R.string.wifi_no_internet_detailed);
} else if (notifyType == NotificationType.PRIVATE_DNS_BROKEN) {
@@ -306,6 +317,24 @@ public class NetworkNotificationManager {
}
}
private boolean maybeNotifyViaDialog(Resources res, NotificationType notifyType,
PendingIntent intent) {
if (notifyType != NotificationType.NO_INTERNET
&& notifyType != NotificationType.PARTIAL_CONNECTIVITY) {
return false;
}
if (!res.getBoolean(R.bool.config_notifyNoInternetAsDialogWhenHighPriority)) {
return false;
}
try {
intent.send();
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Error sending dialog PendingIntent", e);
}
return true;
}
/**
* Clear the notification with the given id, only if it matches the given type.
*/

View File

@@ -58,6 +58,7 @@ android_library {
jarjar_rules: "jarjar-rules.txt",
static_libs: [
"androidx.test.rules",
"androidx.test.uiautomator",
"bouncycastle-repackaged-unbundled",
"core-tests-support",
"FrameworksNetCommonTests",

View File

@@ -53,6 +53,8 @@
<application>
<uses-library android:name="android.test.runner" />
<uses-library android:name="android.net.ipsec.ike" />
<activity
android:name="com.android.server.connectivity.NetworkNotificationManagerTest$TestDialogActivity"/>
</application>
<instrumentation

View File

@@ -27,6 +27,7 @@ import static com.android.server.connectivity.NetworkNotificationManager.Notific
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.SIGN_IN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.clearInvocations;
@@ -39,9 +40,14 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.Instrumentation;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
@@ -49,11 +55,19 @@ import android.net.ConnectivityResources;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.util.DisplayMetrics;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject;
import androidx.test.uiautomator.UiSelector;
import com.android.connectivity.resources.R;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
@@ -84,6 +98,7 @@ public class NetworkNotificationManagerTest {
private static final String TEST_EXTRA_INFO = "extra";
private static final int TEST_NOTIF_ID = 101;
private static final String TEST_NOTIF_TAG = NetworkNotificationManager.tagFor(TEST_NOTIF_ID);
private static final long TEST_TIMEOUT_MS = 10_000L;
static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
@@ -102,6 +117,25 @@ public class NetworkNotificationManagerTest {
VPN_CAPABILITIES.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
}
/**
* Test activity that shows the action it was started with on screen, and dismisses when the
* text is tapped.
*/
public static class TestDialogActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTurnScreenOn(true);
getSystemService(KeyguardManager.class).requestDismissKeyguard(
this, null /* callback */);
final TextView txt = new TextView(this);
txt.setText(getIntent().getAction());
txt.setOnClickListener(e -> finish());
setContentView(txt);
}
}
@Mock Context mCtx;
@Mock Resources mResources;
@Mock DisplayMetrics mDisplayMetrics;
@@ -345,4 +379,82 @@ public class NetworkNotificationManagerTest {
mManager.clearNotification(id, PARTIAL_CONNECTIVITY);
verify(mNotificationManager, never()).cancel(eq(tag), eq(PARTIAL_CONNECTIVITY.eventId));
}
@Test
public void testNotifyNoInternetAsDialogWhenHighPriority() throws Exception {
doReturn(true).when(mResources).getBoolean(
R.bool.config_notifyNoInternetAsDialogWhenHighPriority);
mManager.showNotification(TEST_NOTIF_ID, NETWORK_SWITCH, mWifiNai, mCellNai, null, false);
// Non-"no internet" notifications are not affected
verify(mNotificationManager).notify(eq(TEST_NOTIF_TAG), eq(NETWORK_SWITCH.eventId), any());
final Instrumentation instr = InstrumentationRegistry.getInstrumentation();
final Context ctx = instr.getContext();
final String testAction = "com.android.connectivity.coverage.TEST_DIALOG";
final Intent intent = new Intent(testAction)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.setClassName(ctx.getPackageName(), TestDialogActivity.class.getName());
final PendingIntent pendingIntent = PendingIntent.getActivity(ctx, 0 /* requestCode */,
intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
mManager.showNotification(TEST_NOTIF_ID, NO_INTERNET, mWifiNai, null /* switchToNai */,
pendingIntent, true /* highPriority */);
// Previous notifications are still dismissed
verify(mNotificationManager).cancel(TEST_NOTIF_TAG, NETWORK_SWITCH.eventId);
// Verify that the activity is shown (the activity shows the action on screen)
final UiObject actionText = UiDevice.getInstance(instr).findObject(
new UiSelector().text(testAction));
assertTrue("Activity not shown", actionText.waitForExists(TEST_TIMEOUT_MS));
// Tapping the text should dismiss the dialog
actionText.click();
assertTrue("Activity not dismissed", actionText.waitUntilGone(TEST_TIMEOUT_MS));
// Verify no NO_INTERNET notification was posted
verify(mNotificationManager, never()).notify(any(), eq(NO_INTERNET.eventId), any());
}
private void doNotificationTextTest(NotificationType type, @StringRes int expectedTitleRes,
String expectedTitleArg, @StringRes int expectedContentRes) {
final String expectedTitle = "title " + expectedTitleArg;
final String expectedContent = "expected content";
doReturn(expectedTitle).when(mResources).getString(expectedTitleRes, expectedTitleArg);
doReturn(expectedContent).when(mResources).getString(expectedContentRes);
mManager.showNotification(TEST_NOTIF_ID, type, mWifiNai, mCellNai, null, false);
final ArgumentCaptor<Notification> notifCap = ArgumentCaptor.forClass(Notification.class);
verify(mNotificationManager).notify(eq(TEST_NOTIF_TAG), eq(type.eventId),
notifCap.capture());
final Notification notif = notifCap.getValue();
assertEquals(expectedTitle, notif.extras.getString(Notification.EXTRA_TITLE));
assertEquals(expectedContent, notif.extras.getString(Notification.EXTRA_TEXT));
}
@Test
public void testNotificationText_NoInternet() {
doNotificationTextTest(NO_INTERNET,
R.string.wifi_no_internet, TEST_EXTRA_INFO,
R.string.wifi_no_internet_detailed);
}
@Test
public void testNotificationText_Partial() {
doNotificationTextTest(PARTIAL_CONNECTIVITY,
R.string.network_partial_connectivity, TEST_EXTRA_INFO,
R.string.network_partial_connectivity_detailed);
}
@Test
public void testNotificationText_PartialAsNoInternet() {
doReturn(true).when(mResources).getBoolean(
R.bool.config_partialConnectivityNotifiedAsNoInternet);
doNotificationTextTest(PARTIAL_CONNECTIVITY,
R.string.wifi_no_internet, TEST_EXTRA_INFO,
R.string.wifi_no_internet_detailed);
}
}