Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
cdd49db
Update rclone to v1.73.0 - adds support for Shade, Drime, Filen, Inte…
thies2005 Feb 2, 2026
4cd7e71
Update NDK to r29 (29.0.14206865) - latest stable version with improv…
thies2005 Feb 2, 2026
c550283
Fix Internxt backend: add to interactive auth providers list
thies2005 Feb 2, 2026
d3dbd96
Improve Internxt support: add to interactive auth list and add error …
thies2005 Feb 2, 2026
6e8185d
Add Internxt 2FA support with interactive dialog
thies2005 Feb 2, 2026
c326118
Fix Internxt 2FA trigger: match rclone output '2FA code'
thies2005 Feb 2, 2026
85be4a9
Update README with Drime and Internxt support
thies2005 Feb 3, 2026
6af00d6
Fix sync notification stuck at 'starting sync' and add speed indication
thies2005 Feb 3, 2026
c234655
feat: implement Internxt 2FA support and fix Windows build issues
thies2005 Feb 19, 2026
ddbe7b5
feat: implement Session Guardian architecture for resilient token man…
Mar 20, 2026
c3b148d
fix: enable CGO for Android ARM builds and add ARM64 Linux host support
Mar 20, 2026
7ebbcf9
fix: make rclone build compatible with Windows (Ryzen 8845HS)
Mar 20, 2026
b255a3f
docs: add comprehensive build guide for Windows and GitHub Actions
Mar 20, 2026
e34ffe3
trigger build
Mar 20, 2026
c2c3436
docs: add comprehensive Session Guardian workflow with detailed comments
Mar 20, 2026
a6ecb88
fix: simplify workflow conditions and fix syntax
Mar 20, 2026
9eb0a0c
trigger workflow build for Pixel 9
Mar 20, 2026
455ea89
fix: shell script syntax in Go version step
Mar 20, 2026
d23d995
trigger build for Pixel 9 arm64-v8a
Mar 20, 2026
e33f590
fix: simplify workflow conditions and fix step references
Mar 20, 2026
796baf9
fix: resolve Go syntax errors in auth.go for CGO build
Mar 20, 2026
04d9087
fix: disable CGO for rclone Android build
Mar 20, 2026
b1ada08
fix: re-enable CGO and add std lib build for Android
Mar 20, 2026
9ddcce5
fix: remove duplicate code in build.gradle
Mar 20, 2026
bf0d8b4
fix: remove android build tag to resolve CGO import issues
Mar 20, 2026
41d3d77
fix: revert to working CGO configuration for GitHub Actions
Mar 20, 2026
f03793f
fix: build for linux/arm instead of android/arm to avoid CGO requirement
Mar 20, 2026
7d8302a
fix: revert to Go 1.19.8 to match working configuration
Mar 20, 2026
decea03
docs: add Windows build scripts and checklists
Mar 20, 2026
9dd5601
fix: correct Gradle task syntax and add error checking
Mar 20, 2026
25f0c9f
docs: correct manual build commands in checklist
Mar 20, 2026
19db350
docs: correct ARM64 build command in Windows guide
Mar 20, 2026
91abfe4
feat: add pre-built rclone download option to bypass Go build issues
Mar 20, 2026
9434ad3
fix: build errors and rclone build configuration optimization
thies2005 Mar 24, 2026
98b25da
fix(rclone): Fix TLS verification by providing Android path to SSL_CE…
thies2005 Mar 24, 2026
af4d2f0
fix(rclone): rebuild with patched internxt source and add log copy fe…
thies2005 Mar 24, 2026
724a3ca
Fix Internxt authentication flow: 401 Unauthorized errors and 2FA sup…
thies2005 Mar 26, 2026
3bbfebc
Switch to custom rclone fork for unified Internxt backend development
thies2005 Apr 22, 2026
1b1e874
chore: Rebrand Round Sync to CloudBridge
thies2005 Apr 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 152 additions & 50 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
@@ -1,60 +1,162 @@
name: Android CI
name: Android CI - APK Builds for Round-Sync

# =============================================================================
# Session Guardian Build Workflow
# =============================================================================
#
# Simple, reliable workflow that builds APKs on Ubuntu runners
# GitHub Actions provides 2000 free minutes/month for public repos.
#
# Session Guardian Features Built:
# - TOTP time windows (T, T-1, T+1) for Internxt 2FA
# - Exponential backoff (1m, 5m, 15m, 1h, 1h) with jitter
# - Soft circuit breaker (max 5 retries, resets on success)
# - 8-hour periodic health checks via WorkManager
# - Manual re-auth option in remote menu
# - Session expiry notifications
#
# =============================================================================

# Triggers: Push commits, tags, or manual workflow_dispatch
on:
workflow_dispatch:
push:
branches: [master]
tags:
- '*'
workflow_dispatch:
inputs:
reason:
description: 'Reason for triggering build (e.g., "Test Session Guardian")'
required: false
default: 'Manual build'

jobs:
createArtifacts:
name: Build Android APKs
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Read Go version from project
run: echo "GO_VERSION=$(grep -E "^de\.felixnuesse\.extract\.goVersion=" gradle.properties | cut -d'=' -f2)"
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: gradle
- name: Set up Go from gradle.properties
uses: actions/setup-go@v4
with:
go-version: '${{env.GO_VERSION}}'
id: go
- name: Setup Android SDK/NDK
uses: android-actions/setup-android@v3
- name: Install NDK from gradle.properties
run: |
NDK_VERSION="$(grep -E "^de\.felixnuesse\.extract\.ndkVersion=" gradle.properties | cut -d'=' -f2)"
sdkmanager "ndk;${NDK_VERSION}"
- name: Build app
run: ./gradlew assembleOssDebug
- name: Upload APK (arm)
uses: actions/upload-artifact@v4
with:
name: nightly-armeabi.apk
path: ${{ github.workspace }}/app/build/outputs/apk/oss/debug/*-oss-armeabi-v7a-debug.apk
- name: Upload APK (arm64)
uses: actions/upload-artifact@v4
with:
name: nightly-arm64.apk
path: ${{ github.workspace }}/app/build/outputs/apk/oss/debug/*-oss-arm64-v8a-debug.apk
- name: Upload APK (x86)
uses: actions/upload-artifact@v4
with:
name: nightly-x86.apk
path: ${{ github.workspace }}/app/build/outputs/apk/oss/debug/*-oss-x86-debug.apk
- name: Upload APK (arm)
uses: actions/upload-artifact@v4
with:
name: nightly-x64.apk
path: ${{ github.workspace }}/app/build/outputs/apk/oss/debug/*-oss-x86_64-debug.apk
- name: Upload APK (universal)
uses: actions/upload-artifact@v4
with:
name: nightly-universal.apk
path: ${{ github.workspace }}/app/build/outputs/apk/oss/debug/*-oss-universal-debug.apk
retention-days: 14
# Step 1: Checkout code
- name: Checkout Round-Sync code
uses: actions/checkout@v4

# Step 2: Read Go version from gradle.properties
- name: Read Go version
id: read-go-version
run: |
GO_VERSION=$(grep '^de\.felixnuesse\.extract\.goVersion=' gradle.properties | cut -d'=' -f2)
echo "GO_VERSION=$GO_VERSION" >> $GITHUB_ENV
echo "Go version to build: $GO_VERSION"

# Step 3: Install JDK 17
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: gradle

# Step 4: Install Go
- name: Install Go
uses: actions/setup-go@v5
with:
go-version: '${{env.GO_VERSION}}'
cache: true

# Step 5: Install Android SDK and NDK
- name: Setup Android SDK/NDK
uses: android-actions/setup-android@v3

# Step 6: Install NDK (from gradle.properties)
- name: Install NDK
run: |
NDK_VERSION="$(grep '^de\.felixnuesse\.extract\.ndkVersion=' gradle.properties | cut -d'=' -f2)"
echo "Installing NDK version: $NDK_VERSION"
sdkmanager "ndk;${NDK_VERSION}"

# Step 7: Build Android app (OSS variant)
- name: Build app (OSS)
id: build-oss
run: |
echo "Building OSS Debug APK..."
./gradlew assembleOssDebug
echo "Build completed!"

# Step 8: Upload ARM eabi-v7a APK
- name: Upload APK (arm32 - armeabi-v7a)
if: success()
uses: actions/upload-artifact@v4
with:
name: nightly-armeabi-v7a.apk
path: ${{ github.workspace }}/app/build/outputs/apk/oss/debug/*-oss-armeabi-v7a-debug.apk
if-no-files-found: warn
retention-days: 14

# Step 9: Upload ARM64-v8a APK (for Pixel 9)
- name: Upload APK (arm64 - for Pixel 9)
if: success()
uses: actions/upload-artifact@v4
with:
name: nightly-arm64-v8a.apk
path: ${{ github.workspace }}/app/build/outputs/apk/oss/debug/*-oss-arm64-v8a-debug.apk
if-no-files-found: warn
retention-days: 14

# Step 10: Upload x86 APK
- name: Upload APK (x86)
if: success()
uses: actions/upload-artifact@v4
with:
name: nightly-x86.apk
path: ${{ github.workspace }}/app/build/outputs/apk/oss/debug/*-oss-x86-debug.apk
if-no-files-found: warn
retention-days: 14

# Step 11: Upload x86_64 APK
- name: Upload APK (x86_64)
if: success()
uses: actions/upload-artifact@v4
with:
name: nightly-x86_64.apk
path: ${{ github.workspace }}/app/build/outputs/apk/oss/debug/*-oss-x86_64-debug.apk
if-no-files-found: warn
retention-days: 14

# Step 12: Upload universal APK
- name: Upload APK (universal)
if: success()
uses: actions/upload-artifact@v4
with:
name: nightly-universal.apk
path: ${{ github.workspace }}/app/build/outputs/apk/oss/debug/*-oss-universal-debug.apk
if-no-files-found: warn
retention-days: 14

# Step 13: Build summary
- name: Build summary
if: always()
run: |
echo "## Build Summary"
echo ""
echo "**APKs Generated:**"
echo "- arm64-v8a (for Pixel 9)"
echo "- armeabi-v7a"
echo "- x86"
echo "- x86_64"
echo "- universal"
echo ""
echo "**Session Guardian Features:**"
echo "- TOTP time windows (T, T-1, T+1) for 2FA clock skew"
echo "- Exponential backoff (1m → 5m → 15m → 1h → 1h)"
echo "- Soft circuit breaker (max 5 retries)"
echo "- 8-hour health checks via WorkManager"
echo "- Manual re-auth UI option"
echo "- Session expiry notifications"
echo ""
echo "**Download:**"
echo "After 5-10 minutes, download artifacts from:"
echo "https://github.com/thies2005/Round-Sync/actions"
echo ""
echo "**For Pixel 9 (arm64-v8a):**"
echo "Download: nightly-arm64-v8a.apk"
echo "Install and test Session Guardian features!"
7 changes: 5 additions & 2 deletions .github/workflows/dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,18 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Read Go version from project
run: echo "GO_VERSION=$(grep -E "^de\.felixnuesse\.extract\.goVersion=" gradle.properties | cut -d'=' -f2)"
run: |
GO_VERSION=$(grep -E "^de\.felixnuesse\.extract\.goVersion=" gradle.properties | cut -d'=' -f2)
echo "GO_VERSION=$GO_VERSION" >> $GITHUB_ENV
echo "Go version: $GO_VERSION"
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: gradle
- name: Set up Go from gradle.properties
uses: actions/setup-go@v4
uses: actions/setup-go@v5
with:
go-version: '${{env.GO_VERSION}}'
id: go
Expand Down
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "interactive"
}
96 changes: 96 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# CloudBridge — Agent Notes

Android cloud file manager wrapping [rclone](https://rclone.org). Fork of RCX / rcloneExplorer.

## Build

**Prerequisites**: Go 1.25+, JDK 17, Android SDK with NDK. Versions are pinned in `gradle.properties` — check there first if builds break.

```sh
# Debug (CI uses this)
./gradlew assembleOssDebug

# Release
./gradlew assembleOssRelease
```

- Two product flavors: **`oss`** and **`rs`** (dimension: `edition`). Almost all work targets `oss`.
- APK output: `app/build/outputs/apk/oss/debug/`
- ABI splits: armeabi-v7a, arm64-v8a, x86, x86_64, universal

## Module structure

| Module | Purpose |
|---|---|
| `app` | Main Android application |
| `rclone` | Cross-compiles rclone (Go) into `librclone.so` per ABI |
| `safdav` | SAF/WebDAV bridge library (`io.github.x0b.safdav`) |

`app:preBuild` depends on `:rclone:buildAll`, so the app build automatically triggers rclone cross-compilation. First build downloads and caches rclone source in `rclone/cache/`.

## rclone source

The rclone binary is built from the fork at `https://github.com/thies2005/rclone` (which includes Internxt auto-token-renewal). Source is controlled by two properties in `gradle.properties`:

| Property | What it controls |
|---|---|
| `rCloneRepoUrl` | Git remote URL to clone from |
| `rCloneRef` | Branch, tag, or commit to checkout and build |

**To upgrade the fork**: change `rCloneRef` (e.g. to a newer tag or commit), then rebuild. The build script will `git fetch` + `git checkout` on every build, so no manual cache clearing is needed.

The old `rclone/patches/` directory is no longer used — the fork contains the Internxt backend changes directly.

## Lint

```sh
./gradlew lint -x :rclone:buildAll
```

Lint skips rclone compilation to save time. Lint baselines exist (`lint-baseline.xml` in `app/` and `safdav/`). `abortOnError` is enabled; `MissingTranslation` is demoted to warning.

## Testing

Minimal test coverage — only two unit tests in `app/src/test/`. Run with:

```sh
./gradlew testOssDebugUnitTest
```

No instrumented/androidTest runner is wired in CI.

## Architecture / source layout

- **Package namespace**: `ca.pkay.rcloneexplorer` (legacy from rcloneExplorer fork)
- **Application ID**: `de.schuelken.cloudbridge`
- Newer code lives under `de.schuelken.cloudbridge.*`
- `app/src/rcx/` — additional source set (RCX-specific utilities)
- `rclone/patches/` — **DEPRECATED**, no longer used. Fork already contains Internxt backend.
- The rclone binary is statically compiled with `CGO_ENABLED=0` and shipped as `librclone.so` per ABI in `app/lib/`.

## Key version pins (`gradle.properties`)

| Property | What it controls |
|---|---|
| `de.schuelken.cloudbridge.goVersion` | Go toolchain version (informational) |
| `de.schuelken.cloudbridge.rCloneVersion` | Fallback rclone version (if VERSION file unreadable) |
| `de.schuelken.cloudbridge.rCloneRepoUrl` | Git URL for the rclone fork |
| `de.schuelken.cloudbridge.rCloneRef` | Git ref (branch/tag/commit) to build from |
| `de.schuelken.cloudbridge.ndkVersion` | Android NDK version for cross-compilation |
| `de.schuelken.cloudbridge.ndkToolchainVersion` | NDK toolchain API level |

## CI workflows

- **`android.yml`**: Builds debug APKs on push to master; uploads per-ABI artifacts.
- **`lint.yml`**: Runs lint on every PR (not on master).
- **`dependencies.yml`**: Rebuilds on `build.gradle` changes and runs FOSS library scan.
- **`translations.yml`**: Profanity-checks translated `strings.xml` on PRs.

## Gotchas

- **Windows builds**: The rclone module handles Windows-specific NDK paths (`.cmd` suffixes, CRLF→LF conversion on patched Go files).
- **Debug applicationId**: Debug builds append `.debug` to the application ID, so debug and release can coexist on a device.
- **`versionCode`**: Last digit is reserved for ABI multiplier — version codes end in `0`.
- **Version Updates**: Always update the small versions (patch version and `versionCode`) with each build.
- **`local.properties`** with `sdk.dir` or `ANDROID_HOME` env var is required for rclone cross-compilation.
- Translations are managed via Weblate and Crowdin — don't manually edit localized `strings.xml` unless adding a new language.
Loading