From a0cb251ca6a8ea8df17ff8089573bc50f2f1849f Mon Sep 17 00:00:00 2001 From: phweiss Date: Wed, 14 Dec 2016 21:37:48 +0100 Subject: [PATCH] Show notification when network logging is enabled A notification is shown after network logging is enabled and after the next three reboots that are at least one day apart. Clicking it sends an intent to quick settings to shown its device monitoring dialog. Bug: 29748723 Bug: 33126577 Test: Manual, CTS-Verifier tests will be added later Change-Id: I2bf517bd27ab23ad3f66270602dbf062efab8cbb --- .../app/admin/DevicePolicyManager.java | 9 +++ core/res/AndroidManifest.xml | 1 + .../res/drawable/ic_qs_network_logging.xml | 29 +++++++++ core/res/res/values/strings.xml | 7 +++ core/res/res/values/symbols.xml | 3 + .../src/com/android/systemui/qs/QSFooter.java | 4 ++ .../src/com/android/systemui/qs/QSPanel.java | 4 ++ .../statusbar/phone/PhoneStatusBar.java | 5 ++ .../DevicePolicyManagerService.java | 60 ++++++++++++++++++- 9 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 core/res/res/drawable/ic_qs_network_logging.xml diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index b641e634a8005..21dca385a9796 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1059,6 +1059,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 bc04062563602..218083f3b87de 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 3423f0a11d67f..1cdfbf7e02200 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -386,6 +386,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 c452c6208ace0..1e6156bfde823 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1119,6 +1119,8 @@ + + @@ -1231,6 +1233,7 @@ + diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java index f3da47b1ba82d..337b854c38b39 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java @@ -115,6 +115,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 d8855c87210ee..6b24a1eeef1ee 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -519,6 +519,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 5da652db21565..888b9c64f5e6d 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.animation.AnimatorListenerAdapter; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityOptions; +import android.app.admin.DevicePolicyManager; import android.app.IActivityManager; import android.app.Notification; import android.app.NotificationManager; @@ -1013,6 +1014,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(); @@ -3644,6 +3646,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 3281bd689589f..4d0f5c7f750b8 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.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_CANNOT_ADD_MANAGED_PROFILE; import static android.app.admin.DevicePolicyManager.CODE_DEVICE_ADMIN_NOT_SUPPORTED; @@ -244,6 +245,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"; @@ -635,6 +637,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; @@ -685,6 +689,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; @@ -903,6 +912,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) { @@ -1094,6 +1107,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)); @@ -9867,7 +9884,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); @@ -9883,6 +9905,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; @@ -9948,6 +9971,41 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return mNetworkLogger.retrieveLogs(batchToken); } + 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()); + } + /** * Return the package name of owner in a given user. */