blob: 546e0edc86be45b991695869771564705265eca7 [file] [log] [blame]
// 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.
//
// This file contains the document autocomplete provider. This experimental
// provider uses an experimental API with keys and endpoint provided at
// developer build-time, so it is feature-flagged off by default.
#ifndef COMPONENTS_OMNIBOX_BROWSER_DOCUMENT_PROVIDER_H_
#define COMPONENTS_OMNIBOX_BROWSER_DOCUMENT_PROVIDER_H_
#include <memory>
#include <string>
#include "base/compiler_specific.h"
#include "base/containers/lru_cache.h"
#include "base/feature_list.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/time.h"
#include "components/history/core/browser/history_types.h"
#include "components/omnibox/browser/autocomplete_enums.h"
#include "components/omnibox/browser/autocomplete_provider.h"
#include "components/omnibox/browser/autocomplete_provider_debouncer.h"
#include "third_party/metrics_proto/omnibox_event.pb.h"
#include "url/gurl.h"
class AutocompleteProviderListener;
struct AutocompleteMatch;
class AutocompleteProviderClient;
namespace base {
class Value;
}
namespace network {
class SimpleURLLoader;
}
// Autocomplete provider for personalized documents owned or readable by the
// signed-in user. In practice this is a second request in parallel with that
// to the default search provider.
class DocumentProvider : public AutocompleteProvider {
public:
// Creates and returns an instance of this provider.
static DocumentProvider* Create(AutocompleteProviderClient* client,
AutocompleteProviderListener* listener);
// AutocompleteProvider:
void Start(const AutocompleteInput& input, bool minimal_changes) override;
void Stop(AutocompleteStopReason stop_reason) override;
void DeleteMatch(const AutocompleteMatch& match) override;
void AddProviderInfo(ProvidersInfo* provider_info) const override;
// Returns a set of classifications that highlight all the occurrences of
// |input_text| at word breaks in |text|. E.g., given |input_text|
// "rain if you dare" and |text| "how to tell if your kitten is a rainbow",
// will return the classifications:
// __ ___ ____
// how to tell if your kitten is a rainbow
// ^ ^ ^^ ^ ^ ^
// NONE M |M | | NONE
// NONE NONE MATCH
static ACMatchClassifications Classify(const std::u16string& input_text,
const std::u16string& text);
// Builds a GURL to use for deduping against other document/history
// suggestions. Multiple URLs may refer to the same document.
// Returns an empty GURL if not a recognized Docs URL.
// The URL returned is not guaranteed to be navigable and should only be used
// as a deduping token.
static const GURL GetURLForDeduping(const GURL& url);
private:
friend class FakeDocumentProvider;
using MatchesCache = base::LRUCache<GURL, AutocompleteMatch>;
DocumentProvider(AutocompleteProviderClient* client,
AutocompleteProviderListener* listener);
~DocumentProvider() override;
DocumentProvider(const DocumentProvider&) = delete;
DocumentProvider& operator=(const DocumentProvider&) = delete;
// Determines whether the profile/session/window meet the feature
// prerequisites.
bool IsDocumentProviderAllowed(const AutocompleteInput& input);
// Determines if the input is a URL, or is the start of the user entering one.
// We avoid queries for these cases for quality and scaling reasons.
static bool IsInputLikelyURL(const AutocompleteInput& input);
// Called by |debouncer_|, queued when |start| is called.
void Run(const AutocompleteInput& input);
// Called when the network request for suggestions has completed.
void OnURLLoadComplete(const network::SimpleURLLoader* source,
const int response_code,
std::unique_ptr<std::string> response_body);
// Resets the backoff state on DocumentSuggestionsService to false.
void ResetBackoffState();
// The function updates |matches_| with data parsed from |json_data|.
// The update is not performed if |json_data| is invalid.
// Returns whether |matches_| changed.
bool UpdateResults(const std::string& json_data);
// Callback for when the loader is available with a valid token.
void OnDocumentSuggestionsLoaderAvailable(
std::unique_ptr<network::SimpleURLLoader> loader);
// Parses document search result JSON.
// Returns true if |matches| was populated with fresh suggestions.
ACMatches ParseDocumentSearchResults(const base::Value& root_val);
// Appends |matches_cache_| to |matches_|. Updates their classifications
// according to |input_.text()|.
void CopyCachedMatchesToMatches();
// Sets the scores of all cached matches to 0. This is invoked before pushing
// the latest async response returns so that the scores aren't preserved for
// further inputs. E.g., the input 'london' shouldn't display cached docs from
// a previous input 'paris'. This can't be done by automatically (i.e. set
// scores to 0 before pushing to the cache), as the scores are needed for the
// async pass if the user continued their input.
void SetCachedMatchesScoresTo0();
// Sets the scores of matches beyond the first |provider_max_matches_| to 0.
// This ensures the doc provider doesn't exceed it's allocated suggestions
// while also allowing docs from other providers to be deduped and styled like
// docs from the doc provider.
void DemoteMatchesBeyondMax();
// Generates the localized last-modified timestamp to present to the user.
// Full date for old files, mm/dd within the same calendar year, or time-of-
// day if a file was modified on the same date.
// |now| should generally be base::Time::Now() but is passed in for testing.
static std::u16string GenerateLastModifiedString(
const std::string& modified_timestamp_string,
base::Time now);
// Convert mimetype (e.g. "application/vnd.google-apps.document") to a string
// that can be used in the match description (e.g. "Google Docs").
static std::u16string GetProductDescriptionString(
const std::string& mimetype);
// Construct match description; e.g. "Jan 12 - First Last - Google Docs".
static std::u16string GetMatchDescription(const std::string& update_time,
const std::string& mimetype,
const std::string& owner);
// Whether the server has instructed us to backoff. Used when the backoff
// state is scoped to the current window/AutocompleteController.
bool backoff_for_this_instance_only_ = false;
// Client for accessing TemplateUrlService, prefs, etc.
raw_ptr<AutocompleteProviderClient> client_;
// Saved when starting a new autocomplete request so that it can be retrieved
// when responses return asynchronously.
AutocompleteInput input_;
// Loader used to retrieve results.
std::unique_ptr<network::SimpleURLLoader> loader_;
// The time `Run()` was invoked. Used for histogram logging.
base::TimeTicks time_run_invoked_;
// The time `OnDocumentSuggestionsLoaderAvailable()` was invoked and the
// remote request was sent. Used for histogram logging.
base::TimeTicks time_request_sent_;
// Used to ensure that we don't send multiple requests in quick succession.
std::unique_ptr<AutocompleteProviderDebouncer> debouncer_;
// Because the drive server is async and may intermittently provide a
// particular suggestion for consecutive inputs, without caching, doc
// suggestions flicker between drive format (title - date - doc_type) and URL
// format (title - URL) suggestions from the history and bookmark providers.
// Appending cached doc suggestions with relevance 0 ensures cached
// suggestions only display if deduped with a non-cached suggestion and do not
// affect which autocomplete results are displayed and their ranks.
MatchesCache matches_cache_;
// Used to schedule a reset of the backoff state.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
// For callbacks that may be run after destruction. Must be declared last.
base::WeakPtrFactory<DocumentProvider> weak_ptr_factory_{this};
};
#endif // COMPONENTS_OMNIBOX_BROWSER_DOCUMENT_PROVIDER_H_