Merge "DO NOT MERGE Allow a custom component to handle network policy notifications" into cw-e-dev

This commit is contained in:
Zach Johnson
2015-08-11 23:14:24 +00:00
committed by Android (Google) Code Review
6 changed files with 148 additions and 0 deletions

View File

@@ -48,6 +48,9 @@ interface INetworkPolicyManager {
/** Snooze limit on policy matching given template. */
void snoozeLimit(in NetworkTemplate template);
/** Snooze warning on policy matching given template. */
void snoozeWarning(in NetworkTemplate template);
/** Control if background data is restricted system-wide. */
void setRestrictBackground(boolean restrictBackground);
boolean getRestrictBackground();

View File

@@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.GET_SIGNATURES;
import static android.net.NetworkPolicy.CYCLE_NONE;
import static android.text.format.Time.MONTH_DAY;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -80,6 +81,54 @@ public class NetworkPolicyManager {
*/
public static final String EXTRA_NETWORK_TEMPLATE = "android.net.NETWORK_TEMPLATE";
/**
* Broadcast intent action for informing a custom component about a network policy
* notification.
* @hide
*/
@SystemApi
public static final String ACTION_SHOW_NETWORK_POLICY_NOTIFICATION =
"android.net.action.SHOW_NETWORK_POLICY_NOTIFICATION";
/**
* The sequence number associated with the notification - a higher number
* indicates previous notifications may be disregarded.
* @hide
*/
@SystemApi
public static final String EXTRA_NOTIFICATION_SEQUENCE_NUMBER =
"android.net.extra.NOTIFICATION_SEQUENCE_NUMBER";
/**
* The type of notification that should be presented to the user.
* @hide
*/
@SystemApi
public static final String EXTRA_NOTIFICATION_TYPE = "android.net.extra.NOTIFICATION_TYPE";
@SystemApi
public static final int NOTIFICATION_TYPE_NONE = 0;
@SystemApi
public static final int NOTIFICATION_TYPE_USAGE_WARNING = 1;
@SystemApi
public static final int NOTIFICATION_TYPE_USAGE_REACHED_LIMIT = 2;
@SystemApi
public static final int NOTIFICATION_TYPE_USAGE_EXCEEDED_LIMIT = 3;
/**
* The number of bytes used on the network in the notification.
* @hide
*/
@SystemApi
public static final String EXTRA_BYTES_USED = "android.net.extra.BYTES_USED";
/**
* The network policy for the network in the notification.
* @hide
*/
@SystemApi
public static final String EXTRA_NETWORK_POLICY = "android.net.extra.NETWORK_POLICY";
private final Context mContext;
private INetworkPolicyManager mService;

View File

@@ -320,6 +320,8 @@
<protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
<protected-broadcast android:name="android.app.action.SYSTEM_UPDATE_POLICY_CHANGED" />
<protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" />
<protected-broadcast android:name="android.net.action.SHOW_NETWORK_POLICY_NOTIFICATION" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->

View File

@@ -2275,4 +2275,8 @@
<!-- The OEM specified sensor string type for the gesture to launch camera app, this value
must match the value of config_cameraLaunchGestureSensorType in OEM's HAL -->
<string translatable="false" name="config_cameraLaunchGestureSensorStringType"></string>
<!-- Name of the component to handle network policy notifications. If present,
disables NetworkPolicyManagerService's presentation of data-usage notifications. -->
<string translatable="false" name="config_networkPolicyNotificationComponent"></string>
</resources>

View File

@@ -2321,4 +2321,6 @@
<!-- Gesture -->
<java-symbol type="integer" name="config_cameraLaunchGestureSensorType" />
<java-symbol type="string" name="config_cameraLaunchGestureSensorStringType" />
<java-symbol type="string" name="config_networkPolicyNotificationComponent" />
</resources>

View File

@@ -108,6 +108,7 @@ import android.net.LinkProperties;
import android.net.NetworkIdentity;
import android.net.NetworkInfo;
import android.net.NetworkPolicy;
import android.net.NetworkPolicyManager;
import android.net.NetworkQuotaInfo;
import android.net.NetworkState;
import android.net.NetworkTemplate;
@@ -200,6 +201,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final int VERSION_SWITCH_UID = 10;
private static final int VERSION_LATEST = VERSION_SWITCH_UID;
@VisibleForTesting
public static final int TYPE_NONE = 0;
@VisibleForTesting
public static final int TYPE_WARNING = 0x1;
@VisibleForTesting
@@ -260,6 +263,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private PowerManagerInternal mPowerManagerInternal;
private IDeviceIdleController mDeviceIdleController;
private final ComponentName mNotificationComponent;
private int mNotificationSequenceNumber;
final Object mRulesLock = new Object();
volatile boolean mSystemReady;
@@ -357,6 +363,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
mAppOps = context.getSystemService(AppOpsManager.class);
final String notificationComponent = context.getString(
R.string.config_networkPolicyNotificationComponent);
mNotificationComponent = notificationComponent != null
? ComponentName.unflattenFromString(notificationComponent) : null;
}
public void bindConnectivityManager(IConnectivityManager connManager) {
@@ -778,6 +789,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final ArraySet<String> beforeNotifs = new ArraySet<String>(mActiveNotifs);
mActiveNotifs.clear();
// increment the sequence number so custom components know
// this update is new
mNotificationSequenceNumber++;
boolean hasNotifications = false;
// TODO: when switching to kernel notifications, compute next future
// cycle boundary to recompute notifications.
@@ -794,6 +810,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long totalBytes = getTotalBytes(policy.template, start, end);
if (policy.isOverLimit(totalBytes)) {
hasNotifications = true;
if (policy.lastLimitSnooze >= start) {
enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes);
} else {
@@ -806,10 +823,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (policy.isOverWarning(totalBytes) && policy.lastWarningSnooze < start) {
enqueueNotification(policy, TYPE_WARNING, totalBytes);
hasNotifications = true;
}
}
}
// right now we don't care about restricted background notifications
// in the custom notification component, so trigger an update now
// if we didn't update anything this pass
if (!hasNotifications) {
sendNotificationToCustomComponent(null, TYPE_NONE, 0);
}
// ongoing notification when restricting background data
if (mRestrictBackground) {
enqueueRestrictedNotification(TAG_ALLOW_BACKGROUND);
@@ -856,6 +881,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* {@link NetworkPolicy#limitBytes}, potentially showing dialog to user.
*/
private void notifyOverLimitLocked(NetworkTemplate template) {
if (mNotificationComponent != null) {
// It is the job of the notification component to handle UI,
// so we do nothing here
return;
}
if (!mOverLimitNotified.contains(template)) {
mContext.startActivity(buildNetworkOverLimitIntent(template));
mOverLimitNotified.add(template);
@@ -874,11 +905,55 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
return TAG + ":" + policy.template.hashCode() + ":" + type;
}
private boolean sendNotificationToCustomComponent(
NetworkPolicy policy,
int type,
long totalBytes) {
if (mNotificationComponent == null) {
return false;
}
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setComponent(mNotificationComponent);
int notificationType = NetworkPolicyManager.NOTIFICATION_TYPE_NONE;
switch (type) {
case TYPE_WARNING:
notificationType = NetworkPolicyManager.NOTIFICATION_TYPE_USAGE_WARNING;
break;
case TYPE_LIMIT:
notificationType = NetworkPolicyManager.NOTIFICATION_TYPE_USAGE_REACHED_LIMIT;
break;
case TYPE_LIMIT_SNOOZED:
notificationType = NetworkPolicyManager.NOTIFICATION_TYPE_USAGE_EXCEEDED_LIMIT;
break;
}
intent.setAction(NetworkPolicyManager.ACTION_SHOW_NETWORK_POLICY_NOTIFICATION);
intent.putExtra(NetworkPolicyManager.EXTRA_NOTIFICATION_TYPE, notificationType);
intent.putExtra(
NetworkPolicyManager.EXTRA_NOTIFICATION_SEQUENCE_NUMBER,
mNotificationSequenceNumber);
if (notificationType != NetworkPolicyManager.NOTIFICATION_TYPE_NONE) {
intent.putExtra(NetworkPolicyManager.EXTRA_NETWORK_POLICY, policy);
intent.putExtra(NetworkPolicyManager.EXTRA_BYTES_USED, totalBytes);
}
mContext.sendBroadcast(intent);
return true;
}
/**
* Show notification for combined {@link NetworkPolicy} and specific type,
* like {@link #TYPE_LIMIT}. Okay to call multiple times.
*/
private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
if (sendNotificationToCustomComponent(policy, type, totalBytes)) {
return;
}
final String tag = buildNotificationTag(policy, type);
final Notification.Builder builder = new Notification.Builder(mContext);
builder.setOnlyAlertOnce(true);
@@ -1738,6 +1813,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
@Override
public void snoozeWarning(NetworkTemplate template) {
mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
final long token = Binder.clearCallingIdentity();
try {
// TODO: this seems like a race condition? (along with snoozeLimit above)
performSnooze(template, TYPE_WARNING);
} finally {
Binder.restoreCallingIdentity(token);
}
}
void performSnooze(NetworkTemplate template, int type) {
maybeRefreshTrustedTime();
final long currentTime = currentTimeMillis();