diff options
9 files changed, 121 insertions, 1 deletions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 2bcf9f22611d..1912437e40e0 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -950,6 +950,15 @@ public class DevicePolicyManager { = "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. + * <p class="note">This is a protected intent that can only be sent by the system.</p> + * @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. * That is, when an app in the managed profile calls diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 36311dcf243f..632bcfe1f9fe 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -101,6 +101,7 @@ <protected-broadcast android:name="android.app.action.BUGREPORT_SHARING_DECLINED" /> <protected-broadcast android:name="android.app.action.BUGREPORT_FAILED" /> <protected-broadcast android:name="android.app.action.BUGREPORT_SHARE" /> + <protected-broadcast android:name="android.app.action.SHOW_DEVICE_MONITORING_DIALOG" /> <protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE_OPTIONS" /> <protected-broadcast android:name="android.appwidget.action.APPWIDGET_DELETED" /> 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 000000000000..9e08264156e6 --- /dev/null +++ b/core/res/res/drawable/ic_qs_network_logging.xml @@ -0,0 +1,29 @@ +<!-- +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. +--> + +<!-- STOPSHIP: Placeholder icon for network logging until the real icon is finalized--> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="#4DFFFFFF" > + <path + android:fillColor="#FFFFFFFF" + android:pathData="M2,24v-4h12v4H2z M2,16v-4h20v4H2z M5,7 12,0 19,7 14,7 14,15 10,15 10,7z"/> + +</vector> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 5e24442835a8..382f9023a703 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]--> <string name="work_profile_deleted_description_dpm_wipe">Your work profile is no longer available on this device.</string> + <!-- Content title for a notification. This indicates that network logging was activated by + a device owner. [CHAR LIMIT=NONE]--> + <string name="network_logging_notification_title">Network traffic is being monitored</string> + <!-- Content text for a notification. Tapping opens a dialog with more information on network + logging. [CHAR LIMIT=NONE]--> + <string name="network_logging_notification_text">Tap for more details</string> + <!-- Factory reset warning dialog strings--> <skip /> <!-- Shows up in the dialog's title to warn about an impeding factory reset. [CHAR LIMIT=NONE] --> <string name="factory_reset_warning">Your device will be erased</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index d4ba583932c6..d95f6e9e1a68 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1109,6 +1109,8 @@ <java-symbol type="string" name="work_profile_deleted_description" /> <java-symbol type="string" name="work_profile_deleted_details" /> <java-symbol type="string" name="work_profile_deleted_description_dpm_wipe" /> + <java-symbol type="string" name="network_logging_notification_title" /> + <java-symbol type="string" name="network_logging_notification_text" /> <java-symbol type="string" name="factory_reset_warning" /> <java-symbol type="string" name="factory_reset_message" /> <java-symbol type="string" name="lockscreen_transport_play_description" /> @@ -1221,6 +1223,7 @@ <java-symbol type="drawable" name="ic_print" /> <java-symbol type="drawable" name="ic_print_error" /> <java-symbol type="drawable" name="ic_grayedout_printer" /> + <java-symbol type="drawable" name="ic_qs_network_logging" /> <java-symbol type="drawable" name="jog_dial_arrow_long_left_green" /> <java-symbol type="drawable" name="jog_dial_arrow_long_right_red" /> <java-symbol type="drawable" name="jog_dial_arrow_short_left_and_right" /> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java index 92654b29cfba..9431d8d38034 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 fef89305e553..bdb488feffa5 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 556aac1603f8..4f5048fc3da1 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 8189a7ec3b08..46cc3a900129 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()); + } } |