From 9b27516e962ab55c69e324e232b2dbd6aec6d866 Mon Sep 17 00:00:00 2001 From: kari-ts <135075563+kari-ts@users.noreply.github.com> Date: Tue, 2 Apr 2024 12:28:00 -0700 Subject: [PATCH] MainActivity: bring activity to focus on login (#273) Use CustomTabsIntent to launch login, but fall back to regular intent if Chrome is not installed When logging in, on change in state to login complete, bring activity back to focus Updates tailscale/corp#18202 Signed-off-by: kari-ts --- .../java/com/tailscale/ipn/MainActivity.kt | 48 ++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/android/src/main/java/com/tailscale/ipn/MainActivity.kt b/android/src/main/java/com/tailscale/ipn/MainActivity.kt index 350084b..110ddf5 100644 --- a/android/src/main/java/com/tailscale/ipn/MainActivity.kt +++ b/android/src/main/java/com/tailscale/ipn/MainActivity.kt @@ -16,9 +16,11 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContract +import androidx.browser.customtabs.CustomTabsIntent import androidx.compose.animation.core.tween import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally +import androidx.core.net.toUri import androidx.lifecycle.lifecycleScope import androidx.navigation.NavType import androidx.navigation.compose.NavHost @@ -28,6 +30,7 @@ import androidx.navigation.navArgument import androidx.navigation.navigation import com.tailscale.ipn.Peer.RequestCodes import com.tailscale.ipn.mdm.MDMSettings +import com.tailscale.ipn.ui.model.Ipn import com.tailscale.ipn.ui.notifier.Notifier import com.tailscale.ipn.ui.theme.AppTheme import com.tailscale.ipn.ui.view.AboutView @@ -52,6 +55,7 @@ import com.tailscale.ipn.ui.viewModel.ExitNodePickerNav import com.tailscale.ipn.ui.viewModel.SettingsNav import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.cancel import kotlinx.coroutines.launch class MainActivity : ComponentActivity() { @@ -64,6 +68,7 @@ class MainActivity : ComponentActivity() { @JvmStatic val requestPrepareVPN: Int = 1001 const val WRITE_STORAGE_RESULT = 1000 + private const val TAG = "Main Activity" } override fun onCreate(savedInstanceState: Bundle?) { @@ -182,12 +187,43 @@ class MainActivity : ComponentActivity() { } } - private fun login(url: String) { - // (jonathan) TODO: This is functional, but the navigation doesn't quite work - // as expected. There's probably a better built in way to do this. This will - // unblock in dev for the time being though. - val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) - startActivity(browserIntent) + private fun login(urlString: String) { + // Launch coroutine to listen for state changes. When the user completes login, relaunch + // MainActivity to bring the app back to focus. + App.getApplication().applicationScope.launch { + try { + Notifier.state.collect { state -> + if (state > Ipn.State.NeedsMachineAuth) { + val intent = + Intent(applicationContext, MainActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP) + action = Intent.ACTION_MAIN + addCategory(Intent.CATEGORY_LAUNCHER) + } + startActivity(intent) + + // Cancel coroutine once we've logged in + this@launch.cancel() + } + } + } catch (e: Exception) { + Log.e(TAG, "Login: failed to start MainActivity: $e") + } + } + + val url = urlString.toUri() + try { + val customTabsIntent = CustomTabsIntent.Builder().build() + customTabsIntent.launchUrl(this, url) + } catch (e: Exception) { + // Fallback to a regular browser if CustomTabsIntent fails + try { + val fallbackIntent = Intent(Intent.ACTION_VIEW, url) + startActivity(fallbackIntent) + } catch (e: Exception) { + Log.e(TAG, "Login: failed to open browser: $e") + } + } } override fun onResume() {