Clone this repo:
  1. a13d95d Fix concurrent modification exception. by Andrew Wilson · 3 weeks ago master
  2. b5d9785 [user_device_shell] Actually check for existence before reading a file by Ian McKellar · 3 weeks ago
  3. 943e8fe [build] Add system_image property to package() by Adam Barth · 3 weeks ago
  4. 89fb7ae Patching state transitions by Ross Wang · 3 weeks ago
  5. be00284 Use the common Topaz options. by P.Y. Laligand · 3 weeks ago

Fuchsia System UI

This repository contains System UI bits for the Fuchsia operating system.


Armadillo is currently the default system UI for Fuchsia. Armadillo is written in Flutter and is split into two separate apps: Armadillo and Armadillo User Shell.

Armadillo is a library of Flutter code.

Armadillo User Shell is a thin wrapper around Armadillo that obtains its data from the Fuchsia system and interacts with the Fuchsia system's services via FIDL interfaces. Thus, Armadillo User Shell only runs on Fuchsia.

Important Armadillo Non-Widget Classes

Some important non-Widget classes are the following:

Story instances are typically generated from an external data source (JSON or the Fuchsia system - see StoryModel below). Conceptually a story is a set of apps and/or modules that work together for the user to achieve a goal. Story contains enough information to create the visual representation of that concept as well as tracks the size and position of its window in the UI via a Panel.

StoryCluster displays one or more Story instances. In Armadillo a user can combine stories into a ‘cluster’ such that the stories in the cluster are always displayed together.

Panel tracks the size and position of a Story's window in its StoryCluster's StoryClusterWidget.

Suggestion instances are typically generated from an external data source (JSON or the Fuchsia system - see SuggestionModel below). Conceptually a suggestion is a representation of an action the user can take to augment an existing story or to start a new one. Suggestion contains enough information to create the visual representation of that concept.

RK4SpringSimulation instances are used throughout Armadillo to perform animations.

Armadillo Mega Widgets

Here is a sampling of the important Widgets used by Armadillo:

Armadillo is the main Widget. Its purpose is to set up Models the rest of the Widgets depend upon. It uses the Conductor to display the actual UI Widgets.

Conductor is responsible for putting all the major Widgets together and connecting their events to each other. These Widgets include: Now, StoryList, and SuggestionList. The Conductor also (temporarily) manages things like the on screen Keyboard if applicable.

StoryList is responsible for displaying all of the user's stories in StoryClusters specified by the StoryModel. StoryList creates StoryClusterWidgets to display each StoryCluster. These StoryClusterWidgets are laid out by StoryListRenderBlock using the algorithm specified in StoryListLayout.

SuggestionList is responsible for displaying all of the suggestions the system has come up with for the user's next actions specified by the SuggestionModel.

Now is responsible for displaying UI related to the user's current context as well as having an affordance for user and device settings. Since a lot of the Widgets used by Now animate in concert, the NowModel creates them and provides them to Now.

StoryClusterWidget is responsible for displaying a StoryCluster. This Widget uses PanelDragTargets to manage what happens when another StoryCluster is dragged above this Widget and StoryPanels to display each Story in the StoryCluster.

ArmadilloDragTarget & ArmadilloLongPressDraggable manage the ability of a user to long press to ‘pick up’ a Widget (ArmadilloLongPressDraggable) and ‘drop it’ onto another Widget (ArmadilloDragTarget).

Armadillo Models

Models are used to pass data down the Widget tree. This data can be simple, like a size or it can be complex like the list of the user's stories.

Models within Armadillo serve several purposes:

  1. Performance. Using a model to store data improves performance when only certain parts of a Widget tree depend on that data. Instead of passing that data to the constructors of all the Widgets between the source of the data and the destination of the data which would cause all of those Widgets to rebuild, the destination Widget can look up the data directly and, in so doing, register to be rebuilt when that data changes.

  2. Simplicity. Often a Widget that depends on a piece of data for displaying itself will be a StatefulWidget. By using a Model for that data, that Widget can now become a StatelessWidget which is much simpler to code and to use.

  3. Coordination. Many of the Widgets in Armadillo depend on each other in subtle ways. By pulling the data for that dependency into a Model each Widget can look to the Model for its dependent data instead of worrying about where that data was generated. Since all Widgets that use the data register with the Model to be rebuilt when it changes, all Widgets will be rebuilt at the same time and react together.

  4. Abstraction. Models provide a simple and standard way of abstracting the source of a Widget's dependent data and the Widget itself. One example of this is how Armadillo and Armadillo User Shell use different sources for their StoryModel and SuggestionModel. Armadillo reads its data from JSON files (via JsonStoryGenerator and JsonSuggestionModel) while Armadillo User Shell gets its data from the Fuchsia framework (via StoryProviderStoryGenerator and SuggestionProviderSuggestionModel).

ConstraintsModel contains the constraints used by the ChildConstraintsChanger which are essentially simulated screen sizes Armadillo can emulate.

DebugModel contains debug flags which are used to enable and disable Widgets like TargetInfluenceOverlay and TargetOverlay.

NowModel provides the Widgets for Now to display.

OpacityModel provides an opacity value. This model is typically used for performance reasons when animating opacity.

PanelResizingModel manages the data around panel resizing for stories within a StoryCluster. This model is populated by the PanelResizingOverlay.

SizeModel provides a size value. This model is typically used for performance reasons when a Widget needs the size of a particular Widget.

StoryClusterDragStateModel holds the data around any ongoing drags of a StoryCluster.

StoryClusterPanelsModel tracks changes to the Panels used by the Stories within a StoryCluster.

StoryClusterStoriesModel tracks changes to the Stories within a StoryCluster.

StoryDragTransitionModel tracks the progress of the story drag transition that occurs when a story cluster is first picked up. All story clusters shrink, Now fades, the SuggestionList unpeeks, etc.

StoryModel provides the list of recent stories the user has used in clusters.

StoryRearrangementScrimModel tracks the progress transition that occurs when one cluster is dragged over another cluster. The background darkens and the background story clusters blur.

SuggestionModel provides the list of suggested next actions for the user to perform.