diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 2bcf9f22611d4..1912437e40e02 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -949,6 +949,15 @@ public class DevicePolicyManager {
public static final String ACTION_SET_NEW_PARENT_PROFILE_PASSWORD
= "android.app.action.SET_NEW_PARENT_PROFILE_PASSWORD";
+ /**
+ * Broadcast action: Tell the status bar to open the device monitoring dialog, e.g. when
+ * Network logging was enabled and the user tapped the notification.
+ *
This is a protected intent that can only be sent by the system.
+ * @hide
+ */
+ public static final String ACTION_SHOW_DEVICE_MONITORING_DIALOG
+ = "android.app.action.SHOW_DEVICE_MONITORING_DIALOG";
+
/**
* Flag used by {@link #addCrossProfileIntentFilter} to allow activities in
* the parent profile to access intents sent from the managed profile.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f4d951245840a..0270774ef88df 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -101,6 +101,7 @@
+
diff --git a/core/res/res/drawable/ic_qs_network_logging.xml b/core/res/res/drawable/ic_qs_network_logging.xml
new file mode 100644
index 0000000000000..9e08264156e6a
--- /dev/null
+++ b/core/res/res/drawable/ic_qs_network_logging.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 5e24442835a8f..382f9023a703d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -390,6 +390,13 @@
This indicates that a work profile has been deleted. [CHAR LIMIT=NONE]-->
Your work profile is no longer available on this device.
+
+ Network traffic is being monitored
+
+ Tap for more details
+
Your device will be erased
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e900c19201b54..f3e0f9d4d67e7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1108,6 +1108,8 @@
+
+
@@ -1220,6 +1222,7 @@
+
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 92654b29cfba7..9431d8d38034a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -113,6 +113,10 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
}
private void handleClick() {
+ showDeviceMonitoringDialog();
+ }
+
+ public void showDeviceMonitoringDialog() {
mHost.collapsePanels();
// TODO: Delay dialog creation until after panels are collapsed.
createDialog();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index dfc89fa457060..ca47cb903485f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -511,6 +511,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback {
return mFooter;
}
+ public void showDeviceMonitoringDialog() {
+ mFooter.showDeviceMonitoringDialog();
+ }
+
private class H extends Handler {
private static final int SHOW_DETAIL = 1;
private static final int SET_TILE_VISIBILITY = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 420cdbc888f6f..bbfd5aa150e8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -36,6 +36,7 @@ import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
+import android.app.admin.DevicePolicyManager;
import android.app.IActivityManager;
import android.app.Notification;
import android.app.PendingIntent;
@@ -994,6 +995,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
+ filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
IntentFilter demoFilter = new IntentFilter();
@@ -3572,6 +3574,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
else if (Intent.ACTION_SCREEN_ON.equals(action)) {
notifyNavigationBarScreenOn(true);
}
+ else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
+ mQSPanel.showDeviceMonitoringDialog();
+ }
}
};
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8189a7ec3b083..46cc3a900129d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -17,6 +17,7 @@
package com.android.server.devicepolicy;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
+import static android.app.admin.DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
@@ -218,6 +219,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final int MONITORING_CERT_NOTIFICATION_ID = R.plurals.ssl_ca_cert_warning;
private static final int PROFILE_WIPED_NOTIFICATION_ID = 1001;
+ private static final int NETWORK_LOGGING_NOTIFICATION_ID = 1002;
private static final String ATTR_PERMISSION_PROVIDER = "permission-provider";
private static final String ATTR_SETUP_COMPLETE = "setup-complete";
@@ -605,6 +607,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final String TAG_PARENT_ADMIN = "parent-admin";
private static final String TAG_ORGANIZATION_COLOR = "organization-color";
private static final String TAG_ORGANIZATION_NAME = "organization-name";
+ private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
+ private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
final DeviceAdminInfo info;
@@ -663,6 +667,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean forceEphemeralUsers = false; // Can only be set by a device owner.
boolean isNetworkLoggingEnabled = false; // Can only be set by a device owner.
+ // one notification after enabling + 3 more after reboots
+ static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 4;
+ int numNetworkLoggingNotifications = 0;
+ long lastNetworkLoggingNotificationTimeMs = 0; // Time in milliseconds since epoch
+
ActiveAdmin parentAdmin;
final boolean isParent;
@@ -873,6 +882,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (isNetworkLoggingEnabled) {
out.startTag(null, TAG_IS_NETWORK_LOGGING_ENABLED);
out.attribute(null, ATTR_VALUE, Boolean.toString(isNetworkLoggingEnabled));
+ out.attribute(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS,
+ Integer.toString(numNetworkLoggingNotifications));
+ out.attribute(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION,
+ Long.toString(lastNetworkLoggingNotificationTimeMs));
out.endTag(null, TAG_IS_NETWORK_LOGGING_ENABLED);
}
if (disabledKeyguardFeatures != DEF_KEYGUARD_FEATURES_DISABLED) {
@@ -1064,6 +1077,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
} else if (TAG_IS_NETWORK_LOGGING_ENABLED.equals(tag)) {
isNetworkLoggingEnabled = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_VALUE));
+ lastNetworkLoggingNotificationTimeMs = Long.parseLong(
+ parser.getAttributeValue(null, ATTR_LAST_NETWORK_LOGGING_NOTIFICATION));
+ numNetworkLoggingNotifications = Integer.parseInt(
+ parser.getAttributeValue(null, ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS));
} else if (TAG_DISABLE_KEYGUARD_FEATURES.equals(tag)) {
disabledKeyguardFeatures = Integer.parseInt(
parser.getAttributeValue(null, ATTR_VALUE));
@@ -9464,7 +9481,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// already in the requested state
return;
}
- getDeviceOwnerAdminLocked().isNetworkLoggingEnabled = enabled;
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ deviceOwner.isNetworkLoggingEnabled = enabled;
+ if (!enabled) {
+ deviceOwner.numNetworkLoggingNotifications = 0;
+ deviceOwner.lastNetworkLoggingNotificationTimeMs = 0;
+ }
saveSettingsLocked(mInjector.userHandleGetCallingUserId());
setNetworkLoggingActiveInternal(enabled);
@@ -9480,6 +9502,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slog.wtf(LOG_TAG, "Network logging could not be started due to the logging"
+ " service not being available yet.");
}
+ sendNetworkLoggingNotificationLocked();
} else {
if (mNetworkLogger != null && !mNetworkLogger.stopNetworkLogging()) {
mNetworkLogger = null;
@@ -9532,4 +9555,39 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
? mNetworkLogger.retrieveLogs(batchToken)
: null;
}
+
+ private void sendNetworkLoggingNotificationLocked() {
+ final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ if (deviceOwner == null || !deviceOwner.isNetworkLoggingEnabled) {
+ return;
+ }
+ if (deviceOwner.numNetworkLoggingNotifications >=
+ ActiveAdmin.DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN) {
+ return;
+ }
+ final long now = System.currentTimeMillis();
+ if (now - deviceOwner.lastNetworkLoggingNotificationTimeMs < MS_PER_DAY) {
+ return;
+ }
+ deviceOwner.numNetworkLoggingNotifications++;
+ if (deviceOwner.numNetworkLoggingNotifications
+ >= ActiveAdmin.DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN) {
+ deviceOwner.lastNetworkLoggingNotificationTimeMs = 0;
+ } else {
+ deviceOwner.lastNetworkLoggingNotificationTimeMs = now;
+ }
+ final Intent intent = new Intent(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
+ intent.setPackage("com.android.systemui");
+ final PendingIntent pendingIntent = PendingIntent.getBroadcastAsUser(mContext, 0, intent, 0,
+ UserHandle.CURRENT);
+ Notification notification = new Notification.Builder(mContext)
+ .setSmallIcon(R.drawable.ic_qs_network_logging)
+ .setContentTitle(mContext.getString(R.string.network_logging_notification_title))
+ .setContentText(mContext.getString(R.string.network_logging_notification_text))
+ .setShowWhen(true)
+ .setContentIntent(pendingIntent)
+ .build();
+ mInjector.getNotificationManager().notify(NETWORK_LOGGING_NOTIFICATION_ID, notification);
+ saveSettingsLocked(mOwners.getDeviceOwnerUserId());
+ }
}