| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_ | 5 #ifndef CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_ |
| 6 #define CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_ | 6 #define CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_ |
| 7 | 7 |
| 8 #include <set> | 8 #include <map> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> |
| 10 | 11 |
| 11 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
| 13 #include "base/compiler_specific.h" |
| 12 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
| 13 #include "base/memory/scoped_vector.h" | |
| 14 #include "base/memory/weak_ptr.h" | |
| 15 #include "base/string16.h" | 15 #include "base/string16.h" |
| 16 #include "base/timer.h" |
| 16 #include "chrome/browser/instant/instant_commit_type.h" | 17 #include "chrome/browser/instant/instant_commit_type.h" |
| 17 #include "chrome/browser/instant/instant_loader_delegate.h" | 18 #include "chrome/browser/instant/instant_loader_delegate.h" |
| 18 #include "chrome/browser/search_engines/template_url_id.h" | |
| 19 #include "chrome/common/instant_types.h" | 19 #include "chrome/common/instant_types.h" |
| 20 #include "content/public/common/page_transition_types.h" | 20 #include "content/public/common/page_transition_types.h" |
| 21 #include "googleurl/src/gurl.h" | 21 #include "googleurl/src/gurl.h" |
| 22 #include "ui/gfx/native_widget_types.h" | 22 #include "ui/gfx/native_widget_types.h" |
| 23 #include "ui/gfx/rect.h" | 23 #include "ui/gfx/rect.h" |
| 24 | 24 |
| 25 struct AutocompleteMatch; | 25 struct AutocompleteMatch; |
| 26 class InstantControllerDelegate; | 26 class InstantControllerDelegate; |
| 27 class InstantLoader; | 27 class InstantLoader; |
| 28 class InstantTest; | |
| 29 class PrefService; | 28 class PrefService; |
| 30 class Profile; | 29 class Profile; |
| 31 class TabContents; | 30 class TabContents; |
| 32 class TemplateURL; | 31 class TemplateURL; |
| 33 | 32 |
| 34 // InstantController maintains a WebContents that is intended to give a preview | 33 // InstantController maintains a WebContents that is intended to give a |
| 35 // of a URL. InstantController is owned by Browser. | 34 // preview of search results. InstantController is owned by Browser via |
| 35 // BrowserInstantController. |
| 36 // | 36 // |
| 37 // At any time the WebContents maintained by InstantController may be destroyed | 37 // At any time the WebContents maintained by InstantController may be hidden |
| 38 // by way of |DestroyPreviewContents|, which results in |HideInstant| being | 38 // from view by way of Hide(), which may result in HideInstant() being invoked |
| 39 // invoked on the delegate. Similarly the preview may be committed at any time | 39 // on the delegate. Similarly the preview may be committed at any time by |
| 40 // by invoking |CommitCurrentPreview|, which results in |CommitInstant| | 40 // invoking CommitCurrentPreview(), which results in CommitInstant() being |
| 41 // being invoked on the delegate. Also see |PrepareForCommit| below. | 41 // invoked on the delegate. |
| 42 class InstantController : public InstantLoaderDelegate { | 42 class InstantController : public InstantLoaderDelegate { |
| 43 public: | 43 public: |
| 44 // Amount of time to wait before starting the instant animation. | 44 // Amount of time to wait before starting the animation for suggested text. |
| 45 static const int kAutoCommitPauseTimeMS = 1000; | 45 static const int kInlineAutocompletePauseTimeMS = 1000; |
| 46 // Duration of the instant animation in which the colors change. | 46 |
| 47 static const int kAutoCommitFadeInTimeMS = 300; | 47 // Duration of the suggested text animation in which the colors change. |
| 48 static const int kInlineAutocompleteFadeInTimeMS = 300; |
| 48 | 49 |
| 49 // InstantController may operate in one of these modes: | 50 // InstantController may operate in one of these modes: |
| 50 // INSTANT: The default search engine is preloaded when the omnibox gets | 51 // INSTANT: The default search engine is preloaded when the omnibox gets |
| 51 // focus. Queries are issued as the user types. Predicted queries are | 52 // focus. Queries are issued as the user types. Predicted queries are |
| 52 // are inline autocompleted into the omnibox. Result previews are shown. | 53 // inline autocompleted into the omnibox. Result previews are shown. |
| 53 // SUGGEST: Same as INSTANT, without visible previews. | 54 // SUGGEST: Same as INSTANT, without visible previews. |
| 54 // HIDDEN: Same as SUGGEST, without the inline autocompletion. | 55 // HIDDEN: Same as SUGGEST, without the inline autocompletion. |
| 55 // SILENT: Same as HIDDEN, without issuing queries as the user types. The | 56 // SILENT: Same as HIDDEN, without issuing queries as the user types. The |
| 56 // query is sent only after the user presses <Enter>. | 57 // query is sent only after the user presses <Enter>. |
| 57 enum Mode { | 58 enum Mode { |
| 58 INSTANT, | 59 INSTANT, |
| 59 SUGGEST, | 60 SUGGEST, |
| 60 HIDDEN, | 61 HIDDEN, |
| 61 SILENT | 62 SILENT, |
| 62 }; | 63 }; |
| 63 | 64 |
| 64 InstantController(InstantControllerDelegate* delegate, Mode mode); | 65 InstantController(InstantControllerDelegate* delegate, Mode mode); |
| 65 virtual ~InstantController(); | 66 virtual ~InstantController(); |
| 66 | 67 |
| 67 // Registers instant related preferences. | 68 // Registers Instant related preferences. |
| 68 static void RegisterUserPrefs(PrefService* prefs); | 69 static void RegisterUserPrefs(PrefService* prefs); |
| 69 | 70 |
| 70 // Records instant metrics. | 71 // Returns true if Instant is enabled for the given |profile|. |
| 71 static void RecordMetrics(Profile* profile); | |
| 72 | |
| 73 // Returns true if instant is enabled in the given |profile|'s preferences. | |
| 74 static bool IsEnabled(Profile* profile); | 72 static bool IsEnabled(Profile* profile); |
| 75 | 73 |
| 76 // Enables instant. | 74 // Invoked as the user types into the omnibox. |user_text| is what the user |
| 77 static void Enable(Profile* profile); | 75 // has typed. |suggested_text| is the current inline autocomplete text. It |
| 78 | 76 // may be replaced by Instant's autocomplete suggestion, if any. If |verbatim| |
| 79 // Disables instant. | 77 // is true, search results are shown for |user_text| rather than the best |
| 80 static void Disable(Profile* profile); | 78 // guess as to what Instant thinks the user means. Returns true if the update |
| 81 | 79 // is processed by Instant (i.e., if |match| is a search rather than a URL). |
| 82 // Invoked as the user types in the omnibox with the url to navigate to. If | |
| 83 // the url is valid and a preview WebContents has not been created, it is | |
| 84 // created. If |verbatim| is true search results are shown for |user_text| | |
| 85 // rather than the best guess as to what the search thought the user meant. | |
| 86 // |verbatim| only matters if the AutocompleteMatch is for a search engine | |
| 87 // that supports instant. Returns true if the attempt to update does not | |
| 88 // result in the preview WebContents being destroyed. | |
| 89 bool Update(const AutocompleteMatch& match, | 80 bool Update(const AutocompleteMatch& match, |
| 90 const string16& user_text, | 81 const string16& user_text, |
| 91 bool verbatim, | 82 bool verbatim, |
| 92 string16* suggested_text); | 83 string16* suggested_text, |
| 84 InstantCompleteBehavior* complete_behavior); |
| 93 | 85 |
| 94 // Sets the bounds of the omnibox (in screen coordinates). The bounds are | 86 // Sets the bounds of the omnibox dropdown, in screen coordinates. |
| 95 // remembered until the preview is committed or destroyed. This is only used | |
| 96 // when showing results for a search provider that supports instant. | |
| 97 void SetOmniboxBounds(const gfx::Rect& bounds); | 87 void SetOmniboxBounds(const gfx::Rect& bounds); |
| 98 | 88 |
| 99 // Notifies the delegate to hide the preview and destroys the preview | 89 // The preview TabContents. May be NULL if ReleasePreviewContents() has been |
| 100 // WebContents. Does nothing if the preview WebContents has not been created. | 90 // called, with no subsequent successful call to Update(). InstantController |
| 101 void DestroyPreviewContents(); | 91 // retains ownership of the object. |
| 92 TabContents* GetPreviewContents() const; |
| 102 | 93 |
| 103 // Notifies the delegate to hide the preview but leaves it around in hopes it | 94 // Hides the preview, but doesn't destroy it, in hopes it can be subsequently |
| 104 // can be subsequently used. The preview will not be used until Update() (with | 95 // reused. The preview will not be used until a call to Update() succeeds. |
| 105 // valid parameters) is invoked. | |
| 106 void Hide(); | 96 void Hide(); |
| 107 | 97 |
| 108 // Returns true if we're showing the last URL passed to |Update|. If this is | 98 // Returns true if the Instant preview can be committed now. This can be true |
| 109 // false a commit does not result in committing the last url passed to update. | 99 // even if the preview is not showing yet, because we can commit as long as |
| 110 // A return value of false happens if we're in the process of determining if | 100 // we've processed the last Update() and we know the loader supports Instant. |
| 111 // the page supports instant. | |
| 112 bool IsCurrent() const; | 101 bool IsCurrent() const; |
| 113 | 102 |
| 114 // Returns true if the caller should proceed with committing the preview. A | 103 // Unconditionally commits the preview. Returns the TabContents that contains |
| 115 // return value of false means that there is no valid preview to commit. This | 104 // the committed preview. |
| 116 // is used by Browser, when the user presses <Enter>, to decide whether to | |
| 117 // load the omnibox contents through Instant or otherwise. This is needed | |
| 118 // because calls to |Update| don't necessarily result in a preview being | |
| 119 // shown, such as in the HIDDEN and SILENT modes. | |
| 120 bool PrepareForCommit(); | |
| 121 | |
| 122 // Invoked when the user does some gesture that should trigger making the | |
| 123 // current previewed page the permanent page. Returns the TabContents that | |
| 124 // contains the committed preview. | |
| 125 TabContents* CommitCurrentPreview(InstantCommitType type); | 105 TabContents* CommitCurrentPreview(InstantCommitType type); |
| 126 | 106 |
| 127 // Accepts the currently showing instant preview, if any, and returns true. | 107 // Releases the preview WebContents passing ownership to the caller. This is |
| 128 // Returns false if there is no instant preview showing. | 108 // intended to be called when the preview WebContents is committed. This does |
| 129 bool CommitIfCurrent(); | 109 // not notify the delegate. |
| 110 TabContents* ReleasePreviewContents( |
| 111 InstantCommitType type) WARN_UNUSED_RESULT; |
| 130 | 112 |
| 131 // Sets InstantController so that when the mouse is released or the | 113 // The autocomplete edit that was initiating the current Instant session has |
| 132 // touch-gesture ends, the preview is committed. | |
| 133 void SetCommitOnPointerRelease(); | |
| 134 | |
| 135 bool commit_on_pointer_release() const { return commit_on_pointer_release_; } | |
| 136 | |
| 137 // Calls through to method of same name on loader. | |
| 138 bool IsPointerDownFromActivate(); | |
| 139 | |
| 140 // The autocomplete edit that was initiating the current instant session has | |
| 141 // lost focus. Commit or discard the preview accordingly. | 114 // lost focus. Commit or discard the preview accordingly. |
| 142 void OnAutocompleteLostFocus(gfx::NativeView view_gaining_focus); | 115 void OnAutocompleteLostFocus(gfx::NativeView view_gaining_focus); |
| 143 | 116 |
| 144 // The autocomplete edit has gained focus. Preload the instant URL of the | 117 // The autocomplete edit has gained focus. Preload the Instant URL of the |
| 145 // default search engine, in anticipation of the user typing a query. | 118 // default search engine, in anticipation of the user typing a query. |
| 146 void OnAutocompleteGotFocus(); | 119 void OnAutocompleteGotFocus(); |
| 147 | 120 |
| 148 // Releases the preview WebContents passing ownership to the caller. This is | 121 // Returns whether the preview will be committed when the mouse or touch |
| 149 // intended to be called when the preview WebContents is committed. This does | 122 // pointer is released. |
| 150 // not notify the delegate. |tab_contents| is the underlying tab onto which | 123 bool commit_on_pointer_release() const; |
| 151 // the preview will be committed. It can be NULL when the underlying tab is | |
| 152 // irrelevant, for example when |type| is INSTANT_COMMIT_DESTROY. | |
| 153 // WARNING: be sure and invoke CompleteRelease after adding the returned | |
| 154 // WebContents to a tabstrip. | |
| 155 TabContents* ReleasePreviewContents(InstantCommitType type, | |
| 156 TabContents* tab_contents); | |
| 157 | |
| 158 // Does cleanup after the preview contents has been added to the tabstrip. | |
| 159 // Invoke this if you explicitly invoke ReleasePreviewContents. | |
| 160 void CompleteRelease(TabContents* tab); | |
| 161 | |
| 162 // The preview TabContents; may be null. | |
| 163 TabContents* GetPreviewContents() const; | |
| 164 | |
| 165 // Returns true if the preview TabContents is ready to be displayed. In | |
| 166 // some situations this may return false yet GetPreviewContents() returns | |
| 167 // non-NULL. | |
| 168 bool is_displayable() const { return is_displayable_; } | |
| 169 | 124 |
| 170 // Returns the transition type of the last AutocompleteMatch passed to Update. | 125 // Returns the transition type of the last AutocompleteMatch passed to Update. |
| 171 content::PageTransition last_transition_type() const { | 126 content::PageTransition last_transition_type() const { |
| 172 return last_transition_type_; | 127 return last_transition_type_; |
| 173 } | 128 } |
| 174 | 129 |
| 175 // InstantLoaderDelegate | 130 // InstantLoaderDelegate: |
| 176 virtual void InstantStatusChanged(InstantLoader* loader) OVERRIDE; | 131 virtual void SetSuggestions(InstantLoader* loader, |
| 177 virtual void SetSuggestedTextFor(InstantLoader* loader, | 132 const std::vector<string16>& suggestions, |
| 178 const string16& text, | 133 InstantCompleteBehavior behavior) OVERRIDE; |
| 179 InstantCompleteBehavior behavior) OVERRIDE; | |
| 180 virtual gfx::Rect GetInstantBounds() OVERRIDE; | |
| 181 virtual bool ShouldCommitInstantOnPointerRelease() OVERRIDE; | |
| 182 virtual void CommitInstantLoader(InstantLoader* loader) OVERRIDE; | 134 virtual void CommitInstantLoader(InstantLoader* loader) OVERRIDE; |
| 183 virtual void InstantLoaderDoesntSupportInstant( | 135 virtual void InstantLoaderPreviewLoaded(InstantLoader* loader) OVERRIDE; |
| 184 InstantLoader* loader) OVERRIDE; | 136 virtual void InstantSupportDetermined(InstantLoader* loader, |
| 185 virtual void AddToBlacklist(InstantLoader* loader, | 137 bool supports_instant) OVERRIDE; |
| 186 const GURL& url) OVERRIDE; | |
| 187 virtual void SwappedTabContents(InstantLoader* loader) OVERRIDE; | 138 virtual void SwappedTabContents(InstantLoader* loader) OVERRIDE; |
| 188 virtual void InstantLoaderContentsFocused() OVERRIDE; | 139 virtual void InstantLoaderContentsFocused(InstantLoader* loader) OVERRIDE; |
| 140 |
| 141 #if defined(UNIT_TEST) |
| 142 // Accessors used only in tests. |
| 143 bool is_showing() const { return is_showing_; } |
| 144 InstantLoader* loader() const { return loader_.get(); } |
| 145 #endif |
| 189 | 146 |
| 190 private: | 147 private: |
| 191 friend class InstantTest; | 148 // Creates a new loader if necessary (for example, if the |instant_url| has |
| 149 // changed since the last time we created the loader). |
| 150 void ResetLoader(const std::string& instant_url, |
| 151 const TabContents* active_tab); |
| 192 | 152 |
| 193 typedef std::set<std::string> HostBlacklist; | 153 // Destroys the |loader_| and its preview contents. |
| 154 void DeleteLoader(); |
| 194 | 155 |
| 195 // Updates |is_displayable_| and if necessary notifies the delegate. | 156 // Counterpart to Hide(). Asks the |delegate_| to display the preview. |
| 196 void UpdateIsDisplayable(); | 157 void Show(); |
| 197 | 158 |
| 198 // Updates InstantLoaderManager and its current InstantLoader. This is invoked | 159 // Send the omnibox dropdown bounds to the page. |
| 199 // internally from Update. | 160 void SendBoundsToPage(); |
| 200 void UpdateLoader(TabContents* tab_contents, | |
| 201 const TemplateURL* template_url, | |
| 202 const GURL& url, | |
| 203 content::PageTransition transition_type, | |
| 204 const string16& user_text, | |
| 205 bool verbatim, | |
| 206 string16* suggested_text); | |
| 207 | 161 |
| 208 // Returns true if |template_url| is a valid TemplateURL for use by instant. | 162 // If |template_url| is a valid TemplateURL for use with Instant, fills in |
| 209 bool IsValidInstantTemplateURL(const TemplateURL* template_url); | 163 // |instant_url| and returns true; returns false otherwise. |
| 164 // Note: If the command-line switch kInstantURL is set, this method uses its |
| 165 // value for |instant_url| and returns true without examining |template_url|. |
| 166 bool GetInstantURL(const TemplateURL* template_url, |
| 167 std::string* instant_url) const; |
| 210 | 168 |
| 211 // Marks the loader as not supporting instant. | 169 // Returns true if the preview is no longer relevant, say because the last |
| 212 void BlacklistFromInstant(); | 170 // Update() was for a URL and not a search query, or the user switched tabs. |
| 171 bool IsOutOfDate() const; |
| 213 | 172 |
| 214 // Returns true if the specified id has been blacklisted from supporting | 173 InstantControllerDelegate* const delegate_; |
| 215 // instant. | |
| 216 bool IsBlacklistedFromInstant(TemplateURLID id); | |
| 217 | |
| 218 // Clears the set of search engines blacklisted. | |
| 219 void ClearBlacklist(); | |
| 220 | |
| 221 // Deletes |loader| after a delay. At the time we determine a site doesn't | |
| 222 // want to participate in instant we can't destroy the loader (because | |
| 223 // destroying the loader destroys the WebContents and the WebContents is on | |
| 224 // the stack). Instead we place the loader in |loaders_to_destroy_| and | |
| 225 // schedule a task. | |
| 226 void ScheduleDestroy(InstantLoader* loader); | |
| 227 | |
| 228 // Destroys all loaders scheduled for destruction in |ScheduleForDestroy|. | |
| 229 void DestroyLoaders(); | |
| 230 | |
| 231 InstantControllerDelegate* delegate_; | |
| 232 | |
| 233 // True if |loader_| is ready to be displayed. | |
| 234 bool is_displayable_; | |
| 235 | |
| 236 // Set to true in Hide() and false in Update(). Used when we persist the | |
| 237 // |loader_|, but it isn't up to date. | |
| 238 bool is_out_of_date_; | |
| 239 | 174 |
| 240 scoped_ptr<InstantLoader> loader_; | 175 scoped_ptr<InstantLoader> loader_; |
| 241 | 176 |
| 242 // See description above setter. | |
| 243 gfx::Rect omnibox_bounds_; | |
| 244 | |
| 245 // See descritopn above for SetCommitOnPointerRelease. | |
| 246 bool commit_on_pointer_release_; | |
| 247 | |
| 248 // See description above getter. | |
| 249 content::PageTransition last_transition_type_; | |
| 250 | |
| 251 // The IDs of any search engines that don't support instant. We assume all | |
| 252 // search engines support instant, but if we determine an engine doesn't | |
| 253 // support instant it is added to this list. The list is cleared out on every | |
| 254 // reset/commit. | |
| 255 std::set<TemplateURLID> blacklisted_ids_; | |
| 256 | |
| 257 // Used by ScheduleForDestroy; see it for details. | |
| 258 base::WeakPtrFactory<InstantController> weak_factory_; | |
| 259 | |
| 260 // List of InstantLoaders to destroy. See ScheduleForDestroy for details. | |
| 261 ScopedVector<InstantLoader> loaders_to_destroy_; | |
| 262 | |
| 263 // The URL of the most recent match passed to |Update|. | |
| 264 GURL last_url_; | |
| 265 | |
| 266 // The most recent user_text passed to |Update|. | |
| 267 string16 last_user_text_; | |
| 268 | |
| 269 // See the enum description above. | 177 // See the enum description above. |
| 270 const Mode mode_; | 178 const Mode mode_; |
| 271 | 179 |
| 180 // The active tab at the time of the last Update(). Used by IsOutOfDate() to |
| 181 // know whether the user switched tabs. ***NEVER DEREFERENCE THIS POINTER.*** |
| 182 // It may be a dangling pointer to a freed object. Should only be used for |
| 183 // pointer comparisons. |
| 184 const void* last_active_tab_; |
| 185 |
| 186 // The most recent full omnibox query text known to us. If this is empty, it |
| 187 // could also mean that the omnibox text was a URL (or something else that |
| 188 // we shouldn't be processing). |
| 189 string16 last_full_text_; |
| 190 |
| 191 // The most recent user_text passed to Update(). |
| 192 string16 last_user_text_; |
| 193 |
| 194 // The most recent verbatim passed to Update(). |
| 195 bool last_verbatim_; |
| 196 |
| 197 // The most recent suggestion received from the page, minus any prefix that |
| 198 // the user has typed. |
| 199 string16 last_suggestion_; |
| 200 |
| 201 // The most recent autocomplete behavior for |last_suggestion_|. |
| 202 InstantCompleteBehavior last_complete_behavior_; |
| 203 |
| 204 // See comments on the getter above. |
| 205 content::PageTransition last_transition_type_; |
| 206 |
| 207 // True if the preview is currently being displayed. Guaranteed to be false |
| 208 // if IsOutOfDate() is true. |
| 209 bool is_showing_; |
| 210 |
| 211 // True if we've received a response from the loader for the last Update(), |
| 212 // thus indicating that the page is ready to be shown. |
| 213 bool loader_processed_last_update_; |
| 214 |
| 215 // Current omnibox bounds. |
| 216 gfx::Rect omnibox_bounds_; |
| 217 |
| 218 // Last bounds passed to the page. |
| 219 gfx::Rect last_omnibox_bounds_; |
| 220 |
| 221 // Timer used to update the bounds of the omnibox. |
| 222 base::OneShotTimer<InstantController> update_bounds_timer_; |
| 223 |
| 224 // For each key K => value N, the map says that we found that the search |
| 225 // engine identified by Instant URL K didn't support the Instant API in each |
| 226 // of the last N times that we loaded it. If an Instant URL isn't present in |
| 227 // the map at all or has a value 0, it means that search engine supports the |
| 228 // Instant API (or we assume it does, since we haven't determined it doesn't). |
| 229 std::map<std::string, int> blacklisted_urls_; |
| 230 |
| 231 // Search terms extraction (for autocomplete history matches) doesn't work |
| 232 // on Instant URLs. So, whenever the user commits an Instant search, we add |
| 233 // an equivalent non-Instant search URL to history, so that the search shows |
| 234 // up in autocomplete history matches. |
| 235 GURL url_for_history_; |
| 236 |
| 272 DISALLOW_COPY_AND_ASSIGN(InstantController); | 237 DISALLOW_COPY_AND_ASSIGN(InstantController); |
| 273 }; | 238 }; |
| 274 | 239 |
| 275 #endif // CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_ | 240 #endif // CHROME_BROWSER_INSTANT_INSTANT_CONTROLLER_H_ |
| OLD | NEW |