# VGSCardNumberEditText

A user interface element for entering and modifying the credit card number of different card brands. When you define this input field, you could specify a few attributes that are preferable for this control. For example, `app:numberDivider` or `app:cardBrandIconGravity` which are unique for this field type.

<figure><img src="https://688d347d6ff7e3e8e92ea9d3--vgs-docs.netlify.app/docs/vgs_theme/static/img/vgs-collect-android-card-number.gif" alt=""><figcaption></figcaption></figure>

### Validation <a href="#validation" id="validation"></a>

By default, all fields have their specific validations that allow for getting more accurate user data. In case a developer needs to change or override the default validation, we give such a possibility.

Note: Default behavior validates only already recognized card numbers that meet the requirements. [Read more](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/test-data) about already existing brands.

There are several ways to change the basic validation flow:

* [**XML attributes**](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/android-sdk/determining-validation-rules): `app:enableValidation`, `app:validationRule`;
* [**Validation builder**](https://docs.verygoodsecurity.com/vault/developer-tools/vgs-collect/determining-validation-rules#validation-builder)

#### Determining validation rules <a href="#determining-validation-rules" id="determining-validation-rules"></a>

{% tabs %}
{% tab title="XML" %}

<pre class="language-xml"><code class="lang-xml"><strong>&#x3C;com.verygoodsecurity.vgscollect.widget.VGSCardNumberEditText
</strong>    android:id="@+id/cardNumberField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:validationRule="acceptUnknown"/>
</code></pre>

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val cardNumberField = findViewById<VGSCardNumberEditText>(R.id.cardNumberField)
val rule : PaymentCardNumberRule = PaymentCardNumberRule.ValidationBuilder()
    .setAlgorithm(ChecksumAlgorithm.LUHN)
    .setAllowableMinLength(15)
    .build()

cardNumberField.setRule(rule)
```

{% endtab %}

{% tab title="Java" %}

```java
VGSCardNumberEditText cardNumberField = findViewById(R.id.cardNumberField);
PaymentCardNumberRule rule = new PaymentCardNumberRule.ValidationBuilder()
    .setAlgorithm(ChecksumAlgorithm.LUHN)
    .setAllowableMinLength(15)
    .build();

cardNumberField.setRule(rule);
```

{% endtab %}
{% endtabs %}

### Override valid card brands

By default, popular card brands like Visa, MasterCard, American Express, etc. will be detected by the SDK. You can override this behavior and specify which brands should be detected. You can do it using `setValidCardBrands(vararg cardBrand: CardBrand)` function of `VGSCardNumberEditText`.

You can specify your custom `CardBrand` or use the extension function to map default cards `CardType.VISA.toCardBrand()`

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
val customBrandParams = BrandParams(
    "### ### ### ###",
    ChecksumAlgorithm.LUHN,
    arrayOf(4, 10, 12),
    arrayOf(3, 5)
)
val customBrand = CardBrand(
    "^878",
    "<CUSTOM_BRAND>",
    R.drawable.ic_cards,
    customBrandParams
)

cardNumberField.setValidCardBrands(customBrand, CardType.VISA.toCardBrand())
```

{% endtab %}

{% tab title="Java" %}

```java
BrandParams customBrandParams = new BrandParams(
    "### ### ### ###",
    ChecksumAlgorithm.LUHN,
    new Integer[]{4, 10, 12},
    new Integer[]{3, 5}
);
CardBrand customBrand = new CardBrand(
    "^777",
    "<CUSTOM_BRAND>",
    R.drawable.ic_cards,
    customBrandParams
);

cardNumberField.setValidCardBrands(customBrand, CardTypeKt.toCardBrand(CardType.VISA));
```

{% endtab %}
{% endtabs %}

#### Card brand icon visibility<br>

By default, the payment card brand icon is always visible. VGS Collect SDK gives the ability to change the default behavior and show the brand icon according to the content inside the field. The system makes a decision on how it should adjust the brand visibility based on the `app:brandIconVisibility` attribute.

The `app:brandIconVisibility` attribute could be configured with one of the following parameters:

* **always**: Preview icon is visible all the time.
* **ifDetected**: Preview icon is visible only when the card brand is detected.
* **hasContent**: Preview icon is visible when some input exists.
* **never**: Preview icon is never visible.

```xml
<com.verygoodsecurity.vgscollect.widget.VGSCardNumberEditText
    android:id="@+id/cardNumberField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:fieldName="cardNumber"
    app:brandIconVisibility="ifDetected"/>
```

### Custom card brand <a href="#custom-card-brand" id="custom-card-brand"></a>

By default, `VGSCollect` supports only the default list of payment card brands. For more accurate detection, you can create a local brand or just a new custom brand that we don't support yet.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
val cardNumberField = findViewById<VGSCardNumberEditText>(R.id.cardNumberField)
val brandParams = BrandParams(
    "###### ##### ####",
    ChecksumAlgorithm.LUHN,
    arrayOf(16),
    arrayOf(3)
)

val brand = CardBrand(
    "^878",
    "VGS Brand",
    CardType.MAESTRO.resId,
    brandParams
)
cardNumberField.addCardBrand(brand);
```

{% endtab %}

{% tab title="Java" %}

```java
VGSCardNumberEditText cardNumberField = findViewById(R.id.cardNumberField);
BrandParams brandParams = new BrandParams(
    "###### ##### ####",
    ChecksumAlgorithm.LUHN,
    arrayOf(16),
    arrayOf(3)
);

CardBrand brand = new CardBrand(
    "^878",
    "VGS Brand",
    CardType.MAESTRO.resId,
    brandParams
);
cardNumberField.addCardBrand(brand);
```

{% endtab %}
{% endtabs %}

### Define the number group divider <a href="#define-number-group-divider" id="define-number-group-divider"></a>

To set the symbol that will divide groups of digits in the card number, add `app:numberDivider` to your field's declaration in XML. By default, the widget doesn't have any pre-configured divider and all numbers will be a single line.

{% tabs %}
{% tab title="XML" %}

```xml
<com.verygoodsecurity.vgscollect.widget.VGSCardNumberEditText
    android:id="@+id/cardNumberField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:numberDivider="-"/>
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val cardNumberField = findViewById<VGSCardNumberEditText>(R.id.cardNumberField)
cardNumberField.setDivider('-')
```

{% endtab %}

{% tab title="Java" %}

```java
VGSCardNumberEditText cardNumberField = findViewById(R.id.cardNumberField);
cardNumberField.setDivider('-');
```

{% endtab %}
{% endtabs %}

Also, **VGS Collect SDK** gives the ability to change or remove the divider symbol before it has been submitted to the Proxy.

To set the symbol that will divide groups of digits in the card number, add `app:outputNumberDivider` to your field's declaration in XML. By default, **Collect SDK** removes the divider from the card number.

{% hint style="info" %}
`app:numberDivider` and `app:outputNumberDivider` should contain only one character.
{% endhint %}

{% tabs %}
{% tab title="XML" %}

```xml
<com.verygoodsecurity.vgscollect.widget.VGSCardNumberEditText
    android:id="@+id/cardNumberField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:outputNumberDivider="-"/>
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val cardNumberField = findViewById<VGSCardNumberEditText>(R.id.cardNumberField)
cardNumberField.setOutputDivider('-')
```

{% endtab %}

{% tab title="Java" %}

```java
VGSCardNumberEditText cardNumberField = findViewById(R.id.cardNumberField);
cardNumberField.setOutputDivider('-');
```

{% endtab %}
{% endtabs %}

### Override card brand icon <a href="#override-card-brand-icon" id="override-card-brand-icon"></a>

VGS Collect offers a list of default card brand resources for preview and UI identification of the current ones by your end-user. If none of the prebuilt resources meet your needs, you can override your own resource. Creating your own resource gives you precise control over the appearance of the element on the screen.

You can use `CardIconAdapter` class to create custom Drawables as a preview image for the `VGSCardNumberEditText`.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
val cardNumberField = findViewById<VGSCardNumberEditText>(R.id.cardNumberField)

val adapter = object : CardIconAdapter(this) {
  override fun getIcon(cardType: CardType, name: String?, resId: Int, r: Rect): Drawable {
      return if(cardType == CardType.VISA) {
          getDrawable(R.drawable.ic_visa_light)
      } else {
          super.getIcon(cardType, name, resId, r)
      }
  }
}

cardNumberField.setCardIconAdapter(adapter)
```

{% endtab %}

{% tab title="Java" %}

```java
VGSCardNumberEditText cardNumberField = findViewById(R.id.cardNumberField);

CardIconAdapter adapter = new CardIconAdapter(this) {
    @Override
    protected Drawable getIcon(@NotNull CardType cardType, @Nullable String name, int resId, @NotNull Rect r) {
        if(cardType == CardType.VISA) {
            return getDrawable(R.drawable.ic_visa_light);
        } else {
            return super.getIcon(cardType, name, resId, r);
        }
    }
};
cardNumberField.setCardIconAdapter(adapter);
```

{% endtab %}
{% endtabs %}

### Set brand icon gravity <a href="#set-brand-icon-gravity" id="set-brand-icon-gravity"></a>

Specifies how to align the icon with the view’s x-axis. To specify gravity programmatically, you could use the Android `Gravity` class. By default, gravity is in `end` position.

{% hint style="info" %}
At the current moment, we support only `start` and `end` position.
{% endhint %}

{% tabs %}
{% tab title="XML" %}

```xml
<com.verygoodsecurity.vgscollect.widget.VGSCardNumberEditText
    android:id="@+id/cardNumberField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardBrandIconGravity="end"/>
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val cardNumberField = findViewById<VGSCardNumberEditText>(R.id.cardNumberField)
cardNumberField.setCardBrandIconGravity(Gravity.END)
```

{% endtab %}

{% tab title="Java" %}

```java
VGSCardNumberEditText cardNumberField = findViewById(R.id.cardNumberField);
cardNumberField.setCardBrandIconGravity(Gravity.END);
```

{% endtab %}
{% endtabs %}

### Override card brand number mask <a href="#override-card-brand-number-mask" id="override-card-brand-number-mask"></a>

If you don't want to create a completely new custom card brand, but want just to change the preview number mask, VGSCollect allows you to override card number masks from already defined brands.

{% tabs %}
{% tab title="Kotlin" %}

```kotlin
val cardNumberField = findViewById<VGSCardNumberEditText>(R.id.cardNumberField)

val adapter = object : CardMaskAdapter() {

    override fun getMask(
        cardType: CardType,
        name: String,
        bin: String,
        mask: String
    ): String = when (cardType) {
        CardType.VISA_ELECTRON -> "###### ###### ####"
        else -> super.getMask(cardType, name, bin, mask)
    }
}

cardNumberField.setCardIconAdapter(adapter)
```

{% endtab %}

{% tab title="Java" %}

```java
VGSCardNumberEditText cardNumberField = findViewById(R.id.cardNumberField);

CardMaskAdapter adapter = new CardMaskAdapter() {

    @NotNull
    @Override
    protected String getMask(@NotNull CardType cardType, @NotNull String name, @NotNull String bin, @NotNull String mask) {
        if (cardType == CardType.VISA_ELECTRON) {
            return "###### ###### ####";
        }
        return super.getMask(cardType, name, bin, mask);
    }
};

cardNumberField.setCardIconAdapter(adapter);
```

{% endtab %}
{% endtabs %}

### Set field name <a href="#set-field-name" id="set-field-name"></a>

Sets the text to be used for data transfer to the VGS proxy. Usually, it is similar to field-name in JSON path in your inbound route filters. It is highly important to specify this parameter because the VGSCollect module relies on it too.

{% hint style="warning" %}
You must set up `fieldName` In another way, the input field will be ignored by VGSCollect.
{% endhint %}

{% tabs %}
{% tab title="XML" %}

```xml
<com.verygoodsecurity.vgscollect.widget.VGSCardNumberEditText
    android:id="@+id/cardNumberField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:fieldName="card_number"/>
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val cardNumberField = findViewById<VGSCardNumberEditText>(R.id.cardNumberField)
cardNumberField.setFieldName("card_number")
```

{% endtab %}

{% tab title="Java" %}

```java
VGSCardNumberEditText cardNumberField = findViewById(R.id.cardNumberField);
cardNumberField.setFieldName("card_number");
```

{% endtab %}
{% endtabs %}

### Define the required state <a href="#define-the-required-state" id="define-the-required-state"></a>

Specifies whether the text inside the input field is required to be filled.

When `app:isRequired` set as `true`  thre input data should be valid only. If `app:isRequired` set as `false`, the input data will be valid in case the field is empty. Otherwise input data should be valid.

By default, a widget is required.

{% tabs %}
{% tab title="XML" %}

```xml
<com.verygoodsecurity.vgscollect.widget.VGSCardNumberEditText
    android:id="@+id/cardNumberField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:isRequired="false"/>
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val cardNumberField = findViewById<VGSCardNumberEditText>(R.id.cardNumberField)
cardNumberField.isRequired(false)
```

{% endtab %}

{% tab title="Java" %}

```java
VGSCardNumberEditText cardNumberField = findViewById(R.id.cardNumberField);
cardNumberField.isRequired(false);
```

{% endtab %}
{% endtabs %}

### Specify the keyboard type <a href="#specify-the-keyboard-type" id="specify-the-keyboard-type"></a>

You should always declare the input method for these input fields by adding the `app:inputType` to tell the system to display the appropriate soft input method (such as an on-screen keyboard).

For example, if you'd like an input method for entering a phone number, specify `app:inputType` as `number` or `numberPassword`&#x20;

{% tabs %}
{% tab title="XML" %}

```xml
<com.verygoodsecurity.vgscollect.widget.VGSCardNumberEditText
    android:id="@+id/cardNumberField"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:inputType="number"/>
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val cardNumberField = findViewById<VGSCardNumberEditText>(R.id.cardNumberField)
cardNumberField.setInputType(InputType.TYPE_CLASS_NUMBER)
```

{% endtab %}

{% tab title="Java" %}

```java
VGSCardNumberEditText cardNumberField = findViewById(R.id.cardNumberField);
cardNumberField.setInputType(InputType.TYPE_CLASS_NUMBER);
```

{% endtab %}
{% endtabs %}

### Additional XML attributes <a href="#additional-xml-attributes" id="additional-xml-attributes"></a>

<table data-header-hidden><thead><tr><th>Attribute</th><th>Description</th></tr></thead><tbody><tr><td><pre><code>app:enableValidation
</code></pre></td><td>Set the validation state of this view. Set true if this view has enabled validation, it's false otherwise.</td></tr><tr><td><pre><code>app:validationRule
</code></pre></td><td>Adds a default behavior rule for the validation field.</td></tr><tr><td><pre><code>app:numberDivider
</code></pre></td><td>Sets the symbol that will divide groups of digits in the card number.</td></tr><tr><td><pre><code>app:outputNumberDivider
</code></pre></td><td>Sets the symbol that will divide groups of digits before submit to the Proxy.</td></tr><tr><td><pre><code>app:cardBrandIconGravity
</code></pre></td><td><p>Specifies how to align the icon by the view’s x-axis. To specify gravity programmatically you could use android</p><pre><code>Gravity
</code></pre><p>Plain textclass.</p></td></tr><tr><td><pre><code>app:inputType
</code></pre></td><td>Set the type of the content with a constant as defined for input field.</td></tr><tr><td><pre><code>app:imeOptions
</code></pre></td><td><p>Specify soft input method for the input method action. By default, the system uses a</p><pre><code>actionNext
</code></pre><p>Plain textor</p><pre><code>actionDone
</code></pre><p>Plain textaction.</p></td></tr><tr><td><pre><code>app:fontFamily
</code></pre></td><td>Default font family (named by string or as a font resource reference) for the text.</td></tr><tr><td><pre><code>app:fieldName
</code></pre></td><td>Sets the text to be used for data transfer to VGS proxy. Usually, it is similar to field-name in JSON path in your inbound route filters.</td></tr><tr><td><pre><code>app:isRequired
</code></pre></td><td>Specifies whether the text inside input field is required to be filled.</td></tr><tr><td><pre><code>app:textSize
</code></pre><p></p></td><td>Size of the text.</td></tr><tr><td><pre><code>app:ellipsize
</code></pre></td><td>If set, causes words that are longer than the view is wide to be ellipsized instead of broken in the middle.</td></tr><tr><td><pre><code>app:ellipsize
</code></pre></td><td>If set, causes words that are longer than the view is wide to be ellipsized instead of broken in the middle.</td></tr><tr><td><pre><code>app:text
</code></pre></td><td>Text to display.</td></tr><tr><td><pre><code>app:textColor
</code></pre></td><td>Text color.</td></tr><tr><td><pre><code>app:maxLines
</code></pre></td><td>Makes the View be at most this many lines tall.</td></tr><tr><td><pre><code>app:minLines
</code></pre></td><td>Makes the View be at least this many lines tall.</td></tr><tr><td><pre><code>app:textStyle
</code></pre></td><td>Style (normal, bold, italic) for text.</td></tr><tr><td><pre><code>app:cursorVisible
</code></pre></td><td>Makes the cursor visible (the default) or invisible.</td></tr><tr><td><pre><code>app:gravity
</code></pre></td><td>Specifies how to align the text by the view’s x- or y-axis when the text is smaller than the view.</td></tr><tr><td><pre><code>app:scrollHorizontally
</code></pre></td><td>When the text is allowed to be wider than the view (and therefore can be scrolled horizontally).</td></tr><tr><td><pre><code>app:hint
</code></pre></td><td>Hint text to display when the text is empty.</td></tr><tr><td><pre><code>app:brandIconVisibility
</code></pre></td><td>Specifies visibility for card brand preview icon.</td></tr></tbody></table>
