Add experiment flag for maximum number of smart actions per notification

We here add an experiment flag to limit the number of smart actions
shown per notification (including turning all small actions off) from
the System UI.

Bug: 122506860
Test: atest SystemUITests
Test: call "adb shell settings put global
    smart_replies_in_notifications_flags enabled=true,max_num_actions=X" for
    different values of X and ensure the behaviour is correct.
Change-Id: I2759f4bc297386d20f3a6d1cb2975165e5c87c38
This commit is contained in:
Gustav Sennton
2019-01-16 14:27:25 +00:00
parent 9b23e4f42b
commit 4bf5ff5859
6 changed files with 107 additions and 0 deletions

View File

@@ -14120,6 +14120,7 @@ public final class Settings {
* edit_choices_before_sending (boolean)
* show_in_heads_up (boolean)
* min_num_system_generated_replies (int)
* max_num_actions (int)
* </pre>
* @see com.android.systemui.statusbar.policy.SmartReplyConstants
* @hide

View File

@@ -463,6 +463,10 @@
show none. -->
<integer name="config_smart_replies_in_notifications_min_num_system_generated_replies">0</integer>
<!-- Smart replies in notifications: Maximum number of smart actions to show in notifications.
-->
<integer name="config_smart_replies_in_notifications_max_num_actions">-1</integer>
<!-- Screenshot editing default activity. Must handle ACTION_EDIT image/png intents.
Blank sends the user to the Chooser first.
This name is in the ComponentName flattened format (package/class) -->

View File

@@ -47,6 +47,7 @@ public final class SmartReplyConstants extends ContentObserver {
"edit_choices_before_sending";
private static final String KEY_SHOW_IN_HEADS_UP = "show_in_heads_up";
private static final String KEY_MIN_NUM_REPLIES = "min_num_system_generated_replies";
private static final String KEY_MAX_NUM_ACTIONS = "max_num_actions";
private final boolean mDefaultEnabled;
private final boolean mDefaultRequiresP;
@@ -54,6 +55,7 @@ public final class SmartReplyConstants extends ContentObserver {
private final boolean mDefaultEditChoicesBeforeSending;
private final boolean mDefaultShowInHeadsUp;
private final int mDefaultMinNumSystemGeneratedReplies;
private final int mDefaultMaxNumActions;
private boolean mEnabled;
private boolean mRequiresTargetingP;
@@ -61,6 +63,7 @@ public final class SmartReplyConstants extends ContentObserver {
private boolean mEditChoicesBeforeSending;
private boolean mShowInHeadsUp;
private int mMinNumSystemGeneratedReplies;
private int mMaxNumActions;
private final Context mContext;
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -83,6 +86,8 @@ public final class SmartReplyConstants extends ContentObserver {
R.bool.config_smart_replies_in_notifications_show_in_heads_up);
mDefaultMinNumSystemGeneratedReplies = resources.getInteger(
R.integer.config_smart_replies_in_notifications_min_num_system_generated_replies);
mDefaultMaxNumActions = resources.getInteger(
R.integer.config_smart_replies_in_notifications_max_num_actions);
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS),
@@ -112,6 +117,7 @@ public final class SmartReplyConstants extends ContentObserver {
mShowInHeadsUp = mParser.getBoolean(KEY_SHOW_IN_HEADS_UP, mDefaultShowInHeadsUp);
mMinNumSystemGeneratedReplies =
mParser.getInt(KEY_MIN_NUM_REPLIES, mDefaultMinNumSystemGeneratedReplies);
mMaxNumActions = mParser.getInt(KEY_MAX_NUM_ACTIONS, mDefaultMaxNumActions);
}
}
@@ -170,4 +176,12 @@ public final class SmartReplyConstants extends ContentObserver {
public int getMinNumSystemGeneratedReplies() {
return mMinNumSystemGeneratedReplies;
}
/**
* Returns the maximum number smart actions to show in a notification, or -1 if there shouldn't
* be a limit.
*/
public int getMaxNumActions() {
return mMaxNumActions;
}
}

View File

@@ -372,8 +372,17 @@ public class SmartReplyView extends ViewGroup {
// reply button is added.
SmartSuggestionMeasures actionsMeasures = null;
final int maxNumActions = mConstants.getMaxNumActions();
int numShownActions = 0;
for (View child : smartSuggestions) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (maxNumActions != -1 // -1 means 'no limit'
&& lp.buttonType == SmartButtonType.ACTION
&& numShownActions >= maxNumActions) {
// We've reached the maximum number of actions, don't add another one!
continue;
}
child.setPadding(accumulatedMeasures.mButtonPaddingHorizontal, child.getPaddingTop(),
accumulatedMeasures.mButtonPaddingHorizontal, child.getPaddingBottom());
@@ -457,6 +466,9 @@ public class SmartReplyView extends ViewGroup {
lp.show = true;
displayedChildCount++;
if (lp.buttonType == SmartButtonType.ACTION) {
numShownActions++;
}
}
if (mSmartRepliesGeneratedByAssistant) {

View File

@@ -176,6 +176,19 @@ public class SmartReplyConstantsTest extends SysuiTestCase {
assertFalse(mConstants.getShowInHeadsUp());
}
@Test
public void testMaxNumActionsWithNoConfig() {
assertTrue(mConstants.isEnabled());
assertEquals(-1, mConstants.getMaxNumActions());
}
@Test
public void testMaxNumActionsSet() {
overrideSetting("enabled=true,max_num_actions=10");
triggerConstantsOnChange();
assertEquals(10, mConstants.getMaxNumActions());
}
private void overrideSetting(String flags) {
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS, flags);

View File

@@ -117,6 +117,7 @@ public class SmartReplyViewTest extends SysuiTestCase {
// Any number of replies are fine.
when(mConstants.getMinNumSystemGeneratedReplies()).thenReturn(0);
when(mConstants.getMaxSqueezeRemeasureAttempts()).thenReturn(3);
when(mConstants.getMaxNumActions()).thenReturn(-1);
final Resources res = mContext.getResources();
mSingleLinePaddingHorizontal = res.getDimensionPixelSize(
@@ -1027,4 +1028,66 @@ public class SmartReplyViewTest extends SysuiTestCase {
// smart actions
assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(1));
}
/**
* Test that we don't show more than the maximum number of actions declared in {@link
* SmartReplyConstants}.
*/
@Test
public void testMeasure_maxNumActions() {
when(mConstants.getMaxNumActions()).thenReturn(2);
String[] choices = new String[] {};
String[] actions = new String[] {"a1", "a2", "a3", "a4"};
// All replies should be displayed as single-line smart reply buttons.
ViewGroup expectedView = buildExpectedView(new String[] {},
1 /* lineCount */, createActions(new String[] {"a1", "a2"}));
expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
setSmartRepliesAndActions(choices, actions);
mView.measure(
MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
MeasureSpec.UNSPECIFIED);
assertEqualMeasures(expectedView, mView);
assertReplyButtonShownWithEqualMeasures(
expectedView.getChildAt(0), mView.getChildAt(0)); // a1
assertReplyButtonShownWithEqualMeasures(
expectedView.getChildAt(1), mView.getChildAt(1)); // a2
assertReplyButtonHidden(mView.getChildAt(2)); // a3
assertReplyButtonHidden(mView.getChildAt(3)); // a4
}
/**
* Test that setting maximum number of actions to -1 means there's no limit to number of actions
* to show.
*/
@Test
public void testMeasure_maxNumActions_noLimit() {
when(mConstants.getMaxNumActions()).thenReturn(-1);
String[] choices = new String[] {};
String[] actions = new String[] {"a1", "a2", "a3", "a4"};
// All replies should be displayed as single-line smart reply buttons.
ViewGroup expectedView = buildExpectedView(new String[] {},
1 /* lineCount */, createActions(new String[] {"a1", "a2", "a3", "a4"}));
expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
setSmartRepliesAndActions(choices, actions);
mView.measure(
MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST),
MeasureSpec.UNSPECIFIED);
assertEqualMeasures(expectedView, mView);
assertReplyButtonShownWithEqualMeasures(
expectedView.getChildAt(0), mView.getChildAt(0)); // a1
assertReplyButtonShownWithEqualMeasures(
expectedView.getChildAt(1), mView.getChildAt(1)); // a2
assertReplyButtonShownWithEqualMeasures(
expectedView.getChildAt(2), mView.getChildAt(2)); // a3
assertReplyButtonShownWithEqualMeasures(
expectedView.getChildAt(3), mView.getChildAt(3)); // a4
}
}