diff options
author | Chris Wren <cwren@android.com> | 2014-09-04 15:53:52 -0400 |
---|---|---|
committer | Chris Wren <cwren@android.com> | 2014-09-05 10:36:32 -0400 |
commit | da4bd209cffad7e47a4bc6e9f02c4bfc333d3d8d (patch) | |
tree | 49fdcb07251ffe9c12a1bced660d19c665a01321 | |
parent | b501eb7ae2fc8109246fbf3cf8183a1290d049c8 (diff) | |
download | frameworks_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
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); } } |