Skip to content

Commit

Permalink
Merge pull request #1628 from Adyen/feature/custom-tabs-styling
Browse files Browse the repository at this point in the history
Support changing the custom tabs toolbar and navigation colors
  • Loading branch information
jreij authored May 15, 2024
2 parents 10cc7e4 + 4b348a9 commit 6aa503b
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 90 deletions.
5 changes: 4 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
[//]: # (This file will be used for the release notes on GitHub when publishing.)
[//]: # (Types of changes: `Breaking changes` `New` `Added` `Improved` `Changed` `Deprecated` `Removed` `Fixed`)
[//]: # (Example:)
[//]: # (## Added)
[//]: # (## New)
[//]: # ( - New payment method)
[//]: # (## Changed)
[//]: # ( - DropIn service's package changed from `com.adyen.dropin` to `com.adyen.dropin.services`)
[//]: # (## Deprecated)
[//]: # ( - Configurations public constructor are deprecated, please use each Configuration's builder to make a Configuration object)

## New
- For external redirects launched in a Custom Tab, you can now [customize the toolbar and navigation bar colors](docs/UI_CUSTOMIZATION.md#styling-custom-tabs) of the Custom Tab.

## Fixed
- Fixed various memory leaks.
- Drop-in no longer overrides the log level in case of debug builds.
Expand Down
21 changes: 20 additions & 1 deletion docs/UI_CUSTOMIZATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The base theme can be extended and overridden. You can also use a custom base th
- [Customizing a specific view](#customizing-a-specific-view)
- [Adding dark mode support](#adding-dark-mode-support)
- [Overriding string resources](#overriding-string-resources)
- [Styling Custom Tabs](#styling-custom-tabs)

## Customizing the base theme

Expand Down Expand Up @@ -125,4 +126,22 @@ CheckoutConfiguration(shopperLocale, environment, clientKey) {
}
```

If you cannot find a certain string in the code base, then check whether it is coming from the Checkout API. Make sure you localize these strings by sending the correct [shopperLocale](https://docs.adyen.com/api-explorer/Checkout/latest/post/sessions#request-shopperLocale).
If you cannot find a certain string in the code base, then check whether it is coming from the Checkout API. Make sure you localize these strings by sending the correct [shopperLocale](https://docs.adyen.com/api-explorer/Checkout/latest/post/sessions#request-shopperLocale).

## Styling Custom Tabs

We use Custom Tabs to launch any external redirects that cannot be handled inside the SDK or by another installed native app.
By default we set the toolbar color to match the `colorPrimary` attribute defined in your theme.
To change this color to a different value than your `colorPrimary` attribute, you can override the `AdyenCheckout.CustomTabs` style in your `styles.xml`:

```xml
<style name="AdyenCheckout.CustomTabs">
<item name="adyenCustomTabsToolbarColor">@color/someColor1</item>
<!--
Additional colors that can be overridden as well
<item name="adyenCustomTabsSecondaryToolbarColor">@color/someColor2</item>
<item name="adyenCustomTabsNavigationBarColor">@color/someColor3</item>
<item name="adyenCustomTabsNavigationBarDividerColor">@color/someColor4</item>
-->
</style>
```
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@ import android.net.Uri
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.annotation.RestrictTo
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
import com.adyen.checkout.core.AdyenLogLevel
import com.adyen.checkout.core.exception.CheckoutException
import com.adyen.checkout.core.exception.ComponentException
import com.adyen.checkout.core.internal.util.adyenLog
import com.adyen.checkout.ui.core.internal.util.ThemeUtil
import com.adyen.checkout.ui.core.internal.util.CustomTabsLauncher
import org.json.JSONException
import org.json.JSONObject
import java.lang.ref.WeakReference
Expand Down Expand Up @@ -153,25 +151,15 @@ class DefaultRedirectHandler : RedirectHandler {

private fun launchWithCustomTabs(context: Context, uri: Uri): Boolean {
// open in custom tabs if there's no native app for the target uri
val defaultColors = CustomTabColorSchemeParams.Builder()
.setToolbarColor(ThemeUtil.getPrimaryThemeColor(context))
.build()

@Suppress("SwallowedException")
return try {
CustomTabsIntent.Builder()
.setShowTitle(true)
.setDefaultColorSchemeParams(defaultColors)
.build()
.launchUrl(context, uri)
val isLaunched = CustomTabsLauncher.launchCustomTab(context, uri)
if (isLaunched) {
adyenLog(AdyenLogLevel.DEBUG) { "launchWithCustomTabs - redirect successful with custom tabs" }
true
} catch (e: ActivityNotFoundException) {
} else {
adyenLog(AdyenLogLevel.DEBUG) {
"launchWithCustomTabs - device doesn't support custom tabs or chrome is disabled"
}
false
}
return isLaunched
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 Adyen N.V.
*
* This file is open source and available under the MIT license. See the LICENSE file for more info.
*
* Created by josephj on 6/5/2024.
*/

package com.adyen.checkout.ui.core.internal.util

import android.content.ActivityNotFoundException
import android.content.Context
import android.net.Uri
import androidx.annotation.AttrRes
import androidx.annotation.RestrictTo
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
import com.adyen.checkout.ui.core.R

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
object CustomTabsLauncher {
fun launchCustomTab(context: Context, uri: Uri): Boolean {
@Suppress("SwallowedException")
return try {
CustomTabsIntent.Builder()
.setShowTitle(true)
.setDefaultColorSchemeParams(getDefaultColorSchemeParams(context))
.build()
.launchUrl(context, uri)
true
} catch (e: ActivityNotFoundException) {
false
}
}

private fun getDefaultColorSchemeParams(context: Context): CustomTabColorSchemeParams {
val toolbarColor = context.getColorOrNull(R.attr.adyenCustomTabsToolbarColor)
val secondaryToolbarColor = context.getColorOrNull(R.attr.adyenCustomTabsSecondaryToolbarColor)
val navigationBarColor = context.getColorOrNull(R.attr.adyenCustomTabsNavigationBarColor)
val navigationBarDividerColor = context.getColorOrNull(R.attr.adyenCustomTabsNavigationBarDividerColor)

return CustomTabColorSchemeParams.Builder().apply {
toolbarColor?.let { setToolbarColor(it) }
secondaryToolbarColor?.let { setSecondaryToolbarColor(it) }
navigationBarColor?.let { setNavigationBarColor(it) }
navigationBarDividerColor?.let { setNavigationBarDividerColor(it) }
}.build()
}

private fun Context.getColorOrNull(@AttrRes attribute: Int): Int? {
val typedArray = obtainStyledAttributes(R.style.AdyenCheckout_CustomTabs, intArrayOf(attribute))
val color = typedArray.getColor(0, -1).takeIf { it != -1 }
typedArray.recycle()
return color
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import android.content.Intent
import android.net.Uri
import android.os.Build
import androidx.annotation.RestrictTo
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
import com.adyen.checkout.core.AdyenLogLevel
import com.adyen.checkout.core.internal.util.adyenLog

Expand Down Expand Up @@ -63,23 +61,13 @@ class PdfOpener {

private fun openInCustomTab(context: Context, uri: Uri): Boolean {
// open in custom tabs if there's no native app for the target uri
val defaultColors = CustomTabColorSchemeParams.Builder()
.setToolbarColor(ThemeUtil.getPrimaryThemeColor(context))
.build()

return try {
CustomTabsIntent.Builder()
.setShowTitle(true)
.setDefaultColorSchemeParams(defaultColors)
.build()
.launchUrl(context, uri)

val isLaunched = CustomTabsLauncher.launchCustomTab(context, uri)
if (isLaunched) {
adyenLog(AdyenLogLevel.DEBUG) { "Successfully opened pdf in custom tab" }
true
} catch (e: ActivityNotFoundException) {
adyenLog(AdyenLogLevel.DEBUG, e) { "Couldn't open pdf in custom tab" }
false
} else {
adyenLog(AdyenLogLevel.DEBUG) { "Couldn't open pdf in custom tab" }
}
return isLaunched
}

private fun openInBrowser(context: Context, uri: Uri): Boolean {
Expand Down

This file was deleted.

14 changes: 9 additions & 5 deletions ui-core/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2019 Adyen N.V.
~
~ This file is open source and available under the MIT license. See the LICENSE file for more info.
Expand All @@ -9,8 +8,13 @@

<resources>
<declare-styleable name="RoundCornerImageView">
<attr name="adyenRadius" format="dimension"/>
<attr name="adyenStrokeWidth" format="dimension"/>
<attr name="adyenStrokeColor" format="color"/>
<attr name="adyenRadius" format="dimension" />
<attr name="adyenStrokeWidth" format="dimension" />
<attr name="adyenStrokeColor" format="color" />
</declare-styleable>

<attr name="adyenCustomTabsToolbarColor" format="color" />
<attr name="adyenCustomTabsSecondaryToolbarColor" format="color" />
<attr name="adyenCustomTabsNavigationBarColor" format="color" />
<attr name="adyenCustomTabsNavigationBarDividerColor" format="color" />
</resources>
10 changes: 10 additions & 0 deletions ui-core/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
Expand Up @@ -387,4 +387,14 @@
<item name="android:text">@string/checkout_address_lookup_enter_manually</item>
<item name="android:gravity">center_vertical</item>
</style>

<style name="AdyenCheckout.CustomTabs">
<item name="adyenCustomTabsToolbarColor">?attr/colorPrimary</item>
<!--
Additional colors that can be overridden as well
<item name="adyenCustomTabsSecondaryToolbarColor">someColor1</item>
<item name="adyenCustomTabsNavigationBarColor">someColor2</item>
<item name="adyenCustomTabsNavigationBarDividerColor">someColor3</item>
-->
</style>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,12 @@

package com.adyen.checkout.voucher.internal.ui.view

import android.content.ActivityNotFoundException
import android.content.Context
import android.net.Uri
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import androidx.annotation.StringRes
import androidx.browser.customtabs.CustomTabColorSchemeParams
import androidx.browser.customtabs.CustomTabsIntent
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.doOnNextLayout
import androidx.core.view.isVisible
Expand All @@ -31,7 +28,7 @@ import com.adyen.checkout.core.internal.util.adyenLog
import com.adyen.checkout.ui.core.internal.ui.ComponentView
import com.adyen.checkout.ui.core.internal.ui.LogoSize
import com.adyen.checkout.ui.core.internal.ui.loadLogo
import com.adyen.checkout.ui.core.internal.util.ThemeUtil
import com.adyen.checkout.ui.core.internal.util.CustomTabsLauncher
import com.adyen.checkout.ui.core.internal.util.formatFullStringWithHyperLink
import com.adyen.checkout.ui.core.internal.util.setLocalizedTextFromStyle
import com.adyen.checkout.voucher.R
Expand Down Expand Up @@ -206,20 +203,11 @@ internal class FullVoucherView @JvmOverloads constructor(
}

private fun onReadInstructionsClicked(url: String) {
val defaultColors = CustomTabColorSchemeParams.Builder()
.setToolbarColor(ThemeUtil.getPrimaryThemeColor(context))
.build()

try {
CustomTabsIntent.Builder()
.setShowTitle(true)
.setDefaultColorSchemeParams(defaultColors)
.build()
.launchUrl(context, Uri.parse(url))

val isLaunched = CustomTabsLauncher.launchCustomTab(context, Uri.parse(url))
if (isLaunched) {
adyenLog(AdyenLogLevel.DEBUG) { "Successfully opened instructions in custom tab" }
} catch (e: ActivityNotFoundException) {
adyenLog(AdyenLogLevel.DEBUG, e) { "Couldn't open instructions in custom tab" }
} else {
adyenLog(AdyenLogLevel.ERROR) { "Couldn't open instructions in custom tab" }
}
}

Expand Down

0 comments on commit 6aa503b

Please sign in to comment.