Loading packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +47 −11 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import java.text.BreakIterator; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.PriorityQueue; Loading Loading @@ -294,6 +295,9 @@ public class SmartReplyView extends ViewGroup { // TODO(b/119010281): handle accessibility // Mark this as an Action button final LayoutParams lp = (LayoutParams) button.getLayoutParams(); lp.buttonType = SmartButtonType.ACTION; return button; } Loading Loading @@ -330,18 +334,26 @@ public class SmartReplyView extends ViewGroup { int displayedChildCount = 0; int buttonPaddingHorizontal = mSingleLineButtonPaddingHorizontal; final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); // Set up a list of suggestions where actions come before replies. Note that the Buttons // themselves have already been added to the view hierarchy in an order such that Smart // Replies are shown before Smart Actions. The order of the list below determines which // suggestions will be shown at all - only the first X elements are shown (where X depends // on how much space each suggestion button needs). List<View> smartActions = filterActionsOrReplies(SmartButtonType.ACTION); List<View> smartReplies = filterActionsOrReplies(SmartButtonType.REPLY); List<View> smartSuggestions = new ArrayList<>(smartActions); smartSuggestions.addAll(smartReplies); List<View> coveredSuggestions = new ArrayList<>(); for (View child : smartSuggestions) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (child.getVisibility() != View.VISIBLE || !(child instanceof Button)) { continue; } child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(), buttonPaddingHorizontal, child.getPaddingBottom()); child.measure(MEASURE_SPEC_ANY_LENGTH, heightMeasureSpec); coveredSuggestions.add(child); final int lineCount = ((Button) child).getLineCount(); if (lineCount < 1 || lineCount > 2) { // If smart reply has no text, or more than two lines, then don't show it. Loading Loading @@ -395,7 +407,8 @@ public class SmartReplyView extends ViewGroup { // Mark all buttons from the last squeezing round as "failed to squeeze", so // that they're re-measured without squeezing later. markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_FAILED, i); markButtonsWithPendingSqueezeStatusAs( LayoutParams.SQUEEZE_STATUS_FAILED, coveredSuggestions); // The current button doesn't fit, so there's no point in measuring further // buttons. Loading @@ -404,7 +417,8 @@ public class SmartReplyView extends ViewGroup { // The current button fits, so mark all squeezed buttons as "successfully squeezed" // to prevent them from being un-squeezed in a subsequent squeezing round. markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_SUCCESSFUL, i); markButtonsWithPendingSqueezeStatusAs( LayoutParams.SQUEEZE_STATUS_SUCCESSFUL, coveredSuggestions); } lp.show = true; Loading @@ -423,6 +437,22 @@ public class SmartReplyView extends ViewGroup { mPaddingTop + maxChildHeight + mPaddingBottom), heightMeasureSpec)); } private List<View> filterActionsOrReplies(SmartButtonType buttonType) { List<View> actions = new ArrayList<>(); final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (child.getVisibility() != View.VISIBLE || !(child instanceof Button)) { continue; } if (lp.buttonType == buttonType) { actions.add(child); } } return actions; } private void resetButtonsLayoutParams() { final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { Loading Loading @@ -593,9 +623,9 @@ public class SmartReplyView extends ViewGroup { } } private void markButtonsWithPendingSqueezeStatusAs(int squeezeStatus, int maxChildIndex) { for (int i = 0; i <= maxChildIndex; i++) { final View child = getChildAt(i); private void markButtonsWithPendingSqueezeStatusAs( int squeezeStatus, List<View> coveredChildren) { for (View child : coveredChildren) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (lp.squeezeStatus == LayoutParams.SQUEEZE_STATUS_PENDING) { lp.squeezeStatus = squeezeStatus; Loading Loading @@ -690,6 +720,11 @@ public class SmartReplyView extends ViewGroup { return mActivityStarter; } private enum SmartButtonType { REPLY, ACTION } @VisibleForTesting static class LayoutParams extends ViewGroup.LayoutParams { Loading @@ -715,6 +750,7 @@ public class SmartReplyView extends ViewGroup { private boolean show = false; private int squeezeStatus = SQUEEZE_STATUS_NONE; private SmartButtonType buttonType = SmartButtonType.REPLY; private LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java +51 −0 Original line number Diff line number Diff line Loading @@ -801,4 +801,55 @@ public class SmartReplyViewTest extends SysuiTestCase { assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1)); assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2)); } @Test public void testMeasure_choicesAndActionsPrioritizeActionsOnlyActions() { String[] choices = new String[] {"Reply"}; String[] actions = new String[] {"Looooooong actioooon", "second action", "third action"}; // All actions should be displayed as DOUBLE-line smart action buttons. ViewGroup expectedView = buildExpectedView(new String[0], 2, createActions(new String[] { "Looooooong \nactioooon", "second \naction", "third \naction"})); expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); setSmartRepliesAndActions(choices, actions); mView.measure( MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST), MeasureSpec.UNSPECIFIED); assertEqualMeasures(expectedView, mView); // smart replies assertReplyButtonHidden(mView.getChildAt(0)); // smart actions assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(1)); assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2)); assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3)); } @Test public void testMeasure_choicesAndActionsPrioritizeActions() { String[] choices = new String[] {"Short", "longer reply"}; String[] actions = new String[] {"Looooooong actioooon", "second action"}; // All actions should be displayed as DOUBLE-line smart action buttons. ViewGroup expectedView = buildExpectedView(new String[] {"Short"}, 2, createActions(new String[] {"Looooooong \nactioooon", "second \naction"})); expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); setSmartRepliesAndActions(choices, actions); mView.measure( MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST), MeasureSpec.UNSPECIFIED); Button firstAction = ((Button) mView.getChildAt(1)); assertEqualMeasures(expectedView, mView); // smart replies assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0)); assertReplyButtonHidden(mView.getChildAt(1)); // smart actions assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2)); assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3)); } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java +47 −11 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.phone.KeyguardDismissUtil; import java.text.BreakIterator; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.PriorityQueue; Loading Loading @@ -294,6 +295,9 @@ public class SmartReplyView extends ViewGroup { // TODO(b/119010281): handle accessibility // Mark this as an Action button final LayoutParams lp = (LayoutParams) button.getLayoutParams(); lp.buttonType = SmartButtonType.ACTION; return button; } Loading Loading @@ -330,18 +334,26 @@ public class SmartReplyView extends ViewGroup { int displayedChildCount = 0; int buttonPaddingHorizontal = mSingleLineButtonPaddingHorizontal; final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); // Set up a list of suggestions where actions come before replies. Note that the Buttons // themselves have already been added to the view hierarchy in an order such that Smart // Replies are shown before Smart Actions. The order of the list below determines which // suggestions will be shown at all - only the first X elements are shown (where X depends // on how much space each suggestion button needs). List<View> smartActions = filterActionsOrReplies(SmartButtonType.ACTION); List<View> smartReplies = filterActionsOrReplies(SmartButtonType.REPLY); List<View> smartSuggestions = new ArrayList<>(smartActions); smartSuggestions.addAll(smartReplies); List<View> coveredSuggestions = new ArrayList<>(); for (View child : smartSuggestions) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (child.getVisibility() != View.VISIBLE || !(child instanceof Button)) { continue; } child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(), buttonPaddingHorizontal, child.getPaddingBottom()); child.measure(MEASURE_SPEC_ANY_LENGTH, heightMeasureSpec); coveredSuggestions.add(child); final int lineCount = ((Button) child).getLineCount(); if (lineCount < 1 || lineCount > 2) { // If smart reply has no text, or more than two lines, then don't show it. Loading Loading @@ -395,7 +407,8 @@ public class SmartReplyView extends ViewGroup { // Mark all buttons from the last squeezing round as "failed to squeeze", so // that they're re-measured without squeezing later. markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_FAILED, i); markButtonsWithPendingSqueezeStatusAs( LayoutParams.SQUEEZE_STATUS_FAILED, coveredSuggestions); // The current button doesn't fit, so there's no point in measuring further // buttons. Loading @@ -404,7 +417,8 @@ public class SmartReplyView extends ViewGroup { // The current button fits, so mark all squeezed buttons as "successfully squeezed" // to prevent them from being un-squeezed in a subsequent squeezing round. markButtonsWithPendingSqueezeStatusAs(LayoutParams.SQUEEZE_STATUS_SUCCESSFUL, i); markButtonsWithPendingSqueezeStatusAs( LayoutParams.SQUEEZE_STATUS_SUCCESSFUL, coveredSuggestions); } lp.show = true; Loading @@ -423,6 +437,22 @@ public class SmartReplyView extends ViewGroup { mPaddingTop + maxChildHeight + mPaddingBottom), heightMeasureSpec)); } private List<View> filterActionsOrReplies(SmartButtonType buttonType) { List<View> actions = new ArrayList<>(); final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (child.getVisibility() != View.VISIBLE || !(child instanceof Button)) { continue; } if (lp.buttonType == buttonType) { actions.add(child); } } return actions; } private void resetButtonsLayoutParams() { final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { Loading Loading @@ -593,9 +623,9 @@ public class SmartReplyView extends ViewGroup { } } private void markButtonsWithPendingSqueezeStatusAs(int squeezeStatus, int maxChildIndex) { for (int i = 0; i <= maxChildIndex; i++) { final View child = getChildAt(i); private void markButtonsWithPendingSqueezeStatusAs( int squeezeStatus, List<View> coveredChildren) { for (View child : coveredChildren) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); if (lp.squeezeStatus == LayoutParams.SQUEEZE_STATUS_PENDING) { lp.squeezeStatus = squeezeStatus; Loading Loading @@ -690,6 +720,11 @@ public class SmartReplyView extends ViewGroup { return mActivityStarter; } private enum SmartButtonType { REPLY, ACTION } @VisibleForTesting static class LayoutParams extends ViewGroup.LayoutParams { Loading @@ -715,6 +750,7 @@ public class SmartReplyView extends ViewGroup { private boolean show = false; private int squeezeStatus = SQUEEZE_STATUS_NONE; private SmartButtonType buttonType = SmartButtonType.REPLY; private LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java +51 −0 Original line number Diff line number Diff line Loading @@ -801,4 +801,55 @@ public class SmartReplyViewTest extends SysuiTestCase { assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(1)); assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(2)); } @Test public void testMeasure_choicesAndActionsPrioritizeActionsOnlyActions() { String[] choices = new String[] {"Reply"}; String[] actions = new String[] {"Looooooong actioooon", "second action", "third action"}; // All actions should be displayed as DOUBLE-line smart action buttons. ViewGroup expectedView = buildExpectedView(new String[0], 2, createActions(new String[] { "Looooooong \nactioooon", "second \naction", "third \naction"})); expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); setSmartRepliesAndActions(choices, actions); mView.measure( MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST), MeasureSpec.UNSPECIFIED); assertEqualMeasures(expectedView, mView); // smart replies assertReplyButtonHidden(mView.getChildAt(0)); // smart actions assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(1)); assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2)); assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3)); } @Test public void testMeasure_choicesAndActionsPrioritizeActions() { String[] choices = new String[] {"Short", "longer reply"}; String[] actions = new String[] {"Looooooong actioooon", "second action"}; // All actions should be displayed as DOUBLE-line smart action buttons. ViewGroup expectedView = buildExpectedView(new String[] {"Short"}, 2, createActions(new String[] {"Looooooong \nactioooon", "second \naction"})); expectedView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); setSmartRepliesAndActions(choices, actions); mView.measure( MeasureSpec.makeMeasureSpec(expectedView.getMeasuredWidth(), MeasureSpec.AT_MOST), MeasureSpec.UNSPECIFIED); Button firstAction = ((Button) mView.getChildAt(1)); assertEqualMeasures(expectedView, mView); // smart replies assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(0), mView.getChildAt(0)); assertReplyButtonHidden(mView.getChildAt(1)); // smart actions assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(1), mView.getChildAt(2)); assertReplyButtonShownWithEqualMeasures(expectedView.getChildAt(2), mView.getChildAt(3)); } }