Merge "Make smart suggestion generation configurable"
This commit is contained in:
committed by
Android (Google) Code Review
commit
af7deaba65
@@ -27,20 +27,15 @@ import android.app.ActivityThread;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.database.ContentObserver;
|
||||
import android.ext.services.notification.AgingHelper.Callback;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.Adjustment;
|
||||
import android.service.notification.NotificationAssistantService;
|
||||
import android.service.notification.NotificationStats;
|
||||
@@ -92,8 +87,6 @@ public class Assistant extends NotificationAssistantService {
|
||||
PREJUDICAL_DISMISSALS.add(REASON_LISTENER_CANCEL);
|
||||
}
|
||||
|
||||
private float mDismissToViewRatioLimit;
|
||||
private int mStreakLimit;
|
||||
private SmartActionsHelper mSmartActionsHelper;
|
||||
private NotificationCategorizer mNotificationCategorizer;
|
||||
private AgingHelper mAgingHelper;
|
||||
@@ -107,7 +100,11 @@ public class Assistant extends NotificationAssistantService {
|
||||
private Ranking mFakeRanking = null;
|
||||
private AtomicFile mFile = null;
|
||||
private IPackageManager mPackageManager;
|
||||
protected SettingsObserver mSettingsObserver;
|
||||
|
||||
@VisibleForTesting
|
||||
protected AssistantSettings.Factory mSettingsFactory = AssistantSettings.FACTORY;
|
||||
@VisibleForTesting
|
||||
protected AssistantSettings mSettings;
|
||||
|
||||
public Assistant() {
|
||||
}
|
||||
@@ -118,7 +115,8 @@ public class Assistant extends NotificationAssistantService {
|
||||
// Contexts are correctly hooked up by the creation step, which is required for the observer
|
||||
// to be hooked up/initialized.
|
||||
mPackageManager = ActivityThread.getPackageManager();
|
||||
mSettingsObserver = new SettingsObserver(mHandler);
|
||||
mSettings = mSettingsFactory.createAndRegister(mHandler,
|
||||
getApplicationContext().getContentResolver(), getUserId(), this::updateThresholds);
|
||||
mSmartActionsHelper = new SmartActionsHelper();
|
||||
mNotificationCategorizer = new NotificationCategorizer();
|
||||
mAgingHelper = new AgingHelper(getContext(),
|
||||
@@ -216,11 +214,11 @@ public class Assistant extends NotificationAssistantService {
|
||||
if (!isForCurrentUser(sbn)) {
|
||||
return null;
|
||||
}
|
||||
NotificationEntry entry = new NotificationEntry(
|
||||
ActivityThread.getPackageManager(), sbn, channel);
|
||||
NotificationEntry entry = new NotificationEntry(mPackageManager, sbn, channel);
|
||||
ArrayList<Notification.Action> actions =
|
||||
mSmartActionsHelper.suggestActions(this, entry);
|
||||
ArrayList<CharSequence> replies = mSmartActionsHelper.suggestReplies(this, entry);
|
||||
mSmartActionsHelper.suggestActions(this, entry, mSettings);
|
||||
ArrayList<CharSequence> replies =
|
||||
mSmartActionsHelper.suggestReplies(this, entry, mSettings);
|
||||
return createEnqueuedNotificationAdjustment(entry, actions, replies);
|
||||
}
|
||||
|
||||
@@ -239,8 +237,7 @@ public class Assistant extends NotificationAssistantService {
|
||||
if (!smartReplies.isEmpty()) {
|
||||
signals.putCharSequenceArrayList(Adjustment.KEY_SMART_REPLIES, smartReplies);
|
||||
}
|
||||
if (Settings.Secure.getInt(getContentResolver(),
|
||||
Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL, 1) == 1) {
|
||||
if (mSettings.mNewInterruptionModel) {
|
||||
if (mNotificationCategorizer.shouldSilence(entry)) {
|
||||
final int importance = entry.getImportance() < IMPORTANCE_LOW
|
||||
? entry.getImportance() : IMPORTANCE_LOW;
|
||||
@@ -459,6 +456,11 @@ public class Assistant extends NotificationAssistantService {
|
||||
mPackageManager = pm;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setSmartActionsHelper(SmartActionsHelper smartActionsHelper) {
|
||||
mSmartActionsHelper = smartActionsHelper;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public ChannelImpressions getImpressions(String key) {
|
||||
synchronized (mkeyToImpressions) {
|
||||
@@ -475,10 +477,20 @@ public class Assistant extends NotificationAssistantService {
|
||||
|
||||
private ChannelImpressions createChannelImpressionsWithThresholds() {
|
||||
ChannelImpressions impressions = new ChannelImpressions();
|
||||
impressions.updateThresholds(mDismissToViewRatioLimit, mStreakLimit);
|
||||
impressions.updateThresholds(mSettings.mDismissToViewRatioLimit, mSettings.mStreakLimit);
|
||||
return impressions;
|
||||
}
|
||||
|
||||
private void updateThresholds() {
|
||||
// Update all existing channel impression objects with any new limits/thresholds.
|
||||
synchronized (mkeyToImpressions) {
|
||||
for (ChannelImpressions channelImpressions: mkeyToImpressions.values()) {
|
||||
channelImpressions.updateThresholds(
|
||||
mSettings.mDismissToViewRatioLimit, mSettings.mStreakLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final class AgingCallback implements Callback {
|
||||
@Override
|
||||
public void sendAdjustment(String key, int newImportance) {
|
||||
@@ -495,51 +507,4 @@ public class Assistant extends NotificationAssistantService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Observer for updates on blocking helper threshold values.
|
||||
*/
|
||||
protected final class SettingsObserver extends ContentObserver {
|
||||
private final Uri STREAK_LIMIT_URI =
|
||||
Settings.Global.getUriFor(Settings.Global.BLOCKING_HELPER_STREAK_LIMIT);
|
||||
private final Uri DISMISS_TO_VIEW_RATIO_LIMIT_URI =
|
||||
Settings.Global.getUriFor(
|
||||
Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT);
|
||||
|
||||
public SettingsObserver(Handler handler) {
|
||||
super(handler);
|
||||
ContentResolver resolver = getApplicationContext().getContentResolver();
|
||||
resolver.registerContentObserver(
|
||||
DISMISS_TO_VIEW_RATIO_LIMIT_URI, false, this, getUserId());
|
||||
resolver.registerContentObserver(STREAK_LIMIT_URI, false, this, getUserId());
|
||||
|
||||
// Update all uris on creation.
|
||||
update(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
update(uri);
|
||||
}
|
||||
|
||||
private void update(Uri uri) {
|
||||
ContentResolver resolver = getApplicationContext().getContentResolver();
|
||||
if (uri == null || DISMISS_TO_VIEW_RATIO_LIMIT_URI.equals(uri)) {
|
||||
mDismissToViewRatioLimit = Settings.Global.getFloat(
|
||||
resolver, Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
|
||||
ChannelImpressions.DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT);
|
||||
}
|
||||
if (uri == null || STREAK_LIMIT_URI.equals(uri)) {
|
||||
mStreakLimit = Settings.Global.getInt(
|
||||
resolver, Settings.Global.BLOCKING_HELPER_STREAK_LIMIT,
|
||||
ChannelImpressions.DEFAULT_STREAK_LIMIT);
|
||||
}
|
||||
|
||||
// Update all existing channel impression objects with any new limits/thresholds.
|
||||
synchronized (mkeyToImpressions) {
|
||||
for (ChannelImpressions channelImpressions: mkeyToImpressions.values()) {
|
||||
channelImpressions.updateThresholds(mDismissToViewRatioLimit, mStreakLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Copyright (C) 2018 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.ext.services.notification;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.util.KeyValueListParser;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Observes the settings for {@link Assistant}.
|
||||
*/
|
||||
final class AssistantSettings extends ContentObserver {
|
||||
public static Factory FACTORY = AssistantSettings::createAndRegister;
|
||||
private static final boolean DEFAULT_GENERATE_REPLIES = true;
|
||||
private static final boolean DEFAULT_GENERATE_ACTIONS = true;
|
||||
private static final int DEFAULT_NEW_INTERRUPTION_MODEL_INT = 1;
|
||||
|
||||
private static final Uri STREAK_LIMIT_URI =
|
||||
Settings.Global.getUriFor(Settings.Global.BLOCKING_HELPER_STREAK_LIMIT);
|
||||
private static final Uri DISMISS_TO_VIEW_RATIO_LIMIT_URI =
|
||||
Settings.Global.getUriFor(
|
||||
Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT);
|
||||
private static final Uri SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS_URI =
|
||||
Settings.Global.getUriFor(
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS);
|
||||
private static final Uri NOTIFICATION_NEW_INTERRUPTION_MODEL_URI =
|
||||
Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL);
|
||||
|
||||
private static final String KEY_GENERATE_REPLIES = "generate_replies";
|
||||
private static final String KEY_GENERATE_ACTIONS = "generate_actions";
|
||||
|
||||
private final KeyValueListParser mParser = new KeyValueListParser(',');
|
||||
private final ContentResolver mResolver;
|
||||
private final int mUserId;
|
||||
|
||||
@VisibleForTesting
|
||||
protected final Runnable mOnUpdateRunnable;
|
||||
|
||||
// Actuall configuration settings.
|
||||
float mDismissToViewRatioLimit;
|
||||
int mStreakLimit;
|
||||
boolean mGenerateReplies = DEFAULT_GENERATE_REPLIES;
|
||||
boolean mGenerateActions = DEFAULT_GENERATE_ACTIONS;
|
||||
boolean mNewInterruptionModel;
|
||||
|
||||
private AssistantSettings(Handler handler, ContentResolver resolver, int userId,
|
||||
Runnable onUpdateRunnable) {
|
||||
super(handler);
|
||||
mResolver = resolver;
|
||||
mUserId = userId;
|
||||
mOnUpdateRunnable = onUpdateRunnable;
|
||||
}
|
||||
|
||||
private static AssistantSettings createAndRegister(
|
||||
Handler handler, ContentResolver resolver, int userId, Runnable onUpdateRunnable) {
|
||||
AssistantSettings assistantSettings =
|
||||
new AssistantSettings(handler, resolver, userId, onUpdateRunnable);
|
||||
assistantSettings.register();
|
||||
return assistantSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance but doesn't register it as an observer.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
protected static AssistantSettings createForTesting(
|
||||
Handler handler, ContentResolver resolver, int userId, Runnable onUpdateRunnable) {
|
||||
return new AssistantSettings(handler, resolver, userId, onUpdateRunnable);
|
||||
}
|
||||
|
||||
private void register() {
|
||||
mResolver.registerContentObserver(
|
||||
DISMISS_TO_VIEW_RATIO_LIMIT_URI, false, this, mUserId);
|
||||
mResolver.registerContentObserver(STREAK_LIMIT_URI, false, this, mUserId);
|
||||
mResolver.registerContentObserver(
|
||||
SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS_URI, false, this, mUserId);
|
||||
|
||||
// Update all uris on creation.
|
||||
update(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChange(boolean selfChange, Uri uri) {
|
||||
update(uri);
|
||||
}
|
||||
|
||||
private void update(Uri uri) {
|
||||
if (uri == null || DISMISS_TO_VIEW_RATIO_LIMIT_URI.equals(uri)) {
|
||||
mDismissToViewRatioLimit = Settings.Global.getFloat(
|
||||
mResolver, Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
|
||||
ChannelImpressions.DEFAULT_DISMISS_TO_VIEW_RATIO_LIMIT);
|
||||
}
|
||||
if (uri == null || STREAK_LIMIT_URI.equals(uri)) {
|
||||
mStreakLimit = Settings.Global.getInt(
|
||||
mResolver, Settings.Global.BLOCKING_HELPER_STREAK_LIMIT,
|
||||
ChannelImpressions.DEFAULT_STREAK_LIMIT);
|
||||
}
|
||||
if (uri == null || SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS_URI.equals(uri)) {
|
||||
mParser.setString(
|
||||
Settings.Global.getString(mResolver,
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS));
|
||||
mGenerateReplies =
|
||||
mParser.getBoolean(KEY_GENERATE_REPLIES, DEFAULT_GENERATE_REPLIES);
|
||||
mGenerateActions =
|
||||
mParser.getBoolean(KEY_GENERATE_ACTIONS, DEFAULT_GENERATE_ACTIONS);
|
||||
}
|
||||
if (uri == null || NOTIFICATION_NEW_INTERRUPTION_MODEL_URI.equals(uri)) {
|
||||
int mNewInterruptionModelInt = Settings.Secure.getInt(
|
||||
mResolver, Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL,
|
||||
DEFAULT_NEW_INTERRUPTION_MODEL_INT);
|
||||
mNewInterruptionModel = mNewInterruptionModelInt == 1;
|
||||
}
|
||||
|
||||
mOnUpdateRunnable.run();
|
||||
}
|
||||
|
||||
public interface Factory {
|
||||
AssistantSettings createAndRegister(Handler handler, ContentResolver resolver, int userId,
|
||||
Runnable onUpdateRunnable);
|
||||
}
|
||||
}
|
||||
@@ -69,8 +69,11 @@ public class SmartActionsHelper {
|
||||
* from notification text / message, we can replace most of the code here by consuming that API.
|
||||
*/
|
||||
@NonNull
|
||||
ArrayList<Notification.Action> suggestActions(
|
||||
@Nullable Context context, @NonNull NotificationEntry entry) {
|
||||
ArrayList<Notification.Action> suggestActions(@Nullable Context context,
|
||||
@NonNull NotificationEntry entry, @NonNull AssistantSettings settings) {
|
||||
if (!settings.mGenerateActions) {
|
||||
return EMPTY_ACTION_LIST;
|
||||
}
|
||||
if (!isEligibleForActionAdjustment(entry)) {
|
||||
return EMPTY_ACTION_LIST;
|
||||
}
|
||||
@@ -86,8 +89,11 @@ public class SmartActionsHelper {
|
||||
getMostSalientActionText(entry.getNotification()), MAX_SMART_ACTIONS);
|
||||
}
|
||||
|
||||
ArrayList<CharSequence> suggestReplies(
|
||||
@Nullable Context context, @NonNull NotificationEntry entry) {
|
||||
ArrayList<CharSequence> suggestReplies(@Nullable Context context,
|
||||
@NonNull NotificationEntry entry, @NonNull AssistantSettings settings) {
|
||||
if (!settings.mGenerateReplies) {
|
||||
return EMPTY_REPLY_LIST;
|
||||
}
|
||||
if (!isEligibleForReplyAdjustment(entry)) {
|
||||
return EMPTY_REPLY_LIST;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Copyright (C) 2018 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.ext.services.notification;
|
||||
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.provider.Settings;
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.testing.TestableContext;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AssistantSettingsTest {
|
||||
private static final int USER_ID = 5;
|
||||
|
||||
@Rule
|
||||
public final TestableContext mContext =
|
||||
new TestableContext(InstrumentationRegistry.getContext(), null);
|
||||
|
||||
@Mock Runnable mOnUpdateRunnable;
|
||||
|
||||
private ContentResolver mResolver;
|
||||
private AssistantSettings mAssistantSettings;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mResolver = mContext.getContentResolver();
|
||||
Handler handler = new Handler(Looper.getMainLooper());
|
||||
|
||||
// To bypass real calls to global settings values, set the Settings values here.
|
||||
Settings.Global.putFloat(mResolver,
|
||||
Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT, 0.8f);
|
||||
Settings.Global.putInt(mResolver, Settings.Global.BLOCKING_HELPER_STREAK_LIMIT, 2);
|
||||
Settings.Global.putString(mResolver,
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
|
||||
"generate_replies=true,generate_actions=true");
|
||||
Settings.Secure.putInt(mResolver, Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL, 1);
|
||||
|
||||
mAssistantSettings = AssistantSettings.createForTesting(
|
||||
handler, mResolver, USER_ID, mOnUpdateRunnable);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateRepliesDisabled() {
|
||||
Settings.Global.putString(mResolver,
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS,
|
||||
"generate_replies=false");
|
||||
|
||||
// Notify for the settings values we updated.
|
||||
mAssistantSettings.onChange(false,
|
||||
Settings.Global.getUriFor(
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS));
|
||||
|
||||
|
||||
assertFalse(mAssistantSettings.mGenerateReplies);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateRepliesEnabled() {
|
||||
Settings.Global.putString(mResolver,
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS, "generate_replies=true");
|
||||
|
||||
// Notify for the settings values we updated.
|
||||
mAssistantSettings.onChange(false,
|
||||
Settings.Global.getUriFor(
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS));
|
||||
|
||||
assertTrue(mAssistantSettings.mGenerateReplies);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateActionsDisabled() {
|
||||
Settings.Global.putString(mResolver,
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS, "generate_actions=false");
|
||||
|
||||
// Notify for the settings values we updated.
|
||||
mAssistantSettings.onChange(false,
|
||||
Settings.Global.getUriFor(
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS));
|
||||
|
||||
assertTrue(mAssistantSettings.mGenerateReplies);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateActionsEnabled() {
|
||||
Settings.Global.putString(mResolver,
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS, "generate_actions=true");
|
||||
|
||||
// Notify for the settings values we updated.
|
||||
mAssistantSettings.onChange(false,
|
||||
Settings.Global.getUriFor(
|
||||
Settings.Global.SMART_SUGGESTIONS_IN_NOTIFICATIONS_FLAGS));
|
||||
|
||||
assertTrue(mAssistantSettings.mGenerateReplies);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStreakLimit() {
|
||||
verify(mOnUpdateRunnable, never()).run();
|
||||
|
||||
// Update settings value.
|
||||
int newStreakLimit = 4;
|
||||
Settings.Global.putInt(mResolver,
|
||||
Settings.Global.BLOCKING_HELPER_STREAK_LIMIT, newStreakLimit);
|
||||
|
||||
// Notify for the settings value we updated.
|
||||
mAssistantSettings.onChange(false, Settings.Global.getUriFor(
|
||||
Settings.Global.BLOCKING_HELPER_STREAK_LIMIT));
|
||||
|
||||
assertEquals(newStreakLimit, mAssistantSettings.mStreakLimit);
|
||||
verify(mOnUpdateRunnable).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDismissToViewRatioLimit() {
|
||||
verify(mOnUpdateRunnable, never()).run();
|
||||
|
||||
// Update settings value.
|
||||
float newDismissToViewRatioLimit = 3f;
|
||||
Settings.Global.putFloat(mResolver,
|
||||
Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
|
||||
newDismissToViewRatioLimit);
|
||||
|
||||
// Notify for the settings value we updated.
|
||||
mAssistantSettings.onChange(false, Settings.Global.getUriFor(
|
||||
Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT));
|
||||
|
||||
assertEquals(newDismissToViewRatioLimit, mAssistantSettings.mDismissToViewRatioLimit, 1e-6);
|
||||
verify(mOnUpdateRunnable).run();
|
||||
}
|
||||
}
|
||||
@@ -33,13 +33,11 @@ import android.app.Application;
|
||||
import android.app.INotificationManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.IPackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.service.notification.Adjustment;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.NotificationListenerService.Ranking;
|
||||
@@ -86,8 +84,7 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
|
||||
|
||||
@Mock INotificationManager mNoMan;
|
||||
@Mock AtomicFile mFile;
|
||||
@Mock
|
||||
IPackageManager mPackageManager;
|
||||
@Mock IPackageManager mPackageManager;
|
||||
|
||||
Assistant mAssistant;
|
||||
Application mApplication;
|
||||
@@ -108,20 +105,26 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
|
||||
new Intent("android.service.notification.NotificationAssistantService");
|
||||
startIntent.setPackage("android.ext.services");
|
||||
|
||||
// To bypass real calls to global settings values, set the Settings values here.
|
||||
Settings.Global.putFloat(mContext.getContentResolver(),
|
||||
Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT, 0.8f);
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.BLOCKING_HELPER_STREAK_LIMIT, 2);
|
||||
mApplication = (Application) InstrumentationRegistry.getInstrumentation().
|
||||
getTargetContext().getApplicationContext();
|
||||
// Force the test to use the correct application instead of trying to use a mock application
|
||||
setApplication(mApplication);
|
||||
bindService(startIntent);
|
||||
|
||||
setupService();
|
||||
mAssistant = getService();
|
||||
|
||||
// Override the AssistantSettings factory.
|
||||
mAssistant.mSettingsFactory = AssistantSettings::createForTesting;
|
||||
|
||||
bindService(startIntent);
|
||||
|
||||
mAssistant.mSettings.mDismissToViewRatioLimit = 0.8f;
|
||||
mAssistant.mSettings.mStreakLimit = 2;
|
||||
mAssistant.mSettings.mNewInterruptionModel = true;
|
||||
mAssistant.setNoMan(mNoMan);
|
||||
mAssistant.setFile(mFile);
|
||||
mAssistant.setPackageManager(mPackageManager);
|
||||
|
||||
ApplicationInfo info = mock(ApplicationInfo.class);
|
||||
when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt()))
|
||||
.thenReturn(info);
|
||||
@@ -408,6 +411,8 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
|
||||
mAssistant.writeXml(serializer);
|
||||
|
||||
Assistant assistant = new Assistant();
|
||||
// onCreate is not invoked, so settings won't be initialised, unless we do it here.
|
||||
assistant.mSettings = mAssistant.mSettings;
|
||||
assistant.readXml(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())));
|
||||
|
||||
assertEquals(ci1, assistant.getImpressions(key1));
|
||||
@@ -417,8 +422,6 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
|
||||
|
||||
@Test
|
||||
public void testSettingsProviderUpdate() {
|
||||
ContentResolver resolver = mApplication.getContentResolver();
|
||||
|
||||
// Set up channels
|
||||
String key = mAssistant.getKey("pkg1", 1, "channel1");
|
||||
ChannelImpressions ci = new ChannelImpressions();
|
||||
@@ -435,19 +438,11 @@ public class AssistantTest extends ServiceTestCase<Assistant> {
|
||||
assertEquals(false, ci.shouldTriggerBlock());
|
||||
|
||||
// Update settings values.
|
||||
float newDismissToViewRatioLimit = 0f;
|
||||
int newStreakLimit = 0;
|
||||
Settings.Global.putFloat(resolver,
|
||||
Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
|
||||
newDismissToViewRatioLimit);
|
||||
Settings.Global.putInt(resolver,
|
||||
Settings.Global.BLOCKING_HELPER_STREAK_LIMIT, newStreakLimit);
|
||||
mAssistant.mSettings.mDismissToViewRatioLimit = 0f;
|
||||
mAssistant.mSettings.mStreakLimit = 0;
|
||||
|
||||
// Notify for the settings values we updated.
|
||||
mAssistant.mSettingsObserver.onChange(false, Settings.Global.getUriFor(
|
||||
Settings.Global.BLOCKING_HELPER_STREAK_LIMIT));
|
||||
mAssistant.mSettingsObserver.onChange(false, Settings.Global.getUriFor(
|
||||
Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT));
|
||||
mAssistant.mSettings.mOnUpdateRunnable.run();
|
||||
|
||||
// With the new threshold, the blocking helper should be triggered.
|
||||
assertEquals(true, ci.shouldTriggerBlock());
|
||||
|
||||
Reference in New Issue
Block a user