summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wren <cwren@android.com>2014-09-04 15:53:52 -0400
committerChris Wren <cwren@android.com>2014-09-05 10:36:32 -0400
commitda4bd209cffad7e47a4bc6e9f02c4bfc333d3d8d (patch)
tree49fdcb07251ffe9c12a1bced660d19c665a01321
parentb501eb7ae2fc8109246fbf3cf8183a1290d049c8 (diff)
downloadframeworks_base-da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8d.zip
frameworks_base-da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8d.tar.gz
frameworks_base-da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8d.tar.bz2
Keep contact affinities separate across users.
Also ignore people extras on USER_ALL notifications. Bug: 16213960 Change-Id: Ic0341c88d42d4a4f12cac35c0f41c2746aec02ac
-rw-r--r--core/java/android/app/INotificationManager.aidl1
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java9
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java5
-rw-r--r--services/core/java/com/android/server/notification/ValidateNotificationPeople.java152
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java5
5 files changed, 113 insertions, 59 deletions
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index bdcff38..7d4512b 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -71,6 +71,7 @@ interface INotificationManager
ComponentName getEffectsSuppressor();
boolean matchesCallFilter(in Bundle extras);
+ boolean matchesCallFilterAsUser(in Bundle extras, int userId);
ZenModeConfig getZenModeConfig();
boolean setZenModeConfig(in ZenModeConfig config);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0794edf..dcd8dff 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1470,7 +1470,14 @@ public class NotificationManagerService extends SystemService {
@Override
public boolean matchesCallFilter(Bundle extras) {
enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
- return mZenModeHelper.matchesCallFilter(extras,
+ return matchesCallFilterAsUser(extras, Binder.getCallingUid());
+ }
+
+ @Override
+ public boolean matchesCallFilterAsUser(Bundle extras, int userId) {
+ enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
+ UserHandle userHandle = new UserHandle(userId);
+ return mZenModeHelper.matchesCallFilter(userHandle, extras,
mRankingHelper.findExtractor(ValidateNotificationPeople.class));
}
};
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 84b4d97..fd34aa5 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -21,6 +21,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.media.AudioAttributes;
+import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
import com.android.internal.annotations.VisibleForTesting;
@@ -88,8 +89,10 @@ public final class NotificationRecord {
public Notification getNotification() { return sbn.getNotification(); }
public int getFlags() { return sbn.getNotification().flags; }
- public int getUserId() { return sbn.getUserId(); }
+ public UserHandle getUser() { return sbn.getUser(); }
public String getKey() { return sbn.getKey(); }
+ /** @deprecated Use {@link #getUser()} instead. */
+ public int getUserId() { return sbn.getUserId(); }
void dump(PrintWriter pw, String prefix, Context baseContext) {
final Notification notification = sbn.getNotification();
diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
index aa47858..f266916 100644
--- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
+++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java
@@ -18,18 +18,23 @@ package com.android.server.notification;
import android.app.Notification;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
+import android.os.UserHandle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Log;
import android.util.LruCache;
import android.util.Slog;
import java.util.ArrayList;
import java.util.LinkedList;
+import java.util.Map;
/**
* This {@link NotificationSignalExtractor} attempts to validate
@@ -65,21 +70,88 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
static final float STARRED_CONTACT = 1f;
protected boolean mEnabled;
- private Context mContext;
+ private Context mBaseContext;
// maps raw person handle to resolved person object
private LruCache<String, LookupResult> mPeopleCache;
+ private Map<Integer, Context> mUserToContextMap;
- private RankingReconsideration validatePeople(final NotificationRecord record) {
+ public void initialize(Context context) {
+ if (DEBUG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
+ mUserToContextMap = new ArrayMap<>();
+ mBaseContext = context;
+ mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
+ mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt(
+ mBaseContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1);
+ }
+
+ public RankingReconsideration process(NotificationRecord record) {
+ if (!mEnabled) {
+ if (INFO) Slog.i(TAG, "disabled");
+ return null;
+ }
+ if (record == null || record.getNotification() == null) {
+ if (INFO) Slog.i(TAG, "skipping empty notification");
+ return null;
+ }
+ if (record.getUserId() == UserHandle.USER_ALL) {
+ if (INFO) Slog.i(TAG, "skipping global notification");
+ return null;
+ }
+ Context context = getContextAsUser(record.getUser());
+ if (context == null) {
+ if (INFO) Slog.i(TAG, "skipping notification that lacks a context");
+ return null;
+ }
+ return validatePeople(context, record);
+ }
+
+ @Override
+ public void setConfig(RankingConfig config) {
+ // ignore: config has no relevant information yet.
+ }
+
+ public float getContactAffinity(UserHandle userHandle, Bundle extras) {
+ if (extras == null) return NONE;
+ final String key = Long.toString(System.nanoTime());
+ final float[] affinityOut = new float[1];
+ Context context = getContextAsUser(userHandle);
+ if (context == null) {
+ return NONE;
+ }
+ final PeopleRankingReconsideration prr = validatePeople(context, key, extras, affinityOut);
+ float affinity = affinityOut[0];
+ if (prr != null) {
+ prr.work();
+ affinity = Math.max(prr.getContactAffinity(), affinity);
+ }
+ return affinity;
+ }
+
+ private Context getContextAsUser(UserHandle userHandle) {
+ Context context = mUserToContextMap.get(userHandle.getIdentifier());
+ if (context == null) {
+ try {
+ context = mBaseContext.createPackageContextAsUser("android", 0, userHandle);
+ mUserToContextMap.put(userHandle.getIdentifier(), context);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "failed to create package context for lookups", e);
+ }
+ }
+ return context;
+ }
+
+ private RankingReconsideration validatePeople(Context context,
+ final NotificationRecord record) {
final String key = record.getKey();
final Bundle extras = record.getNotification().extras;
final float[] affinityOut = new float[1];
- final RankingReconsideration rr = validatePeople(key, extras, affinityOut);
+ final RankingReconsideration rr = validatePeople(context, key, extras, affinityOut);
record.setContactAffinity(affinityOut[0]);
return rr;
}
- private PeopleRankingReconsideration validatePeople(String key, Bundle extras,
+ private PeopleRankingReconsideration validatePeople(Context context, String key, Bundle extras,
float[] affinityOut) {
float affinity = NONE;
if (extras == null) {
@@ -98,7 +170,8 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
if (TextUtils.isEmpty(handle)) continue;
synchronized (mPeopleCache) {
- LookupResult lookupResult = mPeopleCache.get(handle);
+ final String cacheKey = getCacheKey(context.getUserId(), handle);
+ LookupResult lookupResult = mPeopleCache.get(cacheKey);
if (lookupResult == null || lookupResult.isExpired()) {
pendingLookups.add(handle);
} else {
@@ -119,7 +192,11 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
}
if (DEBUG) Slog.d(TAG, "Pending: future work scheduled for: " + key);
- return new PeopleRankingReconsideration(key, pendingLookups);
+ return new PeopleRankingReconsideration(context, key, pendingLookups);
+ }
+
+ private String getCacheKey(int userId, String handle) {
+ return Integer.toString(userId) + ":" + handle;
}
// VisibleForTesting
@@ -185,24 +262,24 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
return null;
}
- private LookupResult resolvePhoneContact(final String number) {
+ private LookupResult resolvePhoneContact(Context context, final String number) {
Uri phoneUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(number));
- return searchContacts(phoneUri);
+ return searchContacts(context, phoneUri);
}
- private LookupResult resolveEmailContact(final String email) {
+ private LookupResult resolveEmailContact(Context context, final String email) {
Uri numberUri = Uri.withAppendedPath(
ContactsContract.CommonDataKinds.Email.CONTENT_LOOKUP_URI,
Uri.encode(email));
- return searchContacts(numberUri);
+ return searchContacts(context, numberUri);
}
- private LookupResult searchContacts(Uri lookupUri) {
+ private LookupResult searchContacts(Context context, Uri lookupUri) {
LookupResult lookupResult = new LookupResult();
Cursor c = null;
try {
- c = mContext.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null, null, null);
+ c = context.getContentResolver().query(lookupUri, LOOKUP_PROJECTION, null, null, null);
if (c != null && c.getCount() > 0) {
c.moveToFirst();
lookupResult.readContact(c);
@@ -217,44 +294,6 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
return lookupResult;
}
- public void initialize(Context context) {
- if (DEBUG) Slog.d(TAG, "Initializing " + getClass().getSimpleName() + ".");
- mContext = context;
- mPeopleCache = new LruCache<String, LookupResult>(PEOPLE_CACHE_SIZE);
- mEnabled = ENABLE_PEOPLE_VALIDATOR && 1 == Settings.Global.getInt(
- mContext.getContentResolver(), SETTING_ENABLE_PEOPLE_VALIDATOR, 1);
- }
-
- public RankingReconsideration process(NotificationRecord record) {
- if (!mEnabled) {
- if (INFO) Slog.i(TAG, "disabled");
- return null;
- }
- if (record == null || record.getNotification() == null) {
- if (INFO) Slog.i(TAG, "skipping empty notification");
- return null;
- }
- return validatePeople(record);
- }
-
- @Override
- public void setConfig(RankingConfig config) {
- // ignore: config has no relevant information yet.
- }
-
- public float getContactAffinity(Bundle extras) {
- if (extras == null) return NONE;
- final String key = Long.toString(System.nanoTime());
- final float[] affinityOut = new float[1];
- final PeopleRankingReconsideration prr = validatePeople(key, extras, affinityOut);
- float affinity = affinityOut[0];
- if (prr != null) {
- prr.work();
- affinity = Math.max(prr.getContactAffinity(), affinity);
- }
- return affinity;
- }
-
private static class LookupResult {
private static final long CONTACT_REFRESH_MILLIS = 60 * 60 * 1000; // 1hr
public static final int INVALID_ID = -1;
@@ -317,11 +356,13 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
private class PeopleRankingReconsideration extends RankingReconsideration {
private final LinkedList<String> mPendingLookups;
+ private final Context mContext;
private float mContactAffinity = NONE;
- private PeopleRankingReconsideration(String key, LinkedList<String> pendingLookups) {
+ private PeopleRankingReconsideration(Context context, String key, LinkedList<String> pendingLookups) {
super(key);
+ mContext = context;
mPendingLookups = pendingLookups;
}
@@ -333,20 +374,21 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor {
final Uri uri = Uri.parse(handle);
if ("tel".equals(uri.getScheme())) {
if (DEBUG) Slog.d(TAG, "checking telephone URI: " + handle);
- lookupResult = resolvePhoneContact(uri.getSchemeSpecificPart());
+ lookupResult = resolvePhoneContact(mContext, uri.getSchemeSpecificPart());
} else if ("mailto".equals(uri.getScheme())) {
if (DEBUG) Slog.d(TAG, "checking mailto URI: " + handle);
- lookupResult = resolveEmailContact(uri.getSchemeSpecificPart());
+ lookupResult = resolveEmailContact(mContext, uri.getSchemeSpecificPart());
} else if (handle.startsWith(Contacts.CONTENT_LOOKUP_URI.toString())) {
if (DEBUG) Slog.d(TAG, "checking lookup URI: " + handle);
- lookupResult = searchContacts(uri);
+ lookupResult = searchContacts(mContext, uri);
} else {
lookupResult = new LookupResult(); // invalid person for the cache
Slog.w(TAG, "unsupported URI " + handle);
}
if (lookupResult != null) {
synchronized (mPeopleCache) {
- mPeopleCache.put(handle, lookupResult);
+ final String cacheKey = getCacheKey(mContext.getUserId(), handle);
+ mPeopleCache.put(cacheKey, lookupResult);
}
mContactAffinity = Math.max(mContactAffinity, lookupResult.getAffinity());
}
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index fd35ede..168328f 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -373,13 +373,14 @@ public class ZenModeHelper {
return record.isCategory(Notification.CATEGORY_MESSAGE) || isDefaultMessagingApp(record);
}
- public boolean matchesCallFilter(Bundle extras, ValidateNotificationPeople validator) {
+ public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
+ ValidateNotificationPeople validator) {
final int zen = mZenMode;
if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) return false; // nothing gets through
if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
if (!mConfig.allowCalls) return false; // no calls get through
if (validator != null) {
- final float contactAffinity = validator.getContactAffinity(extras);
+ final float contactAffinity = validator.getContactAffinity(userHandle, extras);
return audienceMatches(contactAffinity);
}
}