Home | History | Annotate | Download | only in people
      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_factory.h"
     14 #include "chrome/browser/signin/signin_manager_factory.h"
     15 #include "chrome/browser/ui/app_list/search/common/url_icon_source.h"
     16 #include "chrome/browser/ui/app_list/search/people/person.h"
     17 #include "chrome/browser/ui/browser_navigator.h"
     18 #include "chrome/common/extensions/api/hangouts_private.h"
     19 #include "chrome/grit/generated_resources.h"
     20 #include "components/signin/core/browser/profile_oauth2_token_service.h"
     21 #include "components/signin/core/browser/signin_manager.h"
     22 #include "content/public/browser/user_metrics.h"
     23 #include "extensions/browser/event_router.h"
     24 #include "grit/theme_resources.h"
     25 #include "ui/base/l10n/l10n_util.h"
     26 #include "ui/base/resource/resource_bundle.h"
     27 
     28 namespace OnHangoutRequested =
     29     extensions::api::hangouts_private::OnHangoutRequested;
     30 
     31 using extensions::api::hangouts_private::User;
     32 using extensions::api::hangouts_private::HangoutRequest;
     33 
     34 namespace {
     35 
     36 const char kImageSizePath[] = "s64-p/";
     37 const char kEmailUrlPrefix[] = "mailto:";
     38 
     39 const char* const kHangoutsExtensionIds[] = {
     40   "nckgahadagoaajjgafhacjanaoiihapd",
     41   "ljclpkphhpbpinifbeabbhlfddcpfdde",
     42   "ppleadejekpmccmnpjdimmlfljlkdfej",
     43   "eggnbpckecmjlblplehfpjjdhhidfdoj",
     44   "jfjjdfefebklmdbmenmlehlopoocnoeh",
     45   "knipolnnllmklapflnccelgolnpehhpl"
     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 64x64 using its smart cropping algorithm.
     51 GURL 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 
     61 namespace app_list {
     62 
     63 PeopleResult::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   int icon_size = GetPreferredIconDimension();
     74   image_ = gfx::ImageSkia(
     75       new UrlIconSource(
     76           base::Bind(&PeopleResult::OnIconLoaded, weak_factory_.GetWeakPtr()),
     77           profile_->GetRequestContext(),
     78           GetImageUrl(person_->image_url),
     79           icon_size,
     80           IDR_PROFILE_PICTURE_LOADING),
     81       gfx::Size(icon_size, icon_size));
     82   SetIcon(image_);
     83 }
     84 
     85 PeopleResult::~PeopleResult() {
     86 }
     87 
     88 void PeopleResult::Open(int event_flags) {
     89   // Action 0 will always be our default action.
     90   InvokeAction(0, event_flags);
     91 }
     92 
     93 void PeopleResult::InvokeAction(int action_index, int event_flags) {
     94   if (hangouts_extension_id_.empty()) {
     95     // If the hangouts app is not available, the only option we are showing
     96     // to the user is 'Send Email'.
     97     SendEmail();
     98   } else {
     99     switch (action_index) {
    100       case 0:
    101         OpenChat();
    102         break;
    103       case 1:
    104         SendEmail();
    105         break;
    106       default:
    107         LOG(ERROR) << "Invalid people search action: " << action_index;
    108     }
    109   }
    110 }
    111 
    112 scoped_ptr<ChromeSearchResult> PeopleResult::Duplicate() {
    113   return scoped_ptr<ChromeSearchResult>(
    114       new PeopleResult(profile_, person_->Duplicate().Pass())).Pass();
    115 }
    116 
    117 void PeopleResult::OnIconLoaded() {
    118   // Remove the existing image reps since the icon data is loaded and they
    119   // need to be re-created.
    120   const std::vector<gfx::ImageSkiaRep>& image_reps = image_.image_reps();
    121   for (size_t i = 0; i < image_reps.size(); ++i)
    122     image_.RemoveRepresentation(image_reps[i].scale());
    123 
    124   SetIcon(image_);
    125 }
    126 
    127 void PeopleResult::SetDefaultActions() {
    128   Actions actions;
    129 
    130   ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
    131   if (!hangouts_extension_id_.empty()) {
    132     actions.push_back(Action(
    133         *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT),
    134         *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT_HOVER),
    135         *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_CHAT_PRESSED),
    136         l10n_util::GetStringUTF16(IDS_PEOPLE_SEARCH_ACTION_CHAT_TOOLTIP)));
    137   }
    138   actions.push_back(Action(
    139       *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_EMAIL),
    140       *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_EMAIL_HOVER),
    141       *bundle.GetImageSkiaNamed(IDR_PEOPLE_SEARCH_ACTION_EMAIL_PRESSED),
    142       l10n_util::GetStringUTF16(IDS_PEOPLE_SEARCH_ACTION_EMAIL_TOOLTIP)));
    143   SetActions(actions);
    144 }
    145 
    146 void PeopleResult::OpenChat() {
    147   HangoutRequest request;
    148 
    149   request.type = extensions::api::hangouts_private::HANGOUT_TYPE_CHAT;
    150 
    151   // from: the user this chat request is originating from.
    152   SigninManagerBase* signin_manager =
    153       SigninManagerFactory::GetInstance()->GetForProfile(profile_);
    154   DCHECK(signin_manager);
    155   request.from = signin_manager->GetAuthenticatedUsername();
    156 
    157   // to: list of users with whom to start this hangout is with.
    158   linked_ptr<User> target(new User());
    159   target->id = person_->owner_id;
    160   request.to.push_back(target);
    161 
    162   scoped_ptr<extensions::Event> event(
    163       new extensions::Event(OnHangoutRequested::kEventName,
    164                             OnHangoutRequested::Create(request)));
    165 
    166   // TODO(rkc): Change this once we remove the hangoutsPrivate API.
    167   // See crbug.com/306672
    168   extensions::EventRouter::Get(profile_)
    169       ->DispatchEventToExtension(hangouts_extension_id_, event.Pass());
    170 
    171   content::RecordAction(base::UserMetricsAction("PeopleSearch_OpenChat"));
    172 }
    173 
    174 void PeopleResult::SendEmail() {
    175   chrome::NavigateParams params(profile_,
    176                                 GURL(kEmailUrlPrefix + person_->email),
    177                                 ui::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 
    184 void 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::EventRouter::Get(profile_)->ExtensionHasEventListener(
    189             kHangoutsExtensionIds[i], OnHangoutRequested::kEventName)) {
    190       hangouts_extension_id_ = kHangoutsExtensionIds[i];
    191       return;
    192     }
    193   }
    194   hangouts_extension_id_.clear();
    195 }
    196 
    197 ChromeSearchResultType PeopleResult::GetType() {
    198   return SEARCH_PEOPLE_SEARCH_RESULT;
    199 }
    200 
    201 }  // namespace app_list
    202