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