From 4b749ef5f2d510b84b99aa269d5c77af22457d04 Mon Sep 17 00:00:00 2001 From: Daniel Sandler Date: Mon, 18 Mar 2013 21:53:04 -0400 Subject: Allow whitelisted non-system packages to listen for notifications. The allowed packages are listed in Settings.Secure.ENABLED_NOTIFICATION_LISTENERS. (Don't let the plural fool you: only one listener will be supported in the UI.) Change-Id: Ia69f2ba05d8e555fd4d40b0cc89c62ed14af3cac --- core/java/android/app/INotificationManager.aidl | 2 +- core/java/android/provider/Settings.java | 8 ++ .../android/server/NotificationManagerService.java | 129 +++++++++++++++++---- 3 files changed, 114 insertions(+), 25 deletions(-) diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index 14bcc0d7fba4..3d9b2ae83518 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -41,7 +41,7 @@ interface INotificationManager StatusBarNotification[] getActiveNotifications(String callingPkg); StatusBarNotification[] getHistoricalNotifications(String callingPkg, int count); - void registerListener(in INotificationListener listener, int userid); + void registerListener(in INotificationListener listener, String pkg, int userid); void unregisterListener(in INotificationListener listener, int userid); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index d251ca25e068..4cb1ae84480d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -4038,6 +4038,14 @@ public final class Settings { */ public static final String SCREENSAVER_DEFAULT_COMPONENT = "screensaver_default_component"; + /** + * Name of a package that the current user has explicitly allowed to see all of that + * user's notifications. + * + * @hide + */ + public static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners"; + /** * This are the settings to be backed up. * diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 9e036d1124ec..5cf1c285f2db 100644 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -50,12 +50,11 @@ import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.os.Message; -import android.os.Parcel; -import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.os.UserManager; import android.os.Vibrator; import android.provider.Settings; import android.telephony.TelephonyManager; @@ -124,6 +123,7 @@ public class NotificationManagerService extends INotificationManager.Stub final Context mContext; final IActivityManager mAm; + final UserManager mUserManager; final IBinder mForegroundToken = new Binder(); private WorkerHandler mHandler; @@ -164,6 +164,7 @@ public class NotificationManagerService extends INotificationManager.Stub private final AppOpsManager mAppOps; private ArrayList mListeners = new ArrayList(); + private ArrayList mEnabledListenersForCurrentUser = new ArrayList(); // Notification control database. For now just contains disabled packages. private AtomicFile mPolicyFile; @@ -180,20 +181,27 @@ public class NotificationManagerService extends INotificationManager.Stub private class NotificationListenerInfo implements DeathRecipient { INotificationListener listener; + String pkg; int userid; - public NotificationListenerInfo(INotificationListener listener, int userid) { + boolean isSystem; + + public NotificationListenerInfo(INotificationListener listener, String pkg, int userid, + boolean isSystem) { this.listener = listener; + this.pkg = pkg; this.userid = userid; + this.isSystem = isSystem; } - boolean userMatches(StatusBarNotification sbn) { + boolean enabledAndUserMatches(StatusBarNotification sbn) { + final int nid = sbn.getUserId(); + if (!(isSystem || isEnabledForUser(nid))) return false; if (this.userid == UserHandle.USER_ALL) return true; - int nid = sbn.getUserId(); return (nid == UserHandle.USER_ALL || nid == this.userid); } public void notifyPostedIfUserMatch(StatusBarNotification sbn) { - if (!userMatches(sbn)) return; + if (!enabledAndUserMatches(sbn)) return; try { listener.onNotificationPosted(sbn); } catch (RemoteException ex) { @@ -202,7 +210,7 @@ public class NotificationManagerService extends INotificationManager.Stub } public void notifyRemovedIfUserMatch(StatusBarNotification sbn) { - if (!userMatches(sbn)) return; + if (!enabledAndUserMatches(sbn)) return; try { listener.onNotificationRemoved(sbn); } catch (RemoteException ex) { @@ -214,6 +222,14 @@ public class NotificationManagerService extends INotificationManager.Stub public void binderDied() { unregisterListener(this.listener, this.userid); } + + /** convenience method for looking in mEnabledListenersForCurrentUser */ + public boolean isEnabledForUser(int userid) { + for (int i=0; i=0; i--) { @@ -740,37 +777,67 @@ public class NotificationManagerService extends INotificationManager.Stub } else if (action.equals(Intent.ACTION_USER_PRESENT)) { // turn off LED when user passes through lock screen mNotificationLight.turnOff(); + } else if (action.equals(Intent.ACTION_USER_SWITCHED)) { + // reload per-user settings + mSettingsObserver.update(null); } } }; class SettingsObserver extends ContentObserver { + private final Uri NOTIFICATION_LIGHT_PULSE_URI + = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE); + + private final Uri ENABLED_NOTIFICATION_LISTENERS_URI + = Settings.System.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); + SettingsObserver(Handler handler) { super(handler); } void observe() { ContentResolver resolver = mContext.getContentResolver(); - resolver.registerContentObserver(Settings.System.getUriFor( - Settings.System.NOTIFICATION_LIGHT_PULSE), false, this); - update(); + resolver.registerContentObserver(NOTIFICATION_LIGHT_PULSE_URI, + false, this); + resolver.registerContentObserver(ENABLED_NOTIFICATION_LISTENERS_URI, + false, this); + update(null); } - @Override public void onChange(boolean selfChange) { - update(); + @Override public void onChange(boolean selfChange, Uri uri) { + update(uri); } - public void update() { + public void update(Uri uri) { ContentResolver resolver = mContext.getContentResolver(); - boolean pulseEnabled = Settings.System.getInt(resolver, - Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; - if (mNotificationPulseEnabled != pulseEnabled) { - mNotificationPulseEnabled = pulseEnabled; - updateNotificationPulse(); + if (uri == null || NOTIFICATION_LIGHT_PULSE_URI.equals(uri)) { + boolean pulseEnabled = Settings.System.getInt(resolver, + Settings.System.NOTIFICATION_LIGHT_PULSE, 0) != 0; + if (mNotificationPulseEnabled != pulseEnabled) { + mNotificationPulseEnabled = pulseEnabled; + updateNotificationPulse(); + } + } + if (uri == null || ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri)) { + String pkglist = Settings.Secure.getString( + mContext.getContentResolver(), + Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); + mEnabledListenersForCurrentUser.clear(); + if (pkglist != null) { + String[] pkgs = pkglist.split(";"); + for (int i=0; i(); mHandler = new WorkerHandler(); @@ -838,6 +906,7 @@ public class NotificationManagerService extends INotificationManager.Stub filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); filter.addAction(Intent.ACTION_USER_PRESENT); filter.addAction(Intent.ACTION_USER_STOPPED); + filter.addAction(Intent.ACTION_USER_SWITCHED); mContext.registerReceiver(mIntentReceiver, filter); IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); @@ -849,8 +918,8 @@ public class NotificationManagerService extends INotificationManager.Stub IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mIntentReceiver, sdFilter); - SettingsObserver observer = new SettingsObserver(mHandler); - observer.observe(); + mSettingsObserver = new SettingsObserver(mHandler); + mSettingsObserver.observe(); } /** @@ -1706,6 +1775,18 @@ public class NotificationManagerService extends INotificationManager.Stub pw.println("Current Notification Manager state:"); + pw.print(" Enabled listeners: ["); + for (String pkg : mEnabledListenersForCurrentUser) { + pw.print(" " + pkg); + } + pw.println(" ]"); + + pw.println(" Live listeners:"); + for (NotificationListenerInfo info : mListeners) { + pw.println(" " + info.pkg + " (user " + info.userid + "): " + info.listener + + (info.isSystem?" SYSTEM":"")); + } + int N; synchronized (mToastQueue) { -- cgit v1.2.3-59-g8ed1b