| // Copyright (c) 2012 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 CHROME_BROWSER_PREDICTORS_AUTOCOMPLETE_ACTION_PREDICTOR_H_ |
| #define CHROME_BROWSER_PREDICTORS_AUTOCOMPLETE_ACTION_PREDICTOR_H_ |
| |
| #include <map> |
| |
| #include "base/gtest_prod_util.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/strings/string16.h" |
| #include "chrome/browser/history/history_types.h" |
| #include "chrome/browser/predictors/autocomplete_action_predictor_table.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/notification_observer.h" |
| #include "content/public/browser/notification_registrar.h" |
| #include "url/gurl.h" |
| |
| struct AutocompleteMatch; |
| class AutocompleteResult; |
| class HistoryService; |
| struct OmniboxLog; |
| class PredictorsHandler; |
| class Profile; |
| |
| namespace content { |
| class SessionStorageNamespace; |
| } |
| |
| namespace gfx { |
| class Size; |
| } |
| |
| namespace history { |
| class URLDatabase; |
| } |
| |
| namespace prerender { |
| class PrerenderHandle; |
| } |
| |
| namespace predictors { |
| |
| // This class is responsible for determining the correct predictive network |
| // action to take given for a given AutocompleteMatch and entered text. It can |
| // be instantiated for both normal and incognito profiles. For normal profiles, |
| // it uses an AutocompleteActionPredictorTable accessed asynchronously on the DB |
| // thread to permanently store the data used to make predictions, and keeps |
| // local caches of that data to be able to make predictions synchronously on the |
| // UI thread where it lives. For incognito profiles, there is no table; the |
| // local caches are copied from the main profile at creation and from there on |
| // are the only thing used. |
| // |
| // This class can be accessed as a weak pointer so that it can safely use |
| // PostTaskAndReply without fear of crashes if it is destroyed before the reply |
| // triggers. This is necessary during initialization. |
| class AutocompleteActionPredictor |
| : public KeyedService, |
| public content::NotificationObserver, |
| public base::SupportsWeakPtr<AutocompleteActionPredictor> { |
| public: |
| enum Action { |
| ACTION_PRERENDER = 0, |
| ACTION_PRECONNECT, |
| ACTION_NONE, |
| LAST_PREDICT_ACTION = ACTION_NONE |
| }; |
| |
| explicit AutocompleteActionPredictor(Profile* profile); |
| virtual ~AutocompleteActionPredictor(); |
| |
| // Registers an AutocompleteResult for a given |user_text|. This will be used |
| // when the user navigates from the Omnibox to determine early opportunities |
| // to predict their actions. |
| void RegisterTransitionalMatches(const base::string16& user_text, |
| const AutocompleteResult& result); |
| |
| // Clears any transitional matches that have been registered. Called when, for |
| // example, the OmniboxEditModel is reverted. |
| void ClearTransitionalMatches(); |
| |
| // Return the recommended action given |user_text|, the text the user has |
| // entered in the Omnibox, and |match|, the suggestion from Autocomplete. |
| // This method uses information from the ShortcutsBackend including how much |
| // of the matching entry the user typed, and how long it's been since the user |
| // visited the matching URL, to calculate a score between 0 and 1. This score |
| // is then mapped to an Action. |
| Action RecommendAction(const base::string16& user_text, |
| const AutocompleteMatch& match) const; |
| |
| // Begin prerendering |url| with |session_storage_namespace|. The |size| gives |
| // the initial size for the target prerender. The predictor will run at most |
| // one prerender at a time, so launching a prerender will cancel our previous |
| // prerenders (if any). |
| void StartPrerendering( |
| const GURL& url, |
| const content::SessionStorageNamespaceMap& session_storage_namespace_map, |
| const gfx::Size& size); |
| |
| // Cancels the current prerender, unless it has already been abandoned. |
| void CancelPrerender(); |
| |
| // Return true if the suggestion type warrants a TCP/IP preconnection. |
| // i.e., it is now quite likely that the user will select the related domain. |
| static bool IsPreconnectable(const AutocompleteMatch& match); |
| |
| // Returns true if there is an active Omnibox prerender and it has been |
| // abandoned. |
| bool IsPrerenderAbandonedForTesting(); |
| |
| private: |
| friend class AutocompleteActionPredictorTest; |
| friend class ::PredictorsHandler; |
| |
| struct TransitionalMatch { |
| TransitionalMatch(); |
| ~TransitionalMatch(); |
| |
| base::string16 user_text; |
| std::vector<GURL> urls; |
| |
| bool operator==(const base::string16& other_user_text) const { |
| return user_text == other_user_text; |
| } |
| }; |
| |
| struct DBCacheKey { |
| base::string16 user_text; |
| GURL url; |
| |
| bool operator<(const DBCacheKey& rhs) const { |
| return (user_text != rhs.user_text) ? |
| (user_text < rhs.user_text) : (url < rhs.url); |
| } |
| |
| bool operator==(const DBCacheKey& rhs) const { |
| return (user_text == rhs.user_text) && (url == rhs.url); |
| } |
| }; |
| |
| struct DBCacheValue { |
| int number_of_hits; |
| int number_of_misses; |
| }; |
| |
| typedef std::map<DBCacheKey, DBCacheValue> DBCacheMap; |
| typedef std::map<DBCacheKey, AutocompleteActionPredictorTable::Row::Id> |
| DBIdCacheMap; |
| |
| static const int kMaximumDaysToKeepEntry; |
| |
| // NotificationObserver |
| virtual void Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) OVERRIDE; |
| |
| // The first step in initializing the predictor is accessing the database and |
| // building the local cache. This should be delayed until after critical DB |
| // and IO processes have completed. |
| void CreateLocalCachesFromDatabase(); |
| |
| // Removes all rows from the database and caches. |
| void DeleteAllRows(); |
| |
| // Removes rows from the database and caches that contain a URL in |rows|. |
| void DeleteRowsWithURLs(const history::URLRows& rows); |
| |
| // Called when NOTIFICATION_OMNIBOX_OPENED_URL is observed. |
| void OnOmniboxOpenedUrl(const OmniboxLog& log); |
| |
| // Adds and updates rows in the database and caches. |
| void AddAndUpdateRows( |
| const AutocompleteActionPredictorTable::Rows& rows_to_add, |
| const AutocompleteActionPredictorTable::Rows& rows_to_update); |
| |
| // Called to populate the local caches. This also calls DeleteOldEntries |
| // if the history service is available, or registers for the notification of |
| // it becoming available. |
| void CreateCaches( |
| std::vector<AutocompleteActionPredictorTable::Row>* row_buffer); |
| |
| // Attempts to call DeleteOldEntries if the in-memory database has been loaded |
| // by |service|. Returns success as a boolean. |
| bool TryDeleteOldEntries(HistoryService* service); |
| |
| // Called to delete any old or invalid entries from the database. Called after |
| // the local caches are created once the history service is available. |
| void DeleteOldEntries(history::URLDatabase* url_db); |
| |
| // Deletes any old or invalid entries from the local caches. |url_db| and |
| // |id_list| must not be NULL. Every row id deleted will be added to id_list. |
| void DeleteOldIdsFromCaches( |
| history::URLDatabase* url_db, |
| std::vector<AutocompleteActionPredictorTable::Row::Id>* id_list); |
| |
| // Called on an incognito-owned predictor to copy the current caches from the |
| // main profile. |
| void CopyFromMainProfile(); |
| |
| // Registers for notifications and sets the |initialized_| flag. |
| void FinishInitialization(); |
| |
| // Uses local caches to calculate an exact percentage prediction that the user |
| // will take a particular match given what they have typed. |is_in_db| is set |
| // to differentiate trivial zero results resulting from a match not being |
| // found from actual zero results where the calculation returns 0.0. |
| double CalculateConfidence(const base::string16& user_text, |
| const AutocompleteMatch& match, |
| bool* is_in_db) const; |
| |
| // Calculates the confidence for an entry in the DBCacheMap. |
| double CalculateConfidenceForDbEntry(DBCacheMap::const_iterator iter) const; |
| |
| Profile* profile_; |
| |
| // Set when this is a predictor for an incognito profile. |
| AutocompleteActionPredictor* main_profile_predictor_; |
| |
| // Set when this is a predictor for a non-incognito profile, and the incognito |
| // profile creates a predictor. If this is non-NULL when we finish |
| // initialization, we should call CopyFromMainProfile() on it. |
| AutocompleteActionPredictor* incognito_predictor_; |
| |
| // The backing data store. This is NULL for incognito-owned predictors. |
| scoped_refptr<AutocompleteActionPredictorTable> table_; |
| |
| content::NotificationRegistrar notification_registrar_; |
| |
| // This is cleared after every Omnibox navigation. |
| std::vector<TransitionalMatch> transitional_matches_; |
| |
| scoped_ptr<prerender::PrerenderHandle> prerender_handle_; |
| |
| // This allows us to predict the effect of confidence threshold changes on |
| // accuracy. This is cleared after every omnibox navigation. |
| mutable std::vector<std::pair<GURL, double> > tracked_urls_; |
| |
| // Local caches of the data store. For incognito-owned predictors this is the |
| // only copy of the data. |
| DBCacheMap db_cache_; |
| DBIdCacheMap db_id_cache_; |
| |
| bool initialized_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AutocompleteActionPredictor); |
| }; |
| |
| } // namespace predictors |
| |
| #endif // CHROME_BROWSER_PREDICTORS_AUTOCOMPLETE_ACTION_PREDICTOR_H_ |