chromium/ash/webui/eche_app_ui/accessibility_provider.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ASH_WEBUI_ECHE_APP_UI_ACCESSIBILITY_PROVIDER_H_
#define ASH_WEBUI_ECHE_APP_UI_ACCESSIBILITY_PROVIDER_H_

#include <memory>

#include "ash/public/cpp/ash_web_view.h"
#include "ash/system/eche/eche_tray.h"
#include "ash/webui/eche_app_ui/mojom/eche_app.mojom.h"

#include "ash/webui/eche_app_ui/proto/accessibility_mojom.pb.h"
#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/accessibility/android/ax_tree_source_android.h"
#include "ui/accessibility/ax_action_data.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/views/view.h"

namespace ash::eche_app {

class AccessibilityProviderProxy {
 public:
  virtual ~AccessibilityProviderProxy() = default;

  virtual bool UseFullFocusMode() = 0;
  virtual bool IsAccessibilityEnabled() = 0;
  virtual ax::android::mojom::AccessibilityFilterType GetFilterType() = 0;
  virtual void OnViewTracked() = 0;
  virtual void SetAccessibilityEnabledStateChangedCallback(
      base::RepeatingCallback<void(bool)>) = 0;
  virtual void SetExploreByTouchEnabledStateChangedCallback(
      base::RepeatingCallback<void(bool)>) = 0;
};
class AccessibilityProvider
    : public mojom::AccessibilityProvider,
      public ax::android::AXTreeSourceAndroid::Delegate {
 public:
  explicit AccessibilityProvider(
      std::unique_ptr<AccessibilityProviderProxy> proxy);
  ~AccessibilityProvider() override;

  // Track the current eche web view.
  void TrackView(AshWebView* view);
  void HandleStreamClosed();
  // Handles the result of a refreshWithExtraData call.
  void OnGetTextLocationDataResult(const ui::AXActionData& action,
                                   const std::optional<std::vector<uint8_t>>&
                                       serialized_text_location) const;

  // mojom::AccessibilityProvider overrides.
  // Proto from ash/webui/eche_app_ui/proto/accessibility_mojom.proto.
  void HandleAccessibilityEventReceived(
      const std::vector<uint8_t>& serialized_proto) override;
  void SetAccessibilityObserver(
      ::mojo::PendingRemote<mojom::AccessibilityObserver> observer) override;
  void IsAccessibilityEnabled(IsAccessibilityEnabledCallback callback) override;

  void Bind(mojo::PendingReceiver<mojom::AccessibilityProvider> receiver);

  // AXTreeSourceAndroid::Delegate
  void OnAction(const ui::AXActionData& data) const override;
  bool UseFullFocusMode() const override;

 private:
  ax::android::mojom::AccessibilityFilterType GetFilterType();
  void UpdateDeviceBounds(const proto::Rect& device_bounds);
  void HandleHitTest(const ui::AXActionData& data) const;
  gfx::Rect OnGetTextLocationDataResultInternal(proto::Rect proto_rect) const;
  // Handles the result from perform action.
  void OnActionResult(const ui::AXActionData& data, bool result) const;
  void OnAccessibilityEnabledStateChanged(bool enabled);
  void OnExploreByTouchEnabledStateChanged(bool enabled);

  class SerializationDelegate
      : public ax::android::AXTreeSourceAndroid::SerializationDelegate {
   public:
    explicit SerializationDelegate(gfx::Rect& device_bounds);

    void PopulateBounds(const ax::android::AccessibilityInfoDataWrapper& node,
                        ui::AXNodeData& out_data) const override;

   private:
    gfx::RectF ScaleAndroidPxToChromePx(
        const ax::android::AccessibilityInfoDataWrapper& node,
        aura::Window* window) const;
    const raw_ref<gfx::Rect> device_bounds_;
  };

  mojo::Receiver<mojom::AccessibilityProvider> receiver_{this};
  mojo::Remote<mojom::AccessibilityObserver> observer_remote_;
  // Eche can only have one app visible at a time, so we only need one tree
  // source. In the future we can swap this to a map if more windows are added.
  std::unique_ptr<ax::android::AXTreeSourceAndroid> tree_source_;

  bool use_full_focus_mode_ = false;

  // device settings
  gfx::Rect device_bounds_;

  // Proxy for accessing accessibility manager in chrome/
  std::unique_ptr<AccessibilityProviderProxy> proxy_;
  base::WeakPtrFactory<AccessibilityProvider> weak_ptr_factory_{this};
};
}  // namespace ash::eche_app
#endif  // ASH_WEBUI_ECHE_APP_UI_ACCESSIBILITY_PROVIDER_H_