From f773e0144d728d8ad13c5095621e4dc19daeb5e2 Mon Sep 17 00:00:00 2001 From: 2ro <17595647+2ro@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:30:00 -0400 Subject: [PATCH] goblin: return to the calling app after a successful sign-in or authorize (Build 151) --- .../app/src/main/java/mw/gri/android/MainActivity.java | 9 +++++++++ src/gui/platform/android/mod.rs | 6 ++++++ src/gui/platform/mod.rs | 8 ++++++++ src/gui/views/goblin/mod.rs | 8 ++++++++ 4 files changed, 31 insertions(+) diff --git a/android/app/src/main/java/mw/gri/android/MainActivity.java b/android/app/src/main/java/mw/gri/android/MainActivity.java index 838e7300..f75408a9 100644 --- a/android/app/src/main/java/mw/gri/android/MainActivity.java +++ b/android/app/src/main/java/mw/gri/android/MainActivity.java @@ -402,6 +402,15 @@ public class MainActivity extends GameActivity { finishAndRemoveTask(); } + // Called from native code after a successful same-device sign-in/authorize + // to hand focus back to the app that deep-linked into us (the browser tab + // that is polling the callback). Backgrounds our task so the OS surfaces the + // previous app; keeps the process alive (unlike exit()) so the callback POST + // finishes and the success toast shows on next foreground. + public void returnToCaller() { + moveTaskToBack(true); + } + @Override protected void onDestroy() { unregisterReceiver(mBroadcastReceiver); diff --git a/src/gui/platform/android/mod.rs b/src/gui/platform/android/mod.rs index 2f53d39e..6a674f4e 100644 --- a/src/gui/platform/android/mod.rs +++ b/src/gui/platform/android/mod.rs @@ -286,6 +286,12 @@ impl PlatformCallbacks for Android { fn vibrate_copy(&self) { let _ = self.call_java_method("vibrateCopy", "()V", &[]); } + + fn return_to_caller(&self) { + // Background our task (Activity.moveTaskToBack(true), wrapped Java-side) + // so the OS brings the app that deep-linked into us back to the front. + let _ = self.call_java_method("returnToCaller", "()V", &[]); + } } lazy_static! { diff --git a/src/gui/platform/mod.rs b/src/gui/platform/mod.rs index 201fffb2..4c4a6389 100644 --- a/src/gui/platform/mod.rs +++ b/src/gui/platform/mod.rs @@ -76,4 +76,12 @@ pub trait PlatformCallbacks { /// Play a tiny "tick" haptic confirming a successful copy. No-op off Android. fn vibrate_copy(&self) {} + + /// Return the user to the app that deep-linked into Goblin (the same-device + /// app-switch flow: a browser hands off a `goblin:login`/`goblin:authorize` + /// URI, we sign, then hand focus back). On Android this backgrounds our task + /// so the OS surfaces the previous app (the polling browser tab). Best-effort + /// and a no-op off Android, where there is no clean "return focus" primitive + /// (egui/winit); desktop leaves the window where it is. + fn return_to_caller(&self) {} } diff --git a/src/gui/views/goblin/mod.rs b/src/gui/views/goblin/mod.rs index 861cc3a3..728da257 100644 --- a/src/gui/views/goblin/mod.rs +++ b/src/gui/views/goblin/mod.rs @@ -6379,6 +6379,10 @@ impl GoblinWalletView { *slot.lock().unwrap() = Some(res); }); Modal::close(); + // Signed and handed to the POST worker: return the user to + // the app that deep-linked in (the polling browser tab), + // without waiting on the HTTP response. Success path only. + cb.return_to_caller(); } Err(e) => { // Signing failed (never expected): consume the request and @@ -6799,6 +6803,10 @@ impl GoblinWalletView { *slot.lock().unwrap() = Some(res); }); Modal::close(); + // Signed and handed to the POST worker: return the user to + // the app that deep-linked in (the polling browser tab), + // without waiting on the HTTP response. Success path only. + cb.return_to_caller(); } Err(e) => { // Signing failed (never expected): consume the request and