summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Spurlock <jspurlock@google.com>2015-06-04 13:01:42 -0400
committerJohn Spurlock <jspurlock@google.com>2015-06-08 11:53:35 -0400
commit7c74f78a85283912d7239214024ccca702622f21 (patch)
tree226b395ce4cada544a8981c337169c2551dcf274
parentac2e3886e3f129b0ee94bb514e026fe72951b4a8 (diff)
downloadframeworks_base-7c74f78a85283912d7239214024ccca702622f21.zip
frameworks_base-7c74f78a85283912d7239214024ccca702622f21.tar.gz
frameworks_base-7c74f78a85283912d7239214024ccca702622f21.tar.bz2
Zen: New user flow for requesting DND access.
- User flow is now similar to requesting access to notification content, namely prompting the user to visit a settings page for enabling/disabling apps access. - New ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED intent for apps to listen to this state change. - Removed obsolete request method and associated internal callback aidl. - Added new android.permission.ACCESS_NOTIFICATION_POLICY permission for apps to include as a signal that they want to request this access (and therefore appear in the list on the settings page). - Improve javadocs, outline the user flow in NotificationManager#isNotificationPolicyAccessGranted and link to this method elsewhere. - NoManService now persists the user-enabled package list across reboots and does so per-user. - Rename public settings intent to correspond with the noman api. Bug: 21621663 Change-Id: I72cbc21cd736e6a157b6be5d1d0ba0b4a8e7ef4e
-rw-r--r--Android.mk1
-rw-r--r--api/current.txt11
-rw-r--r--api/system-current.txt11
-rw-r--r--core/java/android/app/INotificationManager.aidl2
-rw-r--r--core/java/android/app/INotificationManagerCallback.aidl24
-rw-r--r--core/java/android/app/NotificationManager.java77
-rw-r--r--core/java/android/provider/Settings.java18
-rw-r--r--core/res/AndroidManifest.xml6
-rw-r--r--core/res/res/values/strings.xml5
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java111
10 files changed, 133 insertions, 133 deletions
diff --git a/Android.mk b/Android.mk
index d6dac53..ade8536 100644
--- a/Android.mk
+++ b/Android.mk
@@ -74,7 +74,6 @@ LOCAL_SRC_FILES += \
core/java/android/app/IBackupAgent.aidl \
core/java/android/app/IInstrumentationWatcher.aidl \
core/java/android/app/INotificationManager.aidl \
- core/java/android/app/INotificationManagerCallback.aidl \
core/java/android/app/IProcessObserver.aidl \
core/java/android/app/ISearchManager.aidl \
core/java/android/app/ISearchManagerCallback.aidl \
diff --git a/api/current.txt b/api/current.txt
index e1c83e5..68637b3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12,6 +12,7 @@ package android {
field public static final java.lang.String ACCESS_LOCATION_EXTRA_COMMANDS = "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS";
field public static final java.lang.String ACCESS_MOCK_LOCATION = "android.permission.ACCESS_MOCK_LOCATION";
field public static final java.lang.String ACCESS_NETWORK_STATE = "android.permission.ACCESS_NETWORK_STATE";
+ field public static final java.lang.String ACCESS_NOTIFICATION_POLICY = "android.permission.ACCESS_NOTIFICATION_POLICY";
field public static final java.lang.String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
@@ -5122,10 +5123,10 @@ package android.app {
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
method public void notify(java.lang.String, int, android.app.Notification);
- method public void requestPolicyAccess(android.app.NotificationManager.NotificationPolicyAccessRequestCallback, android.os.Handler);
method public final void setInterruptionFilter(int);
method public void setNotificationPolicy(android.app.NotificationManager.Policy);
field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
+ field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -5134,12 +5135,6 @@ package android.app {
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
}
- public static abstract class NotificationManager.NotificationPolicyAccessRequestCallback {
- ctor public NotificationManager.NotificationPolicyAccessRequestCallback();
- method public abstract void onAccessDenied();
- method public abstract void onAccessGranted();
- }
-
public static class NotificationManager.Policy implements android.os.Parcelable {
ctor public NotificationManager.Policy(int, int, int);
method public int describeContents();
@@ -26503,6 +26498,7 @@ package android.provider {
field public static final java.lang.String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
field public static final java.lang.String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
field public static final java.lang.String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
+ field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
field public static final java.lang.String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
@@ -26521,7 +26517,6 @@ package android.provider {
field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
- field public static final java.lang.String ACTION_ZEN_ACCESS_SETTINGS = "android.settings.ZEN_ACCESS_SETTINGS";
field public static final java.lang.String AUTHORITY = "settings";
field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
diff --git a/api/system-current.txt b/api/system-current.txt
index 2839f68..ff9c861 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -18,6 +18,7 @@ package android {
field public static final java.lang.String ACCESS_NETWORK_CONDITIONS = "android.permission.ACCESS_NETWORK_CONDITIONS";
field public static final java.lang.String ACCESS_NETWORK_STATE = "android.permission.ACCESS_NETWORK_STATE";
field public static final java.lang.String ACCESS_NOTIFICATIONS = "android.permission.ACCESS_NOTIFICATIONS";
+ field public static final java.lang.String ACCESS_NOTIFICATION_POLICY = "android.permission.ACCESS_NOTIFICATION_POLICY";
field public static final java.lang.String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
@@ -5218,10 +5219,10 @@ package android.app {
method public boolean isNotificationPolicyAccessGranted();
method public void notify(int, android.app.Notification);
method public void notify(java.lang.String, int, android.app.Notification);
- method public void requestPolicyAccess(android.app.NotificationManager.NotificationPolicyAccessRequestCallback, android.os.Handler);
method public final void setInterruptionFilter(int);
method public void setNotificationPolicy(android.app.NotificationManager.Policy);
field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
+ field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
field public static final int INTERRUPTION_FILTER_ALARMS = 4; // 0x4
field public static final int INTERRUPTION_FILTER_ALL = 1; // 0x1
@@ -5230,12 +5231,6 @@ package android.app {
field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
}
- public static abstract class NotificationManager.NotificationPolicyAccessRequestCallback {
- ctor public NotificationManager.NotificationPolicyAccessRequestCallback();
- method public abstract void onAccessDenied();
- method public abstract void onAccessGranted();
- }
-
public static class NotificationManager.Policy implements android.os.Parcelable {
ctor public NotificationManager.Policy(int, int, int);
method public int describeContents();
@@ -28535,6 +28530,7 @@ package android.provider {
field public static final java.lang.String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
field public static final java.lang.String ACTION_NFC_SETTINGS = "android.settings.NFC_SETTINGS";
field public static final java.lang.String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS";
+ field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
field public static final java.lang.String ACTION_PRINT_SETTINGS = "android.settings.ACTION_PRINT_SETTINGS";
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
@@ -28553,7 +28549,6 @@ package android.provider {
field public static final java.lang.String ACTION_WIFI_IP_SETTINGS = "android.settings.WIFI_IP_SETTINGS";
field public static final java.lang.String ACTION_WIFI_SETTINGS = "android.settings.WIFI_SETTINGS";
field public static final java.lang.String ACTION_WIRELESS_SETTINGS = "android.settings.WIRELESS_SETTINGS";
- field public static final java.lang.String ACTION_ZEN_ACCESS_SETTINGS = "android.settings.ZEN_ACCESS_SETTINGS";
field public static final java.lang.String AUTHORITY = "settings";
field public static final java.lang.String EXTRA_ACCOUNT_TYPES = "account_types";
field public static final java.lang.String EXTRA_AIRPLANE_MODE_ENABLED = "airplane_mode_enabled";
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 63ff005..f78fb47 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -17,7 +17,6 @@
package android.app;
-import android.app.INotificationManagerCallback;
import android.app.ITransientNotification;
import android.app.Notification;
import android.app.NotificationManager;
@@ -87,7 +86,6 @@ interface INotificationManager
oneway void setZenMode(int mode, in Uri conditionId, String reason);
oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
- oneway void requestNotificationPolicyAccess(String pkg, in INotificationManagerCallback callback);
boolean isNotificationPolicyAccessGranted(String pkg);
NotificationManager.Policy getNotificationPolicy(String pkg);
void setNotificationPolicy(String pkg, in NotificationManager.Policy policy);
diff --git a/core/java/android/app/INotificationManagerCallback.aidl b/core/java/android/app/INotificationManagerCallback.aidl
deleted file mode 100644
index 9929745..0000000
--- a/core/java/android/app/INotificationManagerCallback.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * Copyright (c) 2015, 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.
- */
-
-package android.app;
-
-import android.app.NotificationManager;
-
-/** @hide */
-oneway interface INotificationManagerCallback {
- void onPolicyRequestResult(boolean granted);
-}
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 557964b..0904e21 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -101,6 +101,16 @@ public class NotificationManager
= "android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED";
/**
+ * Intent that is broadcast when the state of {@link #isNotificationPolicyAccessGranted()}
+ * changes.
+ *
+ * This broadcast is only sent to registered receivers, and only to the apps that have changed.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED
+ = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
+
+ /**
* Intent that is broadcast when the state of getNotificationPolicy() changes.
* This broadcast is only sent to registered receivers.
*/
@@ -403,55 +413,18 @@ public class NotificationManager
}
/**
- * Requests the ability to read/modify notification policy for the calling package.
- *
- * @param callback required, used to receive the granted or the denied signal.
- * @param handler The handler used when receiving the result.
- * If null, the current thread is used.
- */
- public void requestPolicyAccess(@NonNull final NotificationPolicyAccessRequestCallback callback,
- @Nullable Handler handler) {
- checkRequired("callback", callback);
- final Handler h = handler != null ? handler : new Handler();
- INotificationManager service = getService();
- try {
- service.requestNotificationPolicyAccess(mContext.getOpPackageName(),
- new INotificationManagerCallback.Stub() {
- @Override
- public void onPolicyRequestResult(final boolean granted) throws RemoteException {
- h.post(new Runnable() {
- @Override
- public void run() {
- if (granted) {
- callback.onAccessGranted();
- } else {
- callback.onAccessDenied();
- }
- }
- });
- }
- });
- } catch (RemoteException e) {
- }
- }
-
- /** Callback for receiving the result of a policy access request. */
- public static abstract class NotificationPolicyAccessRequestCallback {
- /**
- * Received if the request was granted for this package.
- */
- public abstract void onAccessGranted();
-
- /**
- * Received if the request was denied for this package.
- */
- public abstract void onAccessDenied();
- }
-
- /**
* Checks the ability to read/modify notification policy for the calling package.
*
+ * <p>
* Returns true if the calling package can read/modify notification policy.
+ *
+ * <p>
+ * Request policy access by sending the user to the activity that matches the system intent
+ * action {@link android.provider.Settings#ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS}.
+ *
+ * <p>
+ * Use {@link #ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED} to listen for
+ * user grant or denial of this access.
*/
public boolean isNotificationPolicyAccessGranted() {
INotificationManager service = getService();
@@ -476,7 +449,8 @@ public class NotificationManager
* Gets the current notification policy.
*
* <p>
- * Only available if policy access is granted.
+ * Only available if policy access is granted to this package.
+ * See {@link #isNotificationPolicyAccessGranted}.
*/
public Policy getNotificationPolicy() {
INotificationManager service = getService();
@@ -491,7 +465,8 @@ public class NotificationManager
* Sets the current notification policy.
*
* <p>
- * Only available if policy access is granted.
+ * Only available if policy access is granted to this package.
+ * See {@link #isNotificationPolicyAccessGranted}.
*
* @param policy The new desired policy.
*/
@@ -716,7 +691,8 @@ public class NotificationManager
* unavailable.
*
* <p>
- * Only available if policy access is granted.
+ * Only available if policy access is granted to this package.
+ * See {@link #isNotificationPolicyAccessGranted}.
*/
public final int getCurrentInterruptionFilter() {
final INotificationManager service = getService();
@@ -738,7 +714,8 @@ public class NotificationManager
* unavailable.
*
* <p>
- * Only available if policy access is granted.
+ * Only available if policy access is granted to this package.
+ * See {@link #isNotificationPolicyAccessGranted}.
*/
public final void setInterruptionFilter(int interruptionFilter) {
final INotificationManager service = getService();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 37645b5..cac4a53 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -811,14 +811,17 @@ public final class Settings {
/**
* Activity Action: Show Do Not Disturb access settings.
* <p>
- * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
+ * Users can grant and deny access to Do Not Disturb configuration from here.
+ * See {@link android.app.NotificationManager#isNotificationPolicyAccessGranted()} for more
+ * details.
* <p>
* Input: Nothing.
* <p>
* Output: Nothing.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_ZEN_ACCESS_SETTINGS = "android.settings.ZEN_ACCESS_SETTINGS";
+ public static final String ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS
+ = "android.settings.NOTIFICATION_POLICY_ACCESS_SETTINGS";
/**
* @hide
@@ -5425,7 +5428,7 @@ public final class Settings {
public static final String ASSIST_STRUCTURE_ENABLED = "assist_structure_enabled";
/**
- * Names of the packages that the current user has explicitly allowed to
+ * Names of the service components that the current user has explicitly allowed to
* see all of the user's notifications, separated by ':'.
*
* @hide
@@ -5433,6 +5436,15 @@ public final class Settings {
public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
/**
+ * Names of the packages that the current user has explicitly allowed to
+ * manage notification policy configuration, separated by ':'.
+ *
+ * @hide
+ */
+ public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES =
+ "enabled_notification_policy_access_packages";
+
+ /**
* @hide
*/
public static final String ENABLED_CONDITION_PROVIDERS = "enabled_condition_providers";
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 439affe..9fc5f13 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2327,6 +2327,12 @@
<permission android:name="android.permission.ACCESS_NOTIFICATIONS"
android:protectionLevel="signature|system" />
+ <!-- Marker permission for applications that wish to access notification policy. -->
+ <permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"
+ android:description="@string/permdesc_access_notification_policy"
+ android:label="@string/permlab_access_notification_policy"
+ android:protectionLevel="normal" />
+
<!-- Allows access to keyguard secure storage. Only allowed for system processes.
@hide -->
<permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 625ab59..95e0531 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1435,6 +1435,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_bindCarrierServices">Allows the holder to bind to carrier services. Should never be needed for normal apps.</string>
+ <!-- Title of an application permission, for applications that wish to access notification policy. -->
+ <string name="permlab_access_notification_policy">access Do Not Disturb</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_access_notification_policy">Allows the app to read and write Do Not Disturb configuration.</string>
+
<!-- Policy administration -->
<!-- Title of policy access to limiting the user's password choices -->
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2d15d13..f12cee2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -29,7 +29,6 @@ import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.app.INotificationManager;
-import android.app.INotificationManagerCallback;
import android.app.ITransientNotification;
import android.app.Notification;
import android.app.NotificationManager;
@@ -130,6 +129,7 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
@@ -237,8 +237,7 @@ public class NotificationManagerService extends SystemService {
new ArrayMap<String, NotificationRecord>();
final ArrayList<ToastRecord> mToastQueue = new ArrayList<ToastRecord>();
final ArrayMap<String, NotificationRecord> mSummaryByGroupKey = new ArrayMap<>();
- private final ArrayMap<String, Boolean> mPolicyAccess = new ArrayMap<>();
-
+ final PolicyAccess mPolicyAccess = new PolicyAccess();
// The last key in this list owns the hardware.
ArrayList<String> mLights = new ArrayList<>();
@@ -787,7 +786,7 @@ public class NotificationManagerService extends SystemService {
}
};
- class SettingsObserver extends ContentObserver {
+ private final class SettingsObserver extends ContentObserver {
private final Uri NOTIFICATION_LIGHT_PULSE_URI
= Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
@@ -1641,7 +1640,7 @@ public class NotificationManagerService extends SystemService {
}
private boolean checkPackagePolicyAccess(String pkg) {
- return Boolean.TRUE.equals(mPolicyAccess.get(pkg));
+ return mPolicyAccess.isPackageGranted(pkg);
}
private boolean checkPolicyAccess(String pkg) {
@@ -1724,31 +1723,6 @@ public class NotificationManagerService extends SystemService {
}
@Override
- public void requestNotificationPolicyAccess(String pkg,
- INotificationManagerCallback callback) throws RemoteException {
- if (callback == null) {
- Slog.w(TAG, "requestNotificationPolicyAccess: no callback specified");
- return;
- }
- if (pkg == null) {
- Slog.w(TAG, "requestNotificationPolicyAccess denied: no package specified");
- callback.onPolicyRequestResult(false);
- return;
- }
- final long identity = Binder.clearCallingIdentity();
- try {
- synchronized (mNotificationList) {
- // immediately grant for now
- mPolicyAccess.put(pkg, true);
- if (DBG) Slog.w(TAG, "requestNotificationPolicyAccess granted for " + pkg);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- callback.onPolicyRequestResult(true);
- }
-
- @Override
public boolean isNotificationPolicyAccessGranted(String pkg) {
return checkPolicyAccess(pkg);
}
@@ -1765,13 +1739,7 @@ public class NotificationManagerService extends SystemService {
enforceSystemOrSystemUI("request policy access packages");
final long identity = Binder.clearCallingIdentity();
try {
- synchronized (mNotificationList) {
- final String[] rt = new String[mPolicyAccess.size()];
- for (int i = 0; i < mPolicyAccess.size(); i++) {
- rt[i] = mPolicyAccess.keyAt(i);
- }
- return rt;
- }
+ return mPolicyAccess.getRequestingPackages();
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -3518,4 +3486,73 @@ public class NotificationManagerService extends SystemService {
return value;
}
}
+
+ private final class PolicyAccess {
+ private static final String SEPARATOR = ":";
+ private final String[] PERM = {
+ android.Manifest.permission.ACCESS_NOTIFICATION_POLICY
+ };
+
+ public boolean isPackageGranted(String pkg) {
+ return pkg != null && getGrantedPackages().contains(pkg);
+ }
+
+ public void put(String pkg, boolean granted) {
+ if (pkg == null) return;
+ final ArraySet<String> pkgs = getGrantedPackages();
+ boolean changed;
+ if (granted) {
+ changed = pkgs.add(pkg);
+ } else {
+ changed = pkgs.remove(pkg);
+ }
+ if (!changed) return;
+ final String setting = TextUtils.join(SEPARATOR, pkgs);
+ final int currentUser = ActivityManager.getCurrentUser();
+ Settings.Secure.putStringForUser(getContext().getContentResolver(),
+ Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+ setting,
+ currentUser);
+ getContext().sendBroadcastAsUser(new Intent(NotificationManager
+ .ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED)
+ .setPackage(pkg)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), new UserHandle(currentUser), null);
+ }
+
+ public ArraySet<String> getGrantedPackages() {
+ final ArraySet<String> pkgs = new ArraySet<>();
+ final String setting = Settings.Secure.getStringForUser(
+ getContext().getContentResolver(),
+ Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+ ActivityManager.getCurrentUser());
+ if (setting != null) {
+ final String[] tokens = setting.split(SEPARATOR);
+ for (int i = 0; i < tokens.length; i++) {
+ String token = tokens[i];
+ if (token != null) {
+ token.trim();
+ }
+ if (TextUtils.isEmpty(token)) {
+ continue;
+ }
+ pkgs.add(token);
+ }
+ }
+ return pkgs;
+ }
+
+ public String[] getRequestingPackages() throws RemoteException {
+ final ParceledListSlice list = AppGlobals.getPackageManager()
+ .getPackagesHoldingPermissions(PERM, 0 /*flags*/,
+ ActivityManager.getCurrentUser());
+ final List<PackageInfo> pkgs = list.getList();
+ if (pkgs == null || pkgs.isEmpty()) return new String[0];
+ final int N = pkgs.size();
+ final String[] rt = new String[N];
+ for (int i = 0; i < N; i++) {
+ rt[i] = pkgs.get(i).packageName;
+ }
+ return rt;
+ }
+ }
}