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