Skip to content

Commit

Permalink
Use ThreadPool to launch browser for authentication (auth0#689)
Browse files Browse the repository at this point in the history
  • Loading branch information
poovamraj committed Sep 22, 2023
1 parent 3394283 commit 70d3d13
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public void launchUri(@NonNull final Uri uri, final boolean launchAsTwa, ThreadS
return;
}

new Thread(() -> {
threadSwitcher.backgroundThread(() -> {
try {
if (launchAsTwa) {
this.launchedAsTwa = true;
Expand All @@ -140,7 +140,7 @@ public void launchUri(@NonNull final Uri uri, final boolean launchAsTwa, ThreadS
"a0.browser_not_available", "Error launching browser for authentication", ex);
threadSwitcher.mainThread(() -> failureCallback.apply(e));
}
}).start();
});
}

private void launchAsDefault(Context context, Uri uri) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.net.Uri;
import android.os.Looper;

import androidx.annotation.NonNull;
import androidx.browser.customtabs.CustomTabsCallback;
import androidx.browser.customtabs.CustomTabsClient;
import androidx.browser.customtabs.CustomTabsIntent;
Expand All @@ -19,6 +20,7 @@
import androidx.browser.trusted.TrustedWebActivityIntentBuilder;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
Expand All @@ -40,9 +42,11 @@
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.Is.isA;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
Expand All @@ -53,7 +57,9 @@
import static org.mockito.Mockito.when;

import com.auth0.android.authentication.AuthenticationException;
import com.auth0.android.request.internal.CommonThreadSwitcher;
import com.auth0.android.request.internal.ThreadSwitcher;
import com.auth0.android.util.CommonThreadSwitcherRule;
import com.google.androidbrowserhelper.trusted.TwaLauncher;
import com.google.androidbrowserhelper.trusted.splashscreens.SplashScreenStrategy;

Expand Down Expand Up @@ -87,7 +93,17 @@ public void setUp() {
MockitoAnnotations.openMocks(this);
Activity activity = Robolectric.setupActivity(Activity.class);
context = spy(activity);
mockThreadSwitcher = spy(ThreadSwitcher.class);
mockThreadSwitcher = spy(new ThreadSwitcher() {
@Override
public void mainThread(@NonNull Runnable runnable) {
runnable.run();
}

@Override
public void backgroundThread(@NonNull Runnable runnable) {
runnable.run();
}
});

//By default, a "compatible" browser is available
BrowserPicker browserPicker = mock(BrowserPicker.class);
Expand Down Expand Up @@ -135,10 +151,11 @@ public void shouldUnbindEvenIfNotBound() throws Exception {
@Test
public void shouldBindAndLaunchUri() throws Exception {
bindService(controller, true);
controller.launchUri(uri, false, mockThreadSwitcher, null);
connectBoundService();
controller.launchUri(uri, false, mockThreadSwitcher, null);

verify(context, timeout(MAX_TEST_WAIT_TIME_MS)).startActivity(launchIntentCaptor.capture());
verify(mockThreadSwitcher).backgroundThread(any());
Intent intent = launchIntentCaptor.getValue();
assertThat(intent.getAction(), is(Intent.ACTION_VIEW));
assertThat(intent.getPackage(), is(DEFAULT_BROWSER_PACKAGE));
Expand Down Expand Up @@ -171,6 +188,7 @@ public void shouldBindAndLaunchUriAsTwa() throws Exception {
runnableArgumentCaptor.capture(),
fallbackStrategyArgumentCaptor.capture());

verify(mockThreadSwitcher).backgroundThread(any());
assertThat(trustedWebActivityIntentBuilderArgumentCaptor.getValue(), is(notNullValue()));
assertThat(customTabsCallbackArgumentCaptor.getValue(), is(nullValue()));
assertThat(splashScreenStrategyArgumentCaptor.getValue(), is(nullValue()));
Expand All @@ -187,6 +205,7 @@ public void shouldLaunchUriUsingFallbackWhenNoCompatibleBrowserIsAvailable() {
controller.launchUri(uri, false, mockThreadSwitcher, null);

verify(context, timeout(MAX_TEST_WAIT_TIME_MS)).startActivity(launchIntentCaptor.capture());
verify(mockThreadSwitcher).backgroundThread(any());
Intent intent = launchIntentCaptor.getValue();
assertThat(intent.getAction(), is(Intent.ACTION_VIEW));
//A null package name would make the OS decide the best app to resolve the intent
Expand All @@ -207,10 +226,11 @@ public void shouldBindAndLaunchUriWithCustomization() throws Exception {
CustomTabsController controller = new CustomTabsController(context, ctOptions, twaLauncher);

bindService(controller, true);
controller.launchUri(uri, false, mockThreadSwitcher, null);
connectBoundService();
controller.launchUri(uri, false, mockThreadSwitcher, null);

verify(context, timeout(MAX_TEST_WAIT_TIME_MS)).startActivity(launchIntentCaptor.capture());
verify(mockThreadSwitcher).backgroundThread(any());
Intent intent = launchIntentCaptor.getValue();
assertThat(intent.getAction(), is(Intent.ACTION_VIEW));
assertThat(intent.getPackage(), is(DEFAULT_BROWSER_PACKAGE));
Expand Down Expand Up @@ -255,6 +275,7 @@ public void shouldBindAndLaunchUriWithCustomizationTwa() throws Exception {
runnableArgumentCaptor.capture(),
fallbackStrategyArgumentCaptor.capture());

verify(mockThreadSwitcher).backgroundThread(any());
assertThat(trustedWebActivityIntentBuilderArgumentCaptor.getValue(), is(notNullValue()));
assertThat(customTabsCallbackArgumentCaptor.getValue(), is(nullValue()));
assertThat(splashScreenStrategyArgumentCaptor.getValue(), is(nullValue()));
Expand All @@ -269,6 +290,7 @@ public void shouldFailToBindButLaunchUri() {

verify(context, timeout(MAX_TEST_WAIT_TIME_MS)).startActivity(launchIntentCaptor.capture());
Intent intent = launchIntentCaptor.getValue();
verify(mockThreadSwitcher).backgroundThread(any());
assertThat(intent.getAction(), is(Intent.ACTION_VIEW));
assertThat(intent.getData(), is(uri));
assertThat(intent.hasExtra(CustomTabsIntent.EXTRA_SESSION), is(true));
Expand All @@ -280,6 +302,7 @@ public void shouldNotLaunchUriIfContextNoLongerValid() {
bindService(controller, true);
controller.clearContext();
controller.launchUri(uri, false, mockThreadSwitcher, null);
verify(mockThreadSwitcher, never()).backgroundThread(any());
verify(context, never()).startActivity(any(Intent.class));
}

Expand All @@ -291,6 +314,7 @@ public void shouldLaunchUriWithFallbackIfCustomTabIntentFails() {
controller.launchUri(uri, false, mockThreadSwitcher, null);

verify(context, timeout(MAX_TEST_WAIT_TIME_MS)).startActivity(launchIntentCaptor.capture());
verify(mockThreadSwitcher).backgroundThread(any());
List<Intent> intents = launchIntentCaptor.getAllValues();

Intent customTabIntent = intents.get(0);
Expand All @@ -313,11 +337,11 @@ public void shouldThrowExceptionIfFailedToLaunchBecauseOfException() {
.when(context).startActivity(any(Intent.class));
controller.launchUri(uri, false, mockThreadSwitcher, (ex) -> {
assertThat(ex, isA(AuthenticationException.class));
assertThat(ex.getCause(), is(eq(e)));
assertThat(ex.getCause(), equalTo(e));
assertThat(ex.getCode(), is("a0.browser_not_available"));
assertThat(ex.getDescription(), is("Error launching browser for authentication"));
verify(mockThreadSwitcher).mainThread(any());
verify(mockThreadSwitcher, Mockito.never()).backgroundThread(any());
verify(mockThreadSwitcher).backgroundThread(any());
});
}

Expand Down

0 comments on commit 70d3d13

Please sign in to comment.