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