Merge "DO NOT MERGE - Port 2D recents implementation from master to nyc-mr2" into nyc-mr2-dev
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 2bcf9f2..1912437 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -950,6 +950,15 @@
= "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 36311dc..632bcfe 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 0000000..9e082641
--- /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 5e24442..382f902 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 d4ba583..d95f6e9 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 8200fcb..2cce532 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 @@
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 0000000..2ba04fd
--- /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 182fa36..d8f9ef4 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 72e10c2..2cff976 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 dca9767..e6194a9 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 2ea475a..0bb58e3 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 756513b6..9431d8d 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.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 @@
}
private void handleClick() {
+ showDeviceMonitoringDialog();
+ }
+
+ public void showDeviceMonitoringDialog() {
mHost.collapsePanels();
// TODO: Delay dialog creation until after panels are collapsed.
createDialog();
@@ -159,24 +168,60 @@
}
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));
+ 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);
- if (mSecurityController.isVpnEnabled() && !mSecurityController.isVpnRestricted()) {
- mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this);
- }
mDialog.show();
+ mDialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
}
private String getSettingsButton() {
@@ -187,22 +232,15 @@
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 @@
}
} 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 @@
}
}
+ 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 fef8930..bdb488f 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 @@
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 556aac1..4f5048f 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.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 @@
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 @@
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 d2db59d..b9d06a0 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 @@
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;
}
+ } 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;
}
- if (result.size() > 1 || addEphemeral) {
- result = filterCandidatesWithDomainPreferredActivitiesLPr(
- intent, flags, result, xpDomainInfo, userId);
- sortResult = true;
- }
+ // 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 8189a7e..46cc3a9 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 @@
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 @@
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 @@
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 @@
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 @@
} 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 @@
// 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 @@
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 @@
? 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());
+ }
}