
This is dangerous because SetUp() in subclass may call this, which in turn may bypass a SetUp in its super class. (like in exo) Instead of adding aonther "set_delegate", CL allows a subclass update init_params_ directly via input_parmas(). This uses reference as the caller should never see nullptr (or it should be treated as fatal). This also updates ctor of ChromeAhsTestBase to call its ctor so that it has single call path to super classe's ctor. Bug: None Change-Id: If18131a3f3e5e893b473013f9383044b22c9e9e7 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6355206 Reviewed-by: Hidehiko Abe <hidehiko@chromium.org> Commit-Queue: Mitsuru Oshima <oshima@chromium.org> Cr-Commit-Position: refs/heads/main@{#1435864}
Shelf
This is the ash shelf, the system interface surface that allows users to launch application shortcuts or go to the home screen, among other things.
Components
The shelf contains the following components, each of which lives in its own widget:
-
The shelf widget contains no actionable UI but contains the semi-opaque background shown behind the whole shelf as well as the drag handle (in certain circumstances) to give users a hint that gestures can be performed. In that sense, even though the shelf widget does not actually contain other components, it usually serves as a backdrop for them.
-
The navigation widget contains the home and back buttons. It is usually shown in clamshell mode (but only with the home button) and hidden in tablet mode, unless the activation of select accessibility features forces it to be shown. When the navigation widget is not shown, the user can achieve the same actions by performing gestures.
-
The hotseat widget contains icons for application shortcuts and running applications. In clamshell mode, it is always visually contained within the shelf widget; in tablet mode, it can appear and move independently.
-
The status area widget (whose code lives in
ash/system
) shows information such as the clock or current battery level, and can toggle the system tray.
Alignment
The shelf is aligned to the bottom of the screen by default, but the user can choose (only in clamshell mode) to align it to the left or right of the screen. It always occupies the entirety of the corresponding dimension (width for a horizontal shelf, height otherwise), with the navigation widget shown at the start (top or left in left-to-right interfaces, bottom or right in right-to-left) and the status area at the other end.
Auto-hiding
The system allows the user to set a boolean preference, on a per-display basis, specifying whether the shelf should "auto-hide". In that case, the shelf and its components will be hidden from the screen most of the time, unless there are no un-minimized windows or unless the user actively brings up the shelf with the mouse or with a swipe.
Centering
The hotseat widget is centered on the screen according to the following principle:
-
All icons are placed at the center of the whole display if they can fit without overlapping with any other shelf component.
-
Otherwise, they are centered within the space available to the hotseat.
-
If there are too many icons to fit in that space, the hotseat becomes scrollable.
Responsive layout
The shelf and its components need to adjust to a certain number of changes that may or may not be user-triggered:
-
Switching between clamshell and tablet mode.
-
Changing the display size (for smaller displays, the shelf becomes more compact) or orientation.
-
Changing the shelf alignment.
-
User events (clicks, taps, swipes).
Coordination
All shelf components need to react to these changes in a coordinated manner to maintain the smoothness of animations.
Components should not register themselves as observers of these changes and react to them on their own, because an adequate reaction may involve other components as well. For instance, whether the navigation widget is shown (or is scheduled to be shown at the end of the animation) will influence the amount of space the hotseat widget can occupy.
Instead, listening to those changes are handled at the ShelfLayoutManager
level, which is then responsible for making the changes trickling down to each
component as necessary.
Aim first, move second
In reaction to any of these global changes, each component must first determine where it wants to be at the end of the animation ("aim"). That calculation may depend on the other shelf components. Then, and only then, should the change of bounds be actually committed to each widget and the animations triggered ("move"). Failing to respect this "two-phase" approach may lead to janky animations as each component may realize, only after it has started moving, that another component's movement forces it to alter its final destination.
ShelfComponent
interface
Each of the shelf components exposes an API to other classes in order to ease the process of responding to layout changes:
-
CalculateTargetBounds
is the "aim" phase, where each component figures out where it wants to be given the new conditions. This method must be called on each component by order of dependency (a component B "depends" on another component A if B needs to know A's target bounds before calculating its own). -
GetTargetBounds
allows for components depending on this one to calculate their own target bounds accordingly. -
UpdateLayout
is the "move" phase, where each component actually changes it bounds according to its target. -
UpdateTargetBoundsForGesture
allows each component to respond to a gesture in progress by determining how (and whether) it should follow other components along in the gesture.
Layout inputs
Each shelf component is aware of the set of inputs that can cause its layout to
change. Each time the UpdateLayout
method is called on it, it determines
whether any of its inputs has changed. If not, the method returns early and
avoids any actual re-layout for itself as well as other components that depend
solely on it.
Keyboard navigation
In order for keyboard users to navigate smoothly between the various parts of
the shelf as they would expect, the ShelfFocusCycler
class passes the focus to
each shelf component as appropriate, depending on which component has just
reliquished focus and on which direction the focus is going. The ShelfWidget
class is the only shelf component that doesn't receive keyboard focus since it
does not have any activatable elements.
Buttons
The base class for all buttons on shelf components is ShelfButton
, which
handles basic logic for keyboard navigation and ink drops. This class is then
derived into ShelfControlButton
for things like the home or back button, and
ShelfAppButton
for application shortcuts.
Tooltips
Tooltips for elements on the shelf require some specific logic on top of the common tooltips because as a user hovers over each app shortcut, trying to figure out what each one does, we do not want to adopt the default tooltip behavior which would be to dismiss the previous tooltip and make the user wait for the common timeout before showing the next one.