diff --git a/browser/android/src/main/java/com/capacitorjs/plugins/browser/Browser.java b/browser/android/src/main/java/com/capacitorjs/plugins/browser/Browser.java index fff0ddc43..937ec3737 100644 --- a/browser/android/src/main/java/com/capacitorjs/plugins/browser/Browser.java +++ b/browser/android/src/main/java/com/capacitorjs/plugins/browser/Browser.java @@ -7,6 +7,7 @@ import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import androidx.activity.result.ActivityResultLauncher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.browser.customtabs.*; @@ -43,7 +44,10 @@ interface BrowserEventListener { private CustomTabsClient customTabsClient; private CustomTabsSession browserSession; private boolean isInitialLoad = false; - private EventGroup group; + + @Nullable + private ActivityResultLauncher customTabLauncher; + private CustomTabsServiceConnection connection = new CustomTabsServiceConnection() { @Override public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) { @@ -61,7 +65,6 @@ public void onServiceDisconnected(ComponentName name) {} */ public Browser(@NonNull Context context) { this.context = context; - this.group = new EventGroup(this::handleGroupCompletion); } /** @@ -81,6 +84,16 @@ public BrowserEventListener getBrowserEventListenerListener() { return browserEventListener; } + /** + * Provide the ActivityResultLauncher used to open the Custom Tab. When + * set, the Custom Tab is launched via this launcher so that + * {@link #notifyBrowserFinished()} can be triggered from the launcher's + * result callback (only when the tab activity actually terminates). + */ + public void setCustomTabLauncher(@Nullable ActivityResultLauncher launcher) { + this.customTabLauncher = launcher; + } + /** * Open the browser to the specified URL. * @param url @@ -108,8 +121,12 @@ public void open(Uri url, @Nullable Integer toolbarColor) { tabsIntent.intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(Intent.URI_ANDROID_APP_SCHEME + "//" + context.getPackageName())); isInitialLoad = true; - group.reset(); - tabsIntent.launchUrl(context, url); + if (customTabLauncher != null) { + tabsIntent.intent.setData(url); + customTabLauncher.launch(tabsIntent.intent); + } else { + tabsIntent.launchUrl(context, url); + } } /** @@ -120,9 +137,7 @@ public boolean bindService() { if (null == customTabPackageName) { customTabPackageName = FALLBACK_CUSTOM_TAB_PACKAGE_NAME; } - boolean result = CustomTabsClient.bindCustomTabsService(context, customTabPackageName, connection); - group.leave(); - return result; + return CustomTabsClient.bindCustomTabsService(context, customTabPackageName, connection); } /** @@ -130,7 +145,6 @@ public boolean bindService() { */ public void unbindService() { context.unbindService(connection); - group.enter(); } private void handledNavigationEvent(int navigationEvent) { @@ -143,19 +157,13 @@ private void handledNavigationEvent(int navigationEvent) { isInitialLoad = false; } break; - case CustomTabsCallback.TAB_HIDDEN: - group.leave(); - break; - case CustomTabsCallback.TAB_SHOWN: - group.enter(); - break; } } - private void handleGroupCompletion() { - // events such as TAB_HIDDEN and onPause can occur for multiple reasons and in - // different sequences so there is no single point to fire this. so we rely on the - // event group to track when it is safe to assume that the browser is done. + public void notifyBrowserFinished() { + // Notify listeners that the browser session has finished. Called by the + // host activity when the Custom Tab activity actually returns a result + // (i.e. the tab was truly dismissed, not just backgrounded or minimised). if (browserEventListener != null) { browserEventListener.onBrowserEvent(BROWSER_FINISHED); } diff --git a/browser/android/src/main/java/com/capacitorjs/plugins/browser/BrowserControllerActivity.java b/browser/android/src/main/java/com/capacitorjs/plugins/browser/BrowserControllerActivity.java index 74fd599c1..4caf3c578 100644 --- a/browser/android/src/main/java/com/capacitorjs/plugins/browser/BrowserControllerActivity.java +++ b/browser/android/src/main/java/com/capacitorjs/plugins/browser/BrowserControllerActivity.java @@ -1,19 +1,28 @@ package com.capacitorjs.plugins.browser; -import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import androidx.activity.ComponentActivity; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.Nullable; -public class BrowserControllerActivity extends Activity { +public class BrowserControllerActivity extends ComponentActivity { - private boolean isCustomTabsOpen = false; + private ActivityResultLauncher customTabLauncher; + private Browser implementation; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - isCustomTabsOpen = false; + + customTabLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), (result) -> { + if (implementation != null) { + implementation.notifyBrowserFinished(); + } + finish(); + }); if (BrowserPlugin.browserControllerListener != null) { BrowserPlugin.browserControllerListener.onControllerReady(this); @@ -28,25 +37,15 @@ protected void onNewIntent(Intent intent) { } } - @Override - protected void onResume() { - super.onResume(); - if (isCustomTabsOpen) { - isCustomTabsOpen = false; - finish(); - } else { - isCustomTabsOpen = true; - } - } - public void open(Browser implementation, Uri url, Integer toolbarColor) { + this.implementation = implementation; + implementation.setCustomTabLauncher(customTabLauncher); implementation.open(url, toolbarColor); } @Override protected void onDestroy() { super.onDestroy(); - isCustomTabsOpen = false; BrowserPlugin.setBrowserControllerListener(null); } } diff --git a/browser/android/src/main/java/com/capacitorjs/plugins/browser/EventGroup.java b/browser/android/src/main/java/com/capacitorjs/plugins/browser/EventGroup.java deleted file mode 100644 index 2c9541edc..000000000 --- a/browser/android/src/main/java/com/capacitorjs/plugins/browser/EventGroup.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.capacitorjs.plugins.browser; - -/** - * Simple class to handle indeterminate sequence of events. Not thread safe. - */ -class EventGroup { - - interface EventGroupCompletion { - void onGroupCompletion(); - } - - private int count; - private boolean isComplete; - private EventGroupCompletion completion; - - public EventGroup(EventGroupCompletion onCompletion) { - super(); - count = 0; - isComplete = false; - completion = onCompletion; - } - - public void enter() { - count++; - } - - public void leave() { - count--; - checkForCompletion(); - } - - public void reset() { - count = 0; - isComplete = false; - } - - private void checkForCompletion() { - if (count <= 0) { - if (isComplete == false && completion != null) { - completion.onGroupCompletion(); - } - isComplete = true; - } - } -}