diff options
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); + } } |