Using Settings

Settings is part of the Fuchsia SDK and is available on products with the proper supporting packages. Applications on these products can interact with Settings if they have the appropriate permissions. The interaction follows a common pattern for accessing and modifying settings across the Settings protocols.

This guide walks through the steps for incorporating Settings into an application and interacting with Settings.

Prerequisites

The Setting Service supports the Settings protocols in Fuchsia. The service's package //src/settings/service:setui_service and one of its core shard such as //src/settings/service:setui_service_core_shard must be present in the product definition in order to use Settings. The following product definition includes Settings:

import("//products/bringup.gni")

base_package_labels += [
  "//src/settings/service:setui_service",
]
core_realm_shards += [
  "//src/settings/service:setui_service_core_shard",
]

For more information about Fuchsia's build system, see The Fuchsia build system.

Permissions

Any application that accesses Settings must declare usage through its component manifest. For example, the following manifest declares access to the fuchsia.settings.accessibility protocol:

{
    program: {
        runner: "elf",
        binary: "bin/example",
    },
    use: [
        { protocol: "fuchsia.settings.Accessibility" },
    ],
}

For more information about Fuchsia components, see Component manifests.

Connecting

Applications access Settings through the runtime bindings found in the Fuchsia SDK. This guide will use Rust for examples, but bindings are available for a variety of other languages, such as C++ and Dart.

Like other FIDL protocols, the first step to accessing Settings is to connect to the Setting Service. The following example connects to fuchsia.settings.accessibility:

let proxy = connect_to_protocol::<AccessibilityMarker>().context("failed to connect to Settings");

In the above example, connect_to_protocol and AccessibilityMarker are provided through the SDK.

Clients should communicate with each Setting protocol over a single connection. Ongoing communication must occur over the same connection to ensure the consistency and continuity of responses, as explored in later sections.

Reading

Each Setting protocol defines a table for conveying relevant details, such as state and status. Organizing data under a single structure allows Settings to succinctly convey information. The structure also facilitates communicating changes, as discussed later. In the Accessibility example, AccessibilitySettings captures relevant details:

/// Supported accessibility settings.
type AccessibilitySettings = table {
    /// For videos, use an alternative audio track (akin to changing languages)
    /// that explains what is happening visually while there is no dialogue.
    1: audio_description bool;

    /// Read aloud elements of the screen selected by the user.
    2: screen_reader bool;

    /// Invert colors on the screen.
    3: color_inversion bool;

    /// Interpret triple-tap on the touchscreen as a command to zoom in.
    4: enable_magnification bool;

    /// What type of color-blindness, if any, to correct for.
    5: color_correction ColorBlindnessType;

    /// What kind of sources get closed captions, and how they look.
    6: captions_settings CaptionsSettings;
};

A method, called Watch, is present in each protocol to provide access to this information. This is the declaration for fuchsia.settings.accessibility:

Watch() -> (struct {
    settings AccessibilitySettings;
});

Watch follows the hanging get pattern, returning the current information on the initial call. Responses to subsequent invocations are deferred until there is an update to the last returned value. Using the same proxy connection across these requests is critical for this behavior as Settings tracks the delivered responses based on the channel. If an error occurs, Settings will close the FIDL channel with a relevant epitaph.

In the Accessibility example, call Watch to determine if the screen reader is enabled:

let settings = proxy.watch().expect("settings retrieved");
let screen_reader_enabled = settings.screen_reader.ok_or(false);

Writing

Applications can affect Settings by utilizing the same table structure found for reading data. Each mutable protocol offers a counterpart method to Watch called Set, which takes AccessibilitySettings as an argument:

Set(struct {
    settings AccessibilitySettings;
}) -> () error Error;

Changes are conveyed by specifying the desired final state in the table fields. Since each field is optional, only affected fields need to be specified. By defining changes as deltas, race conditions from multiple callers are avoided. If successful, the change will be persisted and applied across boots. Continuing the previous example, a caller can enable the screen reader with the following code:

let new_settings = AccessibilitySettings::default();
new_settings.screen_reader = Some(true);
proxy.set(new_settings).await.expect("request completed").expect("request succeeded");

Debugging

Settings offers a Fuchsia CLI tool (ffx setui) for interacting with its protocols. This tool gives developers real-time access to Settings, enabling them to see how their application affects and is affected by Settings. The ffx setui tool comes with the Fuchsia source code and SDK. To use it, run the following command first to opt in:

ffx config set setui true

To retrieve a Setting protocol's current information (except Accessibility and VolumePolicy), you can call ffx setui with the protocol's name as an argument. For example, the following command retrieves information about Privacy:

ffx setui privacy

For Accessibility, add the keyword watch after the protocol's name:

ffx setui accessibility watch

For VolumePolicy, add the keyword get after the protocol's name:

ffx setui volume_policy get

ffx setui can also modify Settings. The utility's help command details the specific modification syntax per protocol:

ffx setui privacy help

Here is an example of setting the user data sharing consent (user-data-sharing-consent) to true:

ffx setui privacy -u true