diff options
16 files changed, 353 insertions, 47 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/res/drawable/ic_qs_network_logging.xml b/packages/SystemUI/res/drawable/ic_qs_network_logging.xml index 8200fcb2ca10..2cce5325a48c 100644 --- a/packages/SystemUI/res/drawable/ic_qs_network_logging.xml +++ b/packages/SystemUI/res/drawable/ic_qs_network_logging.xml @@ -24,6 +24,6 @@ Copyright (C) 2016 The Android Open Source Project android:tint="#4DFFFFFF" > <path android:fillColor="#FFFFFFFF" - android:pathData="M7,18v-2h6v2H7z M7,14v-2h10v2H7z M8.5,9 12,5.5 15.5,9 13,9 13,13 11,13 11,9z"/> + 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/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml b/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml new file mode 100644 index 000000000000..2ba04fd31c0f --- /dev/null +++ b/packages/SystemUI/res/layout/quick_settings_footer_dialog.xml @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/scrollView" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:clipToPadding="false"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="?android:attr/dialogPreferredPadding" + android:paddingRight="?android:attr/dialogPreferredPadding" + android:paddingLeft="?android:attr/dialogPreferredPadding" + android:paddingBottom="?android:attr/dialogPreferredPadding" + android:orientation="vertical"> + <TextView + android:id="@+id/device_owner_warning" + android:layout_width="match_parent" + android:layout_height="wrap_content" + style="@android:style/TextAppearance.Material.Subhead" + android:textColor="?android:attr/textColorPrimaryInverse" + /> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <ImageView + android:id="@+id/vpn_icon" + android:layout_width="@dimen/qs_footer_dialog_icon_size" + android:layout_height="wrap_content" + android:paddingTop="?android:attr/dialogPreferredPadding" + android:layout_marginStart="@dimen/qs_footer_dialog_icon_margin" + android:layout_marginEnd="@dimen/qs_footer_dialog_icon_margin" + android:scaleType="fitCenter" + android:src="@drawable/ic_qs_vpn" + android:tint="?android:attr/textColorPrimaryInverse" + android:adjustViewBounds="true"/> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + <TextView + android:id="@+id/vpn_subtitle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="?android:attr/dialogPreferredPadding" + android:text="@string/monitoring_subtitle_vpn" + style="@android:style/TextAppearance.Material.Title" + android:textColor="?android:attr/textColorPrimaryInverse" + /> + <TextView + android:id="@+id/vpn_warning" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@null" + style="@android:style/TextAppearance.Material.Subhead" + android:textColor="?android:attr/textColorPrimaryInverse" + /> + </LinearLayout> + </LinearLayout> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + <ImageView + android:id="@+id/network_logging_icon" + android:layout_width="@dimen/qs_footer_dialog_icon_size" + android:layout_height="wrap_content" + android:paddingTop="?android:attr/dialogPreferredPadding" + android:layout_marginStart="@dimen/qs_footer_dialog_icon_margin" + android:layout_marginEnd="@dimen/qs_footer_dialog_icon_margin" + android:scaleType="fitCenter" + android:src="@drawable/ic_qs_network_logging" + android:tint="?android:attr/textColorPrimaryInverse" + android:alpha="@dimen/qs_footer_dialog_network_logging_icon_alpha" + android:adjustViewBounds="true"/> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + <TextView + android:id="@+id/network_logging_subtitle" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="?android:attr/dialogPreferredPadding" + android:text="@string/monitoring_subtitle_network_logging" + style="@android:style/TextAppearance.Material.Title" + android:textColor="?android:attr/textColorPrimaryInverse" + /> + <TextView + android:id="@+id/network_logging_warning" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/monitoring_description_network_logging" + style="@android:style/TextAppearance.Material.Subhead" + android:textColor="?android:attr/textColorPrimaryInverse" + /> + </LinearLayout> + </LinearLayout> + </LinearLayout> +</ScrollView> diff --git a/packages/SystemUI/res/values-sw900dp/config.xml b/packages/SystemUI/res/values-sw900dp/config.xml index 182fa3661a30..d8f9ef4e9b2f 100644 --- a/packages/SystemUI/res/values-sw900dp/config.xml +++ b/packages/SystemUI/res/values-sw900dp/config.xml @@ -19,6 +19,6 @@ <resources> <!-- Nav bar button default ordering/layout --> - <string name="config_navBarLayout" translatable="false">space[.2],back,home;space;menu_ime,recent,space[.2]</string> + <string name="config_navBarLayout" translatable="false">back,home;space;menu_ime,recent</string> </resources> diff --git a/packages/SystemUI/res/values-sw900dp/dimens.xml b/packages/SystemUI/res/values-sw900dp/dimens.xml index 72e10c26ddd4..2cff97692d9d 100644 --- a/packages/SystemUI/res/values-sw900dp/dimens.xml +++ b/packages/SystemUI/res/values-sw900dp/dimens.xml @@ -17,7 +17,6 @@ --> <resources> - <!-- All ryu nav buttons are th same size --> <dimen name="button_size">80dp</dimen> <dimen name="navigation_side_padding">@dimen/button_size</dimen> <dimen name="navigation_key_width">@dimen/button_size</dimen> @@ -27,14 +26,6 @@ <dimen name="key_button_ripple_max_width">76dp</dimen> <!-- The padding around the navigation buttons --> - <dimen name="navigation_key_padding">5dp</dimen> + <dimen name="navigation_key_padding">0dp</dimen> - <!-- The inner radius of the halo. --> - <dimen name="halo_inner_radius">12dp</dimen> - - <!-- The thickness of the halo. --> - <dimen name="halo_thickness">1dp</dimen> - - <!-- The diameter of the halo. This is 2*(halo_inner_radius + halo_thickness). --> - <dimen name="halo_diameter">26dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index dca9767fabed..e6194a9cca98 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -212,6 +212,13 @@ <!-- How far the expanded QS panel peeks from the header in collapsed state. --> <dimen name="qs_peek_height">0dp</dimen> + <!-- How large the icons in the quick settings footer dialog are --> + <dimen name="qs_footer_dialog_icon_size">24sp</dimen> + <!-- Left and right margin of the icons --> + <dimen name="qs_footer_dialog_icon_margin">8sp</dimen> + <!-- Alpha value of network logging icon --> + <item name="qs_footer_dialog_network_logging_icon_alpha" format="float" type="dimen">0.3</item> + <!-- Zen mode panel: condition item button padding --> <dimen name="zen_mode_condition_detail_button_padding">8dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 2ea475a1166b..0bb58e37a71e 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1013,6 +1013,13 @@ <!-- Monitoring dialog title for normal devices [CHAR LIMIT=35]--> <string name="monitoring_title">Network monitoring</string> + <!-- STOPSHIP(b/33655277) Monitoring strings still need to be finalized and approved --> + <!-- Monitoring dialog subtitle for the section describing VPN [CHAR LIMIT=TODO]--> + <string name="monitoring_subtitle_vpn">VPN</string> + + <!-- Monitoring dialog subtitle for the section describing network logging [CHAR LIMIT=TODO]--> + <string name="monitoring_subtitle_network_logging">Network Logging</string> + <!-- Monitoring dialog disable vpn button [CHAR LIMIT=30] --> <string name="disable_vpn">Disable VPN</string> @@ -1022,6 +1029,19 @@ <!-- Monitoring dialog device owner body text [CHAR LIMIT=400] --> <string name="monitoring_description_device_owned">Your device is managed by <xliff:g id="organization">%1$s</xliff:g>.\n\nYour administrator can monitor and manage settings, corporate access, apps, data associated with your device, and your device\'s location information. For more information, contact your administrator.</string> + <!-- Monitoring dialog: Part of text body explaining that a VPN is connected and what it can do, for devices managed by a Device Owner app [CHAR LIMIT=130] --> + <string name="monitoring_description_do_body_vpn">You\'re connected to <xliff:g id="vpn_app">%1$s</xliff:g>, which can monitor your network activity, including emails, apps, and websites.</string> + + <!-- Monitoring dialog: Space that separates the VPN body text and the "Open VPN Settings" link that follows it. [CHAR LIMIT=5] --> + <string name="monitoring_description_vpn_settings_separator">" "</string> + + <!-- Monitoring dialog: Link to open the VPN settings page [CHAR LIMIT=TODO] --> + <string name="monitoring_description_vpn_settings">Open VPN Settings</string> + + <!-- Monitoring dialog: Network logging text [CHAR LIMIT=TODO] --> + <string name="monitoring_description_network_logging">Your admin has turned on network logging, which monitors traffic on your device.\n\nFor more information contact your admin.</string> + + <!-- Monitoring dialog VPN text [CHAR LIMIT=400] --> <string name="monitoring_description_vpn">You gave an app permission to set up a VPN connection.\n\nThis app can monitor your device and network activity, including emails, apps, and websites.</string> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java index 756513b61c45..9431d8d38034 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java @@ -24,9 +24,14 @@ import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.UserHandle; +import android.provider.Settings; +import android.text.SpannableStringBuilder; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; import android.util.Log; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.ImageView; import android.widget.TextView; @@ -108,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(); @@ -159,24 +168,60 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene } private void createDialog() { - String deviceOwner = mSecurityController.getDeviceOwnerName(); - String profileOwner = mSecurityController.getProfileOwnerName(); - String primaryVpn = mSecurityController.getPrimaryVpnName(); - String profileVpn = mSecurityController.getProfileVpnName(); - boolean managed = mSecurityController.hasProfileOwner(); - boolean isBranded = deviceOwner == null && mSecurityController.isVpnBranded(); + final String deviceOwnerPackage = mSecurityController.getDeviceOwnerName(); + final String profileOwnerPackage = mSecurityController.getProfileOwnerName(); + final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled(); + final String primaryVpn = mSecurityController.getPrimaryVpnName(); + final String profileVpn = mSecurityController.getProfileVpnName(); + boolean hasProfileOwner = mSecurityController.hasProfileOwner(); + boolean isBranded = deviceOwnerPackage == null && mSecurityController.isVpnBranded(); mDialog = new SystemUIDialog(mContext); if (!isBranded) { - mDialog.setTitle(getTitle(deviceOwner)); + mDialog.setTitle(getTitle(deviceOwnerPackage)); } - mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed, - isBranded)); - mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(isBranded), this); - if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) { - mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this); + CharSequence msg = getMessage(deviceOwnerPackage, profileOwnerPackage, primaryVpn, + profileVpn, hasProfileOwner, isBranded); + if (deviceOwnerPackage == null) { + mDialog.setMessage(msg); + } else { + View dialogView = LayoutInflater.from(mContext) + .inflate(R.layout.quick_settings_footer_dialog, null, false); + mDialog.setView(dialogView); + TextView deviceOwnerWarning = + (TextView) dialogView.findViewById(R.id.device_owner_warning); + deviceOwnerWarning.setText(msg); + // Make the link "learn more" clickable. + deviceOwnerWarning.setMovementMethod(new LinkMovementMethod()); + if (primaryVpn == null) { + dialogView.findViewById(R.id.vpn_icon).setVisibility(View.GONE); + dialogView.findViewById(R.id.vpn_subtitle).setVisibility(View.GONE); + dialogView.findViewById(R.id.vpn_warning).setVisibility(View.GONE); + } else { + final SpannableStringBuilder message = new SpannableStringBuilder(); + message.append(mContext.getString(R.string.monitoring_description_do_body_vpn, + primaryVpn)); + message.append(mContext.getString( + R.string.monitoring_description_vpn_settings_separator)); + message.append(mContext.getString(R.string.monitoring_description_vpn_settings), + new VpnSpan(), 0); + + TextView vpnWarning = (TextView) dialogView.findViewById(R.id.vpn_warning); + vpnWarning.setText(message); + // Make the link "Open VPN Settings" clickable. + vpnWarning.setMovementMethod(new LinkMovementMethod()); + } + if (!isNetworkLoggingEnabled) { + dialogView.findViewById(R.id.network_logging_icon).setVisibility(View.GONE); + dialogView.findViewById(R.id.network_logging_subtitle).setVisibility(View.GONE); + dialogView.findViewById(R.id.network_logging_warning).setVisibility(View.GONE); + } } + + mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(isBranded), this); mDialog.show(); + mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); } private String getSettingsButton() { @@ -187,22 +232,15 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene return mContext.getString(isBranded ? android.R.string.ok : R.string.quick_settings_done); } - private String getMessage(String deviceOwner, String profileOwner, String primaryVpn, - String profileVpn, boolean primaryUserIsManaged, boolean isBranded) { - // Show a special warning when the device has device owner, but -- - // TODO See b/25779452 -- device owner doesn't actually have monitoring power. - if (deviceOwner != null) { - if (primaryVpn != null) { - return mContext.getString(R.string.monitoring_description_vpn_app_device_owned, - deviceOwner, primaryVpn); - } else { - return mContext.getString(R.string.monitoring_description_device_owned, - deviceOwner); - } + protected CharSequence getMessage(String deviceOwnerPackage, String profileOwnerPackage, + String primaryVpn, String profileVpn, boolean hasProfileOwner, boolean isBranded) { + if (deviceOwnerPackage != null) { + return mContext.getString(R.string.monitoring_description_device_owned, + deviceOwnerPackage); } else if (primaryVpn != null) { if (profileVpn != null) { return mContext.getString(R.string.monitoring_description_app_personal_work, - profileOwner, profileVpn, primaryVpn); + profileOwnerPackage, profileVpn, primaryVpn); } else { if (isBranded) { return mContext.getString(R.string.branded_monitoring_description_app_personal, @@ -214,10 +252,10 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene } } else if (profileVpn != null) { return mContext.getString(R.string.monitoring_description_app_work, - profileOwner, profileVpn); - } else if (profileOwner != null && primaryUserIsManaged) { + profileOwnerPackage, profileVpn); + } else if (profileOwnerPackage != null && hasProfileOwner) { return mContext.getString(R.string.monitoring_description_device_owned, - profileOwner); + profileOwnerPackage); } else { // No device owner, no personal VPN, no work VPN, no user owner. Why are we here? return null; @@ -286,4 +324,13 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene } } + protected class VpnSpan extends ClickableSpan { + @Override + public void onClick(View widget) { + final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + mDialog.dismiss(); + mContext.startActivity(intent); + } + } } 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/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index d2db59d9acd0..b9d06a0a60a5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -5398,15 +5398,23 @@ public class PackageManagerService extends IPackageManager.Stub { result.remove(xpResolveInfo); } if (result.size() == 0 && !addEphemeral) { + // No result in current profile, but found candidate in parent user. + // And we are not going to add emphemeral app, so we can return the + // result straight away. result.add(xpDomainInfo.resolveInfo); return result; } - } - if (result.size() > 1 || addEphemeral) { - result = filterCandidatesWithDomainPreferredActivitiesLPr( - intent, flags, result, xpDomainInfo, userId); - sortResult = true; - } + } else if (result.size() <= 1 && !addEphemeral) { + // No result in parent user and <= 1 result in current profile, and we + // are not going to add emphemeral app, so we can return the result without + // further processing. + return result; + } + // We have more than one candidate (combining results from current and parent + // profile), so we need filtering and sorting. + result = filterCandidatesWithDomainPreferredActivitiesLPr( + intent, flags, result, xpDomainInfo, userId); + sortResult = true; } } else { final PackageParser.Package pkg = mPackages.get(pkgName); 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()); + } } |