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