| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/extensions/api/braille_display_private/braille_controll
er_brlapi.h" | 5 #include "chrome/browser/extensions/api/braille_display_private/braille_controll
er_brlapi.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cerrno> | 8 #include <cerrno> |
| 9 #include <cstring> | 9 #include <cstring> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 connect_scheduled_(false) { | 58 connect_scheduled_(false) { |
| 59 create_brlapi_connection_function_ = base::Bind( | 59 create_brlapi_connection_function_ = base::Bind( |
| 60 &BrailleControllerImpl::CreateBrlapiConnection, | 60 &BrailleControllerImpl::CreateBrlapiConnection, |
| 61 base::Unretained(this)); | 61 base::Unretained(this)); |
| 62 } | 62 } |
| 63 | 63 |
| 64 BrailleControllerImpl::~BrailleControllerImpl() { | 64 BrailleControllerImpl::~BrailleControllerImpl() { |
| 65 } | 65 } |
| 66 | 66 |
| 67 void BrailleControllerImpl::TryLoadLibBrlApi() { | 67 void BrailleControllerImpl::TryLoadLibBrlApi() { |
| 68 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 68 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 69 if (libbrlapi_loader_.loaded()) | 69 if (libbrlapi_loader_.loaded()) |
| 70 return; | 70 return; |
| 71 // These versions of libbrlapi work the same for the functions we | 71 // These versions of libbrlapi work the same for the functions we |
| 72 // are using. (0.6.0 adds brlapi_writeWText). | 72 // are using. (0.6.0 adds brlapi_writeWText). |
| 73 static const char* kSupportedVersions[] = { | 73 static const char* kSupportedVersions[] = { |
| 74 "libbrlapi.so.0.5", | 74 "libbrlapi.so.0.5", |
| 75 "libbrlapi.so.0.6" | 75 "libbrlapi.so.0.6" |
| 76 }; | 76 }; |
| 77 for (size_t i = 0; i < arraysize(kSupportedVersions); ++i) { | 77 for (size_t i = 0; i < arraysize(kSupportedVersions); ++i) { |
| 78 if (libbrlapi_loader_.Load(kSupportedVersions[i])) | 78 if (libbrlapi_loader_.Load(kSupportedVersions[i])) |
| 79 return; | 79 return; |
| 80 } | 80 } |
| 81 LOG(WARNING) << "Couldn't load libbrlapi: " << strerror(errno); | 81 LOG(WARNING) << "Couldn't load libbrlapi: " << strerror(errno); |
| 82 } | 82 } |
| 83 | 83 |
| 84 scoped_ptr<DisplayState> BrailleControllerImpl::GetDisplayState() { | 84 scoped_ptr<DisplayState> BrailleControllerImpl::GetDisplayState() { |
| 85 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 85 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 86 StartConnecting(); | 86 StartConnecting(); |
| 87 scoped_ptr<DisplayState> display_state(new DisplayState); | 87 scoped_ptr<DisplayState> display_state(new DisplayState); |
| 88 if (connection_.get() && connection_->Connected()) { | 88 if (connection_.get() && connection_->Connected()) { |
| 89 size_t size; | 89 size_t size; |
| 90 if (!connection_->GetDisplaySize(&size)) { | 90 if (!connection_->GetDisplaySize(&size)) { |
| 91 Disconnect(); | 91 Disconnect(); |
| 92 } else if (size > 0) { // size == 0 means no display present. | 92 } else if (size > 0) { // size == 0 means no display present. |
| 93 display_state->available = true; | 93 display_state->available = true; |
| 94 display_state->text_cell_count.reset(new int(size)); | 94 display_state->text_cell_count.reset(new int(size)); |
| 95 } | 95 } |
| 96 } | 96 } |
| 97 return display_state.Pass(); | 97 return display_state.Pass(); |
| 98 } | 98 } |
| 99 | 99 |
| 100 void BrailleControllerImpl::WriteDots(const std::string& cells) { | 100 void BrailleControllerImpl::WriteDots(const std::string& cells) { |
| 101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 101 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 102 if (connection_ && connection_->Connected()) { | 102 if (connection_ && connection_->Connected()) { |
| 103 size_t size; | 103 size_t size; |
| 104 if (!connection_->GetDisplaySize(&size)) { | 104 if (!connection_->GetDisplaySize(&size)) { |
| 105 Disconnect(); | 105 Disconnect(); |
| 106 } | 106 } |
| 107 std::vector<unsigned char> sizedCells(size); | 107 std::vector<unsigned char> sizedCells(size); |
| 108 std::memcpy(&sizedCells[0], cells.data(), std::min(cells.size(), size)); | 108 std::memcpy(&sizedCells[0], cells.data(), std::min(cells.size(), size)); |
| 109 if (size > cells.size()) | 109 if (size > cells.size()) |
| 110 std::fill(sizedCells.begin() + cells.size(), sizedCells.end(), 0); | 110 std::fill(sizedCells.begin() + cells.size(), sizedCells.end(), 0); |
| 111 if (!connection_->WriteDots(&sizedCells[0])) | 111 if (!connection_->WriteDots(&sizedCells[0])) |
| 112 Disconnect(); | 112 Disconnect(); |
| 113 } | 113 } |
| 114 } | 114 } |
| 115 | 115 |
| 116 void BrailleControllerImpl::AddObserver(BrailleObserver* observer) { | 116 void BrailleControllerImpl::AddObserver(BrailleObserver* observer) { |
| 117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 117 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 118 if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | 118 if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| 119 base::Bind( | 119 base::Bind( |
| 120 &BrailleControllerImpl::StartConnecting, | 120 &BrailleControllerImpl::StartConnecting, |
| 121 base::Unretained(this)))) { | 121 base::Unretained(this)))) { |
| 122 NOTREACHED(); | 122 NOTREACHED(); |
| 123 } | 123 } |
| 124 observers_.AddObserver(observer); | 124 observers_.AddObserver(observer); |
| 125 } | 125 } |
| 126 | 126 |
| 127 void BrailleControllerImpl::RemoveObserver(BrailleObserver* observer) { | 127 void BrailleControllerImpl::RemoveObserver(BrailleObserver* observer) { |
| 128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 128 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 129 observers_.RemoveObserver(observer); | 129 observers_.RemoveObserver(observer); |
| 130 } | 130 } |
| 131 | 131 |
| 132 void BrailleControllerImpl::SetCreateBrlapiConnectionForTesting( | 132 void BrailleControllerImpl::SetCreateBrlapiConnectionForTesting( |
| 133 const CreateBrlapiConnectionFunction& function) { | 133 const CreateBrlapiConnectionFunction& function) { |
| 134 if (function.is_null()) { | 134 if (function.is_null()) { |
| 135 create_brlapi_connection_function_ = base::Bind( | 135 create_brlapi_connection_function_ = base::Bind( |
| 136 &BrailleControllerImpl::CreateBrlapiConnection, | 136 &BrailleControllerImpl::CreateBrlapiConnection, |
| 137 base::Unretained(this)); | 137 base::Unretained(this)); |
| 138 } else { | 138 } else { |
| 139 create_brlapi_connection_function_ = function; | 139 create_brlapi_connection_function_ = function; |
| 140 } | 140 } |
| 141 } | 141 } |
| 142 | 142 |
| 143 void BrailleControllerImpl::PokeSocketDirForTesting() { | 143 void BrailleControllerImpl::PokeSocketDirForTesting() { |
| 144 OnSocketDirChangedOnIOThread(); | 144 OnSocketDirChangedOnIOThread(); |
| 145 } | 145 } |
| 146 | 146 |
| 147 void BrailleControllerImpl::StartConnecting() { | 147 void BrailleControllerImpl::StartConnecting() { |
| 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 148 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 149 if (started_connecting_) | 149 if (started_connecting_) |
| 150 return; | 150 return; |
| 151 started_connecting_ = true; | 151 started_connecting_ = true; |
| 152 TryLoadLibBrlApi(); | 152 TryLoadLibBrlApi(); |
| 153 if (!libbrlapi_loader_.loaded()) { | 153 if (!libbrlapi_loader_.loaded()) { |
| 154 return; | 154 return; |
| 155 } | 155 } |
| 156 // Only try to connect after we've started to watch the | 156 // Only try to connect after we've started to watch the |
| 157 // socket directory. This is necessary to avoid a race condition | 157 // socket directory. This is necessary to avoid a race condition |
| 158 // and because we don't retry to connect after errors that will | 158 // and because we don't retry to connect after errors that will |
| 159 // persist until there's a change to the socket directory (i.e. | 159 // persist until there's a change to the socket directory (i.e. |
| 160 // ENOENT). | 160 // ENOENT). |
| 161 BrowserThread::PostTaskAndReply( | 161 BrowserThread::PostTaskAndReply( |
| 162 BrowserThread::FILE, FROM_HERE, | 162 BrowserThread::FILE, FROM_HERE, |
| 163 base::Bind( | 163 base::Bind( |
| 164 &BrailleControllerImpl::StartWatchingSocketDirOnFileThread, | 164 &BrailleControllerImpl::StartWatchingSocketDirOnFileThread, |
| 165 base::Unretained(this)), | 165 base::Unretained(this)), |
| 166 base::Bind( | 166 base::Bind( |
| 167 &BrailleControllerImpl::TryToConnect, | 167 &BrailleControllerImpl::TryToConnect, |
| 168 base::Unretained(this))); | 168 base::Unretained(this))); |
| 169 ResetRetryConnectHorizon(); | 169 ResetRetryConnectHorizon(); |
| 170 } | 170 } |
| 171 | 171 |
| 172 void BrailleControllerImpl::StartWatchingSocketDirOnFileThread() { | 172 void BrailleControllerImpl::StartWatchingSocketDirOnFileThread() { |
| 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 173 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 174 base::FilePath brlapi_dir(BRLAPI_SOCKETPATH); | 174 base::FilePath brlapi_dir(BRLAPI_SOCKETPATH); |
| 175 if (!file_path_watcher_.Watch( | 175 if (!file_path_watcher_.Watch( |
| 176 brlapi_dir, false, base::Bind( | 176 brlapi_dir, false, base::Bind( |
| 177 &BrailleControllerImpl::OnSocketDirChangedOnFileThread, | 177 &BrailleControllerImpl::OnSocketDirChangedOnFileThread, |
| 178 base::Unretained(this)))) { | 178 base::Unretained(this)))) { |
| 179 LOG(WARNING) << "Couldn't watch brlapi directory " << BRLAPI_SOCKETPATH; | 179 LOG(WARNING) << "Couldn't watch brlapi directory " << BRLAPI_SOCKETPATH; |
| 180 } | 180 } |
| 181 } | 181 } |
| 182 | 182 |
| 183 void BrailleControllerImpl::OnSocketDirChangedOnFileThread( | 183 void BrailleControllerImpl::OnSocketDirChangedOnFileThread( |
| 184 const base::FilePath& path, bool error) { | 184 const base::FilePath& path, bool error) { |
| 185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 185 DCHECK_CURRENTLY_ON(BrowserThread::FILE); |
| 186 if (error) { | 186 if (error) { |
| 187 LOG(ERROR) << "Error watching brlapi directory: " << path.value(); | 187 LOG(ERROR) << "Error watching brlapi directory: " << path.value(); |
| 188 return; | 188 return; |
| 189 } | 189 } |
| 190 BrowserThread::PostTask( | 190 BrowserThread::PostTask( |
| 191 BrowserThread::IO, FROM_HERE, base::Bind( | 191 BrowserThread::IO, FROM_HERE, base::Bind( |
| 192 &BrailleControllerImpl::OnSocketDirChangedOnIOThread, | 192 &BrailleControllerImpl::OnSocketDirChangedOnIOThread, |
| 193 base::Unretained(this))); | 193 base::Unretained(this))); |
| 194 } | 194 } |
| 195 | 195 |
| 196 void BrailleControllerImpl::OnSocketDirChangedOnIOThread() { | 196 void BrailleControllerImpl::OnSocketDirChangedOnIOThread() { |
| 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 197 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 198 VLOG(1) << "BrlAPI directory changed"; | 198 VLOG(1) << "BrlAPI directory changed"; |
| 199 // Every directory change resets the max retry time to the appropriate delay | 199 // Every directory change resets the max retry time to the appropriate delay |
| 200 // into the future. | 200 // into the future. |
| 201 ResetRetryConnectHorizon(); | 201 ResetRetryConnectHorizon(); |
| 202 // Try after an initial delay to give the driver a chance to connect. | 202 // Try after an initial delay to give the driver a chance to connect. |
| 203 ScheduleTryToConnect(); | 203 ScheduleTryToConnect(); |
| 204 } | 204 } |
| 205 | 205 |
| 206 void BrailleControllerImpl::TryToConnect() { | 206 void BrailleControllerImpl::TryToConnect() { |
| 207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 207 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 208 DCHECK(libbrlapi_loader_.loaded()); | 208 DCHECK(libbrlapi_loader_.loaded()); |
| 209 connect_scheduled_ = false; | 209 connect_scheduled_ = false; |
| 210 if (!connection_.get()) | 210 if (!connection_.get()) |
| 211 connection_ = create_brlapi_connection_function_.Run(); | 211 connection_ = create_brlapi_connection_function_.Run(); |
| 212 if (connection_.get() && !connection_->Connected()) { | 212 if (connection_.get() && !connection_->Connected()) { |
| 213 VLOG(1) << "Trying to connect to brlapi"; | 213 VLOG(1) << "Trying to connect to brlapi"; |
| 214 BrlapiConnection::ConnectResult result = connection_->Connect(base::Bind( | 214 BrlapiConnection::ConnectResult result = connection_->Connect(base::Bind( |
| 215 &BrailleControllerImpl::DispatchKeys, | 215 &BrailleControllerImpl::DispatchKeys, |
| 216 base::Unretained(this))); | 216 base::Unretained(this))); |
| 217 switch (result) { | 217 switch (result) { |
| 218 case BrlapiConnection::CONNECT_SUCCESS: | 218 case BrlapiConnection::CONNECT_SUCCESS: |
| 219 DispatchOnDisplayStateChanged(GetDisplayState()); | 219 DispatchOnDisplayStateChanged(GetDisplayState()); |
| 220 break; | 220 break; |
| 221 case BrlapiConnection::CONNECT_ERROR_NO_RETRY: | 221 case BrlapiConnection::CONNECT_ERROR_NO_RETRY: |
| 222 break; | 222 break; |
| 223 case BrlapiConnection::CONNECT_ERROR_RETRY: | 223 case BrlapiConnection::CONNECT_ERROR_RETRY: |
| 224 ScheduleTryToConnect(); | 224 ScheduleTryToConnect(); |
| 225 break; | 225 break; |
| 226 default: | 226 default: |
| 227 NOTREACHED(); | 227 NOTREACHED(); |
| 228 } | 228 } |
| 229 } | 229 } |
| 230 } | 230 } |
| 231 | 231 |
| 232 void BrailleControllerImpl::ResetRetryConnectHorizon() { | 232 void BrailleControllerImpl::ResetRetryConnectHorizon() { |
| 233 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 233 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 234 retry_connect_horizon_ = Time::Now() + TimeDelta::FromMilliseconds( | 234 retry_connect_horizon_ = Time::Now() + TimeDelta::FromMilliseconds( |
| 235 kConnectRetryTimeout); | 235 kConnectRetryTimeout); |
| 236 } | 236 } |
| 237 | 237 |
| 238 void BrailleControllerImpl::ScheduleTryToConnect() { | 238 void BrailleControllerImpl::ScheduleTryToConnect() { |
| 239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 239 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 240 TimeDelta delay(TimeDelta::FromMilliseconds(kConnectionDelayMs)); | 240 TimeDelta delay(TimeDelta::FromMilliseconds(kConnectionDelayMs)); |
| 241 // Don't reschedule if there's already a connect scheduled or | 241 // Don't reschedule if there's already a connect scheduled or |
| 242 // the next attempt would fall outside of the retry limit. | 242 // the next attempt would fall outside of the retry limit. |
| 243 if (connect_scheduled_) | 243 if (connect_scheduled_) |
| 244 return; | 244 return; |
| 245 if (Time::Now() + delay > retry_connect_horizon_) { | 245 if (Time::Now() + delay > retry_connect_horizon_) { |
| 246 VLOG(1) << "Stopping to retry to connect to brlapi"; | 246 VLOG(1) << "Stopping to retry to connect to brlapi"; |
| 247 return; | 247 return; |
| 248 } | 248 } |
| 249 VLOG(1) << "Scheduling connection retry to brlapi"; | 249 VLOG(1) << "Scheduling connection retry to brlapi"; |
| 250 connect_scheduled_ = true; | 250 connect_scheduled_ = true; |
| 251 BrowserThread::PostDelayedTask(BrowserThread::IO, FROM_HERE, | 251 BrowserThread::PostDelayedTask(BrowserThread::IO, FROM_HERE, |
| 252 base::Bind( | 252 base::Bind( |
| 253 &BrailleControllerImpl::TryToConnect, | 253 &BrailleControllerImpl::TryToConnect, |
| 254 base::Unretained(this)), | 254 base::Unretained(this)), |
| 255 delay); | 255 delay); |
| 256 } | 256 } |
| 257 | 257 |
| 258 void BrailleControllerImpl::Disconnect() { | 258 void BrailleControllerImpl::Disconnect() { |
| 259 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 259 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 260 if (!connection_ || !connection_->Connected()) | 260 if (!connection_ || !connection_->Connected()) |
| 261 return; | 261 return; |
| 262 connection_->Disconnect(); | 262 connection_->Disconnect(); |
| 263 DispatchOnDisplayStateChanged(scoped_ptr<DisplayState>(new DisplayState())); | 263 DispatchOnDisplayStateChanged(scoped_ptr<DisplayState>(new DisplayState())); |
| 264 } | 264 } |
| 265 | 265 |
| 266 scoped_ptr<BrlapiConnection> BrailleControllerImpl::CreateBrlapiConnection() { | 266 scoped_ptr<BrlapiConnection> BrailleControllerImpl::CreateBrlapiConnection() { |
| 267 DCHECK(libbrlapi_loader_.loaded()); | 267 DCHECK(libbrlapi_loader_.loaded()); |
| 268 return BrlapiConnection::Create(&libbrlapi_loader_); | 268 return BrlapiConnection::Create(&libbrlapi_loader_); |
| 269 } | 269 } |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 362 } | 362 } |
| 363 return; | 363 return; |
| 364 } | 364 } |
| 365 FOR_EACH_OBSERVER(BrailleObserver, observers_, | 365 FOR_EACH_OBSERVER(BrailleObserver, observers_, |
| 366 OnDisplayStateChanged(*new_state)); | 366 OnDisplayStateChanged(*new_state)); |
| 367 } | 367 } |
| 368 | 368 |
| 369 } // namespace braille_display_private | 369 } // namespace braille_display_private |
| 370 } // namespace api | 370 } // namespace api |
| 371 } // namespace extensions | 371 } // namespace extensions |
| OLD | NEW |