| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/autocomplete/extension_app_provider.h" |
| 6 |
| 7 #include <algorithm> |
| 8 |
| 9 #include "base/string16.h" |
| 10 #include "base/utf_string_conversions.h" |
| 11 #include "chrome/browser/extensions/extension_service.h" |
| 12 #include "chrome/browser/history/history.h" |
| 13 #include "chrome/browser/history/url_database.h" |
| 14 #include "chrome/browser/profiles/profile.h" |
| 15 #include "content/common/notification_service.h" |
| 16 #include "ui/base/l10n/l10n_util.h" |
| 17 |
| 18 ExtensionAppProvider::ExtensionAppProvider(ACProviderListener* listener, |
| 19 Profile* profile) |
| 20 : AutocompleteProvider(listener, profile, "ExtensionApps") { |
| 21 RegisterForNotifications(); |
| 22 RefreshAppList(); |
| 23 } |
| 24 |
| 25 void ExtensionAppProvider::Start(const AutocompleteInput& input, |
| 26 bool minimal_changes) { |
| 27 matches_.clear(); |
| 28 |
| 29 if (input.type() == AutocompleteInput::INVALID) |
| 30 return; |
| 31 |
| 32 if (!input.text().empty()) { |
| 33 std::string input_utf8 = UTF16ToUTF8(input.text()); |
| 34 for (ExtensionApps::const_iterator app = extension_apps_.begin(); |
| 35 app != extension_apps_.end(); ++app) { |
| 36 // See if the input matches this extension application. |
| 37 const std::string& name = app->first; |
| 38 const std::string& url = app->second; |
| 39 std::string::const_iterator name_iter = |
| 40 std::search(name.begin(), |
| 41 name.end(), |
| 42 input_utf8.begin(), |
| 43 input_utf8.end(), |
| 44 base::CaseInsensitiveCompare<char>()); |
| 45 std::string::const_iterator url_iter = |
| 46 std::search(url.begin(), |
| 47 url.end(), |
| 48 input_utf8.begin(), |
| 49 input_utf8.end(), |
| 50 base::CaseInsensitiveCompare<char>()); |
| 51 |
| 52 bool matches_name = name_iter != name.end(); |
| 53 bool matches_url = url_iter != url.end() && |
| 54 input.type() != AutocompleteInput::FORCED_QUERY; |
| 55 if (matches_name || matches_url) { |
| 56 // We have a match, might be a partial match. |
| 57 // TODO(finnur): Figure out what type to return here, might want to have |
| 58 // the extension icon/a generic icon show up in the Omnibox. |
| 59 AutocompleteMatch match(this, 0, false, AutocompleteMatch::HISTORY_URL); |
| 60 match.fill_into_edit = UTF8ToUTF16(url); |
| 61 match.destination_url = GURL(url); |
| 62 match.inline_autocomplete_offset = string16::npos; |
| 63 match.contents = UTF8ToUTF16(name); |
| 64 HighlightMatch(input, &match.contents_class, name_iter, name); |
| 65 match.description = UTF8ToUTF16(url); |
| 66 HighlightMatch(input, &match.description_class, url_iter, url); |
| 67 match.relevance = CalculateRelevance(input.type(), |
| 68 input.text().length(), |
| 69 matches_name ? |
| 70 name.length() : url.length(), |
| 71 GURL(url)); |
| 72 matches_.push_back(match); |
| 73 } |
| 74 } |
| 75 } |
| 76 } |
| 77 |
| 78 ExtensionAppProvider::~ExtensionAppProvider() { |
| 79 } |
| 80 |
| 81 void ExtensionAppProvider::RefreshAppList() { |
| 82 ExtensionService* extension_service = profile_->GetExtensionService(); |
| 83 if (!extension_service) |
| 84 return; // During testing, there is no extension service. |
| 85 const ExtensionList* extensions = extension_service->extensions(); |
| 86 extension_apps_.clear(); |
| 87 for (ExtensionList::const_iterator app = extensions->begin(); |
| 88 app != extensions->end(); ++app) { |
| 89 if ((*app)->is_app() && !(*app)->launch_web_url().empty()) { |
| 90 extension_apps_.push_back(std::make_pair((*app)->name(), |
| 91 (*app)->launch_web_url())); |
| 92 } |
| 93 } |
| 94 } |
| 95 |
| 96 void ExtensionAppProvider::RegisterForNotifications() { |
| 97 registrar_.Add(this, NotificationType::EXTENSION_LOADED, |
| 98 NotificationService::AllSources()); |
| 99 registrar_.Add(this, NotificationType::EXTENSION_UNINSTALLED, |
| 100 NotificationService::AllSources()); |
| 101 } |
| 102 |
| 103 void ExtensionAppProvider::Observe(NotificationType type, |
| 104 const NotificationSource& source, |
| 105 const NotificationDetails& details) { |
| 106 RefreshAppList(); |
| 107 } |
| 108 |
| 109 void ExtensionAppProvider::HighlightMatch(const AutocompleteInput& input, |
| 110 ACMatchClassifications* match_class, |
| 111 std::string::const_iterator iter, |
| 112 const std::string& match_string) { |
| 113 size_t pos = iter - match_string.begin(); |
| 114 bool match_found = iter != match_string.end(); |
| 115 if (!match_found || pos > 0) { |
| 116 match_class->push_back( |
| 117 ACMatchClassification(0, ACMatchClassification::DIM)); |
| 118 } |
| 119 if (match_found) { |
| 120 match_class->push_back( |
| 121 ACMatchClassification(pos, ACMatchClassification::MATCH)); |
| 122 if (pos + input.text().length() < match_string.length()) { |
| 123 match_class->push_back(ACMatchClassification(pos + input.text().length(), |
| 124 ACMatchClassification::DIM)); |
| 125 } |
| 126 } |
| 127 } |
| 128 |
| 129 int ExtensionAppProvider::CalculateRelevance(AutocompleteInput::Type type, |
| 130 int input_length, |
| 131 int target_length, |
| 132 const GURL& url) { |
| 133 // If you update the algorithm here, please remember to update the tables in |
| 134 // autocomplete.h also. |
| 135 const int kMaxRelevance = 1425; |
| 136 |
| 137 if (input_length == target_length) |
| 138 return kMaxRelevance; |
| 139 |
| 140 // We give a boost proportionally based on how much of the input matches the |
| 141 // app name, up to a maximum close to 200 (we can be close to, but we'll never |
| 142 // reach 200 because the 100% match is taken care of above). |
| 143 double fraction_boost = static_cast<double>(200) * |
| 144 input_length / target_length; |
| 145 |
| 146 // We also give a boost of 40 points for each time the user has previously |
| 147 // typed the Extension App URL (up to a 400 point maximum). |
| 148 int type_count_boost = 0; |
| 149 HistoryService* const history_service = |
| 150 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); |
| 151 history::URLDatabase* url_db = history_service ? |
| 152 history_service->InMemoryDatabase() : NULL; |
| 153 if (url_db) { |
| 154 history::URLRow info; |
| 155 url_db->GetRowForURL(url, &info); |
| 156 type_count_boost = std::min(400, info.typed_count() * 40); |
| 157 } |
| 158 int relevance = 400 + type_count_boost + static_cast<int>(fraction_boost); |
| 159 DCHECK_LE(relevance, kMaxRelevance); |
| 160 return relevance; |
| 161 } |
| OLD | NEW |