Skip to content

Conversation

@moehamade
Copy link
Contributor

Closes #609

Description

Checklist

This commit introduces a `QrCodeGenerator` utility object to create QR code bitmaps for both Wi-Fi credentials and URLs.

Key features:
- **`generateWifiQr`**: Creates a QR code using the standard `WIFI:` format, allowing other devices to connect to a hotspot by scanning the code. It properly escapes special characters in the SSID and password.
- **`generateUrlQr`**: Generates a standard QR code for any given URL.
- **Implementation**: Uses the `zxing` library to encode the data and converts the resulting `BitMatrix` into an Android `Bitmap`.
This commit introduces a comprehensive system for fetching, downloading, caching, and managing a "universal" APK of the app, intended for offline sharing with new users.

The core components are:
- `GitHubReleaseClient`: A new client to fetch the latest release information from the project's GitHub repository. It specifically looks for a universal APK asset in the release, parses its download URL, and attempts to extract its SHA256 checksum from the release notes.
- `UniversalApkManager`: Manages the entire lifecycle of the universal APK. It handles:
    - Checking for new versions by comparing the cached APK version against the latest GitHub release.
    - Downloading the APK with progress reporting.
    - Verifying the downloaded file against the SHA256 checksum, if available.
    - Caching the APK and its metadata (version, checksum, size) locally.
    - Cleaning up old APK versions to conserve space.
This commit introduces a comprehensive feature for sharing the BitChat application offline using a self-hosted Wi-Fi Direct hotspot. This enables mesh network expansion by allowing users to distribute the app without requiring an internet connection.

Key components:
- **`HotspotManager`**: A new class that manages the creation and lifecycle of a Wi-Fi P2P (Wi-Fi Direct) group. It handles generating secure credentials (SSID/password), acquiring WakeLocks, and monitoring connected peers. It supports custom credentials on Android 10+ and falls back to system-generated ones on older versions.
- **`ApkWebServer`**: A lightweight HTTP server based on `NanoHTTPD` that serves the APK file and a user-friendly HTML landing page to connected devices.
- **`ApkSharingUtils`**: A utility to detect whether the app is installed as a single or split APK, collect the necessary files, and copy them to a cache directory for sharing.
- **`ApkInstaller`**: A utility using the `PackageInstaller` API to handle the installation of single or split APKs received from another user.
- **`HotspotActivity`**: A new Compose-based UI that guides the user through starting the hotspot, displays connection details (Wi-Fi credentials, QR codes for Wi-Fi and the download URL), and shows the number of connected peers. It also handles the necessary runtime permissions (`NEARBY_WIFI_DEVICES` or `ACCESS_FINE_LOCATION`).
- **Configuration**:
    - Adds necessary Wi-Fi and P2P permissions to `AndroidManifest.xml`.
    - Defines a `FileProvider` path for APK sharing in `file_paths.xml`.
    - Adds numerous string resources for the new UI.
This commit introduces a comprehensive feature set for sharing the application, both offline via a Wi-Fi hotspot and online through standard Android sharing mechanisms.

Key additions:

- **Prepare for Sharing UI:**
    - Adds a "Prepare App for Sharing" option in the settings sheet.
    - This feature downloads a universal APK from a remote source, suitable for all Android devices.
    - The UI displays the status: not downloaded, downloading (with progress), ready, or if an update is available.
    - Users can download, update, or delete the cached universal APK.

- **Offline Sharing via Wi-Fi Hotspot:**
    - Adds a "Share via Wi-Fi Hotspot" option.
    - This launches a new `HotspotActivity` to share the prepared universal APK with nearby devices without an internet connection.
    - A dialog informs the user if the APK hasn't been prepared yet.

- **Online & Local Sharing:**
    - Adds an option to share via Bluetooth, email, etc., using the standard Android share sheet.
    - This method shares the *installed* version of the app, which may be a split APK.
    - An explanatory dialog is shown first, instructing the receiver on how to install split APKs if necessary.
    - Implements logic to correctly package and share single or multiple split APK files using `FileProvider`.
This commit introduces the `nanohttpd` library, which will be used to implement an HTTP server for sharing the application's APK over a local hotspot.

The specific dependency added is `org.nanohttpd:nanohttpd:2.3.1`.
@moehamade moehamade force-pushed the enhancement/apk-sharing branch from b83578e to 949c506 Compare January 18, 2026 13:23
This commit introduces several fixes and refinements to the hotspot sharing and APK handling features, improving stability, user experience, and robustness.

Key changes:

-   **Hotspot Flow:**
    -   Automatically starts the hotspot after the user grants the required Wi-Fi permission, removing the need for a second button press.
    -   Ensures all `HotspotManager` callbacks in `HotspotViewModel` are executed within `viewModelScope` to prevent threading issues and ensure safe UI updates.
    -   Fixes a potential `BroadcastReceiver` leak in `HotspotManager` by tracking its registration state, preventing crashes and resource leaks when stopping the hotspot.
    -   Changes the hotspot `WakeLock` to be non-expiring to prevent the CPU from sleeping while the hotspot is active.

-   **APK Handling & Installation:**
    -   Adds a pre-download disk space check in `UniversalApkManager` to prevent download failures on devices with insufficient storage.
    -   Improves the file move logic after download by falling back to a copy-and-delete strategy if a direct rename fails, making it more robust across different filesystems.
    -   Introduces `InstallResultReceiver` to provide clear Toast notifications to the user about the success or failure of an APK installation, including specific error reasons (e.g., "Not enough storage").

-   **Performance & UI:**
    -   Caches the generated HTML in `ApkWebServer` to improve performance by avoiding regeneration on every request.
    -   Throttles the APK download progress updates to prevent UI jankiness from too-frequent state changes.
    -   Moves hardcoded strings in the "Share App" UI to `strings.xml` for better localization and maintenance.
This commit refactors the "Share App" functionality to exclusively use the new universal APK system, removing the previous logic that shared the installed split APKs. This simplifies the sharing process and ensures a consistent, single-file sharing experience for all users.

Key changes:
- Deletes `ApkSharingUtils.kt`, which was responsible for detecting and copying split APKs from the device's installation directory.
- Updates `AboutSheet.kt` to use `UniversalApkManager` for all sharing actions (Hotspot and "Quick Share").
- Simplifies the sharing intent logic, as it now only needs to handle a single APK file (`ACTION_SEND`) instead of multiple files (`ACTION_SEND_MULTIPLE`).
- The UI for sharing options (Hotspot, Quick Share) is now dynamically hidden until the universal APK is prepared, preventing user confusion.
- Replaces hardcoded strings with string resources for better localization.
Deletes the `InstallResultReceiver` broadcast receiver.

This component was responsible for handling the results of an APK installation initiated via `PackageInstaller`, but it is no longer used in the current implementation.
@moehamade moehamade marked this pull request as ready for review January 18, 2026 15:01
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0109208a3d

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +287 to +292
handler.postDelayed(object : Runnable {
override fun run() {
if (channel != null && currentGroup != null) {
requestGroupInfo()
handler.postDelayed(this, GROUP_INFO_POLL_INTERVAL_MILLIS)
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep polling even when group info is null

The polling loop only reschedules itself when currentGroup != null, but the first requestGroupInfo() after createGroup() can legitimately return null while the group is still forming. In that case the runnable never schedules another poll, onHotspotStarted() is never triggered, and the UI can stay stuck on “Starting…” even though the group eventually comes up. Consider continuing to poll (or adding a timeout) until a non-null group is returned.

Useful? React with 👍 / 👎.

Comment on lines +191 to +195
if (attempt > MAX_FRAMEWORK_ATTEMPTS) {
Log.e(TAG, "Failed to start P2P framework after $MAX_FRAMEWORK_ATTEMPTS attempts")
isStarting = false
callback?.onError("Failed to start hotspot. Please try again.")
return

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Clean up locks/receiver when startup fails

If P2P initialization exhausts retries, this path only sets isStarting = false and calls onError but never releases the WakeLock/WifiLock or unregisters the broadcast receiver that were acquired in startHotspot(). When a device can’t form a group (e.g., Wi‑Fi Direct is unavailable or busy), the locks remain held and the receiver stays registered until the process dies, which can drain battery and break subsequent attempts. Consider calling stopHotspot() or explicitly releasing resources before signaling the error.

Useful? React with 👍 / 👎.

@moehamade moehamade marked this pull request as draft January 18, 2026 21:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Integrated hotspot to share APK

1 participant