diff --git a/app/src/main/java/io/netbird/client/MainActivity.java b/app/src/main/java/io/netbird/client/MainActivity.java index 666b950..c79c3c4 100644 --- a/app/src/main/java/io/netbird/client/MainActivity.java +++ b/app/src/main/java/io/netbird/client/MainActivity.java @@ -73,6 +73,7 @@ private enum ConnectionState { private boolean isSSOFinishedWell = false; private boolean isRunningOnTV = false; + private boolean useDeviceCodeFlow = false; // Last known state for UI updates private ConnectionState lastKnownState = ConnectionState.UNKNOWN; @@ -105,9 +106,13 @@ protected void onCreate(Bundle savedInstanceState) { setSupportActionBar(binding.appBarMain.toolbar); isRunningOnTV = PlatformUtils.isAndroidTV(this); + useDeviceCodeFlow = PlatformUtils.requiresDeviceCodeFlow(this); if (isRunningOnTV) { Log.i(LOGTAG, "Running on Android TV - optimizing for D-pad navigation"); } + if (useDeviceCodeFlow && !isRunningOnTV) { + Log.i(LOGTAG, "Running on ChromeOS - using device code flow for authentication"); + } setVersionText(); @@ -177,7 +182,7 @@ public void onDrawerClosed(View drawerView) { } }); - if (!isRunningOnTV) { + if (!useDeviceCodeFlow) { urlOpener = new CustomTabURLOpener(this, () -> { if (isSSOFinishedWell) { return; @@ -202,11 +207,20 @@ public void open(String url, String userCode) { mBinder.stopEngine(); }); qrCodeDialog.show(getSupportFragmentManager(), "QrCodeDialog"); + + if (!isRunningOnTV) { + try { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(browserIntent); + } catch (Exception e) { + Log.e(LOGTAG, "Failed to open browser for device code flow: " + e.getMessage()); + } + } } @Override public void onLoginSuccess() { - Log.d(LOGTAG, "onLoginSuccess fired for TV."); + Log.d(LOGTAG, "onLoginSuccess fired for device code flow."); if (qrCodeDialog != null && qrCodeDialog.isVisible()) { qrCodeDialog.dismiss(); qrCodeDialog = null; @@ -233,12 +247,12 @@ public void onLoginSuccess() { if (VPNService.isUsingAlwaysOnVPN(this)) { showAlwaysOnDialog(() -> { if (mBinder != null) { - mBinder.runEngine(urlOpener, isRunningOnTV); + mBinder.runEngine(urlOpener, useDeviceCodeFlow); } }); } else { if (mBinder != null) { - mBinder.runEngine(urlOpener, isRunningOnTV); + mBinder.runEngine(urlOpener, useDeviceCodeFlow); } } }); @@ -345,7 +359,7 @@ public void switchConnection(boolean status) { if (prepareIntent != null) { vpnActivityResultLauncher.launch(prepareIntent); } else { - mBinder.runEngine(urlOpener, isRunningOnTV); + mBinder.runEngine(urlOpener, useDeviceCodeFlow); } } diff --git a/app/src/main/java/io/netbird/client/PlatformUtils.java b/app/src/main/java/io/netbird/client/PlatformUtils.java index dd0d6f0..3e06081 100644 --- a/app/src/main/java/io/netbird/client/PlatformUtils.java +++ b/app/src/main/java/io/netbird/client/PlatformUtils.java @@ -2,6 +2,7 @@ import android.app.UiModeManager; import android.content.Context; +import android.content.pm.PackageManager; import android.content.res.Configuration; public final class PlatformUtils { @@ -16,5 +17,15 @@ public static boolean isAndroidTV(Context context) { } return false; } + + public static boolean isChromeOS(Context context) { + PackageManager pm = context.getPackageManager(); + return pm.hasSystemFeature("org.chromium.arc") + || pm.hasSystemFeature("org.chromium.arc.device_management"); + } + + public static boolean requiresDeviceCodeFlow(Context context) { + return isAndroidTV(context) || isChromeOS(context); + } } diff --git a/netbird b/netbird index 245481f..6721101 160000 --- a/netbird +++ b/netbird @@ -1 +1 @@ -Subproject commit 245481f33be5b37a45806d7a56e7190ca38f30e7 +Subproject commit 67211010f7240d53734abd922777c32fccb02754