chromium/components/translate/ios/browser/ios_translate_driver.h

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

#ifndef COMPONENTS_TRANSLATE_IOS_BROWSER_IOS_TRANSLATE_DRIVER_H_
#define COMPONENTS_TRANSLATE_IOS_BROWSER_IOS_TRANSLATE_DRIVER_H_

#include <memory>
#include <string>

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/timer/timer.h"
#include "components/language/ios/browser/ios_language_detection_tab_helper.h"
#include "components/translate/core/browser/translate_driver.h"
#include "components/translate/core/common/translate_errors.h"
#include "components/translate/ios/browser/translate_controller.h"
#include "ios/web/public/web_state_observer.h"

namespace language {
class UrlLanguageHistogram;
}  // namespace language

namespace web {
class WebState;
}

namespace translate {

class LanguageDetectionModelService;
class TranslateManager;

// Content implementation of TranslateDriver.
class IOSTranslateDriver
    : public TranslateDriver,
      public TranslateController::Observer,
      public web::WebStateObserver,
      public language::IOSLanguageDetectionTabHelper::Observer {
 public:
  IOSTranslateDriver(
      web::WebState* web_state,
      LanguageDetectionModelService* language_detection_model_service);

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

  ~IOSTranslateDriver() override;

  TranslateController* translate_controller() {
    return translate_controller_.get();
  }

  // Sets the translate manager and url language histogram to be used by the
  // driver and Inits the driver.
  void Initialize(language::UrlLanguageHistogram* url_language_histogram,
                  TranslateManager* translate_manager);

  void OnLanguageModelFileAvailabilityChanged(bool available);

  // web::WebStateObserver methods.
  void DidStartNavigation(web::WebState* web_state,
                          web::NavigationContext* navigation_context) override;
  void DidFinishNavigation(web::WebState* web_state,
                           web::NavigationContext* navigation_context) override;
  void WebStateDestroyed(web::WebState* web_state) override;

  // language::IOSLanguageDetectionTabHelper::Observer.
  void OnLanguageDetermined(const LanguageDetectionDetails& details) override;
  void IOSLanguageDetectionTabHelperWasDestroyed(
      language::IOSLanguageDetectionTabHelper* tab_helper) override;

  // TranslateDriver methods.
  void OnIsPageTranslatedChanged() override;
  void OnTranslateEnabledChanged() override;
  bool IsLinkNavigation() override;
  void PrepareToTranslatePage(int page_seq_no,
                              const std::string& original_source_lang,
                              const std::string& target_lang,
                              bool triggered_from_menu) override;
  void TranslatePage(int page_seq_no,
                     const std::string& translate_script,
                     const std::string& source_lang,
                     const std::string& target_lang) override;
  void RevertTranslation(int page_seq_no) override;
  bool IsIncognito() const override;
  const std::string& GetContentsMimeType() override;
  const GURL& GetLastCommittedURL() const override;
  const GURL& GetVisibleURL() override;
  ukm::SourceId GetUkmSourceId() override;
  bool HasCurrentPage() const override;

 private:
  FRIEND_TEST_ALL_PREFIXES(IOSTranslateDriverTest, TestTimeout);
  FRIEND_TEST_ALL_PREFIXES(IOSTranslateDriverTest, TestNoTimeout);

  // Called when the translation was successful.
  void TranslationDidSucceed(const std::string& source_lang,
                             const std::string& target_lang,
                             int page_seq_no,
                             const std::string& original_page_language,
                             double translation_time);

  // Returns true if the user has not navigated away and the the page is not
  // being destroyed.
  bool IsPageValid(int page_seq_no) const;

  // TranslateController::Observer methods.
  void OnTranslateScriptReady(TranslateErrors error_type,
                              double load_time,
                              double ready_time) override;
  void OnTranslateComplete(TranslateErrors error_type,
                           const std::string& source_language,
                           double translation_time) override;

  // Stops observing |web_state_| and sets it to null.
  void StopObservingWebState();

  // Stops observing the IOSLanguageDetectionTabHelper instance associated with
  // |web_state_|.
  void StopObservingIOSLanguageDetectionTabHelper();

  // The translation action timed out.
  void OnTranslationTimeout(int pending_page_seq_no);

  // The WebState this instance is observing.
  raw_ptr<web::WebState> web_state_ = nullptr;

  base::WeakPtr<TranslateManager> translate_manager_;
  std::unique_ptr<TranslateController> translate_controller_;

  raw_ptr<LanguageDetectionModelService> language_detection_model_service_ =
      nullptr;

  // An ever-increasing sequence number of the current page, used to match up
  // translation requests with responses.
  // This matches the similar field in TranslateAgent in the renderer on other
  // platforms.
  int page_seq_no_;

  // When a translation is in progress, its page sequence number is stored in
  // |pending_page_seq_no_|.
  int pending_page_seq_no_;

  // Parameters of the current translation.
  std::string source_language_;
  std::string target_language_;

  // A timer to limit the length of translate actions.
  base::OneShotTimer timeout_timer_;

  base::WeakPtrFactory<IOSTranslateDriver> weak_ptr_factory_{this};
};

}  // namespace translate

#endif  // COMPONENTS_TRANSLATE_IOS_BROWSER_IOS_TRANSLATE_DRIVER_H_