chromium/chromeos/components/quick_answers/quick_answers_client.h

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

#ifndef CHROMEOS_COMPONENTS_QUICK_ANSWERS_QUICK_ANSWERS_CLIENT_H_
#define CHROMEOS_COMPONENTS_QUICK_ANSWERS_QUICK_ANSWERS_CLIENT_H_

#include <memory>
#include <string>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "chromeos/components/quick_answers/result_loader.h"
#include "chromeos/components/quick_answers/understanding/intent_generator.h"

namespace network {
class SharedURLLoaderFactory;
}  // namespace network

namespace quick_answers {

class SpellChecker;
struct QuickAnswersRequest;
struct IntentInfo;
enum class IntentType;
enum class ResultType;

// A delegate interface for the QuickAnswersClient.
class QuickAnswersDelegate {
 public:
  QuickAnswersDelegate(const QuickAnswersDelegate&) = delete;
  QuickAnswersDelegate& operator=(const QuickAnswersDelegate&) = delete;

  // Invoked when the `quick_answers_session` is received. Note that
  // `quick_answers_session` may be `nullptr` if no answer found for the
  // selected content.
  virtual void OnQuickAnswerReceived(
      std::unique_ptr<QuickAnswersSession> quick_answers_session) {}

  // Invoked when the query is rewritten.
  virtual void OnRequestPreprocessFinished(
      const QuickAnswersRequest& processed_request) {}

  // Invoked when there is a network error.
  virtual void OnNetworkError() {}

 protected:
  QuickAnswersDelegate() = default;
  virtual ~QuickAnswersDelegate() = default;
};

// Quick answers client to load and parse quick answer results.
class QuickAnswersClient : public ResultLoader::ResultLoaderDelegate {
 public:
  // Method that can be used in tests to change the result loader returned by
  // |CreateResultLoader| in tests.
  using ResultLoaderFactoryCallback =
      base::RepeatingCallback<std::unique_ptr<ResultLoader>()>;

  // Method that can be used in tests to change the intent generator returned by
  // |CreateResultLoader| in tests.
  using IntentGeneratorFactoryCallback =
      base::RepeatingCallback<std::unique_ptr<IntentGenerator>()>;

  QuickAnswersClient(
      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
      QuickAnswersDelegate* delegate);

  QuickAnswersClient(const QuickAnswersClient&) = delete;
  QuickAnswersClient& operator=(const QuickAnswersClient&) = delete;

  ~QuickAnswersClient() override;

  // ResultLoaderDelegate:
  void OnNetworkError() override;
  void OnQuickAnswerReceived(
      std::unique_ptr<QuickAnswersSession> quick_answers_session) override;

  // Send a quick answer request for preprocessing only.
  virtual void SendRequestForPreprocessing(
      const QuickAnswersRequest& quick_answers_request);
  // Fetch quick answers result from the server.
  void FetchQuickAnswers(const QuickAnswersRequest& processed_request);
  // Send a quick answer request. The request is preprocessed before fetching
  // the result from the server. Virtual for testing.
  virtual void SendRequest(const QuickAnswersRequest& quick_answers_request);

  // User clicks on the Quick Answers result. Virtual for testing.
  virtual void OnQuickAnswerClick(ResultType result_type);

  // Quick Answers is dismissed. Virtual for testing.
  virtual void OnQuickAnswersDismissed(ResultType result_type, bool is_active);

  static void SetResultLoaderFactoryForTesting(
      ResultLoaderFactoryCallback* factory);

  static void SetIntentGeneratorFactoryForTesting(
      IntentGeneratorFactoryCallback* factory);

 private:
  FRIEND_TEST_ALL_PREFIXES(QuickAnswersClientTest, SendRequest);
  FRIEND_TEST_ALL_PREFIXES(QuickAnswersClientTest,
                           NotSendRequestForUnknownIntent);
  FRIEND_TEST_ALL_PREFIXES(QuickAnswersClientTest, PreprocessDefinitionIntent);
  FRIEND_TEST_ALL_PREFIXES(QuickAnswersClientTest, PreprocessTranslationIntent);
  FRIEND_TEST_ALL_PREFIXES(QuickAnswersClientTest,
                           PreprocessUnitConversionIntent);

  // Creates a |ResultLoader| instance.
  std::unique_ptr<ResultLoader> CreateResultLoader(IntentType intent_type);

  // Creates an |IntentGenerator| instance.
  std::unique_ptr<IntentGenerator> CreateIntentGenerator(
      const QuickAnswersRequest& request,
      bool skip_fetch);

  // Preprocesses the |QuickAnswersRequest| and fetch quick answers result. Only
  // preprocesses the request and skip fetching result if |skip_fetch| is true.
  void SendRequestInternal(const QuickAnswersRequest& quick_answers_request,
                           bool skip_fetch);
  void IntentGeneratorCallback(const QuickAnswersRequest& quick_answers_request,
                               bool skip_fetch,
                               const IntentInfo& intent_info);
  base::TimeDelta GetImpressionDuration() const;

  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
  raw_ptr<QuickAnswersDelegate> delegate_ = nullptr;
  std::unique_ptr<SpellChecker> spell_checker_;
  std::unique_ptr<ResultLoader> result_loader_;
  std::unique_ptr<IntentGenerator> intent_generator_;
  // Time when the quick answer is received.
  base::TimeTicks quick_answer_received_time_;

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

}  // namespace quick_answers

#endif  // CHROMEOS_COMPONENTS_QUICK_ANSWERS_QUICK_ANSWERS_CLIENT_H_