Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f749198d authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add exp flag for min number of sys gen smart replies in notifications"

parents c2aa6a91 a31f6aed
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -13933,6 +13933,7 @@ public final class Settings {
         * max_squeeze_remeasure_attempts    (int)
         * edit_choices_before_sending       (boolean)
         * show_in_heads_up                  (boolean)
         * min_num_system_generated_replies  (int)
         * </pre>
         * @see com.android.systemui.statusbar.policy.SmartReplyConstants
         * @hide
+5 −0
Original line number Diff line number Diff line
@@ -458,6 +458,11 @@
         heads-up notifications.  -->
    <bool name="config_smart_replies_in_notifications_show_in_heads_up">true</bool>

    <!-- Smart replies in notifications: Minimum number of system generated smart replies that
         should be shown in a notification. If we cannot show at least this many replies we instead
         show none. -->
    <integer name="config_smart_replies_in_notifications_min_num_system_generated_replies">0</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)  -->
+15 −0
Original line number Diff line number Diff line
@@ -46,18 +46,21 @@ public final class SmartReplyConstants extends ContentObserver {
    private static final String KEY_EDIT_CHOICES_BEFORE_SENDING =
            "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 final boolean mDefaultEnabled;
    private final boolean mDefaultRequiresP;
    private final int mDefaultMaxSqueezeRemeasureAttempts;
    private final boolean mDefaultEditChoicesBeforeSending;
    private final boolean mDefaultShowInHeadsUp;
    private final int mDefaultMinNumSystemGeneratedReplies;

    private boolean mEnabled;
    private boolean mRequiresTargetingP;
    private int mMaxSqueezeRemeasureAttempts;
    private boolean mEditChoicesBeforeSending;
    private boolean mShowInHeadsUp;
    private int mMinNumSystemGeneratedReplies;

    private final Context mContext;
    private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -78,6 +81,8 @@ public final class SmartReplyConstants extends ContentObserver {
                R.bool.config_smart_replies_in_notifications_edit_choices_before_sending);
        mDefaultShowInHeadsUp = resources.getBoolean(
                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);

        mContext.getContentResolver().registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS),
@@ -105,6 +110,8 @@ public final class SmartReplyConstants extends ContentObserver {
            mEditChoicesBeforeSending = mParser.getBoolean(
                    KEY_EDIT_CHOICES_BEFORE_SENDING, mDefaultEditChoicesBeforeSending);
            mShowInHeadsUp = mParser.getBoolean(KEY_SHOW_IN_HEADS_UP, mDefaultShowInHeadsUp);
            mMinNumSystemGeneratedReplies =
                    mParser.getInt(KEY_MIN_NUM_REPLIES, mDefaultMinNumSystemGeneratedReplies);
        }
    }

@@ -155,4 +162,12 @@ public final class SmartReplyConstants extends ContentObserver {
    public boolean getShowInHeadsUp() {
        return mShowInHeadsUp;
    }

    /**
     * Returns the minimum number of system generated replies to show in a notification.
     * If we cannot show at least this many system generated replies we should show none.
     */
    public int getMinNumSystemGeneratedReplies() {
        return mMinNumSystemGeneratedReplies;
    }
}
+104 −26
Original line number Diff line number Diff line
@@ -88,6 +88,12 @@ public class SmartReplyView extends ViewGroup {

    private View mSmartReplyContainer;

    /**
     * Whether the smart replies in this view were generated by the notification assistant. If not
     * they're provided by the app.
     */
    private boolean mSmartRepliesGeneratedByAssistant = false;

    @ColorInt
    private int mCurrentBackgroundColor;
    @ColorInt
@@ -202,6 +208,7 @@ public class SmartReplyView extends ViewGroup {
                            getContext(), this, i, smartReplies, smartReplyController, entry);
                    addView(replyButton);
                }
                this.mSmartRepliesGeneratedByAssistant = smartReplies.fromAssistant;
            }
        }
        reallocateCandidateButtonQueueForSqueezing();
@@ -344,10 +351,11 @@ public class SmartReplyView extends ViewGroup {
            mCandidateButtonQueueForSqueezing.clear();
        }

        int measuredWidth = mPaddingLeft + mPaddingRight;
        int maxChildHeight = 0;
        SmartSuggestionMeasures accumulatedMeasures = new SmartSuggestionMeasures(
                mPaddingLeft + mPaddingRight,
                0 /* maxChildHeight */,
                mSingleLineButtonPaddingHorizontal);
        int displayedChildCount = 0;
        int buttonPaddingHorizontal = mSingleLineButtonPaddingHorizontal;

        // 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
@@ -360,11 +368,15 @@ public class SmartReplyView extends ViewGroup {
        smartSuggestions.addAll(smartReplies);
        List<View> coveredSuggestions = new ArrayList<>();

        // SmartSuggestionMeasures for all action buttons, this will be filled in when the first
        // reply button is added.
        SmartSuggestionMeasures actionsMeasures = null;

        for (View child : smartSuggestions) {
            final LayoutParams lp = (LayoutParams) child.getLayoutParams();

            child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
                    buttonPaddingHorizontal, child.getPaddingBottom());
            child.setPadding(accumulatedMeasures.mButtonPaddingHorizontal, child.getPaddingTop(),
                    accumulatedMeasures.mButtonPaddingHorizontal, child.getPaddingBottom());
            child.measure(MEASURE_SPEC_ANY_LENGTH, heightMeasureSpec);

            coveredSuggestions.add(child);
@@ -380,45 +392,52 @@ public class SmartReplyView extends ViewGroup {
            }

            // Remember the current measurements in case the current button doesn't fit in.
            final int originalMaxChildHeight = maxChildHeight;
            final int originalMeasuredWidth = measuredWidth;
            final int originalButtonPaddingHorizontal = buttonPaddingHorizontal;
            SmartSuggestionMeasures originalMeasures = accumulatedMeasures.clone();
            if (actionsMeasures == null && lp.buttonType == SmartButtonType.REPLY) {
                // We've added all actions (we go through actions first), now add their
                // measurements.
                actionsMeasures = accumulatedMeasures.clone();
            }

            final int spacing = displayedChildCount == 0 ? 0 : mSpacing;
            final int childWidth = child.getMeasuredWidth();
            final int childHeight = child.getMeasuredHeight();
            measuredWidth += spacing + childWidth;
            maxChildHeight = Math.max(maxChildHeight, childHeight);
            accumulatedMeasures.mMeasuredWidth += spacing + childWidth;
            accumulatedMeasures.mMaxChildHeight =
                    Math.max(accumulatedMeasures.mMaxChildHeight, childHeight);

            // Do we need to increase the number of lines in smart reply buttons to two?
            final boolean increaseToTwoLines =
                    buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal
                            && (lineCount == 2 || measuredWidth > targetWidth);
                    (accumulatedMeasures.mButtonPaddingHorizontal
                            == mSingleLineButtonPaddingHorizontal)
                    && (lineCount == 2 || accumulatedMeasures.mMeasuredWidth > targetWidth);
            if (increaseToTwoLines) {
                measuredWidth += (displayedChildCount + 1) * mSingleToDoubleLineButtonWidthIncrease;
                buttonPaddingHorizontal = mDoubleLineButtonPaddingHorizontal;
                accumulatedMeasures.mMeasuredWidth +=
                        (displayedChildCount + 1) * mSingleToDoubleLineButtonWidthIncrease;
                accumulatedMeasures.mButtonPaddingHorizontal =
                        mDoubleLineButtonPaddingHorizontal;
            }

            // If the last button doesn't fit into the remaining width, try squeezing preceding
            // smart reply buttons.
            if (measuredWidth > targetWidth) {
            if (accumulatedMeasures.mMeasuredWidth > targetWidth) {
                // Keep squeezing preceding and current smart reply buttons until they all fit.
                while (measuredWidth > targetWidth
                while (accumulatedMeasures.mMeasuredWidth > targetWidth
                        && !mCandidateButtonQueueForSqueezing.isEmpty()) {
                    final Button candidate = mCandidateButtonQueueForSqueezing.poll();
                    final int squeezeReduction = squeezeButton(candidate, heightMeasureSpec);
                    if (squeezeReduction != SQUEEZE_FAILED) {
                        maxChildHeight = Math.max(maxChildHeight, candidate.getMeasuredHeight());
                        measuredWidth -= squeezeReduction;
                        accumulatedMeasures.mMaxChildHeight =
                                Math.max(accumulatedMeasures.mMaxChildHeight,
                                        candidate.getMeasuredHeight());
                        accumulatedMeasures.mMeasuredWidth -= squeezeReduction;
                    }
                }

                // If the current button still doesn't fit after squeezing all buttons, undo the
                // last squeezing round.
                if (measuredWidth > targetWidth) {
                    measuredWidth = originalMeasuredWidth;
                    maxChildHeight = originalMaxChildHeight;
                    buttonPaddingHorizontal = originalButtonPaddingHorizontal;
                if (accumulatedMeasures.mMeasuredWidth > targetWidth) {
                    accumulatedMeasures = originalMeasures;

                    // Mark all buttons from the last squeezing round as "failed to squeeze", so
                    // that they're re-measured without squeezing later.
@@ -440,16 +459,75 @@ public class SmartReplyView extends ViewGroup {
            displayedChildCount++;
        }

        if (mSmartRepliesGeneratedByAssistant) {
            if (!gotEnoughSmartReplies(smartReplies)) {
                // We don't have enough smart replies - hide all of them.
                for (View smartReplyButton : smartReplies) {
                    final LayoutParams lp = (LayoutParams) smartReplyButton.getLayoutParams();
                    lp.show = false;
                }
                // Reset our measures back to when we had only added actions (before adding
                // replies).
                accumulatedMeasures = actionsMeasures;
            }
        }

        // We're done squeezing buttons, so we can clear the priority queue.
        mCandidateButtonQueueForSqueezing.clear();

        // Finally, we need to re-measure some buttons.
        remeasureButtonsIfNecessary(buttonPaddingHorizontal, maxChildHeight);
        remeasureButtonsIfNecessary(accumulatedMeasures.mButtonPaddingHorizontal,
                                    accumulatedMeasures.mMaxChildHeight);

        setMeasuredDimension(
                resolveSize(Math.max(getSuggestedMinimumWidth(), measuredWidth), widthMeasureSpec),
                resolveSize(Math.max(getSuggestedMinimumHeight(),
                        mPaddingTop + maxChildHeight + mPaddingBottom), heightMeasureSpec));
                resolveSize(Math.max(getSuggestedMinimumWidth(),
                                     accumulatedMeasures.mMeasuredWidth),
                            widthMeasureSpec),
                resolveSize(Math.max(getSuggestedMinimumHeight(), mPaddingTop
                        + accumulatedMeasures.mMaxChildHeight + mPaddingBottom),
                            heightMeasureSpec));
    }

    /**
     * Fields we keep track of inside onMeasure() to correctly measure the SmartReplyView depending
     * on which suggestions are added.
     */
    private static class SmartSuggestionMeasures {
        int mMeasuredWidth = -1;
        int mMaxChildHeight = -1;
        int mButtonPaddingHorizontal = -1;

        SmartSuggestionMeasures(int measuredWidth, int maxChildHeight,
                int buttonPaddingHorizontal) {
            this.mMeasuredWidth = measuredWidth;
            this.mMaxChildHeight = maxChildHeight;
            this.mButtonPaddingHorizontal = buttonPaddingHorizontal;
        }

        public SmartSuggestionMeasures clone() {
            return new SmartSuggestionMeasures(
                    mMeasuredWidth, mMaxChildHeight, mButtonPaddingHorizontal);
        }
    }

    /**
     * Returns whether our notification contains at least N smart replies (or 0) where N is
     * determined by {@link SmartReplyConstants}.
     */
    private boolean gotEnoughSmartReplies(List<View> smartReplies) {
        int numShownReplies = 0;
        for (View smartReplyButton : smartReplies) {
            final LayoutParams lp = (LayoutParams) smartReplyButton.getLayoutParams();
            if (lp.show) {
                numShownReplies++;
            }
        }
        if (numShownReplies == 0
                || numShownReplies >= mConstants.getMinNumSystemGeneratedReplies()) {
            // We have enough replies, yay!
            return true;
        }
        return false;
    }

    private List<View> filterActionsOrReplies(SmartButtonType buttonType) {
+16 −0
Original line number Diff line number Diff line
@@ -55,6 +55,9 @@ public class SmartReplyConstantsTest extends SysuiTestCase {
        resources.addOverride(
                R.bool.config_smart_replies_in_notifications_edit_choices_before_sending, false);
        resources.addOverride(R.bool.config_smart_replies_in_notifications_show_in_heads_up, true);
        resources.addOverride(
                R.integer.config_smart_replies_in_notifications_min_num_system_generated_replies,
                2);
        mConstants = new SmartReplyConstants(Handler.createAsync(Looper.myLooper()), mContext);
    }

@@ -178,6 +181,19 @@ public class SmartReplyConstantsTest extends SysuiTestCase {
                Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS, flags);
    }

    @Test
    public void testGetMinNumSystemGeneratedRepliesWithNoConfig() {
        assertTrue(mConstants.isEnabled());
        assertEquals(2, mConstants.getMinNumSystemGeneratedReplies());
    }

    @Test
    public void testGetMinNumSystemGeneratedRepliesWithValidConfig() {
        overrideSetting("enabled=true,min_num_system_generated_replies=5");
        triggerConstantsOnChange();
        assertEquals(5, mConstants.getMinNumSystemGeneratedReplies());
    }

    private void triggerConstantsOnChange() {
        // Since Settings.Global is mocked in TestableContext, we need to manually trigger the
        // content observer.
Loading