blob: 906c708a7a2f37932321b58ef8961db520492f19 [file] [log] [blame]
// Copyright 2018 The Chromium 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 COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BATCH_ELEMENT_CHECKER_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BATCH_ELEMENT_CHECKER_H_
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
namespace autofill_assistant {
class WebController;
// Types of element checks.
enum ElementCheckType { kExistenceCheck, kVisibilityCheck };
// Helper for checking a set of elements at the same time. It avoids duplicate
// checks and supports retries.
//
// Single check:
//
// The simplest way of using a BatchElementChecker is to:
// - create an instance, using WebController::CreateBatchElementChecker or
// ActionDelegate::CreateBatchElementChecker
// - call AddElementCheck() and AddFieldValueCheck()
// - call Run() with duration set to 0.
//
// The result of the checks is reported to the callbacks passed to
// AddElementCheck(kExistenceCheck, ) and AddFieldValueCheck(), then the
// callback passed to Run() is called, to report the end of the a run.
//
// Check with retries:
//
// To check for existence more than once, call Run() with a duration that
// specifies how long you're willing to wait. In that mode, elements that are
// found are reported immediately. Elements that are not found are reported at
// the end, once the specified deadline has passed, just before giving up and
// calling the callback passed to Run().
class BatchElementChecker {
public:
explicit BatchElementChecker(WebController* web_controller);
virtual ~BatchElementChecker();
// Callback for AddElementCheck. Argument is true if the check passed.
using ElementCheckCallback = base::OnceCallback<void(bool)>;
// Callback for AddFieldValueCheck. Argument is true is the element exists.
// The string contains the field value, or an empty string if accessing the
// value failed.
using GetFieldValueCallback =
base::OnceCallback<void(bool, const std::string&)>;
// Checks an an element.
//
// kElementCheck checks whether at least one element given by |selectors|
// exists on the web page.
//
// kVisibilityCheck checks whether at least one element given by |selectors|
// is visible on the page.
//
// New element checks cannot be added once Run has been called.
void AddElementCheck(ElementCheckType check_type,
const std::vector<std::string>& selectors,
ElementCheckCallback callback);
// Gets the value of |selectors| and return the result through |callback|. The
// returned value will be the empty string in case of error or empty value.
//
// New field checks cannot be added once Run has been called.
void AddFieldValueCheck(const std::vector<std::string>& selectors,
GetFieldValueCallback callback);
// Runs the checks until all elements exist or for |duration|, whichever one
// comes first. Elements found are reported as soon as they're founds.
// Elements not found are reported right before |all_done| is run.
//
// |duration| can be 0. In this case the checks are run once, without waiting.
// |try_done| is run at the end of each try.
void Run(const base::TimeDelta& duration,
base::RepeatingCallback<void()> try_done,
base::OnceCallback<void()> all_done);
// Returns true if all element that were asked for have been found. Can be
// called while Run is progress or afterwards.
bool all_found();
private:
// Tries running the checks, reporting only successes.
//
// Calls |try_done_callback| at the end of the run.
void Try(base::OnceCallback<void()> try_done_callback);
void OnTryDone(int64_t remaining_attempts,
base::RepeatingCallback<void()> try_done,
base::OnceCallback<void()> all_done);
// If there are still callbacks not called by a previous call to Try, call
// them now. When this method returns, all callbacks are guaranteed to have
// been run.
void GiveUp();
void OnElementChecked(std::vector<ElementCheckCallback>* callbacks,
bool exists);
void OnGetFieldValue(std::vector<GetFieldValueCallback>* callbacks,
bool exists,
const std::string& value);
void CheckTryDone();
void RunCallbacks(std::vector<ElementCheckCallback>* callbacks, bool result);
void RunCallbacks(std::vector<GetFieldValueCallback>* callbacks,
bool result,
const std::string& value);
bool HasMoreChecksToRun();
WebController* const web_controller_;
// A map of ElementCheck arguments (check_type, selectors) to callbacks that
// take the result of the check.
std::map<std::pair<ElementCheckType, std::vector<std::string>>,
std::vector<ElementCheckCallback>>
element_check_callbacks_;
// A map of GetFieldValue arguments (selectors) to callbacks that take the
// field value.
std::map<std::vector<std::string>, std::vector<GetFieldValueCallback>>
get_field_value_callbacks_;
int pending_checks_count_;
bool all_found_;
// Run() was called. Checking elements might or might not have finished yet.
bool started_;
// The callback built for Try(). It is kept around while going through the
// maps and called once all selectors in that map have been looked up once,
// whether that lookup was successful or not. Also used to guarantee that only
// one Try runs at a time.
base::OnceCallback<void()> try_done_callback_;
base::WeakPtrFactory<BatchElementChecker> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BatchElementChecker);
};
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BATCH_ELEMENT_CHECKER_H_