diff --git a/auth0/src/main/java/com/auth0/android/provider/CustomTabsOptions.java b/auth0/src/main/java/com/auth0/android/provider/CustomTabsOptions.java index 57339ae63..765eed204 100644 --- a/auth0/src/main/java/com/auth0/android/provider/CustomTabsOptions.java +++ b/auth0/src/main/java/com/auth0/android/provider/CustomTabsOptions.java @@ -7,18 +7,20 @@ import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; + import androidx.annotation.ColorRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.browser.customtabs.CustomTabColorSchemeParams; import androidx.browser.customtabs.CustomTabsIntent; import androidx.browser.customtabs.CustomTabsSession; -import androidx.browser.trusted.TrustedWebActivityIntent; import androidx.browser.trusted.TrustedWebActivityIntentBuilder; import androidx.core.content.ContextCompat; import com.auth0.android.authentication.AuthenticationException; +import java.util.List; + /** * Holder for Custom Tabs customization options. Use {@link CustomTabsOptions#newBuilder()} to begin. */ @@ -29,10 +31,14 @@ public class CustomTabsOptions implements Parcelable { private final int toolbarColor; private final BrowserPicker browserPicker; - private CustomTabsOptions(boolean showTitle, @ColorRes int toolbarColor, @NonNull BrowserPicker browserPicker) { + @Nullable + private final List disabledCustomTabsPackages; + + private CustomTabsOptions(boolean showTitle, @ColorRes int toolbarColor, @NonNull BrowserPicker browserPicker, @Nullable List disabledCustomTabsPackages) { this.showTitle = showTitle; this.toolbarColor = toolbarColor; this.browserPicker = browserPicker; + this.disabledCustomTabsPackages = disabledCustomTabsPackages; } @Nullable @@ -44,6 +50,16 @@ boolean hasCompatibleBrowser(@NonNull PackageManager pm) { return getPreferredPackage(pm) != null; } + /** + * Returns whether the browser preferred package has custom tab disabled or not. + * + * @param preferredPackage the preferred browser package name. + * @return whether the browser preferred package has custom tab disabled or not. + */ + boolean isDisabledCustomTabBrowser(@NonNull String preferredPackage) { + return disabledCustomTabsPackages != null && disabledCustomTabsPackages.contains(preferredPackage); + } + /** * Create a new CustomTabsOptions.Builder instance. * @@ -57,6 +73,12 @@ public static Builder newBuilder() { @SuppressLint("ResourceType") Intent toIntent(@NonNull Context context, @Nullable CustomTabsSession session) { + String preferredPackage = this.getPreferredPackage(context.getPackageManager()); + + if (preferredPackage != null && this.isDisabledCustomTabBrowser(preferredPackage)) { + return new Intent(Intent.ACTION_VIEW); + } + final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(session) .setShowTitle(showTitle) .setShareState(CustomTabsIntent.SHARE_STATE_OFF); @@ -85,6 +107,7 @@ protected CustomTabsOptions(@NonNull Parcel in) { showTitle = in.readByte() != 0; toolbarColor = in.readInt(); browserPicker = in.readParcelable(BrowserPicker.class.getClassLoader()); + disabledCustomTabsPackages = in.createStringArrayList(); } @Override @@ -92,6 +115,7 @@ public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeByte((byte) (showTitle ? 1 : 0)); dest.writeInt(toolbarColor); dest.writeParcelable(browserPicker, flags); + dest.writeStringList(disabledCustomTabsPackages); } @Override @@ -120,10 +144,14 @@ public static class Builder { @NonNull private BrowserPicker browserPicker; + @Nullable + private List disabledCustomTabsPackages; + Builder() { this.showTitle = false; this.toolbarColor = 0; this.browserPicker = BrowserPicker.newBuilder().build(); + this.disabledCustomTabsPackages = null; } /** @@ -171,6 +199,19 @@ public Builder withBrowserPicker(@NonNull BrowserPicker browserPicker) { return this; } + /** + * Define a list of browser packages that disables the launching of authentication on custom tabs. + * The authentication url will launch on the preferred package external browser. + * + * @param disabledCustomTabsPackages list of browser packages. + * @return the current builder instance + */ + @NonNull + public Builder withDisabledCustomTabsPackages(List disabledCustomTabsPackages) { + this.disabledCustomTabsPackages = disabledCustomTabsPackages; + return this; + } + /** * Create a new CustomTabsOptions instance with the customization settings. * @@ -178,7 +219,7 @@ public Builder withBrowserPicker(@NonNull BrowserPicker browserPicker) { */ @NonNull public CustomTabsOptions build() { - return new CustomTabsOptions(showTitle, toolbarColor, browserPicker); + return new CustomTabsOptions(showTitle, toolbarColor, browserPicker, disabledCustomTabsPackages); } } diff --git a/auth0/src/test/java/com/auth0/android/provider/CustomTabsOptionsTest.java b/auth0/src/test/java/com/auth0/android/provider/CustomTabsOptionsTest.java index 2537f3e27..c4f03efb4 100644 --- a/auth0/src/test/java/com/auth0/android/provider/CustomTabsOptionsTest.java +++ b/auth0/src/test/java/com/auth0/android/provider/CustomTabsOptionsTest.java @@ -14,12 +14,16 @@ import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.notNullValue; import static org.hamcrest.core.IsNull.nullValue; +import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; @@ -174,4 +178,50 @@ public void shouldSetBrowserPicker() { String preferredPackageNow = parceledOptions.getPreferredPackage(activity.getPackageManager()); assertThat(preferredPackageNow, is("com.auth0.browser")); } + + @Test + public void shouldSetDisabledCustomTabPackages() { + Activity activity = spy(Robolectric.setupActivity(Activity.class)); + BrowserPickerTest.setupBrowserContext(activity, Collections.singletonList("com.auth0.browser"), null, null); + BrowserPicker browserPicker = BrowserPicker.newBuilder().build(); + + CustomTabsOptions options = CustomTabsOptions.newBuilder() + .withBrowserPicker(browserPicker) + .withDisabledCustomTabsPackages(List.of("com.auth0.browser")) + .withToolbarColor(android.R.color.black) + .build(); + assertThat(options, is(notNullValue())); + + Intent intentNoExtras = options.toIntent(activity, null); + + assertThat(intentNoExtras, is(notNullValue())); + assertThat(intentNoExtras.getExtras(), is(nullValue())); + assertEquals(intentNoExtras.getAction(), "android.intent.action.VIEW"); + + Parcel parcel = Parcel.obtain(); + options.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + CustomTabsOptions parceledOptions = CustomTabsOptions.CREATOR.createFromParcel(parcel); + assertThat(parceledOptions, is(notNullValue())); + + Intent parceledIntent = parceledOptions.toIntent(activity, null); + assertThat(parceledIntent, is(notNullValue())); + assertThat(parceledIntent.getExtras(), is(nullValue())); + assertEquals(parceledIntent.getAction(), "android.intent.action.VIEW"); + + BrowserPickerTest.setupBrowserContext(activity, Collections.singletonList("com.another.browser"), null, null); + BrowserPicker browserPicker2 = BrowserPicker.newBuilder().build(); + + CustomTabsOptions options2 = CustomTabsOptions.newBuilder() + .withBrowserPicker(browserPicker2) + .withDisabledCustomTabsPackages(List.of("com.auth0.browser")) + .withToolbarColor(android.R.color.black) + .build(); + + Intent intentWithToolbarExtra = options2.toIntent(activity, null); + assertThat(intentWithToolbarExtra, is(notNullValue())); + assertThat(intentWithToolbarExtra.hasExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR), is(true)); + int resolvedColor = ContextCompat.getColor(activity, android.R.color.black); + assertThat(intentWithToolbarExtra.getIntExtra(CustomTabsIntent.EXTRA_TOOLBAR_COLOR, 0), is(resolvedColor)); + } } \ No newline at end of file