summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/system-current.txt3
-rw-r--r--core/java/android/app/INotificationManager.aidl3
-rw-r--r--core/java/android/app/KeyguardManager.java42
-rw-r--r--core/res/AndroidManifest.xml5
-rw-r--r--data/etc/privapp-permissions-platform.xml1
-rw-r--r--packages/SystemUI/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java3
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java49
8 files changed, 106 insertions, 1 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index 8c070c4e3292..d7265c753e59 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -58,6 +58,7 @@ package android {
field public static final java.lang.String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
field public static final java.lang.String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
field public static final java.lang.String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
+ field public static final java.lang.String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS";
field public static final java.lang.String CONTROL_LOCATION_UPDATES = "android.permission.CONTROL_LOCATION_UPDATES";
field public static final java.lang.String CONTROL_VPN = "android.permission.CONTROL_VPN";
field public static final java.lang.String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
@@ -439,6 +440,8 @@ package android.app {
}
public class KeyguardManager {
+ method public void setPrivateNotificationsAllowed(boolean);
+ method public boolean getPrivateNotificationsAllowed();
method public android.content.Intent createConfirmFactoryResetCredentialIntent(java.lang.CharSequence, java.lang.CharSequence, java.lang.CharSequence);
method public void requestDismissKeyguard(android.app.Activity, java.lang.CharSequence, android.app.KeyguardManager.KeyguardDismissCallback);
}
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 362f4aedc900..e508d42e0168 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -174,4 +174,7 @@ interface INotificationManager
void revokeNotificationDelegate(String callingPkg);
String getNotificationDelegate(String callingPkg);
boolean canNotifyAsPackage(String callingPkg, String targetPkg);
+
+ void setPrivateNotificationsAllowed(boolean allow);
+ boolean getPrivateNotificationsAllowed();
}
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 853fccf3df7c..f8309bcd3267 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -62,6 +62,7 @@ public class KeyguardManager {
private final IWindowManager mWM;
private final IActivityManager mAm;
private final ITrustManager mTrustManager;
+ private final INotificationManager mNotificationManager;
/**
* Intent used to prompt user for device credentials.
@@ -219,6 +220,45 @@ public class KeyguardManager {
return intent;
}
+ /**
+ * Controls whether notifications can be shown atop a securely locked screen in their full
+ * private form (same as when the device is unlocked).
+ *
+ * <p>Other sources like the DevicePolicyManger and Settings app can modify this configuration.
+ * The result is that private notifications are only shown if all sources allow it.
+ *
+ * @param allow secure notifications can be shown if {@code true},
+ * secure notifications cannot be shown if {@code false}
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)
+ @SystemApi
+ public void setPrivateNotificationsAllowed(boolean allow) {
+ try {
+ mNotificationManager.setPrivateNotificationsAllowed(allow);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether notifications can be shown atop a securely locked screen in their full
+ * private form (same as when the device is unlocked).
+ *
+ * @return {@code true} if secure notifications can be shown, {@code false} otherwise.
+ * By default, private notifications are allowed.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)
+ @SystemApi
+ public boolean getPrivateNotificationsAllowed() {
+ try {
+ return mNotificationManager.getPrivateNotificationsAllowed();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private String getSettingsPackageForIntent(Intent intent) {
List<ResolveInfo> resolveInfos = mContext.getPackageManager()
.queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
@@ -335,6 +375,8 @@ public class KeyguardManager {
mAm = ActivityManager.getService();
mTrustManager = ITrustManager.Stub.asInterface(
ServiceManager.getServiceOrThrow(Context.TRUST_SERVICE));
+ mNotificationManager = INotificationManager.Stub.asInterface(
+ ServiceManager.getServiceOrThrow(Context.NOTIFICATION_SERVICE));
}
/**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index af814d962277..533ce64c8493 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3823,6 +3823,11 @@
<permission android:name="android.permission.CONTROL_KEYGUARD"
android:protectionLevel="signature" />
+ <!-- @SystemApi Allows an application to control keyguard features like secure notifications.
+ @hide -->
+ <permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows an application to listen to trust changes. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.TRUST_LISTENER"
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index c5bd03941ff0..9e4ea32ed605 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -375,6 +375,7 @@ applications that come with the platform
<permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
<permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/>
<permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+ <permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/>
<permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/>
<permission name="android.permission.CONTROL_VPN"/>
<permission name="android.permission.DUMP"/>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 8aced6169f51..0b9b27f238d7 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -125,6 +125,7 @@
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT" />
<uses-permission android:name="android.permission.MANAGE_SLICE_PERMISSIONS" />
+ <uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
<!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked -->
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index f7cc9cba6afc..b0724b1e014b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -397,7 +397,8 @@ public class NotificationLockscreenUserManagerImpl implements
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
final boolean allowedByDpm = adminAllowsKeyguardFeature(userHandle,
DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
- final boolean allowed = allowedByUser && allowedByDpm;
+ final boolean allowedBySystem = mKeyguardManager.getPrivateNotificationsAllowed();
+ final boolean allowed = allowedByUser && allowedByDpm && allowedBySystem;
mUsersAllowingNotifications.append(userHandle, allowed);
return allowed;
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 6195ed9e0d79..32990ce1ea2e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -86,6 +86,7 @@ import static com.android.server.utils.PriorityDump.PRIORITY_ARG_CRITICAL;
import static com.android.server.utils.PriorityDump.PRIORITY_ARG_NORMAL;
import android.Manifest;
+import android.Manifest.permission;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -398,6 +399,10 @@ public class NotificationManagerService extends SystemService {
private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
private static final String ATTR_VERSION = "version";
+ private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG =
+ "allow-secure-notifications-on-lockscreen";
+ private static final String LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE = "value";
+
private RankingHelper mRankingHelper;
private PreferencesHelper mPreferencesHelper;
@@ -406,6 +411,7 @@ public class NotificationManagerService extends SystemService {
private NotificationAssistants mAssistants;
private ConditionProviders mConditionProviders;
private NotificationUsageStats mUsageStats;
+ private boolean mLockScreenAllowSecureNotifications;
private static final int MY_UID = Process.myUid();
private static final int MY_PID = Process.myPid();
@@ -552,6 +558,11 @@ public class NotificationManagerService extends SystemService {
mConditionProviders.readXml(parser, mAllowedManagedServicePackages);
migratedManagedServices = true;
}
+ if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
+ mLockScreenAllowSecureNotifications =
+ safeBoolean(parser.getAttributeValue(null,
+ LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true);
+ }
}
if (!migratedManagedServices) {
@@ -626,6 +637,7 @@ public class NotificationManagerService extends SystemService {
mListeners.writeXml(out, forBackup);
mAssistants.writeXml(out, forBackup);
mConditionProviders.writeXml(out, forBackup);
+ writeSecureNotificationsPolicy(out);
out.endTag(null, TAG_NOTIFICATION_POLICY);
out.endDocument();
}
@@ -3693,6 +3705,31 @@ public class NotificationManagerService extends SystemService {
return new ParceledListSlice<>(groups);
}
+ @Override
+ public void setPrivateNotificationsAllowed(boolean allow) {
+ if (PackageManager.PERMISSION_GRANTED
+ != getContext().checkCallingPermission(
+ permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
+ throw new SecurityException(
+ "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
+ }
+ if (allow != mLockScreenAllowSecureNotifications) {
+ mLockScreenAllowSecureNotifications = allow;
+ savePolicyFile();
+ }
+ }
+
+ @Override
+ public boolean getPrivateNotificationsAllowed() {
+ if (PackageManager.PERMISSION_GRANTED
+ != getContext().checkCallingPermission(
+ permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) {
+ throw new SecurityException(
+ "Requires CONTROL_KEYGUARD_SECURE_NOTIFICATIONS permission");
+ }
+ return mLockScreenAllowSecureNotifications;
+ }
+
private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
boolean assistantAllowed) {
ManagedServiceInfo info;
@@ -7562,4 +7599,16 @@ public class NotificationManagerService extends SystemService {
getOutPrintWriter().println(USAGE);
}
}
+
+ private void writeSecureNotificationsPolicy(XmlSerializer out) throws IOException {
+ out.startTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
+ out.attribute(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE,
+ Boolean.toString(mLockScreenAllowSecureNotifications));
+ out.endTag(null, LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG);
+ }
+
+ private static boolean safeBoolean(String val, boolean defValue) {
+ if (TextUtils.isEmpty(val)) return defValue;
+ return Boolean.parseBoolean(val);
+ }
}