Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: chrome/browser/autocomplete/contact_provider_chromeos.cc

Issue 10916304: autocomplete: Make ContactProvider rank contacts by affinity (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: improve error messages Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 #include "chrome/browser/autocomplete/contact_provider_chromeos.h" 5 #include "chrome/browser/autocomplete/contact_provider_chromeos.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath>
8 9
9 #include "base/i18n/break_iterator.h" 10 #include "base/i18n/break_iterator.h"
10 #include "base/i18n/string_search.h" 11 #include "base/i18n/string_search.h"
11 #include "base/string_split.h" 12 #include "base/string_split.h"
12 #include "base/string16.h" 13 #include "base/string16.h"
13 #include "base/utf_string_conversions.h" 14 #include "base/utf_string_conversions.h"
14 #include "chrome/browser/autocomplete/autocomplete_input.h" 15 #include "chrome/browser/autocomplete/autocomplete_input.h"
15 #include "chrome/browser/chromeos/contacts/contact.pb.h" 16 #include "chrome/browser/chromeos/contacts/contact.pb.h"
16 #include "chrome/browser/chromeos/contacts/contact_manager.h" 17 #include "chrome/browser/chromeos/contacts/contact_manager.h"
17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
18 19
19 namespace { 20 namespace {
20 21
22 // Default affinity assigned to contacts whose |affinity| field is unset.
23 // TODO(derat): Set this to something reasonable (probably 0.0) once we're
24 // getting affinity for contacts.
25 float kDefaultAffinity = 1.0;
26
27 // Base match relevance assigned to a contact with an affinity of 0.0.
28 int kBaseRelevance = 1300;
29
30 // Maximum boost to relevance for a contact with an affinity of 1.0.
31 int kAffinityRelevanceBoost = 200;
32
21 // Returns true if |word_to_find| is a prefix of |name_to_search| and marks the 33 // Returns true if |word_to_find| is a prefix of |name_to_search| and marks the
22 // matching text in |classifications| (which corresponds to the contact's full 34 // matching text in |classifications| (which corresponds to the contact's full
23 // name). |name_index_in_full_name| contains |name_to_search|'s index within 35 // name). |name_index_in_full_name| contains |name_to_search|'s index within
24 // the full name or string16::npos if it doesn't appear in it. 36 // the full name or string16::npos if it doesn't appear in it.
25 bool WordIsNamePrefix(const string16& word_to_find, 37 bool WordIsNamePrefix(const string16& word_to_find,
26 const string16& name_to_search, 38 const string16& name_to_search,
27 size_t name_index_in_full_name, 39 size_t name_index_in_full_name,
28 size_t full_name_length, 40 size_t full_name_length,
29 ACMatchClassifications* classifications) { 41 ACMatchClassifications* classifications) {
30 DCHECK(classifications); 42 DCHECK(classifications);
(...skipping 18 matching lines...) Expand all
49 } // namespace 61 } // namespace
50 62
51 // static 63 // static
52 const char ContactProvider::kMatchContactIdKey[] = "contact_id"; 64 const char ContactProvider::kMatchContactIdKey[] = "contact_id";
53 65
54 // Cached information about a contact. 66 // Cached information about a contact.
55 struct ContactProvider::ContactData { 67 struct ContactProvider::ContactData {
56 ContactData(const string16& full_name, 68 ContactData(const string16& full_name,
57 const string16& given_name, 69 const string16& given_name,
58 const string16& family_name, 70 const string16& family_name,
59 const std::string& contact_id) 71 const std::string& contact_id,
72 float affinity)
60 : full_name(full_name), 73 : full_name(full_name),
61 given_name(given_name), 74 given_name(given_name),
62 family_name(family_name), 75 family_name(family_name),
63 given_name_index(string16::npos), 76 given_name_index(string16::npos),
64 family_name_index(string16::npos), 77 family_name_index(string16::npos),
65 contact_id(contact_id) { 78 contact_id(contact_id),
79 affinity(affinity) {
66 base::i18n::StringSearchIgnoringCaseAndAccents( 80 base::i18n::StringSearchIgnoringCaseAndAccents(
67 given_name, full_name, &given_name_index, NULL); 81 given_name, full_name, &given_name_index, NULL);
68 base::i18n::StringSearchIgnoringCaseAndAccents( 82 base::i18n::StringSearchIgnoringCaseAndAccents(
69 family_name, full_name, &family_name_index, NULL); 83 family_name, full_name, &family_name_index, NULL);
70 } 84 }
71 85
72 string16 full_name; 86 string16 full_name;
73 string16 given_name; 87 string16 given_name;
74 string16 family_name; 88 string16 family_name;
75 89
76 // Indices into |full_name| where |given_name| and |family_name| first appear, 90 // Indices into |full_name| where |given_name| and |family_name| first appear,
77 // or string16::npos if they don't appear in it. 91 // or string16::npos if they don't appear in it.
78 size_t given_name_index; 92 size_t given_name_index;
79 size_t family_name_index; 93 size_t family_name_index;
80 94
81 // Unique ID used to look up additional contact information. 95 // Unique ID used to look up additional contact information.
82 std::string contact_id; 96 std::string contact_id;
97
98 // Affinity between the user and this contact, in the range [0.0, 1.0].
99 float affinity;
83 }; 100 };
84 101
85 ContactProvider::ContactProvider( 102 ContactProvider::ContactProvider(
86 AutocompleteProviderListener* listener, 103 AutocompleteProviderListener* listener,
87 Profile* profile, 104 Profile* profile,
88 base::WeakPtr<contacts::ContactManagerInterface> contact_manager) 105 base::WeakPtr<contacts::ContactManagerInterface> contact_manager)
89 : AutocompleteProvider(listener, profile, TYPE_CONTACT), 106 : AutocompleteProvider(listener, profile, TYPE_CONTACT),
90 contact_manager_(contact_manager) { 107 contact_manager_(contact_manager) {
91 contact_manager_->AddObserver(this, profile); 108 contact_manager_->AddObserver(this, profile);
92 RefreshContacts(); 109 RefreshContacts();
(...skipping 15 matching lines...) Expand all
108 base::i18n::BreakIterator break_iterator( 125 base::i18n::BreakIterator break_iterator(
109 input.text(), 126 input.text(),
110 base::i18n::BreakIterator::BREAK_WORD); 127 base::i18n::BreakIterator::BREAK_WORD);
111 if (break_iterator.Init()) { 128 if (break_iterator.Init()) {
112 while (break_iterator.Advance()) { 129 while (break_iterator.Advance()) {
113 if (break_iterator.IsWord()) 130 if (break_iterator.IsWord())
114 input_words.push_back(break_iterator.GetString()); 131 input_words.push_back(break_iterator.GetString());
115 } 132 }
116 } 133 }
117 134
135 // |contacts_| is ordered by descending affinity. Since affinity is currently
136 // the only signal used for computing relevance, we can stop after we've found
137 // kMaxMatches results.
118 for (ContactDataVector::const_iterator it = contacts_.begin(); 138 for (ContactDataVector::const_iterator it = contacts_.begin();
119 it != contacts_.end(); ++it) 139 it != contacts_.end() && matches_.size() < kMaxMatches; ++it)
120 AddContactIfMatched(input, input_words, *it); 140 AddContactIfMatched(input, input_words, *it);
121 } 141 }
122 142
123 void ContactProvider::OnContactsUpdated(Profile* profile) { 143 void ContactProvider::OnContactsUpdated(Profile* profile) {
124 DCHECK_EQ(profile, profile_); 144 DCHECK_EQ(profile, profile_);
125 RefreshContacts(); 145 RefreshContacts();
126 } 146 }
127 147
128 ContactProvider::~ContactProvider() { 148 ContactProvider::~ContactProvider() {
129 // Like ContactProvider, ContactManager gets destroyed at profile destruction. 149 // Like ContactProvider, ContactManager gets destroyed at profile destruction.
130 // Make sure that this class doesn't try to access ContactManager after 150 // Make sure that this class doesn't try to access ContactManager after
131 // ContactManager is gone. 151 // ContactManager is gone.
132 if (contact_manager_.get()) 152 if (contact_manager_.get())
133 contact_manager_->RemoveObserver(this, profile_); 153 contact_manager_->RemoveObserver(this, profile_);
134 } 154 }
135 155
156 // static
157 bool ContactProvider::CompareAffinity(const ContactData& a,
158 const ContactData& b) {
159 return a.affinity > b.affinity;
160 }
161
136 void ContactProvider::RefreshContacts() { 162 void ContactProvider::RefreshContacts() {
137 if (!contact_manager_.get()) 163 if (!contact_manager_.get())
138 return; 164 return;
139 165
140 scoped_ptr<contacts::ContactPointers> contacts = 166 scoped_ptr<contacts::ContactPointers> contacts =
141 contact_manager_->GetAllContacts(profile_); 167 contact_manager_->GetAllContacts(profile_);
142 168
143 contacts_.clear(); 169 contacts_.clear();
170 contacts_.reserve(contacts->size());
144 for (contacts::ContactPointers::const_iterator it = contacts->begin(); 171 for (contacts::ContactPointers::const_iterator it = contacts->begin();
145 it != contacts->end(); ++it) { 172 it != contacts->end(); ++it) {
146 const contacts::Contact& contact = **it; 173 const contacts::Contact& contact = **it;
147 string16 full_name = 174 string16 full_name =
148 AutocompleteMatch::SanitizeString(UTF8ToUTF16(contact.full_name())); 175 AutocompleteMatch::SanitizeString(UTF8ToUTF16(contact.full_name()));
149 string16 given_name = 176 string16 given_name =
150 AutocompleteMatch::SanitizeString(UTF8ToUTF16(contact.given_name())); 177 AutocompleteMatch::SanitizeString(UTF8ToUTF16(contact.given_name()));
151 string16 family_name = 178 string16 family_name =
152 AutocompleteMatch::SanitizeString(UTF8ToUTF16(contact.family_name())); 179 AutocompleteMatch::SanitizeString(UTF8ToUTF16(contact.family_name()));
180 float affinity =
181 contact.has_affinity() ? contact.affinity() : kDefaultAffinity;
153 182
154 if (!full_name.empty()) { 183 if (!full_name.empty()) {
155 contacts_.push_back( 184 contacts_.push_back(
156 ContactData( 185 ContactData(full_name, given_name, family_name, contact.contact_id(),
157 full_name, given_name, family_name, contact.contact_id())); 186 affinity));
158 } 187 }
159 } 188 }
189 std::sort(contacts_.begin(), contacts_.end(), CompareAffinity);
160 } 190 }
161 191
162 void ContactProvider::AddContactIfMatched( 192 void ContactProvider::AddContactIfMatched(
163 const AutocompleteInput& input, 193 const AutocompleteInput& input,
164 const std::vector<string16>& input_words, 194 const std::vector<string16>& input_words,
165 const ContactData& contact) { 195 const ContactData& contact) {
166 // First, check if the whole input string is a prefix of the full name. 196 // First, check if the whole input string is a prefix of the full name.
167 // TODO(derat): Consider additionally segmenting the full name so we can match 197 // TODO(derat): Consider additionally segmenting the full name so we can match
168 // e.g. middle names or initials even when they aren't typed as a prefix of 198 // e.g. middle names or initials even when they aren't typed as a prefix of
169 // the full name. 199 // the full name.
(...skipping 23 matching lines...) Expand all
193 matches_.back().contents_class = classifications; 223 matches_.back().contents_class = classifications;
194 } 224 }
195 225
196 AutocompleteMatch ContactProvider::CreateAutocompleteMatch( 226 AutocompleteMatch ContactProvider::CreateAutocompleteMatch(
197 const AutocompleteInput& input, 227 const AutocompleteInput& input,
198 const ContactData& contact) { 228 const ContactData& contact) {
199 AutocompleteMatch match(this, 0, false, AutocompleteMatch::CONTACT); 229 AutocompleteMatch match(this, 0, false, AutocompleteMatch::CONTACT);
200 match.inline_autocomplete_offset = string16::npos; 230 match.inline_autocomplete_offset = string16::npos;
201 match.contents = contact.full_name; 231 match.contents = contact.full_name;
202 match.fill_into_edit = match.contents; 232 match.fill_into_edit = match.contents;
203 // TODO(derat): Implement ranking. 233 match.relevance = kBaseRelevance +
204 match.relevance = 1; 234 static_cast<int>(roundf(kAffinityRelevanceBoost * contact.affinity));
205 match.RecordAdditionalInfo(kMatchContactIdKey, contact.contact_id); 235 match.RecordAdditionalInfo(kMatchContactIdKey, contact.contact_id);
206 return match; 236 return match;
207 } 237 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698