people_result.cc revision f2477e01787aa58f445919b809d89e252beef54f
1// Copyright 2013 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/ui/app_list/search/people/people_result.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/memory/ref_counted.h"
11#include "base/strings/utf_string_conversions.h"
12#include "chrome/browser/extensions/extension_system.h"
13#include "chrome/browser/profiles/profile.h"
14#include "chrome/browser/signin/profile_oauth2_token_service.h"
15#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
16#include "chrome/browser/ui/app_list/search/common/url_icon_source.h"
17#include "chrome/browser/ui/app_list/search/people/person.h"
18#include "chrome/browser/ui/browser_navigator.h"
19#include "chrome/common/extensions/api/hangouts_private.h"
20#include "content/public/browser/user_metrics.h"
21#include "extensions/browser/event_router.h"
22#include "grit/generated_resources.h"
23#include "grit/theme_resources.h"
24#include "ui/base/l10n/l10n_util.h"
25#include "ui/base/resource/resource_bundle.h"
26
27namespace OnHangoutRequested =
28    extensions::api::hangouts_private::OnHangoutRequested;
29
30using extensions::api::hangouts_private::User;
31using extensions::api::hangouts_private::HangoutRequest;
32
33namespace {
34
35const int kIconSize = 32;
36const char kImageSizePath[] = "s32-p/";
37const char kEmailUrlPrefix[] = "mailto:";
38
39const char* const kHangoutsExtensionIds[] = {
40  "nckgahadagoaajjgafhacjanaoiihapd",
41  "ljclpkphhpbpinifbeabbhlfddcpfdde",
42  "ppleadejekpmccmnpjdimmlfljlkdfej",
43  "eggnbpckecmjlblplehfpjjdhhidfdoj"
44};
45
46// Add a query parameter to specify the size to fetch the image in. The
47// original profile image can be of an arbitrary size, we ask the server to
48// crop it to a square 32x32 using its smart cropping algorithm.
49GURL GetImageUrl(const GURL& url) {
50  std::string image_filename = url.ExtractFileName();
51  if (image_filename.empty())
52    return url;
53
54  return url.Resolve(kImageSizePath + image_filename);
55}
56
57}  // namespace
58
59namespace app_list {
60
61PeopleResult::PeopleResult(Profile* profile, scoped_ptr<Person> person)
62    : profile_(profile), person_(person.Pass()), weak_factory_(this) {
63  set_id(person_->id);
64  set_title(UTF8ToUTF16(person_->display_name));
65  set_relevance(person_->interaction_rank);
66  set_details(UTF8ToUTF16(person_->email));
67
68  RefreshHangoutsExtensionId();
69  SetDefaultActions();
70
71  image_ = gfx::ImageSkia(
72      new UrlIconSource(base::Bind(&PeopleResult::OnIconLoaded,
73                                   weak_factory_.GetWeakPtr()),
74                        profile_->GetRequestContext(),
75                        GetImageUrl(person_->image_url),
76                        kIconSize,
77                        IDR_PROFILE_PICTURE_LOADING),
78      gfx::Size(kIconSize, kIconSize));
79  SetIcon(image_);
80}
81
82PeopleResult::~PeopleResult() {
83}
84
85void PeopleResult::Open(int event_flags) {
86  // Action 0 will always be our default action.
87  InvokeAction(0, event_flags);
88}
89
90void PeopleResult::InvokeAction(int action_index, int event_flags) {
91  if (hangouts_extension_id_.empty()) {
92    // If the hangouts app is not available, the only option we are showing
93    // to the user is 'Send Email'.
94    SendEmail();
95  } else {
96    switch (action_index) {
97      case 0:
98        OpenChat();
99        break;
100      case 1:
101        SendEmail();
102        break;
103      default:
104        LOG(ERROR) << "Invalid people search action: " << action_index;
105    }
106  }
107}
108
109scoped_ptr<ChromeSearchResult> PeopleResult::Duplicate() {
110  return scoped_ptr<ChromeSearchResult>(
111      new PeopleResult(profile_, person_->Duplicate().Pass())).Pass();
112}
113
114void PeopleResult::OnIconLoaded() {
115  // Remove the existing image reps since the icon data is loaded and they
116  // need to be re-created.
117  const std::vector<gfx::ImageSkiaRep>& image_reps = image_.image_reps();
118  for (size_t i = 0; i < image_reps.size(); ++i)
119    image_.RemoveRepresentation(image_reps[i].scale());
120
121  SetIcon(image_);
122}
123
124void PeopleResult::SetDefaultActions() {
125  Actions actions;
126
127  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
128  if (!hangouts_extension_id_.empty()) {
129    actions.push_back(Action(
130        *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT),
131        *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT_HOVER),
132        *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT_PRESSED),
133        l10n_util::GetStringUTF16(IDS_PEOPLE_SEARCH_ACTION_CHAT_TOOLTIP)));
134  }
135  actions.push_back(Action(
136      *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_EMAIL),
137      *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_EMAIL_HOVER),
138      *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_EMAIL_PRESSED),
139      l10n_util::GetStringUTF16(IDS_PEOPLE_SEARCH_ACTION_EMAIL_TOOLTIP)));
140  SetActions(actions);
141}
142
143void PeopleResult::OpenChat() {
144  HangoutRequest request;
145
146  request.type = extensions::api::hangouts_private::HANGOUT_TYPE_CHAT;
147
148  // from: the user this chat request is originating from.
149  ProfileOAuth2TokenService* token_service =
150      ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
151  DCHECK(token_service);
152  request.from = token_service->GetPrimaryAccountId();
153
154  // to: list of users with whom to start this hangout is with.
155  linked_ptr<User> target(new User());
156  target->id = person_->owner_id;
157  request.to.push_back(target);
158
159  scoped_ptr<extensions::Event> event(
160      new extensions::Event(OnHangoutRequested::kEventName,
161                            OnHangoutRequested::Create(request)));
162
163  // TODO(rkc): Change this once we remove the hangoutsPrivate API.
164  // See crbug.com/306672
165  extensions::ExtensionSystem::Get(
166      profile_)->event_router()->DispatchEventToExtension(
167          hangouts_extension_id_, event.Pass());
168
169  content::RecordAction(content::UserMetricsAction("PeopleSearch_OpenChat"));
170}
171
172void PeopleResult::SendEmail() {
173  chrome::NavigateParams params(profile_,
174                                GURL(kEmailUrlPrefix + person_->email),
175                                content::PAGE_TRANSITION_LINK);
176  // If no window exists, this will open a new window this one tab.
177  params.disposition = NEW_FOREGROUND_TAB;
178  chrome::Navigate(&params);
179  content::RecordAction(content::UserMetricsAction("PeopleSearch_SendEmail"));
180}
181
182void PeopleResult::RefreshHangoutsExtensionId() {
183  // TODO(rkc): Change this once we remove the hangoutsPrivate API.
184  // See crbug.com/306672
185  for (size_t i = 0; i < arraysize(kHangoutsExtensionIds); ++i) {
186    if (extensions::ExtensionSystem::Get(
187        profile_)->event_router()->ExtensionHasEventListener(
188            kHangoutsExtensionIds[i], OnHangoutRequested::kEventName)) {
189      hangouts_extension_id_ = kHangoutsExtensionIds[i];
190      return;
191    }
192  }
193  hangouts_extension_id_.clear();
194}
195
196ChromeSearchResultType PeopleResult::GetType() {
197  return SEARCH_PEOPLE_SEARCH_RESULT;
198}
199
200}  // namespace app_list
201