privet_notifications.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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/local_discovery/privet_notifications.h" 6 7#include "base/bind.h" 8#include "base/message_loop/message_loop.h" 9#include "base/strings/utf_string_conversions.h" 10#include "chrome/browser/local_discovery/privet_device_lister_impl.h" 11#include "chrome/browser/notifications/notification.h" 12#include "chrome/browser/profiles/profile.h" 13#include "chrome/browser/ui/browser.h" 14#include "chrome/browser/ui/browser_finder.h" 15#include "chrome/browser/ui/host_desktop.h" 16#include "chrome/browser/ui/tabs/tab_strip_model.h" 17#include "chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h" 18#include "content/public/browser/browser_context.h" 19#include "content/public/browser/navigation_controller.h" 20#include "content/public/browser/web_contents.h" 21#include "content/public/common/page_transition_types.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#include "ui/message_center/notifier_settings.h" 27 28namespace local_discovery { 29 30namespace { 31const int kTenMinutesInSeconds = 600; 32const char kPrivetInfoKeyUptime[] = "uptime"; 33const char kPrivetNotificationIDPrefix[] = "privet_notification:"; 34const char kPrivetNotificationOriginUrl[] = "chrome://devices"; 35} 36 37PrivetNotificationsListener::PrivetNotificationsListener( 38 scoped_ptr<PrivetHTTPAsynchronousFactory> privet_http_factory, 39 Delegate* delegate) : delegate_(delegate) { 40 privet_http_factory_.swap(privet_http_factory); 41} 42 43PrivetNotificationsListener::~PrivetNotificationsListener() { 44} 45 46void PrivetNotificationsListener::DeviceChanged( 47 bool added, 48 const std::string& name, 49 const DeviceDescription& description) { 50 DeviceContextMap::iterator found = devices_seen_.find(name); 51 if (found != devices_seen_.end()) { 52 if (!description.id.empty() && // Device is registered 53 found->second->notification_may_be_active) { 54 found->second->notification_may_be_active = false; 55 delegate_->PrivetRemoveNotification(name); 56 } 57 return; // Already saw this device. 58 } 59 60 linked_ptr<DeviceContext> device_context(new DeviceContext); 61 62 device_context->notification_may_be_active = false; 63 device_context->registered = !description.id.empty(); 64 device_context->human_readable_name = description.name; 65 device_context->description = description.description; 66 67 devices_seen_.insert(make_pair(name, device_context)); 68 69 if (!device_context->registered) { 70 device_context->privet_http_resolution = 71 privet_http_factory_->CreatePrivetHTTP( 72 name, 73 description.address, 74 base::Bind(&PrivetNotificationsListener::CreateInfoOperation, 75 base::Unretained(this))); 76 77 device_context->privet_http_resolution->Start(); 78 } 79} 80 81void PrivetNotificationsListener::CreateInfoOperation( 82 scoped_ptr<PrivetHTTPClient> http_client) { 83 std::string name = http_client->GetName(); 84 DeviceContextMap::iterator device_iter = devices_seen_.find(name); 85 DCHECK(device_iter != devices_seen_.end()); 86 DeviceContext* device = device_iter->second.get(); 87 device->privet_http.swap(http_client); 88 device->info_operation = 89 device->privet_http->CreateInfoOperation(this); 90 device->info_operation->Start(); 91} 92 93void PrivetNotificationsListener::OnPrivetInfoDone( 94 PrivetInfoOperation* operation, 95 int http_code, 96 const base::DictionaryValue* json_value) { 97 std::string name = operation->GetHTTPClient()->GetName(); 98 DeviceContextMap::iterator device_iter = devices_seen_.find(name); 99 DCHECK(device_iter != devices_seen_.end()); 100 DeviceContext* device = device_iter->second.get(); 101 102 int uptime; 103 104 if (!json_value || 105 !json_value->GetInteger(kPrivetInfoKeyUptime, &uptime) || 106 uptime > kTenMinutesInSeconds) { 107 return; 108 } 109 110 DCHECK(!device->notification_may_be_active); 111 device->notification_may_be_active = true; 112 delegate_->PrivetNotify(name, device->human_readable_name, 113 device->description); 114} 115 116void PrivetNotificationsListener::DeviceRemoved(const std::string& name) { 117 DCHECK_EQ(1u, devices_seen_.count(name)); 118 DeviceContextMap::iterator device_iter = devices_seen_.find(name); 119 DCHECK(device_iter != devices_seen_.end()); 120 DeviceContext* device = device_iter->second.get(); 121 122 device->info_operation.reset(); 123 device->privet_http_resolution.reset(); 124 device->notification_may_be_active = false; 125 delegate_->PrivetRemoveNotification(name); 126} 127 128PrivetNotificationsListener::DeviceContext::DeviceContext() { 129} 130 131PrivetNotificationsListener::DeviceContext::~DeviceContext() { 132} 133 134PrivetNotificationService::PrivetNotificationService( 135 content::BrowserContext* profile, 136 NotificationUIManager* notification_manager) 137 : profile_(profile), 138 notification_manager_(notification_manager) { 139 base::MessageLoop::current()->PostTask( 140 FROM_HERE, 141 base::Bind(&PrivetNotificationService::Start, AsWeakPtr())); 142} 143 144PrivetNotificationService::~PrivetNotificationService() { 145 ServiceDiscoveryHostClientFactory::ReleaseClient(); 146} 147 148void PrivetNotificationService::DeviceChanged( 149 bool added, 150 const std::string& name, 151 const DeviceDescription& description) { 152 privet_notifications_listener_->DeviceChanged(added, name, description); 153} 154 155void PrivetNotificationService::DeviceRemoved(const std::string& name) { 156 privet_notifications_listener_->DeviceRemoved(name); 157} 158 159void PrivetNotificationService::PrivetNotify( 160 const std::string& device_name, 161 const std::string& human_readable_name, 162 const std::string& description) { 163 if (!LocalDiscoveryUIHandler::GetHasVisible()) { 164 Profile* profile_object = Profile::FromBrowserContext(profile_); 165 message_center::RichNotificationData rich_notification_data; 166 167 rich_notification_data.buttons.push_back( 168 message_center::ButtonInfo(l10n_util::GetStringUTF16( 169 IDS_LOCAL_DISOCVERY_NOTIFICATION_BUTTON_PRINTER))); 170 171 Notification notification( 172 message_center::NOTIFICATION_TYPE_SIMPLE, 173 GURL(kPrivetNotificationOriginUrl), 174 l10n_util::GetStringUTF16( 175 IDS_LOCAL_DISOCVERY_NOTIFICATION_TITLE_PRINTER), 176 l10n_util::GetStringFUTF16( 177 IDS_LOCAL_DISOCVERY_NOTIFICATION_CONTENTS_PRINTER, 178 UTF8ToUTF16(human_readable_name)), 179 ui::ResourceBundle::GetSharedInstance().GetImageNamed( 180 IDR_LOCAL_DISCOVERY_CLOUDPRINT_ICON), 181 WebKit::WebTextDirectionDefault, 182 message_center::NotifierId( 183 message_center::NotifierId::SYSTEM_COMPONENT), 184 l10n_util::GetStringUTF16( 185 IDS_LOCAL_DISOCVERY_NOTIFICATION_DISPLAY_SOURCE_PRINTER), 186 UTF8ToUTF16(kPrivetNotificationIDPrefix + 187 device_name), 188 rich_notification_data, 189 new PrivetNotificationDelegate(device_name, profile_)); 190 191 notification_manager_->Add(notification, profile_object); 192 } 193} 194 195void PrivetNotificationService::PrivetRemoveNotification( 196 const std::string& device_name) { 197 notification_manager_->CancelById(kPrivetNotificationIDPrefix + device_name); 198} 199 200void PrivetNotificationService::Start() { 201 service_discovery_client_ = ServiceDiscoveryHostClientFactory::GetClient(); 202 device_lister_.reset(new PrivetDeviceListerImpl(service_discovery_client_, 203 this)); 204 device_lister_->Start(); 205 206 scoped_ptr<PrivetHTTPAsynchronousFactory> http_factory( 207 new PrivetHTTPAsynchronousFactoryImpl(service_discovery_client_.get(), 208 profile_->GetRequestContext())); 209 210 privet_notifications_listener_.reset(new PrivetNotificationsListener( 211 http_factory.Pass(), this)); 212} 213 214PrivetNotificationDelegate::PrivetNotificationDelegate( 215 const std::string& device_id, content::BrowserContext* profile) 216 : device_id_(device_id), profile_(profile) { 217} 218 219PrivetNotificationDelegate::~PrivetNotificationDelegate() { 220} 221 222std::string PrivetNotificationDelegate::id() const { 223 return kPrivetNotificationIDPrefix + device_id_; 224} 225 226content::RenderViewHost* PrivetNotificationDelegate::GetRenderViewHost() const { 227 return NULL; 228} 229 230void PrivetNotificationDelegate::Display() { 231} 232 233void PrivetNotificationDelegate::Error() { 234 LOG(ERROR) << "Error displaying privet notification " << device_id_; 235} 236 237void PrivetNotificationDelegate::Close(bool by_user) { 238} 239 240void PrivetNotificationDelegate::Click() { 241} 242 243void PrivetNotificationDelegate::ButtonClick(int button_index) { 244 if (button_index == 0) { 245 // TODO(noamsml): Direct-to-register URL 246 OpenTab(GURL(kPrivetNotificationOriginUrl)); 247 } 248} 249 250void PrivetNotificationDelegate::OpenTab(const GURL& url) { 251 Profile* profile_obj = Profile::FromBrowserContext(profile_); 252 253 Browser* browser = FindOrCreateTabbedBrowser(profile_obj, 254 chrome::GetActiveDesktop()); 255 content::WebContents::CreateParams create_params(profile_obj); 256 257 scoped_ptr<content::WebContents> contents( 258 content::WebContents::Create(create_params)); 259 contents->GetController().LoadURL(url, 260 content::Referrer(), 261 content::PAGE_TRANSITION_AUTO_TOPLEVEL, 262 ""); 263 264 browser->tab_strip_model()->AppendWebContents(contents.release(), true); 265} 266 267 268} // namespace local_discovery 269