Refactor NetworkNotificationManager.
1. Move from deprecated network types to transport types.
2. Rename and simplify (by passing in a NetworkAgentInfo object)
the call signature of the method that displays notifications.
3. Add a method to clear notification, and unindent lots of code.
4. Move the legacy DcTracker-issued notification code to
NetworkNotificationManager.
Bug: 31025214
Change-Id: Ie49c60126d0ed5bac620bc47e84fe038791b2d6c
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6c26165..fbd57df 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2929,6 +2929,18 @@
<!-- A notification is shown when the user connects to a Wi-Fi network and the system detects that that network has no Internet access. This is the notification's message. -->
<string name="wifi_no_internet_detailed">Tap for options</string>
+ <!-- Network type names used in the network_switch_metered and network_switch_metered_detail strings. These must be kept in the sync with the values NetworkCapabilities.TRANSPORT_xxx values, and in the same order. -->
+ <string-array name="network_switch_type_name">
+ <item>cellular data</item>
+ <item>Wi-Fi</item>
+ <item>Bluetooth</item>
+ <item>Ethernet</item>
+ <item>VPN</item>
+ </string-array>
+
+ <!-- Network type name displayed if one of the types is not found in network_switch_type_name. -->
+ <string name="network_switch_type_name_unknown">an unknown network type</string>
+
<!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems. This is the notification's title / ticker. -->
<string name="wifi_watchdog_network_disabled">Couldn\'t connect to Wi-Fi</string>
<!-- A notification is shown when a user's selected SSID is later disabled due to connectivity problems. The complete alert msg is: <hotspot name> + this string, i.e. "Linksys has a poor internet connection" -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c9ed497..70f1d43 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -947,6 +947,8 @@
<java-symbol type="string" name="wifi_available_sign_in" />
<java-symbol type="string" name="network_available_sign_in" />
<java-symbol type="string" name="network_available_sign_in_detailed" />
+ <java-symbol type="array" name="network_switch_type_name" />
+ <java-symbol type="string" name="network_switch_type_name_unknown" />
<java-symbol type="string" name="wifi_no_internet" />
<java-symbol type="string" name="wifi_no_internet_detailed" />
<java-symbol type="string" name="wifi_connect_alert_title" />
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1e0ebc2..0793832 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -38,6 +38,7 @@
import android.annotation.Nullable;
import android.app.BroadcastOptions;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -833,7 +834,8 @@
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mKeepaliveTracker = new KeepaliveTracker(mHandler);
- mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
+ mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager,
+ mContext.getSystemService(NotificationManager.class));
}
private NetworkRequest createInternetRequestForTransport(int transportType) {
@@ -2232,18 +2234,15 @@
updateCapabilities(nai, nai.networkCapabilities);
}
if (!visible) {
- mNotifier.setProvNotificationVisibleIntent(false, netId, null, 0, null,
- null, false);
+ mNotifier.clearNotification(netId);
} else {
if (nai == null) {
loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
break;
}
if (!nai.networkMisc.provisioningNotificationDisabled) {
- mNotifier.setProvNotificationVisibleIntent(true, netId,
- NotificationType.SIGN_IN,
- nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(),
- (PendingIntent)msg.obj, nai.networkMisc.explicitlySelected);
+ mNotifier.showNotification(netId, NotificationType.SIGN_IN, nai,
+ (PendingIntent) msg.obj, nai.networkMisc.explicitlySelected);
}
}
break;
@@ -2714,9 +2713,8 @@
PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
- mNotifier.setProvNotificationVisibleIntent(true, nai.network.netId,
- NotificationType.NO_INTERNET, nai.networkInfo.getType(),
- nai.networkInfo.getExtraInfo(), pendingIntent, true);
+ mNotifier.showNotification(nai.network.netId, NotificationType.NO_INTERNET, nai,
+ pendingIntent, true);
}
private class InternalHandler extends Handler {
@@ -3725,7 +3723,9 @@
enforceConnectivityInternalPermission();
final long ident = Binder.clearCallingIdentity();
try {
- mNotifier.setProvNotificationVisible(visible, networkType, action);
+ // Concatenate the range of types onto the range of NetIDs.
+ int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
+ mNotifier.setProvNotificationVisible(visible, id, action);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 2c147a4..4680a8a 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -20,15 +20,16 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
-import android.net.ConnectivityManager;
+import android.net.NetworkCapabilities;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.util.Slog;
import com.android.internal.R;
-import static android.net.ConnectivityManager.getNetworkTypeName;
+import static android.net.NetworkCapabilities.*;
public class NetworkNotificationManager {
@@ -43,10 +44,36 @@
private final Context mContext;
private final TelephonyManager mTelephonyManager;
+ private final NotificationManager mNotificationManager;
- public NetworkNotificationManager(Context context, TelephonyManager telephonyManager) {
- mContext = context;
- mTelephonyManager = telephonyManager;
+ public NetworkNotificationManager(Context c, TelephonyManager t, NotificationManager n) {
+ mContext = c;
+ mTelephonyManager = t;
+ mNotificationManager = n;
+ }
+
+ // TODO: deal more gracefully with multi-transport networks.
+ private static int getFirstTransportType(NetworkAgentInfo nai) {
+ for (int i = 0; i < 64; i++) {
+ if (nai.networkCapabilities.hasTransport(i)) return i;
+ }
+ return -1;
+ }
+
+ private static String getTransportName(int transportType) {
+ Resources r = Resources.getSystem();
+ String[] networkTypes = r.getStringArray(R.array.network_switch_type_name);
+ try {
+ return networkTypes[transportType];
+ } catch (IndexOutOfBoundsException e) {
+ return r.getString(R.string.network_switch_type_name_unknown);
+ }
+ }
+
+ private static int getIcon(int transportType) {
+ return (transportType == TRANSPORT_WIFI) ?
+ R.drawable.stat_notify_wifi_in_range : // TODO: Distinguish ! from ?.
+ R.drawable.stat_notify_rssi_in_range;
}
/**
@@ -64,98 +91,103 @@
* between show and hide calls. We use the NetID value but for legacy callers
* we concatenate the range of types with the range of NetIDs.
*/
- public void setProvNotificationVisibleIntent(boolean visible, int id,
- NotificationType notifyType, int networkType, String extraInfo, PendingIntent intent,
- boolean highPriority) {
- if (VDBG || (DBG && visible)) {
- Slog.d(TAG, "setProvNotificationVisibleIntent " + notifyType + " visible=" + visible
- + " networkType=" + getNetworkTypeName(networkType)
+ public void showNotification(int id, NotificationType notifyType,
+ NetworkAgentInfo nai, PendingIntent intent, boolean highPriority) {
+ int transportType;
+ String extraInfo;
+ if (nai != null) {
+ transportType = getFirstTransportType(nai);
+ extraInfo = nai.networkInfo.getExtraInfo();
+ // Only notify for Internet-capable networks.
+ if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
+ } else {
+ // Legacy notifications.
+ transportType = TRANSPORT_CELLULAR;
+ extraInfo = null;
+ }
+
+ if (DBG) {
+ Slog.d(TAG, "showNotification " + notifyType
+ + " transportType=" + getTransportName(transportType)
+ " extraInfo=" + extraInfo + " highPriority=" + highPriority);
}
Resources r = Resources.getSystem();
- NotificationManager notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
-
- if (visible) {
- CharSequence title;
- CharSequence details;
- int icon;
- if (notifyType == NotificationType.NO_INTERNET &&
- networkType == ConnectivityManager.TYPE_WIFI) {
- title = r.getString(R.string.wifi_no_internet, 0);
- details = r.getString(R.string.wifi_no_internet_detailed);
- icon = R.drawable.stat_notify_wifi_in_range; // TODO: Need new icon.
- } else if (notifyType == NotificationType.SIGN_IN) {
- switch (networkType) {
- case ConnectivityManager.TYPE_WIFI:
- title = r.getString(R.string.wifi_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed,
- extraInfo);
- icon = R.drawable.stat_notify_wifi_in_range;
- break;
- case ConnectivityManager.TYPE_MOBILE:
- case ConnectivityManager.TYPE_MOBILE_HIPRI:
- title = r.getString(R.string.network_available_sign_in, 0);
- // TODO: Change this to pull from NetworkInfo once a printable
- // name has been added to it
- details = mTelephonyManager.getNetworkOperatorName();
- icon = R.drawable.stat_notify_rssi_in_range;
- break;
- default:
- title = r.getString(R.string.network_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed,
- extraInfo);
- icon = R.drawable.stat_notify_rssi_in_range;
- break;
- }
- } else {
- Slog.wtf(TAG, "Unknown notification type " + notifyType + "on network type "
- + getNetworkTypeName(networkType));
- return;
- }
-
- Notification notification = new Notification.Builder(mContext)
- .setWhen(0)
- .setSmallIcon(icon)
- .setAutoCancel(true)
- .setTicker(title)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(details)
- .setContentIntent(intent)
- .setLocalOnly(true)
- .setPriority(highPriority ?
- Notification.PRIORITY_HIGH :
- Notification.PRIORITY_DEFAULT)
- .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
- .setOnlyAlertOnce(true)
- .build();
-
- try {
- notificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
- } catch (NullPointerException npe) {
- Slog.d(TAG, "setNotificationVisible: visible notificationManager npe=" + npe);
+ CharSequence title;
+ CharSequence details;
+ int icon = getIcon(transportType);
+ if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
+ title = r.getString(R.string.wifi_no_internet, 0);
+ details = r.getString(R.string.wifi_no_internet_detailed);
+ } else if (notifyType == NotificationType.SIGN_IN) {
+ switch (transportType) {
+ case TRANSPORT_WIFI:
+ title = r.getString(R.string.wifi_available_sign_in, 0);
+ details = r.getString(R.string.network_available_sign_in_detailed, extraInfo);
+ break;
+ case TRANSPORT_CELLULAR:
+ title = r.getString(R.string.network_available_sign_in, 0);
+ // TODO: Change this to pull from NetworkInfo once a printable
+ // name has been added to it
+ details = mTelephonyManager.getNetworkOperatorName();
+ break;
+ default:
+ title = r.getString(R.string.network_available_sign_in, 0);
+ details = r.getString(R.string.network_available_sign_in_detailed, extraInfo);
+ break;
}
} else {
- try {
- notificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
- } catch (NullPointerException npe) {
- Slog.d(TAG, "setNotificationVisible: cancel notificationManager npe=" + npe);
- }
+ Slog.wtf(TAG, "Unknown notification type " + notifyType + "on network transport "
+ + getTransportName(transportType));
+ return;
+ }
+
+ Notification notification = new Notification.Builder(mContext)
+ .setWhen(0)
+ .setSmallIcon(icon)
+ .setAutoCancel(true)
+ .setTicker(title)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(details)
+ .setContentIntent(intent)
+ .setLocalOnly(true)
+ .setPriority(highPriority ?
+ Notification.PRIORITY_HIGH :
+ Notification.PRIORITY_DEFAULT)
+ .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
+ .setOnlyAlertOnce(true)
+ .build();
+
+ try {
+ mNotificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
+ } catch (NullPointerException npe) {
+ Slog.d(TAG, "setNotificationVisible: visible notificationManager npe=" + npe);
+ }
+ }
+
+ public void clearNotification(int id) {
+ if (DBG) {
+ Slog.d(TAG, "clearNotification id=" + id);
+ }
+ try {
+ mNotificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
+ } catch (NullPointerException npe) {
+ Slog.d(TAG, "setNotificationVisible: cancel notificationManager npe=" + npe);
}
}
/**
* Legacy provisioning notifications coming directly from DcTracker.
*/
- public void setProvNotificationVisible(boolean visible, int networkType, String action) {
- Intent intent = new Intent(action);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
- // Concatenate the range of types onto the range of NetIDs.
- int id = MAX_NET_ID + 1 + (networkType - ConnectivityManager.TYPE_NONE);
- mNotifier.setProvNotificationVisibleIntent(visible, id, NotificationType.SIGN_IN,
- networkType, null, pendingIntent, false);
+ public void setProvNotificationVisible(boolean visible, int id, String action) {
+ if (visible) {
+ Intent intent = new Intent(action);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ showNotification(id, NotificationType.SIGN_IN, null, pendingIntent, false);
+ } else {
+ clearNotification(id);
+ }
}
}