Change by task

July 29, 2026 · View on GitHub

简体中文 · Maintainer guide

Before editing code, write the complete path: who creates the request, which Hook is called, who applies the result, and where the user sees the change. A contract with no host caller or result applier is still a placeholder.

Add or change a Hook

Work in this order:

  1. Define request, result, and HookSpec in :extension:api. Put general features in HostHookContracts.kt and provider features under subscription/.
  2. Add that official HookSpec and its base capabilities to the single ExtensionContractCatalog entry list. Its supported-schema and capability views are derived from this list.
  3. Cover affected registration, version, capability, error, size, timeout, and cancellation behavior in ExtensionRuntimeTest.
  4. Add a real host caller; the manifest declaration only advertises that the Hook is available.
  5. Add a scoped host applier and test errors, oversized results, partial failure, and successful empty results.
  6. Update an APK example with TypedExtensionService, then cover cross-process behavior in extension-reference.
  7. Update the English and Chinese developer feature page and maintainer status page.

Additive compatible fields need defaults. Raise the Hook schema version when an old implementation cannot safely handle the new shape; raise the API major only for platform-wide incompatibility.

Change the built-in Emby/Jellyfin provider

The complete path is:

SubscriptionProviderRepositoryImpl
  -> ExtensionRuntime.invoke(SubscriptionHookSpecs.*)
  -> EmbyCompatibleProvider -> EmbyCompatibleClient
  <- typed result
SubscriptionProviderRepositoryImpl -> SubscriptionProviderImporter

Start in EmbyCompatibleProviderIntegrationTest for HTTP behavior and SubscriptionProviderRepositoryIntegrationTest for persistence and lifecycle.

New provider kinds are driven by descriptors and declarative settings. The generic source selector, form state, subscription repository, and importer do not branch on concrete ProviderKind; only the provider implementation does. New subscriptions are stored as DataSource.Provider. DataSource.Emby and DataSource.Jellyfin remain legacy compatibility inputs.

Change APK discovery, trust, or IPC

ChangeMain files
Service action, discovery, and package identityExtensionProtocol, AndroidExtensionDiscovery
Explicit binding, handshake, PFD, and callsAndroidBoundExtensionTransport
APK-side Binder implementationExtensionService
APK-side typed Hook registrationTypedExtensionService
Certificate pinning and user authorizationExtensionTrustStore, ExtensionPluginRepositoryImpl
Cross-process fixturetesting/extension-reference

Every lifecycle change must cover normal return, cancellation, timeout, Binder death, disable, revocation, and process restart. Use ExtensionConnectionStateTest for connection state and ExternalExtensionIpcTest for the cross-process path.

Change a result applier

An applier must define the current request scope, result owner, and old-data replacement scope.

At minimum, cover that:

  • a failure or exception preserves previous valid data;
  • one extension failure does not affect another extension;
  • a successful empty result clears only the current owner's data;
  • cancellation continues upward;
  • count or field overflow is not treated as a complete truncated success;
  • deletion and insertion happen in one transaction.

For persistent channel, provider, and EPG work, start with SubscriptionProviderImporter, ExtensionContributionRepositoryImplTest, and ExtensionContributionImporterTest.

Change settings, credentials, or the network broker

ExtensionSettingsRepositoryImpl owns settings schema and ordinary values. Host vaults encrypt secret settings and provider tokens. Extension contracts carry credential handles, never plaintext secrets.

When changing the broker, add denial cases to HostNetworkBrokerSecurityTest before implementing behavior. Changes to owner, origin, redirect, authentication headers, response size, or credential capture must also be checked against the external extension release gates.

Change phone or TV UI

UI observes repository state and sends operations; it does not discover or bind services directly.

Check full-row clicks, scrollable authorization, visible errors, and settings persistence on phone. Check DPad order, focus contrast, back behavior, and long text on TV.

Validation evidence

ChangeClosest evidence
API or runtimeExtensionContractTest, ExtensionRuntimeTest
APK SDK and typed handlersTypedExtensionServiceTest, hello-extension
Certificate trust and connection stateCertificateSetFingerprintTest, ExtensionTrustStoreTest, ExtensionConnectionStateTest
Cross-process discovery, binding, PFD, invocation, and cancellationExternalExtensionIpcTest, extension-reference
External provider lifecycleExternalProviderEndToEndTest, extension-reference, mock-server
Built-in provider and importerEmbyCompatibleProviderIntegrationTest, SubscriptionProviderRepositoryIntegrationTest, and the applier tests linked above
Phone or TV product flowThe product UI test for the changed trigger and visible result