chromium/chrome/browser/keyboard_accessory/android/manual_filling_controller_impl.h

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

#ifndef CHROME_BROWSER_KEYBOARD_ACCESSORY_ANDROID_MANUAL_FILLING_CONTROLLER_IMPL_H_
#define CHROME_BROWSER_KEYBOARD_ACCESSORY_ANDROID_MANUAL_FILLING_CONTROLLER_IMPL_H_

#include <memory>
#include <vector>

#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "base/trace_event/memory_dump_provider.h"
#include "chrome/browser/autofill/manual_filling_view_interface.h"
#include "chrome/browser/keyboard_accessory/android/accessory_controller.h"
#include "chrome/browser/keyboard_accessory/android/accessory_sheet_enums.h"
#include "chrome/browser/keyboard_accessory/android/manual_filling_controller.h"
#include "components/autofill/core/common/mojom/autofill_types.mojom-shared.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/plus_addresses/plus_address_types.h"
#include "content/public/browser/web_contents_user_data.h"

namespace autofill {
class AddressAccessoryController;
class PaymentMethodAccessoryController;
}  // namespace autofill

class AffiliatedPlusProfilesCache;
class PasswordAccessoryController;

// Use ManualFillingController::GetOrCreate to obtain instances of this class.
class ManualFillingControllerImpl
    : public ManualFillingController,
      public content::WebContentsUserData<ManualFillingControllerImpl>,
      public base::trace_event::MemoryDumpProvider {
 public:
  ManualFillingControllerImpl(const ManualFillingControllerImpl&) = delete;
  ManualFillingControllerImpl& operator=(const ManualFillingControllerImpl&) =
      delete;

  ~ManualFillingControllerImpl() override;

  // ManualFillingController:
  void NotifyFocusedInputChanged(
      autofill::FieldRendererId focused_field_id,
      autofill::mojom::FocusedFieldType focused_field_type) override;
  autofill::FieldGlobalId GetLastFocusedFieldId() const override;
  void UpdateSourceAvailability(FillingSource source,
                                bool has_suggestions) override;
  void Hide() override;
  void OnAccessoryActionAvailabilityChanged(
      ShouldShowAction shouldShowAction,
      autofill::AccessoryAction action) override;
  void ShowAccessorySheetTab(
      const autofill::AccessoryTabType& tab_type) override;
  void OnFillingTriggered(
      autofill::AccessoryTabType type,
      const autofill::AccessorySheetField& selection) override;
  void OnPasskeySelected(autofill::AccessoryTabType type,
                         const std::vector<uint8_t>& passkey_id) override;
  void OnOptionSelected(
      autofill::AccessoryAction selected_action) const override;
  void OnToggleChanged(autofill::AccessoryAction toggled_action,
                       bool enabled) const override;
  void RequestAccessorySheet(
      autofill::AccessoryTabType tab_type,
      base::OnceCallback<void(autofill::AccessorySheetData)> callback) override;

  gfx::NativeView container_view() const override;

  // Returns a weak pointer for this object.
  base::WeakPtr<ManualFillingController> AsWeakPtr();

  // Like |CreateForWebContents|, it creates the controller and attaches it to
  // the given |web_contents|. Additionally, it allows injecting a fake/mock
  // view and type-specific controllers.
  static void CreateForWebContentsForTesting(
      content::WebContents* web_contents,
      base::WeakPtr<PasswordAccessoryController> pwd_controller,
      base::WeakPtr<autofill::AddressAccessoryController> address_controller,
      base::WeakPtr<autofill::PaymentMethodAccessoryController>
          payment_method_controller,
      std::unique_ptr<ManualFillingViewInterface> test_view);

#if defined(UNIT_TEST)
  // Returns the held view for testing.
  ManualFillingViewInterface* view() const { return view_.get(); }

  // Returns the plus profiles cache for testing.
  AffiliatedPlusProfilesCache* plus_profiles_cache() const {
    return plus_profiles_cache_.get();
  }
#endif  // defined(UNIT_TEST)

 protected:
  friend class ManualFillingController;  // Allow protected access in factories.

  // Enables calling initialization code that relies on a fully constructed
  // ManualFillingController that is attached to a WebContents instance.
  // This is matters for subcomponents which lazily trigger the creation of this
  // class. If called in constructors, it would cause an infinite creation loop.
  void Initialize();

 private:
  friend class content::WebContentsUserData<ManualFillingControllerImpl>;

  // Required for construction via |CreateForWebContents|:
  explicit ManualFillingControllerImpl(content::WebContents* contents);

  // Constructor that allows to inject a mock view.
  ManualFillingControllerImpl(
      content::WebContents* web_contents,
      base::WeakPtr<PasswordAccessoryController> pwd_controller,
      base::WeakPtr<autofill::AddressAccessoryController> address_controller,
      base::WeakPtr<autofill::PaymentMethodAccessoryController>
          payment_method_controller,
      std::unique_ptr<ManualFillingViewInterface> view);

  // Creates the plus profiles cache if the feature flag is enabled and all its
  // dependencies are not `nullptr`.
  void InitializePlusProfilesCache();

  // MemoryDumpProvider:
  bool OnMemoryDump(
      const base::trace_event::MemoryDumpArgs& args,
      base::trace_event::ProcessMemoryDump* process_memory_dump) override;

  // Returns true if the keyboard accessory needs to be shown.
  bool ShouldShowAccessory() const;

  // Adjusts visibility based on focused field type and available suggestions.
  void UpdateVisibility();

  // Registers this filling controller as observer on all sources which are
  // allowed for this tab. This means `OnSourceAvailabilityChanged()` triggers
  // as soon as the observed source changes.
  void RegisterObserverForAllowedSources();

  void OnSourceAvailabilityChanged(
      FillingSource source,
      AccessoryController* source_controller,
      AccessoryController::IsFillingSourceAvailable is_source_available);

  // Returns the controller that is responsible for a tab of given `type`.
  AccessoryController* GetControllerForTabType(
      autofill::AccessoryTabType type) const;

  // Returns the controller that is responsible to handle requests for a given
  // `filling_source`.
  AccessoryController* GetControllerForFillingSource(
      const FillingSource& filling_source) const;

  // Returns the controller that is responsible for a given `action`.
  AccessoryController* GetControllerForAction(
      autofill::AccessoryAction action) const;

  // This set contains sources to be shown to the user.
  base::flat_set<FillingSource> available_sources_;

  // The unique renderer ID of the last known selected field.
  autofill::FieldGlobalId last_focused_field_id_;

  // Type of the last known selected field. Helps to determine UI visibility.
  autofill::mojom::FocusedFieldType last_focused_field_type_ =
      autofill::mojom::FocusedFieldType::kUnknown;

  // Controllers which handle events relating to a specific tab and the
  // associated data.
  base::WeakPtr<PasswordAccessoryController> pwd_controller_;
  base::WeakPtr<autofill::AddressAccessoryController> address_controller_;
  base::WeakPtr<autofill::PaymentMethodAccessoryController>
      payment_method_controller_;

  // This cache is initialized if the manual fallback feature flag is enabled
  // and its dependencies are not null. The cached plus providers are accessed
  // by individual accessory controllers.
  // The cache is populated when the manual filling component is shown and
  // cleared when the component is hidden. The cache is cleared for memory
  // efficiency to avoid caching the list of plus addresses for every open
  // browser tab.
  std::unique_ptr<AffiliatedPlusProfilesCache> plus_profiles_cache_;

  // Hold the native instance of the view. Must be last declared and initialized
  // member so the view can be created in the constructor with a fully set up
  // controller instance.
  std::unique_ptr<ManualFillingViewInterface> view_ =
      ManualFillingViewInterface::Create(this, &GetWebContents());

  base::WeakPtrFactory<ManualFillingControllerImpl> weak_factory_{this};

  WEB_CONTENTS_USER_DATA_KEY_DECL();
};

#endif  // CHROME_BROWSER_KEYBOARD_ACCESSORY_ANDROID_MANUAL_FILLING_CONTROLLER_IMPL_H_