blob: dfc6701e81a245992a980759931887a787aa9a2d [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_UI_A11Y_LIB_FOCUS_CHAIN_FOCUS_CHAIN_MANAGER_H_
#define SRC_UI_A11Y_LIB_FOCUS_CHAIN_FOCUS_CHAIN_MANAGER_H_
#include <fuchsia/ui/focus/cpp/fidl.h>
#include <lib/async/cpp/wait.h>
#include <memory>
#include <vector>
#include "src/ui/a11y/lib/focus_chain/accessibility_focus_chain_listener.h"
#include "src/ui/a11y/lib/focus_chain/accessibility_focus_chain_requester.h"
#include "src/ui/a11y/lib/semantics/semantics_source.h"
namespace a11y {
// The Focus Chain manager processes Focus Chain Updates and dispatches to
// registered a11y services the views that are currently in focus.
//
// This manager also can request Focus Chain Updates. It exposes
// |AccessibilityFocusChainRequester| interface, which accessibility services
// can use to change the Focus Chain to a different view.
class FocusChainManager : public fuchsia::ui::focus::FocusChainListener,
public AccessibilityFocusChainRegistry,
public AccessibilityFocusChainRequester {
public:
// |focuser| is the client-side channel interface used to request Focus Chain Updates.
// |semantics_source| object must outlive FocusChainManager.
FocusChainManager(fuchsia::ui::views::FocuserPtr focuser, SemanticsSource* semantics_source);
~FocusChainManager() = default;
// |fuchsia.ui.focus.FocusChainListener|
void OnFocusChange(fuchsia::ui::focus::FocusChain focus_chain,
OnFocusChangeCallback callback) override;
// |AccessibilityFocusChainRegistry|
void Register(fxl::WeakPtr<AccessibilityFocusChainListener> listener) override;
// |AccessibilityFocusChainRequester|
void ChangeFocusToView(zx_koid_t view_ref_koid, ChangeFocusToViewCallback callback) override;
private:
// A ViewRefWatcher holds a ViewRef and watches for any signaling on the ViewRef.
class ViewRefWatcher {
public:
using OnViewRefInvalidatedCallback = fit::function<void()>;
ViewRefWatcher(fuchsia::ui::views::ViewRef view_ref, OnViewRefInvalidatedCallback callback);
~ViewRefWatcher();
zx_koid_t koid() const;
private:
// |async::WaitMethod|
// When called, |callback_| is invoked.
void OnViewRefSignaled(async_dispatcher_t* dispatcher, async::WaitBase* wait,
zx_status_t status, const zx_packet_signal* signal);
fuchsia::ui::views::ViewRef view_ref_;
OnViewRefInvalidatedCallback callback_;
async::WaitMethod<ViewRefWatcher, &ViewRefWatcher::OnViewRefSignaled> wait_;
};
// Invalidates the Focus Chain owned by this manager. This causes |Notify()| to be invoked,
// informing every registered listener to the focus being updated.
void InvalidateFocusChain();
// Returns the ViewRef KoID of the view that has the focus in this Focus Chain.
// If no view is in focus, returns ZX_KOID_INVALID.
zx_koid_t GetFocusedView() const;
// Notifies all registered listeners of the new view in focus.
void Notify();
// Registered listeners with this manager.
std::vector<fxl::WeakPtr<AccessibilityFocusChainListener>> listeners_;
// Note that ViewRefWatcher can't have a move constructor due to
// async::WaitMethod. Thus, this object is created only once and later moved
// via an unique_ptr.
std::vector<std::unique_ptr<ViewRefWatcher>> focus_chain_;
// Responsible for requesting Focus Chain updates.
fuchsia::ui::views::FocuserPtr focuser_;
// Right now, this manager only responds to Focus Chain Requests to Views that
// are providing semantics. It uses |semantics_source_| to validate if a
// view is providing semantics before doing the request.
SemanticsSource* const semantics_source_ = nullptr;
};
} // namespace a11y
#endif // SRC_UI_A11Y_LIB_FOCUS_CHAIN_FOCUS_CHAIN_MANAGER_H_