Files
MrbWebLibre/packages/flutter_mozilla_components/pigeons/gecko.dart
T
2026-07-30 15:00:26 +02:00

3557 lines
99 KiB
Dart

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import 'package:pigeon/pigeon.dart';
/// Translation options that map to the Gecko Translations Options.
///
/// @property downloadModel If the necessary models should be downloaded on request. If false, then
/// the translation will not complete and throw an exception if the models are not already available.
class TranslationOptions {
final bool downloadModel;
TranslationOptions({this.downloadModel = true});
}
/// A language supported by the translation engine.
class TranslationLanguage {
final String code;
final String localizedDisplayName;
TranslationLanguage({required this.code, required this.localizedDisplayName});
}
/// Detected languages for a page.
class TranslationDetectedLanguages {
final String? documentLangTag;
final bool? supportedDocumentLang;
final String? userPreferredLangTag;
TranslationDetectedLanguages({
this.documentLangTag,
this.supportedDocumentLang,
this.userPreferredLangTag,
});
}
/// A from/to language pair for translation.
class TranslationPair {
final String fromLanguage;
final String toLanguage;
TranslationPair({required this.fromLanguage, required this.toLanguage});
}
/// Browser-level translation engine state (global).
class TranslationEngineStateData {
final bool? isEngineSupported;
final List<TranslationLanguage?>? fromLanguages;
final List<TranslationLanguage?>? toLanguages;
TranslationEngineStateData({
this.isEngineSupported,
this.fromLanguages,
this.toLanguages,
});
}
/// Per-tab translation state.
class TabTranslationStateData {
final String tabId;
final bool isTranslated;
final bool isTranslateProcessing;
final bool isOfferTranslate;
final bool isExpectedTranslate;
final String? detectedLanguageCode;
final String? userPreferredLanguageCode;
final String? requestedFromLanguage;
final String? requestedToLanguage;
final String? translationErrorName;
final bool? displayError;
TabTranslationStateData({
required this.tabId,
required this.isTranslated,
required this.isTranslateProcessing,
required this.isOfferTranslate,
required this.isExpectedTranslate,
this.detectedLanguageCode,
this.userPreferredLanguageCode,
this.requestedFromLanguage,
this.requestedToLanguage,
this.translationErrorName,
this.displayError,
});
}
/// Value type that represents the state of reader mode/view.
class ReaderState {
/// Whether or not the current page can be transformed to
/// be displayed in a reader view.
final bool readerable;
/// Whether or not reader view is active.
final bool active;
/// Whether or not a readerable check is required for the
/// current page.
final bool checkRequired;
/// Whether or not a new connection to the reader view
/// content script is required.
final bool connectRequired;
/// The base URL of the reader view extension page.
final String? baseUrl;
/// The URL of the page currently displayed in reader view.
final String? activeUrl;
/// The vertical scroll position of the page currently
/// displayed in reader view.
final int? scrollY;
const ReaderState({
this.readerable = false,
this.active = false,
this.checkRequired = false,
this.connectRequired = false,
this.baseUrl,
this.activeUrl,
this.scrollY,
});
}
/// Parameters for adding a new tab.
class AddTabParams {
final String url;
final bool startLoading;
final String? parentId;
final LoadUrlFlagsValue flags;
final String? contextId;
final SourceValue source;
final bool private;
final HistoryMetadataKey? historyMetadata;
final Map<String, String>? additionalHeaders;
const AddTabParams({
required this.url,
required this.startLoading,
this.parentId,
required this.flags,
this.contextId,
required this.source,
required this.private,
this.historyMetadata,
this.additionalHeaders,
});
}
/// Details about the last playing media in this tab.
class LastMediaAccessState {
/// [TabContentState.url] when media started playing.
/// This is not the URL of the media but of the page when media started.
/// Defaults to "" (an empty String) if media hasn't started playing.
/// This value is only updated when media starts playing.
/// Can be used as a backup to [mediaSessionActive] for knowing the user is still on the same website
/// on which media was playing before media started playing in another tab.
final String lastMediaUrl;
/// The last time media started playing in the current web document.
/// Defaults to [0] if media hasn't started playing.
/// This value is only updated when media starts playing.
final int lastMediaAccess;
/// Whether or not the last accessed media is still active.
/// Can be used as a backup to [lastMediaUrl] on websites which allow media to continue playing
/// even when the users accesses another page (with another URL) in that same HTML document.
final bool mediaSessionActive;
const LastMediaAccessState({
this.lastMediaUrl = "",
this.lastMediaAccess = 0,
this.mediaSessionActive = false,
});
}
/// Represents a set of history metadata values that uniquely identify a record. Note that
/// when recording observations, the same set of values may or may not cause a new record to be
/// created, depending on the de-bouncing logic of the underlying storage i.e. recording history
/// metadata observations with the exact same values may be combined into a single record.
class HistoryMetadataKey {
/// A url of the page.
final String url;
/// An optional search term if this record was
/// created as part of a search by the user.
final String? searchTerm;
/// An optional url of the parent/referrer if
/// this record was created in response to a user opening
/// a page in a new tab.
final String? referrerUrl;
const HistoryMetadataKey({
required this.url,
this.searchTerm,
this.referrerUrl,
});
}
class PackageCategoryValue {
final int value;
const PackageCategoryValue(this.value);
}
/// Describes an external package.
class ExternalPackage {
/// An Android package id.
final String packageId;
/// A [PackageCategory] as defined by the application.
final PackageCategoryValue category;
const ExternalPackage(this.packageId, this.category);
}
class LoadUrlFlagsValue {
final int value;
const LoadUrlFlagsValue(this.value);
}
class SourceValue {
final int id;
final ExternalPackage? caller;
const SourceValue(this.id, this.caller);
}
/// A tab that is no longer open and in the list of tabs, but that can be restored (recovered) at
/// any time if it's combined with an [EngineSessionState] to form a [RecoverableTab].
///
/// The values of this data class are usually filled with the values of a [TabSessionState] when
/// getting closed.
class TabState {
/// Unique ID identifying this tab.
final String id;
/// The last URL of this tab.
final String url;
/// The unique ID of the parent tab if this tab was opened from another tab (e.g. via
/// the context menu).
final String? parentId;
/// The last title of this tab (or an empty String).
final String title;
/// The last used search terms, or an empty string if no
/// search was executed for this session.
final String searchTerm;
/// The context ID ("container") this tab used (or null).
final String? contextId;
/// The last [ReaderState] of the tab.
final ReaderState readerState;
/// The last time this tab was selected.
final int lastAccess;
/// Timestamp of the tab's creation.
final int createdAt;
/// Details about the last time was playing in this tab.
final LastMediaAccessState lastMediaAccessState;
/// If tab was private.
final bool private;
/// The last [HistoryMetadataKey] of the tab.
final HistoryMetadataKey? historyMetadata;
/// The last [IconSource] of the tab.
final SourceValue source;
/// The index the tab should be restored at.
final int index;
/// Whether the tab has form data.
final bool hasFormData;
TabState({
required this.id,
required this.url,
this.parentId,
this.title = "",
this.searchTerm = "",
this.contextId,
this.readerState = const ReaderState(),
this.lastAccess = 0,
this.createdAt = 0,
this.lastMediaAccessState = const LastMediaAccessState(),
this.private = false,
this.historyMetadata,
required this.source, //= Internal.none,
this.index = -1,
this.hasFormData = false,
});
}
/// A recoverable version of [TabState].
class RecoverableTab {
/// The [EngineSessionState] needed for restoring the previous state of this tab.
final String? engineSessionStateJson;
/// A [TabState] instance containing basic tab state.
final TabState state;
const RecoverableTab({this.engineSessionStateJson, required this.state});
}
/// Indicates what location the tabs should be restored at
enum RestoreLocation {
/// Restore tabs at the beginning of the tab list
beginning,
/// Restore tabs at the end of the tab list
end,
/// Restore tabs at a specific index in the tab list
atIndex,
}
/// An icon resource type.
enum IconType {
favicon,
appleTouchIcon,
fluidIcon,
imageSrc,
openGraph,
twitter,
microsoftTile,
tippyTop,
manifestIcon,
}
/// Supported sizes.
///
/// We are trying to limit the supported sizes in order to optimize our caching strategy.
enum IconSize { defaultSize, launcher, launcherAdaptive }
/// A request to load an [Icon].
class IconRequest {
final String url;
final IconSize size;
final List<Resource?> resources;
final int? color;
final bool isPrivate;
final bool waitOnNetworkLoad;
IconRequest({
required this.url,
this.size = IconSize.defaultSize,
this.resources = const [],
this.color,
this.isPrivate = false,
this.waitOnNetworkLoad = true,
});
}
class ResourceSize {
final int height;
final int width;
const ResourceSize({required this.height, required this.width});
}
/// An icon resource that can be loaded.
class Resource {
final String url;
final IconType type;
final List<ResourceSize?> sizes;
final String? mimeType;
final bool maskable;
Resource({
required this.url,
required this.type,
this.sizes = const [],
this.mimeType,
this.maskable = false,
});
}
/// An [Icon] returned by [BrowserIcons] after processing an [IconRequest]
class IconResult {
/// The loaded icon as an [Uint8List].
final Uint8List image;
/// The dominant color of the icon. Will be null if no color could be extracted.
final int? color;
/// The source of the icon.
final IconSource source;
/// True if the icon represents as full-bleed icon that can be cropped to other shapes.
final bool maskable;
IconResult({
required this.image,
this.color,
required this.source,
this.maskable = false,
});
}
/// The source of an [Icon].
enum IconSource {
/// This icon was generated.
generator,
/// This icon was downloaded.
download,
/// This icon was inlined in the document.
inline,
/// This icon was loaded from an in-memory cache.
memory,
/// This icon was loaded from a disk cache.
disk,
}
enum CookieSameSiteStatus { noRestriction, lax, strict, unspecified }
class CookiePartitionKey {
final String topLevelSite;
CookiePartitionKey(this.topLevelSite);
}
class Cookie {
final String domain;
final int? expirationDate;
final String firstPartyDomain;
final bool hostOnly;
final bool httpOnly;
final String name;
final CookiePartitionKey? partitionKey;
final String path;
final bool secure;
final bool session;
final CookieSameSiteStatus sameSite;
final String storeId;
final String value;
Cookie(
this.domain,
this.expirationDate,
this.firstPartyDomain,
this.hostOnly,
this.httpOnly,
this.name,
this.partitionKey,
this.path,
this.secure,
this.session,
this.sameSite,
this.storeId,
this.value,
);
}
enum VisitType {
/// The user followed a link and got a new toplevel window.
link,
/// The user typed the page's URL in the URL bar or selected it from
/// URL bar autocomplete results, clicked on it from a history query
/// (from the History sidebar, History menu, or history query in the
/// personal toolbar or Places organizer.
typed,
/// The user followed a bookmark to get to the page.
bookmark,
/// Some inner content is loaded. This is true of all images on a
/// page, and the contents of the iframe. It is also true of any
/// content in a frame if the user did not explicitly follow a link
/// to get there.
embed,
/// Set when the transition was a permanent redirect.
redirectPermanent,
/// Set when the transition was a temporary redirect.
redirectTemporary,
/// Set when the transition is a download.
download,
/// The user followed a link and got a visit in a frame.
framedLink,
/// The user reloaded a page.
reload,
}
class VisitInfo {
final String url;
final String? title;
final int visitTime;
final VisitType visitType;
final String? previewImageUrl;
final bool isRemote;
final String? contentId;
VisitInfo(
this.url,
this.title,
this.visitTime,
this.visitType,
this.previewImageUrl,
this.isRemote,
this.contentId,
);
}
class HistoryHighlightWeights {
final double viewTime;
final double frequency;
HistoryHighlightWeights(this.viewTime, this.frequency);
}
class HistoryHighlight {
final double score;
final int placeId;
final String url;
final String? title;
final String? previewImageUrl;
HistoryHighlight(
this.score,
this.placeId,
this.url,
this.title,
this.previewImageUrl,
);
}
class TopFrecentSiteInfo {
final String url;
final String? title;
TopFrecentSiteInfo(this.url, this.title);
}
enum FrecencyThresholdOption { none, skipOneTimePages }
/// Document type associated with a [HistoryMetadata] record.
enum DocumentType { regular, media }
/// Per-URL metadata maintained by Places. The unique identity of a record is
/// [HistoryMetadataKey] (url + searchTerm + referrerUrl); we surface only the
/// most recent record per URL via `getLatestHistoryMetadataForUrl`.
class HistoryMetadata {
final HistoryMetadataKey key;
final String? title;
/// Unix milliseconds.
final int createdAt;
/// Unix milliseconds.
final int updatedAt;
/// Total view time in milliseconds.
final int totalViewTime;
final DocumentType documentType;
final String? previewImageUrl;
HistoryMetadata(
this.key,
this.title,
this.createdAt,
this.updatedAt,
this.totalViewTime,
this.documentType,
this.previewImageUrl,
);
}
/// Frecency-ranked autocomplete suggestion. Backs `getSuggestions`.
class HistorySuggestion {
final String url;
final String? title;
/// Larger is more relevant. Unbounded; only meaningful relative to other
/// suggestions returned in the same call.
final int score;
HistorySuggestion(this.url, this.title, this.score);
}
/// Optional metadata observation for a URL. `null` fields are not written.
class PageObservation {
final String? title;
final String? previewImageUrl;
PageObservation({this.title, this.previewImageUrl});
}
class HistoryItem {
final String url;
final String title;
HistoryItem(this.url, this.title);
}
class HistoryState {
final List<HistoryItem?> items;
final int currentIndex;
final bool canGoBack;
final bool canGoForward;
HistoryState(
this.items,
this.currentIndex,
this.canGoBack,
this.canGoForward,
);
}
class ReaderableState {
/// Whether or not the current page can be transformed to
/// be displayed in a reader view.
final bool readerable;
/// Whether or not reader view is active.
final bool active;
ReaderableState(this.readerable, this.active);
}
class SecurityInfoState {
final bool secure;
final String host;
final String issuer;
SecurityInfoState(this.secure, this.host, this.issuer);
}
class TabContentState {
final String id;
final String? parentId;
final String? contextId;
final String url;
final String title;
final int progress;
final bool isPrivate;
final bool isFullScreen;
final bool isLoading;
final bool showToolbarAsExpanded;
TabContentState(
this.id,
this.parentId,
this.contextId,
this.url,
this.title,
this.progress,
this.isPrivate,
this.isFullScreen,
this.isLoading,
this.showToolbarAsExpanded,
);
}
class FindResultState {
final int activeMatchOrdinal;
final int numberOfMatches;
final bool isDoneCounting;
FindResultState(
this.activeMatchOrdinal,
this.numberOfMatches,
this.isDoneCounting,
);
}
enum SelectionPattern { phone, email }
class CustomSelectionAction {
final String id;
final String title;
final SelectionPattern? pattern;
CustomSelectionAction(this.id, this.title, this.pattern);
}
enum WebExtensionActionType { browser, page }
class WebExtensionData {
final String extensionId;
final String? title;
final bool? enabled;
final String? badgeText;
final int? badgeTextColor;
final int? badgeBackgroundColor;
WebExtensionData(
this.extensionId,
this.title,
this.enabled,
this.badgeText,
this.badgeTextColor,
this.badgeBackgroundColor,
);
}
enum AddonDisabledReason {
unsupported,
blocklisted,
userRequested,
notCorrectlySigned,
incompatible,
softBlocked,
}
enum AddonIncognito { spanning, split, notAllowed }
enum AddonUpdateStatus {
notInstalled,
successfullyUpdated,
noUpdateAvailable,
error,
}
class AddonInfo {
final String id;
final String displayName;
final String? summary;
final String description;
final String downloadUrl;
final String version;
final String? installedVersion;
final List<String> translatedPermissions;
final List<String> translatedRequiredDataCollectionPermissions;
final String? authorName;
final String? authorUrl;
final String homepageUrl;
final String detailUrl;
final String ratingUrl;
final double? ratingAverage;
final int? ratingReviews;
final String createdAt;
final String updatedAt;
final Uint8List? icon;
final bool isInstalled;
final bool isEnabled;
final bool isSupported;
final bool isAllowedInPrivateBrowsing;
final bool isAutoUpdateEnabled;
final bool isLocalFileInstalled;
final String? optionsPageUrl;
final bool openOptionsPageInTab;
final AddonDisabledReason? disabledReason;
final AddonIncognito incognito;
const AddonInfo({
required this.id,
required this.displayName,
this.summary,
required this.description,
required this.downloadUrl,
required this.version,
this.installedVersion,
required this.translatedPermissions,
required this.translatedRequiredDataCollectionPermissions,
this.authorName,
this.authorUrl,
required this.homepageUrl,
required this.detailUrl,
required this.ratingUrl,
this.ratingAverage,
this.ratingReviews,
required this.createdAt,
required this.updatedAt,
this.icon,
required this.isInstalled,
required this.isEnabled,
required this.isSupported,
required this.isAllowedInPrivateBrowsing,
required this.isAutoUpdateEnabled,
required this.isLocalFileInstalled,
this.optionsPageUrl,
required this.openOptionsPageInTab,
this.disabledReason,
this.incognito = AddonIncognito.spanning,
});
}
enum AddonStoreApp { android, firefox }
enum AddonStorePromoted { none, recommended, line }
class AddonListingPreview {
final String imageUrl;
final String? thumbnailUrl;
final String? caption;
const AddonListingPreview({
required this.imageUrl,
this.thumbnailUrl,
this.caption,
});
}
class AddonListing {
final String id;
final String name;
final String? summary;
final String? description;
final String? iconUrl;
final String latestVersion;
final String downloadUrl;
final double? ratingAverage;
final int? ratingReviews;
final String? authorName;
final String? authorUrl;
final String? homepageUrl;
final String detailUrl;
final String? ratingUrl;
final int? averageDailyUsers;
final AddonStorePromoted promoted;
final List<AddonListingPreview> previews;
final List<String> permissions;
final List<String> hostPermissions;
final List<String> optionalPermissions;
final List<String> dataCollectionPermissions;
final int? fileSize;
final String? lastUpdated;
final String? licenseName;
final String? licenseUrl;
final String? supportUrl;
final String? supportEmail;
final List<String> categories;
final bool hasPrivacyPolicy;
final String? slug;
const AddonListing({
required this.id,
required this.name,
this.summary,
this.description,
this.iconUrl,
required this.latestVersion,
required this.downloadUrl,
this.ratingAverage,
this.ratingReviews,
this.authorName,
this.authorUrl,
this.homepageUrl,
required this.detailUrl,
this.ratingUrl,
this.averageDailyUsers,
this.promoted = AddonStorePromoted.none,
this.previews = const [],
this.permissions = const [],
this.hostPermissions = const [],
this.optionalPermissions = const [],
this.dataCollectionPermissions = const [],
this.fileSize,
this.lastUpdated,
this.licenseName,
this.licenseUrl,
this.supportUrl,
this.supportEmail,
this.categories = const [],
this.hasPrivacyPolicy = false,
this.slug,
});
}
class AddonStoreInfo {
final String latestVersion;
final String latestXpiUrl;
final double? ratingAverage;
final int? ratingReviews;
final String? summary;
final String? description;
final String? homepageUrl;
final String? detailUrl;
final String? ratingUrl;
final String? authorName;
final String? authorUrl;
const AddonStoreInfo({
required this.latestVersion,
required this.latestXpiUrl,
this.ratingAverage,
this.ratingReviews,
this.summary,
this.description,
this.homepageUrl,
this.detailUrl,
this.ratingUrl,
this.authorName,
this.authorUrl,
});
}
class AddonUpdateAttemptInfo {
final String addonId;
final int dateMillisecondsSinceEpoch;
final AddonUpdateStatus? status;
final String? message;
const AddonUpdateAttemptInfo({
required this.addonId,
required this.dateMillisecondsSinceEpoch,
this.status,
this.message,
});
}
enum GeckoSuggestionType { session, clipboard, history }
class GeckoSuggestion {
final String id;
final GeckoSuggestionType type;
final int score;
final String? title;
final String? description;
final String? editSuggestion;
final Uint8List? icon;
GeckoSuggestion(
this.id,
this.type,
this.score,
this.title,
this.description,
this.editSuggestion,
this.icon,
);
}
class TabContent {
final String tabId;
final String? fullContentMarkdown;
final String? fullContentPlain;
final bool isProbablyReaderable;
final String? extractedContentMarkdown;
final String? extractedContentPlain;
TabContent(
this.tabId,
this.fullContentMarkdown,
this.fullContentPlain,
this.isProbablyReaderable,
this.extractedContentMarkdown,
this.extractedContentPlain,
);
}
enum TrackingProtectionPolicy { none, recommended, strict, custom }
enum HttpsOnlyMode { disabled, privateOnly, enabled }
enum QueryParameterStripping { disabled, privateOnly, enabled }
enum BounceTrackingProtectionMode {
/// Fully disabled.
disabled,
/// Fully enabled.
enabled,
/// Disabled, but collects user interaction data. Use this mode as the
/// "disabled" state when the feature can be toggled on and off, e.g. via
/// preferences.
enabledStandby,
/// Feature enabled, but tracker purging is only simulated. Used for
/// testing and telemetry collection.
enabledDryRun,
}
enum ColorScheme { system, light, dark }
enum CookieBannerHandlingMode { disabled, rejectAll, rejectOrAcceptAll }
/// App links behavior mode - controls how external app links are handled
enum AppLinksMode {
/// Always open links in their native apps without prompting
always,
/// Prompt user before opening in app (with "Always open" checkbox)
ask,
/// Never open links in external apps, always use browser
never,
}
enum WebContentIsolationStrategy {
isolateNothing,
isolateEverything,
isolateHighValue,
}
/// Cookie blocking policy for Custom tracking protection mode.
/// Note: These only apply when blockCookies is true.
enum CustomCookiePolicy {
/// Total Cookie Protection - Dynamic First-Party Isolation (dFPI)
/// Most private option, isolates cookies per site
totalProtection,
/// Block cross-site and social media tracker cookies
/// Allows most cookies but blocks tracking cookies
crossSiteTrackers,
/// Block cookies from sites you haven't visited
/// Balances privacy with functionality
unvisited,
/// Block all third-party cookies
/// Only allows first-party cookies
thirdParty,
/// Block all cookies (may break many sites)
allCookies,
}
/// Scope for applying tracking protection features
enum TrackingScope {
/// Apply to all browsing (normal + private)
all,
/// Apply only to private browsing tabs
privateOnly,
}
class ContentBlocking {
QueryParameterStripping queryParameterStripping;
String queryParameterStrippingAllowList;
String queryParameterStrippingStripList;
BounceTrackingProtectionMode bounceTrackingProtectionMode;
ContentBlocking(
this.queryParameterStripping,
this.queryParameterStrippingAllowList,
this.queryParameterStrippingStripList,
this.bounceTrackingProtectionMode,
);
}
enum DohSettingsMode { geckoDefault, increased, max, off }
class DohSettings {
final DohSettingsMode dohSettingsMode;
final String dohProviderUrl;
final String dohDefaultProviderUrl;
final List<String> dohExceptionsList;
DohSettings(
this.dohSettingsMode,
this.dohProviderUrl,
this.dohDefaultProviderUrl,
this.dohExceptionsList,
);
}
class GeckoEngineSettings {
final bool? javascriptEnabled;
final TrackingProtectionPolicy? trackingProtectionPolicy;
final HttpsOnlyMode? httpsOnlyMode;
final bool? globalPrivacyControlEnabled;
final ColorScheme? preferredColorScheme;
final CookieBannerHandlingMode? cookieBannerHandlingMode;
final CookieBannerHandlingMode? cookieBannerHandlingModePrivateBrowsing;
final bool? cookieBannerHandlingGlobalRules;
final bool? cookieBannerHandlingGlobalRulesSubFrames;
final WebContentIsolationStrategy? webContentIsolationStrategy;
final String? userAgent;
final ContentBlocking? contentBlocking;
final bool? enterpriseRootsEnabled;
final DohSettings? dohSettings;
final String? fingerprintingProtectionOverrides;
final List<String>? locales;
/// Use GeckoView's content-blocking database for tracking protection.
/// This is applied when the engine is created and requires app restart.
final bool? useContentBlockingDatabase;
// Custom Tracking Protection Settings
/// Master toggle for cookie blocking in Custom mode
final bool? blockCookies;
/// Cookie policy selection (only applies when blockCookies is true)
final CustomCookiePolicy? customCookiePolicy;
/// Block tracking scripts and content
final bool? blockTrackingContent;
/// Scope for tracking content blocking
final TrackingScope? trackingContentScope;
/// Block cryptomining scripts
final bool? blockCryptominers;
/// Block known fingerprinters (FINGERPRINTING tracking category)
final bool? blockFingerprinters;
/// Block redirect trackers via cookie purging
final bool? blockRedirectTrackers;
/// Block suspected fingerprinters (separate from FINGERPRINTING category)
/// Controls GeckoView's fingerprintingProtection settings
final bool? blockSuspectedFingerprinters;
/// Scope for suspected fingerprinters blocking
final TrackingScope? suspectedFingerprintersScope;
/// Allow baseline tracking protection exceptions (prevents major site breakage)
final bool? allowListBaseline;
/// Allow convenience tracking protection exceptions (fixes minor issues)
final bool? allowListConvenience;
/// Block advertising, analytics, social, and Mozilla social trackers
final bool? blockAdsAnalyticsSocialTrackers;
// Web Content Settings
final bool? webFontsEnabled;
final bool? automaticFontSizeAdjustment;
final double? fontSizeFactor;
final bool? fontInflationEnabled;
final double? displayDensityOverride;
final int? screenWidthOverride;
final int? screenHeightOverride;
final bool? inputAutoZoomEnabled;
/// Forces pinch-to-zoom to work even on websites that set
/// `user-scalable=no` (or a restrictive `maximum-scale`) on the viewport.
final bool? forceUserScalableContent;
// Process Isolation Settings (require app restart)
final bool? fissionEnabled;
final bool? isolatedProcessEnabled;
final bool? appZygoteProcessEnabled;
final bool? extensionsWebAPIEnabled;
// Local Network Access (LNA) Settings
final bool? lnaBlocking;
final bool? lnaBlockTrackers;
final bool? lnaEnabled;
GeckoEngineSettings(
this.javascriptEnabled,
this.trackingProtectionPolicy,
this.httpsOnlyMode,
this.globalPrivacyControlEnabled,
this.preferredColorScheme,
this.cookieBannerHandlingMode,
this.cookieBannerHandlingModePrivateBrowsing,
this.cookieBannerHandlingGlobalRules,
this.cookieBannerHandlingGlobalRulesSubFrames,
this.webContentIsolationStrategy,
this.userAgent,
this.contentBlocking,
this.enterpriseRootsEnabled,
this.dohSettings,
this.fingerprintingProtectionOverrides,
this.locales,
this.useContentBlockingDatabase,
this.blockCookies,
this.customCookiePolicy,
this.blockTrackingContent,
this.trackingContentScope,
this.blockCryptominers,
this.blockFingerprinters,
this.blockRedirectTrackers,
this.blockSuspectedFingerprinters,
this.suspectedFingerprintersScope,
this.allowListBaseline,
this.allowListConvenience,
this.blockAdsAnalyticsSocialTrackers,
this.webFontsEnabled,
this.automaticFontSizeAdjustment,
this.fontSizeFactor,
this.fontInflationEnabled,
this.displayDensityOverride,
this.screenWidthOverride,
this.screenHeightOverride,
this.inputAutoZoomEnabled,
this.forceUserScalableContent,
this.fissionEnabled,
this.isolatedProcessEnabled,
this.appZygoteProcessEnabled,
this.extensionsWebAPIEnabled,
this.lnaBlocking,
this.lnaBlockTrackers,
this.lnaEnabled,
);
}
class AutocompleteResult {
final String input;
final String text;
final String url;
final String source;
final int totalItems;
AutocompleteResult(
this.input,
this.text,
this.url,
this.source,
this.totalItems,
);
}
/// Represents all the different supported types of data that can be found from long clicking
/// an element.
sealed class HitResult {}
/// Default type if we're unable to match the type to anything. It may or may not have a src.
class UnknownHitResult extends HitResult {
final String src;
final String? linkText;
UnknownHitResult(this.src, {this.linkText});
}
/// If the HTML element was of type 'HTMLImageElement'.
class ImageHitResult extends HitResult {
final String src;
final String? title;
ImageHitResult(this.src, {this.title});
}
/// If the HTML element was of type 'HTMLVideoElement'.
class VideoHitResult extends HitResult {
final String src;
final String? title;
VideoHitResult(this.src, {this.title});
}
/// If the HTML element was of type 'HTMLAudioElement'.
class AudioHitResult extends HitResult {
final String src;
final String? title;
AudioHitResult(this.src, {this.title});
}
/// If the HTML element was of type 'HTMLImageElement' and contained a URI.
class ImageSrcHitResult extends HitResult {
final String src;
final String uri;
ImageSrcHitResult(this.src, this.uri);
}
/// The type used if the URI is prepended with 'tel:'.
class PhoneHitResult extends HitResult {
final String src;
PhoneHitResult(this.src);
}
/// The type used if the URI is prepended with 'mailto:'.
class EmailHitResult extends HitResult {
final String src;
EmailHitResult(this.src);
}
/// The type used if the URI is prepended with 'geo:'.
class GeoHitResult extends HitResult {
final String src;
GeoHitResult(this.src);
}
/// Status that represents every state that a download can be in.
enum DownloadStatus {
/// Indicates that the download is in the first state after creation but not yet [DOWNLOADING].
initiated,
/// Indicates that an [INITIATED] download is now actively being downloaded.
downloading,
/// Indicates that the download that has been [DOWNLOADING] has been paused.
paused,
/// Indicates that the download that has been [DOWNLOADING] has been cancelled.
cancelled,
/// Indicates that the download that has been [DOWNLOADING] has moved to failed because
/// something unexpected has happened.
failed,
/// Indicates that the [DOWNLOADING] download has been completed.
completed,
}
class DownloadState {
final String url;
final String? fileName;
final String? contentType;
final int? contentLength;
final int? currentBytesCopied;
final DownloadStatus? status;
final String? userAgent;
final String? destinationDirectory;
final String? directoryPath;
final String? referrerUrl;
final bool? skipConfirmation;
final bool? openInApp;
final String? id;
final String? sessionId;
final bool? private;
final int? createdTime;
//final Response? response;
final int? notificationId;
DownloadState(
this.url,
this.fileName,
this.contentType,
this.contentLength,
this.currentBytesCopied,
this.status,
this.userAgent,
this.destinationDirectory,
this.directoryPath,
this.referrerUrl,
this.skipConfirmation,
this.openInApp,
this.id,
this.sessionId,
this.private,
this.createdTime,
this.notificationId,
);
}
class ShareInternetResourceState {
final String url;
final String? contentType;
final bool private;
// final Response? response ;
final String? referrerUrl;
ShareInternetResourceState(
this.url,
this.contentType,
this.private,
this.referrerUrl,
);
}
enum LogLevel { debug, info, warn, error }
class AddonCollection {
final String serverURL;
final String collectionUser;
final String collectionName;
AddonCollection({
required this.serverURL,
required this.collectionUser,
required this.collectionName,
});
}
@ConfigurePigeon(
PigeonOptions(
dartOut: 'lib/src/pigeons/gecko.g.dart',
dartOptions: DartOptions(),
kotlinOut:
'android/src/main/kotlin/eu/weblibre/flutter_mozilla_components/pigeons/Gecko.g.kt',
kotlinOptions: KotlinOptions(
package: 'eu.weblibre.flutter_mozilla_components.pigeons',
),
dartPackageName: 'flutter_mozilla_components',
),
)
@HostApi()
abstract class GeckoBrowserApi {
String getGeckoVersion();
// [startupUBlockFilterListsPref] is the JSON-encoded value to write to the
// managed-storage pref read by uBlock Origin at extension startup. The pref
// must be written before the extension registers, so it is plumbed through
// initialize rather than set later.
// If [clearStartupUBlockFilterListsPref] is true, the pref is cleared and
// [startupUBlockFilterListsPref] is ignored. If both are unset/false, the
// pref is left untouched.
void initialize(
String profileFolder,
LogLevel logLevel,
ContentBlocking contentBlocking,
AddonCollection? addonCollection,
String? fxaServerOverride,
String? syncTokenServerOverride,
GeckoEngineSettings? startupSettings,
String? startupUBlockFilterListsPref,
bool clearStartupUBlockFilterListsPref,
);
bool showNativeFragment();
void onTrimMemory(int level);
void openInCustomTab({
required String url,
required bool private,
required String? contextId,
});
bool isDefaultBrowser();
void requestDefaultBrowser();
void shutdown();
}
enum SyncEngineValue { history, bookmarks, tabs }
class SyncEngineStatus {
final SyncEngineValue engine;
final bool enabled;
SyncEngineStatus({required this.engine, required this.enabled});
}
class SyncAccountInfo {
final bool authenticated;
final bool syncing;
final bool needsReauth;
final String? email;
final String? displayName;
final int? lastSyncedAt;
final List<SyncEngineStatus> engines;
SyncAccountInfo({
required this.authenticated,
required this.syncing,
required this.needsReauth,
required this.email,
required this.displayName,
required this.lastSyncedAt,
required this.engines,
});
}
class SyncDevice {
final String deviceId;
final String displayName;
final bool isCurrentDevice;
final bool canSendTab;
SyncDevice({
required this.deviceId,
required this.displayName,
required this.isCurrentDevice,
required this.canSendTab,
});
}
class SyncIncomingTab {
final String title;
final String url;
final String? fromDeviceId;
final String? fromDeviceName;
SyncIncomingTab({
required this.title,
required this.url,
required this.fromDeviceId,
required this.fromDeviceName,
});
}
class SyncRemoteTab {
final String title;
final String url;
final String? iconUrl;
final int lastUsed;
final bool inactive;
SyncRemoteTab({
required this.title,
required this.url,
required this.iconUrl,
required this.lastUsed,
required this.inactive,
});
}
class SyncDeviceTabs {
final String deviceId;
final String deviceName;
final List<SyncRemoteTab> tabs;
SyncDeviceTabs({
required this.deviceId,
required this.deviceName,
required this.tabs,
});
}
@HostApi()
abstract class GeckoSyncApi {
@async
SyncAccountInfo getAccountInfo();
@async
void beginAuthentication();
@async
void beginPairingAuthentication(String pairingUrl);
@async
void logout();
@async
void syncNow();
@async
void setEngineEnabled(SyncEngineValue engine, bool enabled);
@async
List<SyncDeviceTabs> getSyncedTabs();
@async
List<SyncDevice> getDevices();
@async
bool sendTabToDevice(String deviceId, String title, String url, bool private);
@async
void refreshDevices();
@async
void pollDeviceCommands();
@async
List<SyncIncomingTab> drainIncomingTabs();
@async
String? getDeviceName();
@async
bool setDeviceName(String newName);
}
@HostApi()
abstract class GeckoEngineSettingsApi {
void setDefaultSettings(GeckoEngineSettings settings);
void updateRuntimeSettings(GeckoEngineSettings settings);
void setScreenshotProtectionEnabled(bool enabled);
void setPullToRefreshEnabled(bool enabled);
/// Sets whether to use external download managers for downloads.
/// When enabled, downloads are forwarded to third-party apps like ADM, 1DM, AB DM.
void setUseExternalDownloadManager(bool enabled);
bool getUseExternalDownloadManager();
/// Sets the browser-wide default desktop mode (BrowserState.desktopMode).
/// Newly opened tabs inherit this default; a per-tab requestDesktopSite
/// still overrides it for that tab.
///
/// When [applyToExistingTabs] is true, the new value is also applied to all
/// currently open tabs (loaded tabs are reloaded, suspended tabs are updated
/// in place). This should only be requested for an explicit user toggle, not
/// during startup/replication restore, to avoid clobbering per-tab overrides.
void setGlobalDesktopMode(bool enable, bool applyToExistingTabs);
/// Sets whether the reader view dark color scheme should be rendered as pure
/// black (AMOLED). Mirrors WebLibre's "pure black" theme setting into
/// Mozilla's reader view extension. Persisted in SharedPreferences so a
/// cold-started reader view resolves the right value before Flutter runs.
void setReaderViewPureBlack(bool enabled);
/// The set of Gecko contextual-identity ids ("container" contextIds) whose
/// browsing history must NOT be written to Mozilla Places (hard
/// exclude-from-history / "incognito container"). WebLibreHistoryDelegate
/// skips the Places write for a visit resolved to one of these containers.
void setExcludedHistoryContextIds(List<String> contextIds);
}
@HostApi()
abstract class GeckoSessionApi {
void loadUrl({
required String? tabId, //If null = current tab
required String url,
required LoadUrlFlagsValue flags, //== LoadUrlFlagsBuilder.NONE,
required Map<String, String>? additionalHeaders,
});
void loadData({
required String? tabId, //If null = current tab
required String data,
required String mimeType,
required String encoding,
});
void reload({
required String? tabId, //If null = current tab
required LoadUrlFlagsValue flags, //== LoadUrlFlagsBuilder.NONE,
});
void stopLoading({
required String? tabId, //If null = current tab
});
void goBack({
required String? tabId, //If null = current tab
required bool userInteraction,
});
void goForward({
required String? tabId, //If null = current tab
required bool userInteraction,
});
void goToHistoryIndex({
required int index,
required String? tabId, //If null = current tab
});
void requestDesktopSite({
required String? tabId, //If null = current tab
required bool enable,
});
void exitFullscreen({
required String? tabId, //If null = current tab
});
void saveToPdf({
required String? tabId, //If null = current tab
});
void printContent({
required String? tabId, //If null = current tab
});
void translate({
required String? tabId, //If null = current tab
required String fromLanguage,
required String toLanguage,
required TranslationOptions? options,
});
void translateRestore({
required String? tabId, //If null = current tab
});
void crashRecovery({required List<String>? tabIds});
void purgeHistory();
void updateLastAccess({
required String? tabId, //If null = current tab
required int? lastAccess, //If null datetime.now
});
@async
Uint8List? requestScreenshot(bool sendBack);
void dispatchKeyEvent({required int keyCode});
}
@HostApi()
abstract class GeckoTabsApi {
void syncEvents({
required bool onSelectedTabChange,
required bool onTabListChange,
required bool onRestoreComplete,
required bool onTabContentStateChange,
required bool onIconChange,
required bool onSecurityInfoStateChange,
required bool onReaderableStateChange,
required bool onHistoryStateChange,
required bool onFindResults,
required bool onThumbnailChange,
required bool onBrowserExtensionsChange,
required bool onPageExtensionsChange,
required bool onBrowserExtensionIcons,
required bool onPageExtensionIcons,
required bool onTranslationStateChange,
});
void selectTab({required String tabId});
void removeTab({required String tabId});
String addTab({
required String url,
required bool selectTab,
required bool startLoading,
required String? parentId,
required LoadUrlFlagsValue flags,
required String? contextId,
//engineSession: EngineSession? = null,
required SourceValue source, //Internal.NewTab
//searchTerms: String = "",
required bool private,
required HistoryMetadataKey? historyMetadata,
//isSearch: Boolean = false,
//searchEngineName: String? = null,
required Map<String, String>? additionalHeaders,
});
List<String> addMultipleTabs({
required List<AddTabParams> tabs,
required String? selectTabId,
});
void removeAllTabs({required bool recoverable});
void removeTabs({required List<String> ids});
void removeNormalTabs();
void removePrivateTabs();
void undo();
//restoreTabs invokes splitted
void restoreTabsByList({
required List<RecoverableTab> tabs,
required String? selectTabId,
required RestoreLocation restoreLocation,
});
//The calls with engin storage for restore are not supported at the moment
//selectOrAddTab invokes splitted
/// Selects an already existing tab with the matching [HistoryMetadataKey] or otherwise
/// creates a new tab with the given [url].
String selectOrAddTabByHistory({
required String url,
required HistoryMetadataKey historyMetadata,
});
/// Selects an already existing tab displaying [url] or otherwise creates a new tab.
String selectOrAddTabByUrl({
required String url,
required bool private,
required SourceValue source, // = Internal.newTab,
required LoadUrlFlagsValue flags,
required bool ignoreFragment,
});
String duplicateTab({
required String? selectTabId,
required bool selectNewTab,
required String? newContextId,
});
void moveTabs({
required List<String> tabIds,
required String targetTabId,
required bool placeAfter,
});
String migratePrivateTabUseCase({
required String tabId,
required String? alternativeUrl,
});
}
@HostApi()
abstract class GeckoFindApi {
void findAll(String? tabId, String text);
void findNext(String? tabId, bool forward);
void clearMatches(String? tabId);
}
@HostApi()
abstract class GeckoIconsApi {
@async
IconResult loadIcon(IconRequest request);
}
class GeckoPref {
final String name;
final Object? value;
final Object? defaultValue;
final Object? userValue;
final bool hasUserChangedValue;
GeckoPref(
this.name,
this.value,
this.defaultValue,
this.userValue,
this.hasUserChangedValue,
);
}
@HostApi()
abstract class GeckoPrefApi {
@async
Map<String, GeckoPref> getPrefs(List<String> preferenceFilter);
@async
Map<String, GeckoPref> applyPrefs(Map<String, Object> prefs);
@async
void resetPrefs(List<String> preferenceNames);
void startObserveChanges();
void stopObserveChanges();
@async
void registerPrefForObservation(String name);
@async
void unregisterPrefForObservation(String name);
}
/// Type of ML model operation
enum MlProgressType { downloading, loadingFromCache, runningInference }
/// Status of the ML operation
enum MlProgressStatus { initiate, sizeEstimate, inProgress, done }
/// Progress information for ML model operations
class MlProgressData {
/// The type of ML model being loaded
final String modelType;
/// Percentage of completion (0-100)
final double progress;
/// Type of operation (download, cache load, or inference)
final MlProgressType type;
/// Current status of the operation
final MlProgressStatus status;
/// Total bytes loaded so far
final int totalLoaded;
/// Bytes loaded in current update
final int currentLoaded;
/// Total size estimate
final int total;
/// Units of measurement (e.g., "bytes")
final String units;
/// Whether the operation completed successfully
final bool ok;
/// Unique identifier for this operation
final String? id;
const MlProgressData({
required this.modelType,
required this.progress,
required this.type,
required this.status,
required this.totalLoaded,
required this.currentLoaded,
required this.total,
required this.units,
required this.ok,
this.id,
});
}
@HostApi()
abstract class GeckoMlApi {
@async
String predictDocumentTopic(List<String> documents);
@async
List generateDocumentEmbeddings(List<String> documents);
@async
void clearMlCache();
}
@HostApi()
abstract class GeckoBrowserExtensionApi {
@async
List<Object> getMarkdown(List<String> htmlList);
}
class GeckoProxySettings {
final String id;
final String title;
final String type;
final String host;
final int port;
final String? username;
final String? password;
final bool proxyDNS;
final bool doNotProxyLocal;
const GeckoProxySettings({
required this.id,
required this.title,
required this.type,
required this.host,
required this.port,
this.username,
this.password,
this.proxyDNS = true,
this.doNotProxyLocal = true,
});
}
@HostApi()
abstract class GeckoContainerProxyApi {
void setProxyPort(int port);
void addContainerProxy(String contextId);
void removeContainerProxy(String contextId);
void upsertProxy(GeckoProxySettings proxy);
void removeProxy(String proxyId);
void setContainerProxy(String contextId, String proxyId);
void setContainerDirectConnection(String contextId, String scopeId);
void clearContainerProxy(String contextId);
void removeContainerProxyRelation(String contextId, String proxyId);
void setSiteAssignments(Map<String, String> assignments);
/// Strict-mode enforcement map. Keys are Gecko cookie-store contexts to
/// enforce (a strict container's base context plus its isolated tabs'
/// isolation contexts); each value contains the container base contexts that
/// site assignments are keyed on. Tabs in these contexts may only load
/// origins assigned to one of the mapped base contexts (exact match, no proxy
/// equivalence); any other top-level navigation is cancelled and reported
/// back with `strict = true`.
void setStrictContexts(Map<String, List<String>> contexts);
@async
bool healthcheck();
}
@HostApi()
abstract class GeckoCookieApi {
@async
Cookie getCookie(
String? firstPartyDomain,
String name,
CookiePartitionKey? partitionKey,
String? storeId,
String url,
);
@async
List<Cookie> getAllCookies(
String? domain,
String? firstPartyDomain,
String? name,
CookiePartitionKey? partitionKey,
String? storeId,
String url,
);
@async
void setCookie(
String? domain,
int? expirationDate,
String? firstPartyDomain,
bool? httpOnly,
String? name,
CookiePartitionKey? partitionKey,
String? path,
CookieSameSiteStatus? sameSite,
bool? secure,
String? storeId,
String url,
String? value,
);
@async
void removeCookie(
String? firstPartyDomain,
String name,
CookiePartitionKey? partitionKey,
String? storeId,
String url,
);
}
class ContainerSiteAssignment {
final String requestId;
final String? tabId;
final String? originUrl;
final String url;
final bool blocked;
/// True when the navigation was cancelled because the tab's container is in
/// strict mode and the target origin is not assigned to it (as opposed to an
/// ordinary re-open-in-assigned-container block). Strict blocks have no
/// destination container; the app just surfaces a message.
final bool strict;
ContainerSiteAssignment({
required this.requestId,
required this.tabId,
required this.originUrl,
required this.url,
required this.blocked,
required this.strict,
});
}
class ProxyLoadError {
final String? tabId;
final String? contextId;
final String? url;
final String errorType;
ProxyLoadError({
required this.tabId,
required this.contextId,
required this.url,
required this.errorType,
});
}
@FlutterApi()
abstract class GeckoStateEvents {
void onViewReadyStateChange(int sequence, bool state);
void onEngineReadyStateChange(int sequence, bool state);
void onIconUpdate(int sequence, String url, Uint8List bytes);
void onTabAdded(int sequence, String tabId);
void onTabListChange(int sequence, List<String> tabIds);
void onSelectedTabChange(int sequence, String? id);
/// Mirrors `BrowserState.restoreComplete`: false until the native session
/// restore has dispatched all persisted tabs into the store.
void onRestoreCompleteChange(int sequence, bool restoreComplete);
void onTabContentStateChange(int sequence, TabContentState state);
void onHistoryStateChange(int sequence, String id, HistoryState state);
void onReaderableStateChange(int sequence, String id, ReaderableState state);
void onSecurityInfoStateChange(
int sequence,
String id,
SecurityInfoState state,
);
void onIconChange(int sequence, String id, Uint8List? bytes);
void onThumbnailChange(int sequence, String id, Uint8List? bytes);
void onFindResults(int sequence, String id, List<FindResultState> results);
void onLongPress(int sequence, String id, HitResult hitResult);
// void onScrollChange(int sequence, String tabId, int scrollY);
void onPreferenceChange(int sequence, GeckoPref value);
void onContainerSiteAssignment(int sequence, ContainerSiteAssignment details);
void onProxyLoadError(int sequence, ProxyLoadError details);
void onMlProgress(int sequence, MlProgressData progress);
void onDownloadStopped(int sequence, DownloadState state);
void onManifestUpdate(int sequence, String tabId, PwaManifest? manifest);
void onTranslationEngineStateChange(
int sequence,
TranslationEngineStateData state,
);
void onTabTranslationStateChange(int sequence, TabTranslationStateData state);
}
@FlutterApi()
abstract class GeckoSyncStateEvents {
void onAuthStateChanged(int sequence, SyncAccountInfo accountInfo);
void onSyncStarted(int sequence);
void onSyncCompleted(int sequence);
void onSyncError(int sequence, String? errorMessage);
}
@FlutterApi()
abstract class GeckoLogging {
void onLog(LogLevel level, String message);
}
@HostApi()
abstract class ReaderViewEvents {
void onToggleReaderView(bool enable);
void onAppearanceButtonTap();
}
@FlutterApi()
abstract class ReaderViewController {
void appearanceButtonVisibility(int sequence, bool visible);
}
@HostApi()
abstract class GeckoSelectionActionController {
void setActions(List<CustomSelectionAction> actions);
}
@FlutterApi()
abstract class GeckoSelectionActionEvents {
void performSelectionAction(String id, String selectedText);
}
@HostApi()
abstract class GeckoAddonsApi {
@async
List<AddonInfo> getAddons(bool allowCache);
@async
AddonInfo? getAddonById(String addonId, bool allowCache);
@async
AddonStoreInfo? getAddonStoreInfo(String addonId);
@async
List<AddonListing> searchAddonListings(
String query,
AddonStoreApp app,
int page,
int pageSize,
);
@async
List<AddonListing> getFeaturedAddonListings(AddonStoreApp app, int pageSize);
void invokeAddonAction(String extensionId, WebExtensionActionType actionType);
@async
AddonInfo enableAddon(String addonId);
@async
AddonInfo disableAddon(String addonId);
@async
AddonInfo setAddonAllowedInPrivateBrowsing(String addonId, bool allowed);
@async
AddonInfo setAddonAutoUpdateEnabledForAddon(String addonId, bool enabled);
@async
void uninstallAddon(String addonId);
@async
AddonUpdateAttemptInfo? triggerAddonUpdate(String addonId);
@async
void triggerAllAddonUpdates();
@async
AddonUpdateAttemptInfo? getLastAddonUpdateAttempt(String addonId);
@async
void installAddon(String url);
@async
bool isAddonAutoUpdateEnabled();
@async
void setAddonAutoUpdateEnabled(bool enabled);
}
@FlutterApi()
abstract class GeckoAddonEvents {
void onUpsertWebExtensionAction(
int sequence,
String extensionId,
WebExtensionActionType actionType,
WebExtensionData extensionData,
);
void onRemoveWebExtensionAction(
int sequence,
String extensionId,
WebExtensionActionType actionType,
);
void onUpdateWebExtensionIcon(
int sequence,
String extensionId,
WebExtensionActionType actionType,
Uint8List icon,
);
void onWebExtensionPopupRequested(String extensionId, String extensionName);
void onOpenAddonSettingsRequested(String addonId);
}
@HostApi()
abstract class GeckoSuggestionApi {
@async
AutocompleteResult? getAutocompleteSuggestion(String query);
void querySuggestions(String text, List<GeckoSuggestionType> providers);
}
@FlutterApi()
abstract class GeckoSuggestionEvents {
void onSuggestionResult(
int sequence,
GeckoSuggestionType suggestionType,
List<GeckoSuggestion> suggestions,
);
}
@FlutterApi()
abstract class GeckoTabContentEvents {
void onContentUpdate(int sequence, TabContent content);
}
@HostApi()
abstract class GeckoDeleteBrowsingDataController {
@async
void deleteTabs();
@async
void deleteBrowsingHistory();
@async
void deleteCookiesAndSiteData();
@async
void deleteCachedFiles();
@async
void deleteSitePermissions();
@async
void deleteDownloads();
@async
void clearDataForSessionContext(String contextId);
/// Clear browsing data for a specific host/domain
@async
void clearDataForHost(String host, List<ClearDataType> dataTypes);
}
/// Types of browsing data that can be cleared
enum ClearDataType {
/// Authentication sessions
authSessions,
/// All site data (cookies, storage, etc.)
/// WARNING: If this is set it already includes cookies and allCaches. Passing the additionally will lead to issues
allSiteData,
/// Cookies only
onlyCookies,
/// Cache only
onlyCaches,
}
/// Native -> Dart history visit notifications. Fired from WebLibreHistoryDelegate
/// on each recorded Mozilla Places visit so WebLibre can persist the one thing
/// Places can't store: which container the visit belonged to. The visit itself
/// (title, visit type, exact time) stays owned by Places.
@FlutterApi()
abstract class GeckoHistoryEvents {
/// [contextId] is the Gecko contextual identity of the tab that produced the
/// visit, resolved via the URL→contextId correlation cache (null when it
/// couldn't be resolved / the tab was uncontained). Dart maps it to a
/// WebLibre container and writes the visit→container relation, keyed on
/// ([url], [visitTime]) to join back to the Places visit.
void onVisitRecorded(String url, int visitTime, String? contextId);
}
@HostApi()
abstract class GeckoHistoryApi {
@async
List<VisitInfo> getDetailedVisits(
int startMillis,
int endMillis,
List<VisitType> excludeTypes,
);
@async
List<VisitInfo> getVisitsPaginated(
int offset,
int count,
List<VisitType> excludeTypes,
);
@async
void deleteVisit(String url, int timestamp);
@async
void deleteDownload(String id);
@async
void deleteVisitsBetween(int startMillis, int endMillis);
@async
List<HistoryHighlight> getHistoryHighlights(
HistoryHighlightWeights weights,
int limit,
);
@async
List<TopFrecentSiteInfo> getTopFrecentSites(
int limit,
FrecencyThresholdOption frecencyThreshold,
);
/// Returns the most recent [HistoryMetadata] record for [url], or `null` if
/// no metadata has been recorded for that URL.
@async
HistoryMetadata? getLatestHistoryMetadataForUrl(String url);
/// Bulk variant of [getLatestHistoryMetadataForUrl]. Returns one entry per
/// input URL aligned by index; entries are `null` for URLs Places has no
/// metadata for. Used by the local search re-rank to collapse N IPC
/// roundtrips into one.
@async
List<HistoryMetadata?> getLatestHistoryMetadataForUrls(List<String> urls);
/// Bulk visited check: returns booleans aligned with [urls] indicating
/// whether Places has any visit recorded for each URL.
@async
List<bool> getVisited(List<String> urls);
/// Frecency-ranked autocomplete results. Mirrors Places' awesomebar input.
@async
List<HistorySuggestion> getSuggestions(String query, int limit);
/// Places' built-in metadata text search (matches title / url / searchTerm).
/// Useful as a comparison baseline against the local content FTS.
@async
List<HistoryMetadata> queryHistoryMetadata(String query, int limit);
/// Records a title / preview-image observation for [url] without recording
/// a visit. Intended for manual flows; the engine middleware records these
/// automatically as the user browses.
@async
void recordObservation(String url, PageObservation observation);
/// Records a view-time observation against the metadata record identified
/// by [key]. View time is added to the existing total.
@async
void noteHistoryMetadataViewTime(HistoryMetadataKey key, int viewTimeMs);
/// Records a document-type observation against the metadata record
/// identified by [key].
@async
void noteHistoryMetadataDocumentType(
HistoryMetadataKey key,
DocumentType documentType,
);
/// Removes all visits for [url]. May propagate to remote devices via Sync.
@async
void deleteVisitsFor(String url);
/// Removes all visits since [sinceMillis] (inclusive). May propagate to
/// remote devices via Sync.
@async
void deleteVisitsSince(int sinceMillis);
/// Removes all locally stored history. Sync will not remove remote history,
/// but it will prevent deleted entries from returning.
@async
void deleteEverything();
/// Prunes history metadata older than [olderThanMillis] (exclusive).
@async
void deleteHistoryMetadataOlderThan(int olderThanMillis);
}
@HostApi()
abstract class GeckoDownloadsApi {
void requestDownload(String tabId, DownloadState state);
void copyInternetResource(String tabId, ShareInternetResourceState state);
void shareInternetResource(String tabId, ShareInternetResourceState state);
bool openDownloadedFile(
String fileName,
String directoryPath,
String? contentType,
);
}
@FlutterApi()
abstract class BrowserExtensionEvents {
void onFeedRequested(int sequence, String url);
}
class GeckoHeader {
final String key;
final String value;
GeckoHeader({required this.key, required this.value});
}
enum GeckoFetchMethod { get, head, post, put, delete, connect, options, trace }
enum GeckoFetchRedircet { follow, manual }
enum GeckoFetchCookiePolicy { include, omit }
class GeckoFetchRequest {
final String url;
final GeckoFetchMethod method;
final List<GeckoHeader> headers;
final int? connectTimeoutMillis;
final int? readTimeoutMillis;
final String? body;
final GeckoFetchRedircet redirect;
final GeckoFetchCookiePolicy cookiePolicy;
final bool useCaches;
final bool private;
final bool useOhttp;
final String? referrerUrl;
final bool conservative;
GeckoFetchRequest({
required this.url,
required this.method,
required this.headers,
required this.connectTimeoutMillis,
required this.readTimeoutMillis,
required this.body,
required this.redirect,
required this.cookiePolicy,
required this.useCaches,
required this.private,
required this.useOhttp,
required this.referrerUrl,
required this.conservative,
});
}
class GeckoFetchResponse {
final String url;
final int status;
final List<GeckoHeader> headers;
final Uint8List body;
GeckoFetchResponse({
required this.url,
required this.status,
required this.headers,
required this.body,
});
}
@HostApi()
abstract class GeckoFetchApi {
@async
GeckoFetchResponse fetch(GeckoFetchRequest request);
}
enum BookmarkNodeType { item, folder, separator }
class BookmarkNode {
final BookmarkNodeType type;
final String guid;
final String? parentGuid;
final int? position;
final String? title;
final String? url;
final int dateAdded;
final int lastModified;
final List<BookmarkNode>? children;
BookmarkNode({
required this.type,
required this.guid,
required this.parentGuid,
required this.position,
required this.title,
required this.url,
required this.dateAdded,
required this.lastModified,
required this.children,
});
}
/// A node of a bookmark tree that is about to be bulk-inserted into storage.
///
/// Unlike [BookmarkNode] this carries no guids or parent links: the tree is
/// described purely by nesting, and storage assigns guids while inserting.
///
/// @property type Whether this node is an item, a folder or a separator.
/// @property title The title of the item or folder. Ignored for separators.
/// @property url The URL of the item. Must be non-null for items, ignored otherwise.
/// @property dateAdded Creation timestamp in milliseconds since epoch, or 0 if unknown.
/// @property lastModified Modification timestamp in milliseconds since epoch, or 0 if unknown.
/// @property children Child nodes of a folder, in insertion order. Empty for items and separators.
class BookmarkImportNode {
final BookmarkNodeType type;
final String? title;
final String? url;
final int dateAdded;
final int lastModified;
final List<BookmarkImportNode> children;
BookmarkImportNode({
required this.type,
required this.title,
required this.url,
required this.dateAdded,
required this.lastModified,
required this.children,
});
}
/// Outcome of a bulk bookmark tree insertion.
///
/// @property insertedItemCount The number of bookmark items (not folders or
/// separators) that were inserted.
/// @property failedNodeCount The number of top-level nodes that could not be
/// inserted. Their subtrees are missing entirely.
class BookmarkInsertTreeResult {
final int insertedItemCount;
final int failedNodeCount;
BookmarkInsertTreeResult({
required this.insertedItemCount,
required this.failedNodeCount,
});
}
/// Native -> Dart progress for a bulk bookmark insertion.
///
/// A large import is a single [GeckoBookmarksApi.insertTree] call that can run
/// for a long time, so it reports how far along it is rather than leaving the
/// app with nothing to show. Emission is throttled natively, so this fires
/// far less often than once per bookmark.
@FlutterApi()
abstract class GeckoBookmarksEvents {
/// [insertedItemCount] is the running number of bookmark items written by the
/// insertion currently in progress, counted from the start of that one call.
/// Dart adds the offset of any earlier calls to get an overall figure.
void onImportProgress(int insertedItemCount);
}
/// Class for making alterations to any bookmark node
class BookmarkInfo {
final String? parentGuid;
final int? position;
final String? title;
final String? url;
BookmarkInfo({
required this.parentGuid,
required this.position,
required this.title,
required this.url,
});
}
// =============================================================================
// Viewport & Dynamic Toolbar APIs
// =============================================================================
/// Controls GeckoView's viewport behavior for dynamic toolbar and keyboard handling.
///
/// This API allows Flutter to control how GeckoView adjusts its internal viewport
/// without resizing the platform view itself, avoiding visual flickering.
///
/// The dynamic toolbar system works by:
/// 1. Setting the maximum toolbar height via [setDynamicToolbarMaxHeight]
/// 2. Updating the vertical clipping as toolbar animates via [setVerticalClipping]
/// 3. GeckoView internally adjusts viewport and notifies the website
@HostApi()
abstract class GeckoViewportApi {
/// Sets the maximum height that dynamic toolbars (top + bottom) can occupy.
///
/// GeckoView will adjust its internal viewport calculations to account for
/// this space. The website will receive proper viewport dimensions through
/// standard web APIs (CSS viewport units, window.innerHeight).
///
/// Call this once when toolbar dimensions are known, and again if they change.
///
/// [heightPx] Combined height of top and bottom toolbars in pixels.
void setDynamicToolbarMaxHeight(int heightPx);
/// Sets the vertical clipping offset for the GeckoView content.
///
/// Use this as the toolbar animates to clip content at the bottom.
/// Negative values clip from the bottom (for bottom toolbar sliding up).
/// Positive values clip from the top (for top toolbar sliding down).
///
/// Call this during toolbar animation frames to smoothly adjust the visible area.
///
/// [clippingPx] The clipping offset in pixels. Negative = bottom clip.
void setVerticalClipping(int clippingPx);
}
/// Events from native side about viewport and input-related changes.
///
/// These events allow Flutter to react to native viewport changes,
/// particularly keyboard visibility which is detected natively.
@FlutterApi()
abstract class GeckoViewportEvents {
/// Called when keyboard visibility changes.
///
/// This is detected natively using WindowInsets API and provides
/// accurate keyboard height information.
///
/// [sequence] Event sequence number for ordering.
/// [heightPx] Keyboard height in pixels (0 when hidden).
/// [isVisible] Whether the keyboard is currently visible.
/// [isAnimating] Whether the keyboard is currently animating.
void onKeyboardVisibilityChanged(
int sequence,
int heightPx,
bool isVisible,
bool isAnimating,
);
/// Called when GeckoView scroll-handling eligibility changes.
///
/// [sequence] Event sequence number for ordering.
/// [isHandling] True when browser content can consume scrolling for
/// dynamic toolbar behavior. False when content is not scrollable or
/// the page consumed touch input.
void onBrowserHandlingScrollChanged(int sequence, bool isHandling);
}
// =============================================================================
// Bookmarks API
// =============================================================================
@HostApi()
abstract class GeckoBookmarksApi {
/// Produces a bookmarks tree for the given guid string.
///
/// @param guid The bookmark guid to obtain.
/// @param recursive Whether to recurse and obtain all levels of children.
/// @return The populated root starting from the guid.
@async
BookmarkNode? getTree(String guid, bool recursive);
/// Obtains the details of a bookmark without children, if one exists with that guid. Otherwise, null.
///
/// @param guid The bookmark guid to obtain.
/// @return The bookmark node or null if it does not exist.
@async
BookmarkNode? getBookmark(String guid);
/// Produces a list of all bookmarks with the given URL.
///
/// @param url The URL string.
/// @return The list of bookmarks that match the URL
@async
List<BookmarkNode> getBookmarksWithUrl(String url);
/// Produces a list of the most recently added bookmarks.
///
/// @param limit The maximum number of entries to return.
/// @param maxAge Optional parameter used to filter out entries older than this number of milliseconds.
/// @param currentTime Optional parameter for current time. Defaults toSystem.currentTimeMillis()
/// @return The list of bookmarks that have been recently added up to the limit number of items.
@async
List<BookmarkNode> getRecentBookmarks(
int limit,
int? maxAge,
int currentTime,
);
/// Searches bookmarks with a query string.
///
/// @param query The query string to search.
/// @param limit The maximum number of entries to return.
/// @return The list of matching bookmark nodes up to the limit number of items.
@async
List<BookmarkNode> searchBookmarks(String query, int limit);
/// Adds a new bookmark item to a given node.
///
/// Sync behavior: will add new bookmark item to remote devices.
///
/// @param parentGuid The parent guid of the new node.
/// @param url The URL of the bookmark item to add.
/// @param title The title of the bookmark item to add.
/// @param position The optional position to add the new node or null to append.
/// @return The guid of the newly inserted bookmark item.
@async
String addItem(String parentGuid, String url, String title, int? position);
/// Adds a new bookmark folder to a given node.
///
/// Sync behavior: will add new separator to remote devices.
///
/// @param parentGuid The parent guid of the new node.
/// @param title The title of the bookmark folder to add.
/// @param position The optional position to add the new node or null to append.
/// @return The guid of the newly inserted bookmark item.
@async
String addFolder(String parentGuid, String title, int? position);
/// Edits the properties of an existing bookmark item and/or moves an existing one underneath a new parent guid.
///
/// Sync behavior: will alter bookmark item on remote devices.
///
/// @param guid The guid of the item to update.
/// @param info The info to change in the bookmark.
@async
void updateNode(String guid, BookmarkInfo info);
/// Deletes a bookmark node and all of its children, if any.
///
/// Sync behavior: will remove bookmark from remote devices.
///
/// @return Whether the bookmark existed or not.
@async
bool deleteNode(String guid);
/// Bulk-inserts [children] underneath [parentGuid], appending them after any
/// nodes the parent already contains.
///
/// Each top-level folder is handed to the storage layer as a single tree
/// insertion, so importing a large bookmark file costs one platform channel
/// call instead of one per node. Separators are preserved.
///
/// Timestamps survive in full for everything nested inside a top-level
/// folder. Loose top-level items and separators keep their [dateAdded], but
/// their [lastModified] is set to the time of import: the only storage call
/// that accepts timestamps creates a folder, so nodes landing directly in
/// [parentGuid] have to be moved into place afterwards.
///
/// Sync behavior: will add the inserted bookmarks to remote devices.
///
/// Unlike [addItem] and [addFolder] this does *not* emit a
/// `bookmarks.onCreated` extension event per node, since a large import would
/// otherwise flood every installed WebExtension.
///
/// @param parentGuid The guid of the existing folder to insert underneath.
/// @param children The nodes to insert, in the order they should appear.
/// @return The number of inserted bookmark items and failed top-level nodes.
@async
BookmarkInsertTreeResult insertTree(
String parentGuid,
List<BookmarkImportNode> children,
);
/// Counts the bookmark items contained in the trees rooted at [guids].
///
/// Folders and separators are not counted, and a guid that does not exist
/// contributes nothing. Lets the app report how much a destructive action
/// affects without loading the subtrees into Dart.
///
/// @param guids The guids of the folders to count within.
/// @return The total number of bookmark items across all trees.
@async
int countBookmarksInTrees(List<String> guids);
}
// =============================================================================
// Site Permissions API
// =============================================================================
/// Permission status for a site permission
enum SitePermissionStatus {
/// Permission has been granted
allowed,
/// Permission has been denied
blocked,
/// No decision has been made yet (ask to allow)
noDecision,
}
/// Autoplay permission values (matches Fenix's 4 states)
enum AutoplayStatus {
/// Allow all autoplay (audible and inaudible)
allowed,
/// Block all autoplay
blocked,
/// Block audible autoplay only (allow inaudible)
blockAudible,
/// Allow autoplay on WiFi only
allowOnWifi,
}
/// Site permissions data structure
class SitePermissions {
final String origin;
final SitePermissionStatus? camera;
final SitePermissionStatus? microphone;
final SitePermissionStatus? location;
final SitePermissionStatus? notification;
final SitePermissionStatus? persistentStorage;
final SitePermissionStatus? crossOriginStorageAccess;
final SitePermissionStatus? mediaKeySystemAccess;
final SitePermissionStatus? localDeviceAccess;
final SitePermissionStatus? localNetworkAccess;
final AutoplayStatus? autoplayAudible;
final AutoplayStatus? autoplayInaudible;
final int savedAt;
SitePermissions({
required this.origin,
this.camera,
this.microphone,
this.location,
this.notification,
this.persistentStorage,
this.crossOriginStorageAccess,
this.mediaKeySystemAccess,
this.localDeviceAccess,
this.localNetworkAccess,
this.autoplayAudible,
this.autoplayInaudible,
this.savedAt = 0,
});
}
/// API for managing site permissions stored in GeckoView
@HostApi()
abstract class GeckoSitePermissionsApi {
/// Get permissions for origin (single source of truth from GeckoView)
@async
SitePermissions? getSitePermissions(String origin, bool private);
/// Save/update permissions (persisted by GeckoView)
@async
void setSitePermissions(SitePermissions permissions, bool private);
/// Delete permissions for origin (removed from GeckoView storage)
@async
void deleteSitePermissions(String origin, bool private);
}
// =============================================================================
// Public Suffix List API
// =============================================================================
/// Native wrapper for Mozilla's Public Suffix List
@HostApi()
abstract class GeckoPublicSuffixListApi {
/// Get base domain (eTLD+1) from host using Mozilla's Public Suffix List
/// Returns the host unchanged if PSL lookup fails
@async
String getPublicSuffixPlusOne(String host);
}
/// Tracking protection exception for a site
///
/// This represents a site that has been added to the exceptions list,
/// meaning tracking protection is disabled for this specific site.
class TrackingProtectionException {
final String url;
TrackingProtectionException({required this.url});
}
/// API for managing per-site tracking protection exceptions
///
/// This API wraps Mozilla Android Components' TrackingProtectionUseCases
/// to allow Flutter code to add/remove/check tracking protection exceptions
/// on a per-site basis.
@HostApi()
abstract class GeckoTrackingProtectionApi {
/// Check if a tab has a tracking protection exception
///
/// Uses callback pattern to match Mozilla Android Components API.
/// Returns true if the site is in the exceptions list (ETP disabled).
@async
bool containsException(String tabId);
/// Add tracking protection exception for a tab (disable ETP for this site)
///
/// This adds the current tab's URL to the exceptions list.
/// ETP will be disabled for this site until the exception is removed.
void addException(String tabId);
/// Remove tracking protection exception for a tab (enable ETP for this site)
///
/// This removes the current tab's URL from the exceptions list.
/// ETP will be re-enabled for this site.
void removeException(String tabId);
/// Remove a specific exception by URL
///
/// Alternative to removeException(tabId) for cases where you
/// have a URL rather than a tabId.
@async
void removeExceptionByUrl(String url);
/// Fetch all tracking protection exceptions
///
/// Returns list of all sites that have exceptions (ETP disabled).
@async
List<TrackingProtectionException> fetchExceptions();
/// Remove all tracking protection exceptions
///
/// This re-enables ETP for all exception sites.
@async
void removeAllExceptions();
}
// =============================================================================
// App Links API
// =============================================================================
/// Resolved external-app target for a URL (see APP_LINKS_OWN_IMPLEMENTATION_PLAN.md §2.8).
class AppLinkTarget {
/// The URL that was resolved.
final String url;
/// User-facing app label (control/bidi-sanitised), or null when unknown.
final String? appName;
/// Resolved package name, or null when ambiguous / unknown.
final String? packageName;
/// Pre-validated http(s) fallback URL, or null.
final String? fallbackUrl;
/// True when the only offer is a marketplace (install-app) intent.
final bool isMarketplace;
/// True when resolution is ambiguous (chooser / multiple handlers / no default).
final bool isAmbiguous;
/// True when the Gecko engine can load the URL scheme itself.
final bool engineSupportsScheme;
/// Canonical native-owned rule scope key ("host:youtube.com" | "pkg:...").
final String scopeKey;
const AppLinkTarget({
required this.url,
this.appName,
this.packageName,
this.fallbackUrl,
required this.isMarketplace,
required this.isAmbiguous,
required this.engineSupportsScheme,
required this.scopeKey,
});
}
/// Target-side protection pattern replicated to native (§2.3/§2.8). Any target
/// assigned to an effectively-proxied or strict container is protected
/// independent of the source tab.
class ProtectedTargetPattern {
final String scheme;
final String hostOrSuffix;
final bool includeSubdomains;
/// Effective port for exact entries; null for wildcard entries (ignore port).
final int? port;
const ProtectedTargetPattern({
required this.scheme,
required this.hostOrSuffix,
required this.includeSubdomains,
this.port,
});
}
enum NativeAppLinkRuleDecision { alwaysOpen, neverOpen }
/// A remembered per-scope rule replicated to native (§2.8). Distinct from the
/// Dart-persisted `PersistedAppLinkRule`; explicit mappers bridge the two.
class NativeAppLinkRule {
final NativeAppLinkRuleDecision decision;
final String scope;
final String? packageName;
const NativeAppLinkRule({
required this.decision,
required this.scope,
this.packageName,
});
}
/// A container's self-contained app-link policy override (§ container isolation).
/// Present only for containers with "isolated app link settings" enabled; when a
/// navigation's source contextId has an entry here, it fully *replaces* the
/// global mode + rules for that navigation (no layering with the global policy).
class NativeContextAppLinkPolicy {
final AppLinksMode mode;
/// The container's own remembered rules keyed by canonical scope.
final Map<String, NativeAppLinkRule> rules;
const NativeContextAppLinkPolicy({required this.mode, required this.rules});
}
/// Complete, last-write-wins policy snapshot pushed from the single Dart writer
/// to native (§2.8). Native persists it to the profile-scoped prefs record
/// before swapping the in-memory reference.
class AppLinkPolicySnapshot {
final AppLinksMode globalMode;
/// Remembered rules keyed by canonical scope.
final Map<String, NativeAppLinkRule> rules;
final bool marketplaceFallbackEnabled;
/// Regular / no-contextId tabs are proxied via the `general` scope.
final bool protectGeneralContext;
/// contextIds that resolve to a proxy after inherit/bypass/alias.
final List<String> protectedContextIds;
/// strictMode containers, independent of routing.
final List<String> strictContextIds;
final List<ProtectedTargetPattern> protectedTargetPatterns;
/// Per-container app-link policy overrides keyed by contextId. Only isolated
/// containers appear here; a navigation whose source contextId is a key uses
/// the entry's mode + rules in place of the global ones (replace semantics).
final Map<String, NativeContextAppLinkPolicy> contextOverrides;
const AppLinkPolicySnapshot({
required this.globalMode,
required this.rules,
required this.marketplaceFallbackEnabled,
required this.protectGeneralContext,
required this.protectedContextIds,
required this.strictContextIds,
required this.protectedTargetPatterns,
required this.contextOverrides,
});
}
/// Which surface owns a pending prompt (§2.6). Fixed at creation, never transfers.
enum AppLinkPromptOwner { flutterBrowser, nativeExternal }
/// A pending app-link prompt request held in the native `PendingAppLinkStore`
/// until resolved, invalidated, or expired (§2.6/§2.8). Holds only stable
/// identifiers and sanitised data — never engine/store references.
class AppLinkPromptRequest {
/// Monotonic per-process id (Kotlin Long).
final int requestId;
final AppLinkPromptOwner owner;
final String tabId;
final String? contextId;
final String? sourceUrl;
final bool isPrivate;
final bool isWallet;
final bool isProtectedContext;
final bool canRemember;
/// false for the http(s) banner class (non-modal); true for the modal
/// unsupported-scheme prompt.
final bool isModal;
final AppLinkTarget target;
const AppLinkPromptRequest({
required this.requestId,
required this.owner,
required this.tabId,
this.contextId,
this.sourceUrl,
required this.isPrivate,
required this.isWallet,
required this.isProtectedContext,
required this.canRemember,
required this.isModal,
required this.target,
});
}
/// User decision on a pending prompt (§2.6).
enum AppLinkDecision { open, cancel, dismiss }
/// Result of resolving a pending prompt (§2.8).
class AppLinkResolutionResult {
final bool launched;
final bool loadedFallback;
/// "stale" | "dead_session" | "launch_failed" | null.
final String? failureReason;
const AppLinkResolutionResult({
required this.launched,
required this.loadedFallback,
this.failureReason,
});
}
/// API for detecting and launching external applications that can handle URLs.
///
/// WebLibre-owned resolution/launch surface (replaces the Mozilla AC use-case
/// wrappers). Policy lives in Dart; this surface owns PackageManager resolution
/// and Intent launch.
@HostApi()
abstract class GeckoAppLinksApi {
/// Push the complete policy snapshot to native (last-write-wins). Native
/// persists it durably to the active profile's prefs record before acking.
@async
void setAppLinkPolicy(AppLinkPolicySnapshot snapshot);
/// Non-consuming query of pending prompts for [owner] (§2.6). Surfaces call
/// this on attach/resume/rotation and when the availability event fires, and
/// render idempotently by requestId.
@async
List<AppLinkPromptRequest> getPendingAppLinkPrompts(AppLinkPromptOwner owner);
/// Atomically resolve a pending prompt: validate it still exists and its tab
/// is alive, consume it (double-resolve is a no-op), then perform side effects
/// after releasing the store lock (§2.6).
@async
AppLinkResolutionResult resolvePendingAppLink(
int requestId,
AppLinkDecision decision,
);
/// Resolve [url] to an external-app target.
///
/// Returns null when no external app is available, on any resolution error, or
/// for always-denied schemes — callers cannot distinguish "nothing installed"
/// from "resolution failed", matching the previous `hasExternalApp` contract.
///
/// [includeHttpAppLinks] when true, an app resolving an engine-supported
/// (http(s)) URL is surfaced (e.g. the YouTube app for a youtube.com link).
@async
AppLinkTarget? resolveAppLink(String url, bool includeHttpAppLinks);
/// Re-resolve [url] and launch it in an external app.
///
/// Re-resolves internally immediately before launch and returns false on
/// no-app or ActivityNotFoundException/SecurityException; never throws across
/// the channel for expected conditions.
@async
bool launchAppLink(String url);
}
/// Optimisation-only availability signal for pending app-link prompts (§2.8).
///
/// A Pigeon `@FlutterApi()` callback has no buffering or replay: an event
/// emitted while Flutter is detached is lost. The `PendingAppLinkStore` is the
/// source of truth; surfaces query on attach/resume and dedupe by requestId.
@FlutterApi()
abstract class GeckoAppLinkEvents {
void onAppLinkPromptAvailable(int sequence, AppLinkPromptOwner owner);
}
// =============================================================================
// PWA API
// =============================================================================
/// Represents an icon from a PWA manifest.
class PwaIcon {
final String src;
final String? sizes;
final String? type;
const PwaIcon({required this.src, this.sizes, this.type});
}
/// Represents a file entry in share target params.
class ShareTargetFiles {
final String name;
final List<String?> accept;
const ShareTargetFiles({required this.name, required this.accept});
}
/// Represents share target params.
class ShareTargetParams {
final String? title;
final String? text;
final String? url;
final List<ShareTargetFiles?> files;
const ShareTargetParams({
this.title,
this.text,
this.url,
this.files = const [],
});
}
/// Represents a share target for PWA.
class ShareTarget {
final String action;
final String? method;
final String? encType;
final ShareTargetParams? params;
const ShareTarget({
required this.action,
this.method,
this.encType,
this.params,
});
}
/// Represents an external application resource.
class ExternalApplicationResource {
final String platform;
final String? url;
final String? id;
final String? minVersion;
const ExternalApplicationResource({
required this.platform,
this.url,
this.id,
this.minVersion,
});
}
/// Represents a PWA web app manifest.
///
/// Mirrors Mozilla Android Components' WebAppManifest structure.
/// https://firefox-source-docs.mozilla.org/mobile/android/geckoview/api/mozilla.components.concept.engine.manifest.WebAppManifest.html
class PwaManifest {
final String startUrl;
final String? name;
final String? shortName;
final String? display;
final String? themeColor;
final String? backgroundColor;
final String? scope;
final String? description;
final List<PwaIcon?> icons;
final String? dir;
final String? lang;
final String? orientation;
final List<ExternalApplicationResource?> relatedApplications;
final bool preferRelatedApplications;
final ShareTarget? shareTarget;
/// The URL of the page when the manifest was detected.
/// Used for HTTPS/installability checks.
final String currentUrl;
/// Storage context (container contextualIdentity or isolated `iso1_…` id)
/// that this install was pinned with. Only populated by
/// `getInstalledWebApps` — read from the pinned shortcut's intent extras,
/// not from the manifest itself, because the same URL can have multiple
/// installs that differ only in contextId.
final String? contextId;
/// User-chosen launcher label for this specific install (from the pinned
/// shortcut's shortLabel). May differ from `name`/`shortName` because the
/// underlying manifest is shared across install variants of the same URL.
/// Only populated by `getInstalledWebApps`.
final String? installLabel;
const PwaManifest({
required this.startUrl,
required this.currentUrl,
this.name,
this.shortName,
this.display,
this.themeColor,
this.backgroundColor,
this.scope,
this.description,
this.icons = const [],
this.dir,
this.lang,
this.orientation,
this.relatedApplications = const [],
this.preferRelatedApplications = false,
this.shareTarget,
this.contextId,
this.installLabel,
});
}
/// API for PWA (Progressive Web App) installation and management.
///
/// Wraps Mozilla Android Components' WebAppUseCases and ManifestStorage
/// to provide PWA install and query functionality to Flutter.
@HostApi()
abstract class GeckoPwaApi {
/// Installs the current page as a PWA (adds to home screen).
///
/// Creates an Android shortcut with profile and container metadata embedded
/// in the intent extras. This ensures the PWA opens with the same profile
/// and container context that was active during installation.
///
/// The [tabId] identifies which tab to install from. If null, uses the selected tab.
/// The [profileUuid] is the UUID of the current user profile.
/// The [contextId] is the container's contextual identity (optional, null for default container).
/// The [overrideAppName] customizes the installed app's displayed name and persists in the saved manifest.
/// Returns true if installation was successful.
@async
bool installWebApp(
String? tabId,
String profileUuid,
String? contextId,
String? overrideAppName,
);
/// Returns a list of all installed PWA manifests.
@async
List<PwaManifest> getInstalledWebApps();
/// Creates a basic bookmark shortcut on the home screen (no manifest required).
///
/// Unlike [installWebApp], this creates a simple shortcut that opens
/// in a regular browser tab rather than standalone PWA mode.
/// Uses the page title and favicon for the shortcut.
///
/// The [tabId] identifies which tab to create the shortcut for. If null, uses the selected tab.
/// The [profileUuid] is the UUID of the current user profile.
/// The [contextId] is the container's contextual identity (optional).
/// The [overrideShortcutName] allows customizing the shortcut label.
/// Returns true if the shortcut was created successfully.
@async
bool installBasicShortcut(
String? tabId,
String profileUuid,
String? contextId,
String? overrideShortcutName,
);
}
/// Per-tab sandbox capture state shared with the native side. The Kotlin
/// [AppRequestInterceptor] consults an in-memory registry populated from
/// these entries to decide how to handle loads in sandbox tabs.
///
/// [redirectUrl] is precomputed by Dart and always points at a loopback URL
/// (loader or capture). Dart is responsible for keeping it current; Kotlin
/// never calls back into Dart to resolve it.
class SandboxCaptureEntry {
final String tabId;
final String captureId;
final String sourceUrl;
/// `http://127.0.0.1:<port>/loader?…` while pending/failed, or
/// `http://127.0.0.1:<port>/captures/…?t=<token>` once ready.
final String redirectUrl;
/// `pending` | `ready` | `failed`.
final String status;
SandboxCaptureEntry({
required this.tabId,
required this.captureId,
required this.sourceUrl,
required this.redirectUrl,
required this.status,
});
}
/// Dart → Kotlin. Mutates the native [SandboxCaptureRegistry] that the
/// request interceptor consults on every load.
@HostApi()
abstract class SandboxCaptureApi {
/// Replaces the entire registry with [entries]. Called at startup after
/// Dart has brought up [CaptureServer] and reconciled local artifacts with
/// the `capture_tab` rows.
void resetAll(List<SandboxCaptureEntry> entries);
/// Inserts or updates the registry entry for [entry.tabId].
void mark(SandboxCaptureEntry entry);
/// Removes the registry entry for [tabId].
void unmark(String tabId);
}
/// Kotlin → Dart. Fire-and-forget notifications from the request
/// interceptor / BrowserStore middleware. All handlers are non-blocking;
/// the interceptor never waits for a Dart response.
@FlutterApi()
abstract class SandboxCaptureHostEvents {
/// Emitted when a sandbox tab attempted to navigate to a non-loopback,
/// non-source URL (e.g., user clicked a link or typed a new URL into the
/// address bar). Dart should open a new sandbox tab and capture [targetUrl].
void onSandboxLinkClick(int sequence, String parentTabId, String targetUrl);
/// Emitted when GeckoView created a new tab (via `window.open`,
/// `target="_blank"`, or a middle-click) whose parent is a sandbox tab.
/// The native middleware has already rewritten the new tab's URL to
/// `about:blank`; Dart should register it as sandbox and run the capture
/// pipeline for [targetUrl].
void onSandboxNewTab(
int sequence,
String parentTabId,
String newTabId,
String targetUrl,
);
}
// =============================================================================
// Touch Gestures API
// =============================================================================
/// Configuration for native touch-gesture recognition.
///
/// Pushed from Dart whenever the user's gesture settings change. Native
/// recognition is purely observational: it assembles a canonical stroke key
/// (start-position prefix + finger-count prefix + dash-joined directions, e.g.
/// `R:2:D-L`) and only emits when that key matches an entry in
/// [activeGestureKeys]. Strokes that do not match are ignored, so normal
/// scrolling, tapping and pinch-zoom are never affected.
class GestureConfig {
final bool enabled;
/// Base stroke length in logical pixels, scaled at runtime by
/// `min(viewWidth, viewHeight) / 320` to match the reference gesture add-on.
final int strokeSize;
/// Milliseconds of inactivity after which an in-progress gesture is
/// discarded.
final int timeoutMs;
/// Maximum number of simultaneous pointers a gesture may use.
final int maxFingers;
/// Minimum milliseconds required between two consecutive direction changes
/// within a single gesture. A new direction registered faster than this
/// aborts the in-progress gesture, so accidental fast scribbles match
/// nothing. `0` disables the check.
final int minStrokeIntervalMs;
/// Canonical keys that currently have an action bound, e.g. `D-R`,
/// `R:2:D-L`. Native only emits [GeckoGestureEvents.onGestureRecognized]
/// when an assembled stroke matches one of these.
final List<String> activeGestureKeys;
GestureConfig({
this.enabled = false,
this.strokeSize = 50,
this.timeoutMs = 1500,
this.maxFingers = 1,
this.minStrokeIntervalMs = 0,
this.activeGestureKeys = const [],
});
}
/// Dart → Kotlin. Pushes the current gesture-recognition configuration.
@HostApi()
abstract class GeckoGestureApi {
void setGestureConfig(GestureConfig config);
}
/// Kotlin → Dart. Emitted when an assembled touch stroke matches a configured
/// gesture key.
@FlutterApi()
abstract class GeckoGestureEvents {
/// [sequence] Event sequence number for ordering.
/// [gestureKey] Canonical key of the recognized gesture, e.g. `D-R`.
void onGestureRecognized(int sequence, String gestureKey);
/// Emitted while a stroke is being drawn, each time a new direction arrow is
/// appended. Drives the live feedback overlay.
///
/// [sequence] Event sequence number for ordering.
/// [partialKey] Current partial canonical key including start/finger
/// prefixes, e.g. `R:D`.
void onGestureProgress(int sequence, String partialKey);
/// Emitted when an in-progress stroke ends (release, cancel or idle timeout)
/// so the live feedback overlay can be hidden.
///
/// [sequence] Event sequence number for ordering.
void onGestureReset(int sequence);
}
/// Lifecycle state of the selected UnifiedPush distributor.
enum PushDistributorStatus {
/// No distributor app is installed on the device.
noneAvailable,
/// Distributors are installed but the user has not chosen one.
notSelected,
/// A distributor is chosen but has not acknowledged our registration yet.
pending,
/// A distributor is chosen and has acknowledged our registration.
ready,
/// A distributor was chosen previously but is no longer installed. Web push
/// is dead in this state and there is no fallback transport.
unavailable,
}
class PushDistributor {
final String packageName;
/// Human-readable app label, or null if the package is no longer installed.
final String? label;
PushDistributor({required this.packageName, required this.label});
}
class PushStatus {
final PushDistributorStatus status;
final PushDistributor? current;
final List<PushDistributor> available;
/// Most recent distributor registration failure, or null if none.
///
/// Held natively rather than delivered as a one-shot event: registrations are
/// attempted at startup and from background broadcasts, both of which can run
/// long before any Dart listener exists.
final String? lastError;
PushStatus({
required this.status,
required this.current,
required this.available,
required this.lastError,
});
}
class PushSubscription {
/// Subscription identifier, which for web push is the site's origin.
final String scope;
/// Whether the distributor has handed back an endpoint for this scope.
final bool hasEndpoint;
PushSubscription({required this.scope, required this.hasEndpoint});
}
/// Dart → Kotlin. UnifiedPush distributor management and web push introspection.
@HostApi()
abstract class GeckoPushApi {
@async
PushStatus getPushStatus();
/// Selects [packageName], which must be one of [PushStatus.available].
///
/// The picker is built in Dart rather than delegated to the connector's own
/// dialog, which would save the selection against a non-profile context.
@async
void setDistributor(String packageName);
/// Forgets the current distributor. This is the off switch for web push.
@async
void removeDistributor();
@async
void renewRegistration();
/// Pauses push transport for the current profile before switching profiles.
/// Site subscriptions and the chosen distributor are retained for restoration
/// when this profile becomes active again.
@async
void suspendForProfileSwitch(String targetProfileId);
/// Subscriptions Gecko has created, read from the UnifiedPush store. Read-only:
/// there is no app→Gecko channel to revoke a subscription, so removal has to go
/// through the site's notification permission instead.
@async
List<PushSubscription> getSubscriptions();
}
/// Kotlin → Dart. Push registration lifecycle.
///
/// Registration failures reach Dart through [PushStatus.lastError] rather than a
/// dedicated event, so a failure raised before any Dart listener is attached is
/// still visible the first time the settings screen reads the status.
@FlutterApi()
abstract class GeckoPushEvents {
/// [sequence] Event sequence number for ordering.
void onPushStatusChanged(int sequence, PushStatus status);
}