1 // Copyright (c) 2012 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/extensions/api/dial/dial_api.h" 6 7 #include <vector> 8 9 #include "base/time/time.h" 10 #include "chrome/browser/extensions/api/dial/dial_api_factory.h" 11 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/common/extensions/api/dial.h" 13 #include "content/public/browser/browser_thread.h" 14 #include "extensions/browser/event_router.h" 15 #include "extensions/browser/extension_system.h" 16 17 using base::TimeDelta; 18 using content::BrowserThread; 19 20 namespace { 21 22 const char kDialServiceError[] = "Dial service error."; 23 24 // How often to poll for devices. 25 const int kDialRefreshIntervalSecs = 120; 26 27 // We prune a device if it does not respond after this time. 28 const int kDialExpirationSecs = 240; 29 30 // The maximum number of devices retained at once in the registry. 31 const size_t kDialMaxDevices = 256; 32 33 } // namespace 34 35 namespace extensions { 36 37 namespace dial = api::dial; 38 39 DialAPI::DialAPI(Profile* profile) 40 : RefcountedBrowserContextKeyedService(BrowserThread::IO), 41 profile_(profile) { 42 EventRouter::Get(profile) 43 ->RegisterObserver(this, dial::OnDeviceList::kEventName); 44 } 45 46 DialAPI::~DialAPI() {} 47 48 DialRegistry* DialAPI::dial_registry() { 49 DCHECK_CURRENTLY_ON(BrowserThread::IO); 50 if (!dial_registry_.get()) { 51 dial_registry_.reset(new DialRegistry(this, 52 TimeDelta::FromSeconds(kDialRefreshIntervalSecs), 53 TimeDelta::FromSeconds(kDialExpirationSecs), 54 kDialMaxDevices)); 55 } 56 return dial_registry_.get(); 57 } 58 59 void DialAPI::OnListenerAdded(const EventListenerInfo& details) { 60 DCHECK_CURRENTLY_ON(BrowserThread::UI); 61 BrowserThread::PostTask( 62 BrowserThread::IO, FROM_HERE, 63 base::Bind(&DialAPI::NotifyListenerAddedOnIOThread, this)); 64 } 65 66 void DialAPI::OnListenerRemoved(const EventListenerInfo& details) { 67 DCHECK_CURRENTLY_ON(BrowserThread::UI); 68 BrowserThread::PostTask( 69 BrowserThread::IO, FROM_HERE, 70 base::Bind(&DialAPI::NotifyListenerRemovedOnIOThread, this)); 71 } 72 73 void DialAPI::NotifyListenerAddedOnIOThread() { 74 DCHECK_CURRENTLY_ON(BrowserThread::IO); 75 VLOG(1) << "DIAL device event listener added."; 76 dial_registry()->OnListenerAdded(); 77 } 78 79 void DialAPI::NotifyListenerRemovedOnIOThread() { 80 DCHECK_CURRENTLY_ON(BrowserThread::IO); 81 VLOG(1) << "DIAL device event listener removed"; 82 dial_registry()->OnListenerRemoved(); 83 } 84 85 void DialAPI::OnDialDeviceEvent(const DialRegistry::DeviceList& devices) { 86 DCHECK_CURRENTLY_ON(BrowserThread::IO); 87 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 88 base::Bind(&DialAPI::SendEventOnUIThread, this, devices)); 89 } 90 91 void DialAPI::OnDialError(const DialRegistry::DialErrorCode code) { 92 DCHECK_CURRENTLY_ON(BrowserThread::IO); 93 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 94 base::Bind(&DialAPI::SendErrorOnUIThread, this, code)); 95 } 96 97 void DialAPI::SendEventOnUIThread(const DialRegistry::DeviceList& devices) { 98 DCHECK_CURRENTLY_ON(BrowserThread::UI); 99 100 std::vector<linked_ptr<api::dial::DialDevice> > args; 101 for (DialRegistry::DeviceList::const_iterator it = devices.begin(); 102 it != devices.end(); ++it) { 103 linked_ptr<api::dial::DialDevice> api_device = 104 make_linked_ptr(new api::dial::DialDevice); 105 it->FillDialDevice(api_device.get()); 106 args.push_back(api_device); 107 } 108 scoped_ptr<base::ListValue> results = api::dial::OnDeviceList::Create(args); 109 scoped_ptr<Event> event( 110 new Event(dial::OnDeviceList::kEventName, results.Pass())); 111 EventRouter::Get(profile_)->BroadcastEvent(event.Pass()); 112 } 113 114 void DialAPI::SendErrorOnUIThread(const DialRegistry::DialErrorCode code) { 115 DCHECK_CURRENTLY_ON(BrowserThread::UI); 116 117 api::dial::DialError dial_error; 118 switch (code) { 119 case DialRegistry::DIAL_NO_LISTENERS: 120 dial_error.code = api::dial::DIAL_ERROR_CODE_NO_LISTENERS; 121 break; 122 case DialRegistry::DIAL_NO_INTERFACES: 123 dial_error.code = api::dial::DIAL_ERROR_CODE_NO_VALID_NETWORK_INTERFACES; 124 break; 125 case DialRegistry::DIAL_CELLULAR_NETWORK: 126 dial_error.code = api::dial::DIAL_ERROR_CODE_CELLULAR_NETWORK; 127 break; 128 case DialRegistry::DIAL_NETWORK_DISCONNECTED: 129 dial_error.code = api::dial::DIAL_ERROR_CODE_NETWORK_DISCONNECTED; 130 break; 131 case DialRegistry::DIAL_SOCKET_ERROR: 132 dial_error.code = api::dial::DIAL_ERROR_CODE_SOCKET_ERROR; 133 break; 134 default: 135 dial_error.code = api::dial::DIAL_ERROR_CODE_UNKNOWN; 136 break; 137 } 138 139 scoped_ptr<base::ListValue> results = api::dial::OnError::Create(dial_error); 140 scoped_ptr<Event> event(new Event(dial::OnError::kEventName, results.Pass())); 141 EventRouter::Get(profile_)->BroadcastEvent(event.Pass()); 142 } 143 144 void DialAPI::ShutdownOnUIThread() {} 145 146 namespace api { 147 148 DialDiscoverNowFunction::DialDiscoverNowFunction() 149 : dial_(NULL), result_(false) { 150 } 151 152 bool DialDiscoverNowFunction::Prepare() { 153 DCHECK_CURRENTLY_ON(BrowserThread::UI); 154 DCHECK(browser_context()); 155 dial_ = DialAPIFactory::GetForBrowserContext(browser_context()).get(); 156 return true; 157 } 158 159 void DialDiscoverNowFunction::Work() { 160 DCHECK_CURRENTLY_ON(BrowserThread::IO); 161 result_ = dial_->dial_registry()->DiscoverNow(); 162 } 163 164 bool DialDiscoverNowFunction::Respond() { 165 DCHECK_CURRENTLY_ON(BrowserThread::UI); 166 if (!result_) 167 error_ = kDialServiceError; 168 169 SetResult(new base::FundamentalValue(result_)); 170 return true; 171 } 172 173 } // namespace api 174 175 } // namespace extensions 176