people_result.cc revision 0529e5d033099cbfc42635f6f6183833b09dff6e
169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal// Copyright 2013 The Chromium Authors. All rights reserved.
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal// Use of this source code is governed by a BSD-style license that can be
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal// found in the LICENSE file.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "chrome/browser/ui/app_list/search/people/people_result.h"
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include <vector>
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "base/bind.h"
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "base/memory/ref_counted.h"
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "base/strings/utf_string_conversions.h"
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "chrome/browser/profiles/profile.h"
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "chrome/browser/signin/signin_manager_factory.h"
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "chrome/browser/ui/app_list/search/common/url_icon_source.h"
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "chrome/browser/ui/app_list/search/people/person.h"
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "chrome/browser/ui/browser_navigator.h"
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "chrome/common/extensions/api/hangouts_private.h"
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "components/signin/core/browser/profile_oauth2_token_service.h"
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "components/signin/core/browser/signin_manager.h"
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "content/public/browser/user_metrics.h"
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "extensions/browser/event_router.h"
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "grit/generated_resources.h"
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "grit/theme_resources.h"
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "ui/base/l10n/l10n_util.h"
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal#include "ui/base/resource/resource_bundle.h"
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalnamespace OnHangoutRequested =
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    extensions::api::hangouts_private::OnHangoutRequested;
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalusing extensions::api::hangouts_private::User;
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalusing extensions::api::hangouts_private::HangoutRequest;
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalnamespace {
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalconst int kIconSize = 32;
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalconst char kImageSizePath[] = "s64-p/";
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalconst char kEmailUrlPrefix[] = "mailto:";
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalconst char* const kHangoutsExtensionIds[] = {
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  "nckgahadagoaajjgafhacjanaoiihapd",
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  "ljclpkphhpbpinifbeabbhlfddcpfdde",
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  "ppleadejekpmccmnpjdimmlfljlkdfej",
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  "eggnbpckecmjlblplehfpjjdhhidfdoj"
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal};
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal// Add a query parameter to specify the size to fetch the image in. The
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal// original profile image can be of an arbitrary size, we ask the server to
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal// crop it to a square 64x64 using its smart cropping algorithm.
5069e17611504376e4d4603925f8528dfc890fd2c6Luis SigalGURL GetImageUrl(const GURL& url) {
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  std::string image_filename = url.ExtractFileName();
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  if (image_filename.empty())
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    return url;
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  return url.Resolve(kImageSizePath + image_filename);
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}  // namespace
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalnamespace app_list {
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6269e17611504376e4d4603925f8528dfc890fd2c6Luis SigalPeopleResult::PeopleResult(Profile* profile, scoped_ptr<Person> person)
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    : profile_(profile), person_(person.Pass()), weak_factory_(this) {
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  set_id(person_->id);
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  set_title(base::UTF8ToUTF16(person_->display_name));
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  set_relevance(person_->interaction_rank);
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  set_details(base::UTF8ToUTF16(person_->email));
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  RefreshHangoutsExtensionId();
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  SetDefaultActions();
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  image_ = gfx::ImageSkia(
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      new UrlIconSource(base::Bind(&PeopleResult::OnIconLoaded,
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                   weak_factory_.GetWeakPtr()),
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        profile_->GetRequestContext(),
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        GetImageUrl(person_->image_url),
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        kIconSize,
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        IDR_PROFILE_PICTURE_LOADING),
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      gfx::Size(kIconSize, kIconSize));
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  SetIcon(image_);
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8369e17611504376e4d4603925f8528dfc890fd2c6Luis SigalPeopleResult::~PeopleResult() {
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid PeopleResult::Open(int event_flags) {
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  // Action 0 will always be our default action.
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  InvokeAction(0, event_flags);
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid PeopleResult::InvokeAction(int action_index, int event_flags) {
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  if (hangouts_extension_id_.empty()) {
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    // If the hangouts app is not available, the only option we are showing
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    // to the user is 'Send Email'.
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    SendEmail();
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  } else {
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    switch (action_index) {
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      case 0:
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        OpenChat();
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        break;
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      case 1:
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        SendEmail();
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        break;
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      default:
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        LOG(ERROR) << "Invalid people search action: " << action_index;
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  }
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalscoped_ptr<ChromeSearchResult> PeopleResult::Duplicate() {
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  return scoped_ptr<ChromeSearchResult>(
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      new PeopleResult(profile_, person_->Duplicate().Pass())).Pass();
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid PeopleResult::OnIconLoaded() {
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  // Remove the existing image reps since the icon data is loaded and they
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  // need to be re-created.
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  const std::vector<gfx::ImageSkiaRep>& image_reps = image_.image_reps();
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  for (size_t i = 0; i < image_reps.size(); ++i)
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    image_.RemoveRepresentation(image_reps[i].scale());
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  SetIcon(image_);
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid PeopleResult::SetDefaultActions() {
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  Actions actions;
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  if (!hangouts_extension_id_.empty()) {
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    actions.push_back(Action(
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT),
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT_HOVER),
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT_PRESSED),
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        l10n_util::GetStringUTF16(IDS_PEOPLE_SEARCH_ACTION_CHAT_TOOLTIP)));
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  }
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  actions.push_back(Action(
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_EMAIL),
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_EMAIL_HOVER),
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_EMAIL_PRESSED),
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      l10n_util::GetStringUTF16(IDS_PEOPLE_SEARCH_ACTION_EMAIL_TOOLTIP)));
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  SetActions(actions);
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid PeopleResult::OpenChat() {
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  HangoutRequest request;
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  request.type = extensions::api::hangouts_private::HANGOUT_TYPE_CHAT;
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  // from: the user this chat request is originating from.
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  SigninManagerBase* signin_manager =
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      SigninManagerFactory::GetInstance()->GetForProfile(profile_);
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  DCHECK(signin_manager);
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  request.from = signin_manager->GetAuthenticatedAccountId();
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  // to: list of users with whom to start this hangout is with.
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  linked_ptr<User> target(new User());
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  target->id = person_->owner_id;
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  request.to.push_back(target);
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  scoped_ptr<extensions::Event> event(
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      new extensions::Event(OnHangoutRequested::kEventName,
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                            OnHangoutRequested::Create(request)));
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  // TODO(rkc): Change this once we remove the hangoutsPrivate API.
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  // See crbug.com/306672
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  extensions::EventRouter::Get(profile_)
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal      ->DispatchEventToExtension(hangouts_extension_id_, event.Pass());
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  content::RecordAction(base::UserMetricsAction("PeopleSearch_OpenChat"));
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid PeopleResult::SendEmail() {
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  chrome::NavigateParams params(profile_,
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                GURL(kEmailUrlPrefix + person_->email),
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                                content::PAGE_TRANSITION_LINK);
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  // If no window exists, this will open a new window this one tab.
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  params.disposition = NEW_FOREGROUND_TAB;
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  chrome::Navigate(&params);
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  content::RecordAction(base::UserMetricsAction("PeopleSearch_SendEmail"));
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalvoid PeopleResult::RefreshHangoutsExtensionId() {
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  // TODO(rkc): Change this once we remove the hangoutsPrivate API.
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  // See crbug.com/306672
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal  for (size_t i = 0; i < arraysize(kHangoutsExtensionIds); ++i) {
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    if (extensions::EventRouter::Get(profile_)->ExtensionHasEventListener(
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            kHangoutsExtensionIds[i], OnHangoutRequested::kEventName)) {
188      hangouts_extension_id_ = kHangoutsExtensionIds[i];
189      return;
190    }
191  }
192  hangouts_extension_id_.clear();
193}
194
195ChromeSearchResultType PeopleResult::GetType() {
196  return SEARCH_PEOPLE_SEARCH_RESULT;
197}
198
199}  // namespace app_list
200