Move notification code out of ConnectivityService.

Bug: 31025214
Change-Id: I4190be6b57f92298b79bea8868f1876ecbfd2d75
This commit is contained in:
Lorenzo Colitti
2016-08-22 16:30:00 +09:00
parent 208c01039f
commit 74c205f5ea
2 changed files with 173 additions and 119 deletions

View File

@@ -38,8 +38,6 @@ import static android.net.NetworkPolicyManager.uidRulesToString;
import android.annotation.Nullable;
import android.app.BroadcastOptions;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -135,6 +133,8 @@ import com.android.server.connectivity.Nat464Xlat;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkDiagnostics;
import com.android.server.connectivity.NetworkMonitor;
import com.android.server.connectivity.NetworkNotificationManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.PacManager;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.Tethering;
@@ -436,6 +436,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
TelephonyManager mTelephonyManager;
private KeepaliveTracker mKeepaliveTracker;
private NetworkNotificationManager mNotifier;
// sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
private final static int MIN_NET_ID = 100; // some reserved marks
@@ -832,6 +833,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mKeepaliveTracker = new KeepaliveTracker(mHandler);
mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
}
private NetworkRequest createInternetRequestForTransport(int transportType) {
@@ -2230,14 +2232,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
updateCapabilities(nai, nai.networkCapabilities);
}
if (!visible) {
setProvNotificationVisibleIntent(false, netId, null, 0, null, null, false);
mNotifier.setProvNotificationVisibleIntent(false, netId, null, 0, null,
null, false);
} else {
if (nai == null) {
loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
break;
}
if (!nai.networkMisc.provisioningNotificationDisabled) {
setProvNotificationVisibleIntent(true, netId, NotificationType.SIGN_IN,
mNotifier.setProvNotificationVisibleIntent(true, netId,
NotificationType.SIGN_IN,
nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(),
(PendingIntent)msg.obj, nai.networkMisc.explicitlySelected);
}
@@ -2710,8 +2714,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
setProvNotificationVisibleIntent(true, nai.network.netId, NotificationType.NO_INTERNET,
nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(), pendingIntent, true);
mNotifier.setProvNotificationVisibleIntent(true, nai.network.netId,
NotificationType.NO_INTERNET, nai.networkInfo.getType(),
nai.networkInfo.getExtraInfo(), pendingIntent, true);
}
private class InternalHandler extends Handler {
@@ -3617,118 +3622,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return -1;
}
private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
private static enum NotificationType { SIGN_IN, NO_INTERNET; };
private 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);
setProvNotificationVisibleIntent(visible, id, NotificationType.SIGN_IN,
networkType, null, pendingIntent, false);
}
/**
* Show or hide network provisioning notifications.
*
* We use notifications for two purposes: to notify that a network requires sign in
* (NotificationType.SIGN_IN), or to notify that a network does not have Internet access
* (NotificationType.NO_INTERNET). We display at most one notification per ID, so on a
* particular network we can display the notification type that was most recently requested.
* So for example if a captive portal fails to reply within a few seconds of connecting, we
* might first display NO_INTERNET, and then when the captive portal check completes, display
* SIGN_IN.
*
* @param id an identifier that uniquely identifies this notification. This must match
* 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.
*/
private void setProvNotificationVisibleIntent(boolean visible, int id,
NotificationType notifyType, int networkType, String extraInfo, PendingIntent intent,
boolean highPriority) {
if (VDBG || (DBG && visible)) {
log("setProvNotificationVisibleIntent " + notifyType + " visible=" + visible
+ " networkType=" + getNetworkTypeName(networkType)
+ " 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) {
loge("setNotificationVisible: visible notificationManager npe=" + npe);
npe.printStackTrace();
}
} else {
try {
notificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
} catch (NullPointerException npe) {
loge("setNotificationVisible: cancel notificationManager npe=" + npe);
npe.printStackTrace();
}
}
}
/** Location to an updatable file listing carrier provisioning urls.
* An example:
*
@@ -3832,7 +3725,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
enforceConnectivityInternalPermission();
final long ident = Binder.clearCallingIdentity();
try {
setProvNotificationVisible(visible, networkType, action);
mNotifier.setProvNotificationVisible(visible, networkType, action);
} finally {
Binder.restoreCallingIdentity(ident);
}

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2016 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.server.connectivity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.util.Slog;
import com.android.internal.R;
import static android.net.ConnectivityManager.getNetworkTypeName;
public class NetworkNotificationManager {
public static enum NotificationType { SIGN_IN, NO_INTERNET; };
private static final String NOTIFICATION_ID = "CaptivePortal.Notification";
private static final String TAG = NetworkNotificationManager.class.getSimpleName();
private static final boolean DBG = true;
private static final boolean VDBG = false;
private final Context mContext;
private final TelephonyManager mTelephonyManager;
public NetworkNotificationManager(Context context, TelephonyManager telephonyManager) {
mContext = context;
mTelephonyManager = telephonyManager;
}
/**
* Show or hide network provisioning notifications.
*
* We use notifications for two purposes: to notify that a network requires sign in
* (NotificationType.SIGN_IN), or to notify that a network does not have Internet access
* (NotificationType.NO_INTERNET). We display at most one notification per ID, so on a
* particular network we can display the notification type that was most recently requested.
* So for example if a captive portal fails to reply within a few seconds of connecting, we
* might first display NO_INTERNET, and then when the captive portal check completes, display
* SIGN_IN.
*
* @param id an identifier that uniquely identifies this notification. This must match
* 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)
+ " 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);
}
} else {
try {
notificationManager.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);
}
}