Skip to content

Latest commit

 

History

History
57 lines (47 loc) · 22.6 KB

features-android.md

File metadata and controls

57 lines (47 loc) · 22.6 KB

Dao Browser Android Feature Inventory

Android release notes have an independent version history in English and Simplified Chinese, with generated translations for other locales. npm run release:android archives Android Unreleased entries in the same commit as its version update; desktop and iOS notes remain pending. See the changelog guide.

This document catalogs features owned by the standalone Android GeckoView application under android/. Desktop Chromium features are documented in features.md.

1. Android Foundation

  • Application updates — Settings > About supports manual checks, release notes, download progress/cancellation/retry, and installation. Default-enabled automatic checks run quietly on foreground entry at most once per day, including failed attempts; Settings shows an update hint and About shows the last successful check. Checks paginate GitHub releases, select only stable android-vX.Y.Z tags numerically, choose the preferred supported ABI, and require the matching SHA256SUMS entry. Manual checks bypass the daily interval but respect server rate limits. Existing DownloadManager tasks persist their expected version and hash and are reused across recreation. Both About and Downloads stage the completed APK privately, verify its SHA-256, size, package name, exact version name, and increasing version code, then grant the system installer read access through FileProvider. Unknown-source permission returns resume verification; denial or installer cancellation keeps the download available. Update completion notifications do not offer a direct installation bypass. The system installer enforces signing identity and compatibility; there are no silent downloads, forced updates, or background workers.
  • Standalone GeckoView application (android/) — A Kotlin/Compose Android application that consumes Mozilla Android Components and GeckoView as pinned Maven dependencies and builds locally on macOS.
  • Signed release publishing — npm run release:android prompts for increasing Android versions, updates the Gradle version file and archives the pending Android entries in docs/changelog/*.md under the new version and date, commits the version file and archived locales together, creates an android-v* tag, and atomically pushes it with main. Both release workflows enable Gradle ABI splits and build standalone arm64-v8a, armeabi-v7a, and x86_64 APKs instead of bundling all native engines into one download. The tag workflow uses the existing signing secrets, verifies each APK's signature, versions, non-debuggable flag, and single-ABI Gecko libraries, and publishes all three with SHA256SUMS as an ordinary GitHub Release without replacing desktop Latest. Local builds keep a single APK unless -PsplitApks=true is supplied. Dry-run previews leave files and remotes unchanged; workflow reruns recover draft uploads and preserve published APKs. No R2 upload is involved. See android/README.md for prerequisites and recovery.
  • English-first system localization — The unqualified Android catalog is canonical English, Simplified Chinese is a complete qualified resource, and standard Android resource resolution follows the system locale with English fallback. Chromium's id and no translation codes are written to Android's values-in and values-nb qualifiers, which the runtime resolves for Indonesian and Norwegian Bokmål. Locale-sensitive history and new-tab formatting use the selected resource pattern and active locale. The root i18n.sh command dispatches independent desktop and Android GPT-5.5 translators; Android generation validates complete key parity, format placeholders, inline markup, and atomic XML output without sharing runtime resource files with desktop Chromium.
  • Android Components tab store — A ViewModel-owned BrowserStore, backed by EngineMiddleware, is the single source of truth for Gecko tabs, selection, navigation actions, and engine-session lifecycle.
  • Mobile tab switcher — Compact Chrome-style count frames expose the live tab count from the idle new-tab search field and browsing address bar, and open a full-screen two-column grid. The grid opens scrolled to the selected tab and scrolls it back into view when the selection or tab count changes, since new tabs are appended at the bottom. The frame disappears while the new-tab search editor is expanded so editing actions remain uncluttered. Cards support tap-to-switch, an explicit close action, swipe-right-to-close, and new-tab creation; closing the final tab immediately creates a replacement with the same privacy mode.
  • Real tab thumbnails — Opening the tab grid captures the visible page, including the Compose-based new-tab page and Gecko-rendered web content, into a bounded thumbnail before the grid reads it. Regular thumbnails are cached atomically on disk, while private thumbnails remain memory-only and are removed with their tabs.
  • Regular-session restore — Mozilla Android Components SessionStorage restores regular tab order, selection, URLs, Gecko navigation history, and the active page's scroll position after process death. Before the activity leaves the foreground, Dao asks each regular Gecko session to flush its latest state so the background snapshot contains the current viewport. Private tabs are intentionally excluded; default-private startup clears any regular snapshot before creating a private blank tab.
  • Address-or-search navigation — Localized browser chrome resolves HTTP(S), domain, and search input and sends navigation through the Android Components engine session.
  • System web-link handling — Android registers Dao as an HTTP(S) browser candidate and routes both cold-start and warm ACTION_VIEW intents into Gecko. An external link reuses a selected blank tab or opens beside an occupied tab with the same privacy mode, while non-web intents and malformed hostless URLs are ignored.
  • Default browser entry — A standalone Set as default browser card at the top of Settings appears only while Dao is not the system default. Status is checked on entry, when the system picker returns, and whenever Settings resumes, using Android's browser role on Android 10+ and the default generic web-link handler when the role is unavailable or on Android 8–9. Tapping opens Android's browser-role confirmation on supported devices; older versions, an unavailable role, or a failed role-dialog launch open system Default apps settings instead. Selection remains under Android's control: accepting hides the card, cancellation preserves it, and switching the default away from Dao restores it on return. Unavailable or restricted settings show localized feedback.
  • External app links — Gecko navigation delegates custom schemes such as MakerWorld's bambulab:// and Android intent:// links to Mozilla App Links. The foreground activity asks for confirmation before opening an installed app, including from private tabs. The confirmation dialog follows Dao's effective light/dark theme, including a manual override of the system theme. Ordinary HTTP(S) navigation stays in Dao, silent subframe requests are filtered, and only valid HTTP(S) fallback URLs can load in the browser. Android package visibility is limited to browsable URL handlers. A failed launch follows a safe web fallback or shows localized feedback.
  • Safe edge-to-edge browser chrome — The Compose root stays inside safe drawing insets for system bars and display cutouts while the activity uses consistent edge-to-edge behavior. Screens hosting Gecko content apply the software keyboard inset in a single step when the keyboard starts opening or closing rather than following its animation, so GeckoView resizes once and the page does not reflow or jitter while the keyboard moves; Compose-only screens keep following the animated inset. An engine view requests a fresh insets pass when it attaches, and navigating to the current destination again reuses its screen instead of composing a second one, so Gecko's keyboard height stays in sync after returning to a tab or following an external link.
  • Hierarchical destination motion — Utility and nested pages use short directional slide-and-fade transitions, the tab grid uses subtle fade-and-scale motion, and changes among the browser, new-tab page, and address editor remain immediate.
  • Shared Dao brand identity — The Android launcher, new-tab page, and About page reuse the canonical borderless ink-circle artwork rather than the macOS-specific framed application icon. Dao's effective theme, not an Android night resource qualifier, selects the existing dark artwork from branding/dao_logo.png (dao_brand_logo) on light surfaces and the existing white artwork from branding/product_logo_dark.svg (dao_brand_logo_dark) on dark surfaces without runtime tinting, so the mark stays legible when the user overrides the system theme. The adaptive launcher foreground uses its own ic_launcher_logo copy of the dark artwork so the white mark can never land on the white launcher background; it and the legacy mipmap fallbacks remain untinted and keep the mark inside OEM-safe insets so vendor launchers, installers, masks, and scaling do not crop or overfill it.
  • Nova new-tab experience — A token-driven Compose start page provides animated search activation, persisted recent visits and bookmark suggestions, highlighted matches, and a CameraX/ZXing QR scanner that opens decoded content through the normal navigation policy. The scanner uses a centered 300 dp square guide shared by the new-tab and browser-drawer entries. A localized top-right Settings action opens the existing preference screen and hides while search editing is expanded. The idle search pill is a non-editable surface; activation composes the real input, focuses it, and opens the software keyboard. Because Compose never takes Android focus away from an embedded view, the input waits a few frames for the exiting page's engine view to release focus before requesting it, so the keyboard also opens when the user had touched the page. Editing an existing page address opens with its whole URL selected so typing replaces it.
  • Minimal browsing chrome — Real GeckoView content is paired with a single top address bar and a right-side drawer containing back, forward, reload, share, Home, QR scanning, browser-library destinations, and a direct light/dark theme toggle. Reload closes the drawer before refreshing. Android Back closes an open drawer first; Android Back and a left-edge right swipe otherwise navigate the current Gecko page backward when history is available, and Android Back from Settings, History, Bookmarks, Downloads, or Extensions returns to the originating page. When Android kills a tab's content process, its next session reloads the tab's URL over the restored state, so the page never stays on a blank document and its history is kept; that reload drops the restored scroll position. Home reuses the selected tab, preserves its count, and restores the previous page on Back. The address security icon opens a localized bottom sheet backed only by the selected Gecko session's live security state, including available certificate identity, validity, serial number, and SHA-256 fingerprint fields. Unavailable navigation actions use disabled semantics and faint styling, drawer-button ripples stay clipped to their rounded shapes, real Gecko loading progress animates as a clipped address-background fill without moving page content, and top-edge pull-to-refresh reloads without intercepting ordinary mid-page scrolling.
  • Image long-press menu — Long-pressing an image on a page, including one inside a link, opens a localized bottom sheet with Download image, Copy image, Preview image, and Open image in new tab. Images are fetched through Gecko's networking with the browser's cookies and the tab's private mode (no Referer is sent); a response that is a web page instead of an image fails. Download hands that response to the system downloads pipeline, so it streams into Downloads with a notification. Copy saves the image in Dao's cache and puts a FileProvider content:// URI on the clipboard; only the most recent successful copy is kept, a failed copy leaves the previous clipboard image intact, and a toast confirms it below Android 13, where the system does not. Preview opens a full-screen black viewer with pinch-to-zoom and pan, decoding up to 32 MB and downsampling to at most 2048 px on the long edge. Open in new tab is offered only for HTTP(S) images and adds a background tab with the same privacy and shows a toast. Started downloads and copies finish even if the user leaves the browsing screen. Failures show localized action-specific toasts; formats Android cannot decode, such as SVG, cannot be previewed, and page-scoped blob: images may fail.
  • Persistent browser library — SQLite-backed history, bookmarks, reading-list entries, and bookmark folders drive both the new-tab suggestions and the library screens. Visits are recorded after real Gecko loads complete, and the drawer's current-page action switches between an outlined and filled star as its Favorites state changes. Moving an entry into a list that already holds its URL keeps that list's existing entry, with its title and folder, and drops the moved duplicate instead of failing.
  • System downloads — Downloads a page starts first show a themed confirmation dialog that emphasizes the file name in larger semibold text, keeps the confirmation question secondary, shows the size when known, and offers Cancel plus a filled Download action. Only confirmation creates a task or starts saving; dismissing, closing the source tab, or ending the browser session releases the pending response. Multiple requests wait for separate confirmations, and rotation keeps pending requests. Confirmed downloads are saved from the response Gecko already opened, so session cookies, POST results, and page-generated blob:/data: files download exactly as the page served them; Content-Disposition file names come from Mozilla's download utilities after their parameters are ordered for its parser, so extra parameters before a file name do not turn it into a URL endpoint name such as down; encoded filename* takes precedence over filename, quoted semicolons are preserved, and names without an extension get one from the MIME type, and nameless blob:/data: files are called download. They stream into the public Downloads collection through MediaStore on Android 10+ (before that into Dao's app-specific Download folder, shared through Dao's FileProvider) inside a dataSync foreground service whose notification shows progress, and completion or failure posts a notification that opens the file or Dao. On Android 13+ the first active download asks for notification permission; declining only hides those notifications. A body that ends before its unencoded Content-Length fails instead of saving a truncated file, and downloads unfinished when the process died show as failed. Retry re-fetches HTTP(S) downloads through Gecko's networking with the browser's cookies and measures the new response against its own length, and a re-fetch that returns a web page for a non-HTML download fails; failed blob:/data: downloads only offer delete. Private-tab downloads still save their file, but their rows never reach Dao's persisted download list and disappear with the process; data: downloads persist only their URL header. Deleting a finished download also removes its completion notification. App-update APKs keep using Android DownloadManager. Dao persists its own task metadata for both, exposes real status and progress, and supports cancel, retry, delete, and open actions. A repeated Retry on an already-replaced task is ignored, and a failed re-enqueue removes the row with a localized failure toast instead of crashing. Completed files open through their content:// URI with a temporary read grant. APK files use the package-installer MIME type and declared installation-request permission; Android controls whether this source may install apps. Missing or unsafe URIs, unavailable handlers, and denied launch access show localized failure feedback. Deleting a task in edit mode removes the task together with its file and shows a localized toast stating whether the file was deleted or was already missing so only the record was removed. The Downloads screen estimates each running task's transfer speed from byte deltas and monotonic elapsed time using its existing one-second polling. Speed appears on a separate line with Android-localized file-size units, including for unknown total sizes. Each task keeps its sampling baseline and displayed speed between batched system progress updates; five seconds without published progress shows zero. The first sample, non-running states, byte-counter resets, query failures, and polling gaps longer than five seconds hide speed until fresh running samples are available.
  • Persistent browser preferences — DataStore saves the theme override, Gecko page font scale, the selected Google, Baidu, Bing, or DuckDuckGo search engine, recommended tracking protection, and default-private startup behavior. Until the user toggles the theme, Dao follows the Android system light/dark mode; the browsing drawer and Settings toggle then persist an explicit light or dark override. The effective theme drives the Compose chrome, system bar icons, brand logo, and Gecko's preferred color scheme together, so pages' prefers-color-scheme switches with Dao without a reload. Runtime-safe Gecko settings update the active engine/session immediately. Gecko automatic font-size adjustment is disabled so applying Dao's explicit page font scale does not crash startup.
  • Dedicated About and bundled notices — Settings opens a dedicated About screen that reads the installed app version and the build-owned Mozilla Components engine version. Its Open Source Licenses route lists the APK-bundled uBlock Origin and KISS Translator notices and opens their legal text from local assets without a network request. Back returns Licenses to About to Settings, then restores the browser or new-tab destination that originally opened Settings.
  • Opt-in USB remote debugging — An always-visible developer-tools setting enables GeckoView's Firefox DevTools channel only after a first-use security acknowledgement. The persisted switch applies before the first browser session and updates the process-wide runtime immediately; an in-app guide opens Android developer settings and copies about:debugging. Android ADB authorization remains mandatory, and Dao exposes no network listener.
  • Installed extension management — The extensions screen lists only WebExtensions reported by Gecko, displays their real metadata and enabled state, and forwards toggles to the engine. Its Store is a native Compose catalog: a blank search shows AMO recommendations, submitted searches replace the catalog, and later pages append without duplicate extension IDs. Catalog requests ask AMO for Android extensions compatible with the running Gecko major version, then accept only public HTTPS .xpi results. Opening the Store, reviewing an add-on, and installing it do not replace or reselect the active BrowserStore tab. Store installs pass AMO's direct package URL to Gecko with RTAMO; before Gecko completes an install, Dao shows its requested browser permissions, site access, and data-collection permissions and requires explicit approval. The local .xpi picker flow remains available and stages a selected package for Gecko's FROM_FILE path until that install finishes or fails. Release GeckoView still enforces Mozilla signatures, compatibility, and blocklists for both paths; unsigned, incompatible, corrupt, or blocklisted packages are rejected. Catalog fetch failures show a Retry action. Remote install failures reuse the localized extension-install status; after the user dismisses that result with Done, the add-on's Install action becomes available again. Extensions with a Gecko browser action expose an Open control; popup sessions render in a full-screen extension surface while BrowserStore keeps the originating web tab selected, preserving the extension's active-page context. User-installed extensions can be disabled or uninstalled, while APK-bundled extensions cannot be removed from the UI.

2. Built-in Ad Blocking

  • uBlock Origin 1.72.2 — The APK includes a GeckoView compatibility variant of the Firefox WebExtension and requests its installation through the process-wide GeckoEngine before the first regular session is created. The bundled manifest removes only the unsupported desktop menus permission and commands entry; blocking code and filter assets remain unchanged.
  • Offline default enablement — Blocking is enabled by default, requires no first-run download, and updates with the APK.
  • Failure isolation — Installation failure is logged without blocking browser startup.
  • Packaging integrity — Build verification pins the extension ID, version, manifest version, provenance, required files, GeckoView manifest compatibility, and _locales packaging.

3. Built-in Translation

  • KISS Translator 2.0.29 — The APK includes the unmodified Mozilla-signed Firefox package under GPL-3.0-only and installs it as a built-in Gecko extension. A Gecko profile that does not yet contain KISS starts with the extension disabled; later launches preserve Gecko's existing user-selected enabled state. Its upstream UI provides paragraph-by-paragraph bilingual page translation, input and selected-text translation, and subtitle translation without a Dao-owned translation service.
  • Service and migration boundary — Page content is sent to the translation service selected inside KISS Translator, subject to that service's privacy policy. After KISS installs successfully, Dao removes the previously bundled TWP extension from upgraded profiles while preserving other extensions.
  • Packaging integrity and failure isolation — The pre-build audit pins the stable Gecko ID, version, SHA-256, source, GPL-3.0-only notice and license, popup/options UI, locale data, and Mozilla signature metadata. Installation or legacy cleanup failure is logged independently and does not block startup.

Current Status

  • Target: API 26+ application, compiled and targeted against SDK 36.
  • Engine: Mozilla Android Components and GeckoView 153.0.2. The About page identifies the browser engine as Gecko 153.0.2, with the version sourced from the Gradle catalog.
  • Verification: Local build, unit, lint, APK-content, and API 34 emulator checks are available.
  • Foundation gaps: An in-session regular/private mode switch, password storage, sync, Agent, MCP, and a dedicated ad-blocking preference are not implemented.