Snap for 13204655 from 336fb77956cd0bd0136684ad8195f640947f7c19 to 25Q2-release
Change-Id: I626c278a66123d608ec00c686fbed7e4b09dd369
diff --git a/main/java/com/google/android/setupcompat/template/FooterBarMixin.java b/main/java/com/google/android/setupcompat/template/FooterBarMixin.java
index 0c58a24..7afa16d 100644
--- a/main/java/com/google/android/setupcompat/template/FooterBarMixin.java
+++ b/main/java/com/google/android/setupcompat/template/FooterBarMixin.java
@@ -87,11 +87,14 @@
@VisibleForTesting public LinearLayout buttonContainer;
private FooterButton primaryButton;
private FooterButton secondaryButton;
+ private FooterButton tertiaryButton;
private LoggingObserver loggingObserver;
@IdRes private int primaryButtonId;
@IdRes private int secondaryButtonId;
+ @IdRes private int tertiaryButtonId;
@VisibleForTesting public FooterButtonPartnerConfig primaryButtonPartnerConfigForTesting;
@VisibleForTesting public FooterButtonPartnerConfig secondaryButtonPartnerConfigForTesting;
+ @VisibleForTesting public FooterButtonPartnerConfig tertiaryButtonPartnerConfigForTesting;
private int footerBarPaddingTop;
private int footerBarPaddingBottom;
@@ -168,7 +171,9 @@
autoSetButtonBarVisibility();
if (PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
- setButtonWidthForExpressiveStyle();
+ // Re-layout the buttons when visibility changes, especially when tertiary button is
+ // enabled to avoid the button layout is not correct.
+ repopulateButtons();
}
}
}
@@ -701,6 +706,125 @@
}
/**
+ * Sets tertiary button for footer. The button will use the primary button style by default.
+ *
+ * <p>NOTE: This method is only available when glif expressive is ENABLED and primary and
+ * secondary buttons are both VISIBLE.
+ *
+ * @param footerButton The {@link FooterButton} to set as the tertiary button.
+ */
+ @MainThread
+ public void setTertiaryButton(FooterButton footerButton) {
+ setTertiaryButton(footerButton, /* usePrimaryStyle= */ true);
+ }
+
+ /**
+ * Sets tertiary button for footer. Allow to use the primary or secondary button style.
+ *
+ * <p>NOTE: This method is only available when glif expressive is ENABLED and primary and
+ * secondary buttons are both VISIBLE.
+ *
+ * @param footerButton The {@link FooterButton} to set as the tertiary button.
+ * @param usePrimaryStyle Whether to use the primary or secondary button style.
+ */
+ @MainThread
+ public void setTertiaryButton(FooterButton footerButton, boolean usePrimaryStyle) {
+ if (!PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
+ LOG.atDebug("Cannot set tertiary button when glif expressive is not enabled.");
+ return;
+ }
+
+ ensureOnMainThread("setTertiaryButton");
+ ensureFooterInflated();
+
+ // Setup button partner config
+ FooterButtonPartnerConfig footerButtonPartnerConfig =
+ new FooterButtonPartnerConfig.Builder(footerButton)
+ .setPartnerTheme(
+ getPartnerTheme(
+ footerButton,
+ /* defaultPartnerTheme= */ R.style.SucGlifMaterialButton_Primary,
+ /* buttonBackgroundColorConfig= */ usePrimaryStyle
+ ? PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_BG_COLOR
+ : PartnerConfig.CONFIG_FOOTER_SECONDARY_BUTTON_BG_COLOR))
+ .setButtonBackgroundConfig(
+ usePrimaryStyle
+ ? PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_BG_COLOR
+ : PartnerConfig.CONFIG_FOOTER_SECONDARY_BUTTON_BG_COLOR)
+ .setButtonDisableAlphaConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_DISABLED_ALPHA)
+ .setButtonDisableBackgroundConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_DISABLED_BG_COLOR)
+ .setButtonDisableTextColorConfig(
+ usePrimaryStyle
+ ? PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_DISABLED_TEXT_COLOR
+ : PartnerConfig.CONFIG_FOOTER_SECONDARY_BUTTON_DISABLED_TEXT_COLOR)
+ .setButtonIconConfig(getDrawablePartnerConfig(footerButton.getButtonType()))
+ .setButtonRadiusConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_RADIUS)
+ .setButtonRippleColorAlphaConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_RIPPLE_COLOR_ALPHA)
+ .setTextColorConfig(
+ usePrimaryStyle
+ ? PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_TEXT_COLOR
+ : PartnerConfig.CONFIG_FOOTER_SECONDARY_BUTTON_TEXT_COLOR)
+ .setMarginStartConfig(PartnerConfig.CONFIG_FOOTER_PRIMARY_BUTTON_MARGIN_START)
+ .setTextSizeConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_TEXT_SIZE)
+ .setButtonMinHeight(PartnerConfig.CONFIG_FOOTER_BUTTON_MIN_HEIGHT)
+ .setTextTypeFaceConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_FONT_FAMILY)
+ .setTextWeightConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_FONT_WEIGHT)
+ .setTextStyleConfig(PartnerConfig.CONFIG_FOOTER_BUTTON_TEXT_STYLE)
+ .build();
+
+ IFooterActionButton buttonImpl = inflateButton(footerButton, footerButtonPartnerConfig);
+ // Update information for tertiary button. Need to update as long as the button inflated.
+ Button button = (Button) buttonImpl;
+ tertiaryButtonId = button.getId();
+ if (buttonImpl instanceof MaterialFooterActionButton materialFooterActionButton) {
+ materialFooterActionButton.setPrimaryButtonStyle(usePrimaryStyle);
+ }
+ tertiaryButton = footerButton;
+ tertiaryButtonPartnerConfigForTesting = footerButtonPartnerConfig;
+ onFooterButtonInflated(button, footerBarPrimaryBackgroundColor);
+ onFooterButtonApplyPartnerResource(button, footerButtonPartnerConfig);
+
+ boolean enabled = tertiaryButton.isEnabled();
+ if (usePrimaryStyle) {
+ updateTextColorForButton(
+ button,
+ enabled,
+ enabled
+ ? footerBarPrimaryButtonEnabledTextColor
+ : footerBarPrimaryButtonDisabledTextColor);
+ } else {
+ updateTextColorForButton(
+ button,
+ enabled,
+ enabled
+ ? footerBarSecondaryButtonEnabledTextColor
+ : footerBarSecondaryButtonDisabledTextColor);
+ }
+
+ // Make sure the position of buttons are correctly and prevent tertiary button create twice or
+ // more.
+ repopulateButtons();
+
+ // The requestFocus() is only working after activity onResume.
+ button.post(
+ () -> {
+ if (KeyboardHelper.isKeyboardFocusEnhancementEnabled(context)
+ && KeyboardHelper.hasHardwareKeyboard(context)) {
+ button.requestFocus();
+ }
+ });
+ }
+
+ @Nullable
+ public Button getTertiaryButtonView() {
+ if (!PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
+ LOG.atDebug("Cannot get tertiary button when glif expressive is not enabled.");
+ return null;
+ }
+ return buttonContainer == null ? null : buttonContainer.findViewById(tertiaryButtonId);
+ }
+
+ /**
* Corrects the order of footer buttons after the button has been inflated to the view hierarchy.
* Subclasses can implement this method to modify the order of footer buttons as necessary.
*/
@@ -708,6 +832,7 @@
LinearLayout buttonContainer = ensureFooterInflated();
Button tempPrimaryButton = getPrimaryButtonView();
Button tempSecondaryButton = getSecondaryButtonView();
+ Button tempTertiaryButton = getTertiaryButtonView();
buttonContainer.removeAllViews();
boolean isEvenlyWeightedButtons = isFooterButtonsEvenlyWeighted();
@@ -737,6 +862,15 @@
if (!isFooterButtonAlignedEnd() && !PartnerConfigHelper.isGlifExpressiveEnabled(context)) {
addSpace();
}
+
+ if (PartnerConfigHelper.isGlifExpressiveEnabled(context) && tempTertiaryButton != null) {
+ if (isBothButtons(tempPrimaryButton, tempSecondaryButton)) {
+ buttonContainer.addView(tempTertiaryButton);
+ } else {
+ LOG.atDebug("Cannot add tertiary button when primary or secondary button is null.");
+ }
+ }
+
if (tempPrimaryButton != null) {
buttonContainer.addView(tempPrimaryButton);
}
@@ -789,6 +923,7 @@
int containerWidth = buttonContainer.getMeasuredWidth();
Button primaryButton = getPrimaryButtonView();
Button secondaryButton = getSecondaryButtonView();
+ Button tertiaryButton = getTertiaryButtonView();
if (isTwoPaneLayout()) {
containerWidth = containerWidth / 2;
buttonContainer.setGravity(Gravity.END);
@@ -801,7 +936,11 @@
- footerBarPaddingEnd
- footerBarButtonMiddleSpacing;
int maxButtonWidth = availableFooterBarWidth / 2;
- if (isBothButtons(primaryButton, secondaryButton)) {
+
+ if (isThreeButtons(primaryButton, secondaryButton, tertiaryButton)) {
+ forceStackButtonInThreeButtonMode(
+ primaryButton, secondaryButton, tertiaryButton, availableFooterBarWidth);
+ } else if (isBothButtons(primaryButton, secondaryButton)) {
LayoutParams primaryLayoutParams = (LayoutParams) primaryButton.getLayoutParams();
LayoutParams secondaryLayoutParams = (LayoutParams) secondaryButton.getLayoutParams();
boolean isButtonStacked =
@@ -938,10 +1077,47 @@
return false;
}
+ // TODO: b/400831621 - Consider to combine this method to #stackButtonIfTextOverFlow
+ private void forceStackButtonInThreeButtonMode(
+ Button primaryButton,
+ Button secondaryButton,
+ Button tertiaryButton,
+ int availableFooterBarWidth) {
+
+ LayoutParams primaryLayoutParams = (LayoutParams) primaryButton.getLayoutParams();
+ LayoutParams secondaryLayoutParams = (LayoutParams) secondaryButton.getLayoutParams();
+ LayoutParams tertiaryLayoutParams = (LayoutParams) tertiaryButton.getLayoutParams();
+
+ if (buttonContainer instanceof ButtonBarLayout buttonBarLayout) {
+ buttonBarLayout.setStackedButtonForExpressiveStyle(true);
+ int stackButtonMiddleSpacing = footerBarButtonMiddleSpacing / 2;
+ secondaryLayoutParams.width = availableFooterBarWidth;
+ secondaryLayoutParams.topMargin = stackButtonMiddleSpacing;
+ secondaryButton.setLayoutParams(secondaryLayoutParams);
+
+ tertiaryLayoutParams.width = availableFooterBarWidth;
+ tertiaryLayoutParams.topMargin = stackButtonMiddleSpacing;
+ tertiaryLayoutParams.bottomMargin = stackButtonMiddleSpacing;
+ tertiaryButton.setLayoutParams(tertiaryLayoutParams);
+
+ primaryLayoutParams.width = availableFooterBarWidth;
+ primaryLayoutParams.bottomMargin = stackButtonMiddleSpacing;
+ primaryButton.setLayoutParams(primaryLayoutParams);
+ }
+ }
+
private boolean isTwoPaneLayout() {
return context.getResources().getBoolean(R.bool.sucTwoPaneLayoutStyle);
}
+ private boolean isThreeButtons(
+ Button primaryButton, Button secondaryButton, Button tertiaryButton) {
+ boolean isTertiaryButtonVisible =
+ tertiaryButton != null && tertiaryButton.getVisibility() == View.VISIBLE;
+ LOG.atDebug("isTertiaryButtonVisible=" + isTertiaryButtonVisible);
+ return isTertiaryButtonVisible && isBothButtons(primaryButton, secondaryButton);
+ }
+
private boolean isBothButtons(Button primaryButton, Button secondaryButton) {
boolean isPrimaryVisible =
primaryButton != null && primaryButton.getVisibility() == View.VISIBLE;