158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// found in the LICENSE file. 458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 5d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h" 658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <algorithm> 858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <cerrno> 958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <cstring> 1058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include <vector> 1158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 1258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/bind.h" 1358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/bind_helpers.h" 1458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "base/time/time.h" 1558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "chrome/browser/extensions/api/braille_display_private/brlapi_connection.h" 16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/extensions/api/braille_display_private/brlapi_keycode_map.h" 1758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)#include "content/public/browser/browser_thread.h" 1858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 1958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace extensions { 2058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using content::BrowserThread; 21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)using base::Time; 2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)using base::TimeDelta; 2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace api { 2458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace braille_display_private { 2558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 2658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)namespace { 2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Delay between detecting a directory update and trying to connect 2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// to the brlapi. 29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int64 kConnectionDelayMs = 500; 30d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// How long to periodically retry connecting after a brltty restart. 31d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Some displays are slow to connect. 32d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)const int64 kConnectRetryTimeout = 20000; 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace 3458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)BrailleController::BrailleController() { 3658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 3758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)BrailleController::~BrailleController() { 3958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 4058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// static 4258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)BrailleController* BrailleController::GetInstance() { 4358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return BrailleControllerImpl::GetInstance(); 4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 4558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// static 4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)BrailleControllerImpl* BrailleControllerImpl::GetInstance() { 4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return Singleton<BrailleControllerImpl, 4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) LeakySingletonTraits<BrailleControllerImpl> >::get(); 5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)BrailleControllerImpl::BrailleControllerImpl() 53d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) : started_connecting_(false), 54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) connect_scheduled_(false) { 5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) create_brlapi_connection_function_ = base::Bind( 5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) &BrailleControllerImpl::CreateBrlapiConnection, 5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Unretained(this)); 5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)BrailleControllerImpl::~BrailleControllerImpl() { 6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrailleControllerImpl::TryLoadLibBrlApi() { 64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (libbrlapi_loader_.loaded()) 6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // These versions of libbrlapi work the same for the functions we 6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // are using. (0.6.0 adds brlapi_writeWText). 6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) static const char* kSupportedVersions[] = { 7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) "libbrlapi.so.0.5", 7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) "libbrlapi.so.0.6" 7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) }; 7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) for (size_t i = 0; i < arraysize(kSupportedVersions); ++i) { 7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (libbrlapi_loader_.Load(kSupportedVersions[i])) 7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) LOG(WARNING) << "Couldn't load libbrlapi: " << strerror(errno); 7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 80d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)scoped_ptr<DisplayState> BrailleControllerImpl::GetDisplayState() { 81effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 82d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) StartConnecting(); 83d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) scoped_ptr<DisplayState> display_state(new DisplayState); 8458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (connection_.get() && connection_->Connected()) { 8558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) size_t size; 8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!connection_->GetDisplaySize(&size)) { 87d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) Disconnect(); 8858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (size > 0) { // size == 0 means no display present. 89d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) display_state->available = true; 90d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) display_state->text_cell_count.reset(new int(size)); 9158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 9258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 93d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return display_state.Pass(); 9458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 9558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 9658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrailleControllerImpl::WriteDots(const std::string& cells) { 97effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 9858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (connection_ && connection_->Connected()) { 9958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) size_t size; 10058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!connection_->GetDisplaySize(&size)) { 101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) Disconnect(); 10258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 10358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::vector<unsigned char> sizedCells(size); 10458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::memcpy(&sizedCells[0], cells.data(), std::min(cells.size(), size)); 10558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (size > cells.size()) 10658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) std::fill(sizedCells.begin() + cells.size(), sizedCells.end(), 0); 10758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!connection_->WriteDots(&sizedCells[0])) 108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) Disconnect(); 10958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 11058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 11158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 11258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrailleControllerImpl::AddObserver(BrailleObserver* observer) { 113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::UI); 1141e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, 1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::Bind( 1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) &BrailleControllerImpl::StartConnecting, 1171e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::Unretained(this)))) { 1181e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) NOTREACHED(); 1191e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 12058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) observers_.AddObserver(observer); 12158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 12258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrailleControllerImpl::RemoveObserver(BrailleObserver* observer) { 124effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::UI); 12558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) observers_.RemoveObserver(observer); 12658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 12758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 12858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrailleControllerImpl::SetCreateBrlapiConnectionForTesting( 12958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const CreateBrlapiConnectionFunction& function) { 13058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (function.is_null()) { 13158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) create_brlapi_connection_function_ = base::Bind( 13258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) &BrailleControllerImpl::CreateBrlapiConnection, 13358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Unretained(this)); 13458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else { 13558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) create_brlapi_connection_function_ = function; 13658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 13758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 13858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 139d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BrailleControllerImpl::PokeSocketDirForTesting() { 14068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) OnSocketDirChangedOnIOThread(); 141d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 142d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 14358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrailleControllerImpl::StartConnecting() { 144effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 145d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (started_connecting_) 146d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return; 147d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) started_connecting_ = true; 14858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) TryLoadLibBrlApi(); 14958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!libbrlapi_loader_.loaded()) { 15058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 15158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 1520f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // Only try to connect after we've started to watch the 1530f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // socket directory. This is necessary to avoid a race condition 1540f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // and because we don't retry to connect after errors that will 1550f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // persist until there's a change to the socket directory (i.e. 1560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // ENOENT). 1570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) BrowserThread::PostTaskAndReply( 1580f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) BrowserThread::FILE, FROM_HERE, 1590f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) base::Bind( 16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) &BrailleControllerImpl::StartWatchingSocketDirOnFileThread, 1610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) base::Unretained(this)), 1620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) base::Bind( 1630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) &BrailleControllerImpl::TryToConnect, 16468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) base::Unretained(this))); 16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) ResetRetryConnectHorizon(); 16668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 16768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 16868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void BrailleControllerImpl::StartWatchingSocketDirOnFileThread() { 169effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::FILE); 17058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::FilePath brlapi_dir(BRLAPI_SOCKETPATH); 17158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!file_path_watcher_.Watch( 17258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) brlapi_dir, false, base::Bind( 17368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) &BrailleControllerImpl::OnSocketDirChangedOnFileThread, 17458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Unretained(this)))) { 17558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) LOG(WARNING) << "Couldn't watch brlapi directory " << BRLAPI_SOCKETPATH; 17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 17758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 17858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 17968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void BrailleControllerImpl::OnSocketDirChangedOnFileThread( 18068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) const base::FilePath& path, bool error) { 181effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::FILE); 18258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (error) { 18358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) LOG(ERROR) << "Error watching brlapi directory: " << path.value(); 18458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 18558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 18668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) BrowserThread::PostTask( 18768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) BrowserThread::IO, FROM_HERE, base::Bind( 18868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) &BrailleControllerImpl::OnSocketDirChangedOnIOThread, 18968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) base::Unretained(this))); 19068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)} 19168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles) 19268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)void BrailleControllerImpl::OnSocketDirChangedOnIOThread() { 193effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 1940f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) VLOG(1) << "BrlAPI directory changed"; 195d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Every directory change resets the max retry time to the appropriate delay 196d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // into the future. 197d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ResetRetryConnectHorizon(); 198d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Try after an initial delay to give the driver a chance to connect. 199d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) ScheduleTryToConnect(); 20058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 20158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 20258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrailleControllerImpl::TryToConnect() { 203effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 20458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(libbrlapi_loader_.loaded()); 205d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) connect_scheduled_ = false; 20658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!connection_.get()) 20758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) connection_ = create_brlapi_connection_function_.Run(); 20858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (connection_.get() && !connection_->Connected()) { 2090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) VLOG(1) << "Trying to connect to brlapi"; 2100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) BrlapiConnection::ConnectResult result = connection_->Connect(base::Bind( 2110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) &BrailleControllerImpl::DispatchKeys, 2120f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) base::Unretained(this))); 2130f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) switch (result) { 2140f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) case BrlapiConnection::CONNECT_SUCCESS: 2150f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) DispatchOnDisplayStateChanged(GetDisplayState()); 2160f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) break; 2170f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) case BrlapiConnection::CONNECT_ERROR_NO_RETRY: 2180f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) break; 2190f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) case BrlapiConnection::CONNECT_ERROR_RETRY: 2200f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) ScheduleTryToConnect(); 2210f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) break; 2220f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) default: 2230f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) NOTREACHED(); 224d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 22558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 22658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 22758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 228d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BrailleControllerImpl::ResetRetryConnectHorizon() { 229effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 230d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) retry_connect_horizon_ = Time::Now() + TimeDelta::FromMilliseconds( 231d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) kConnectRetryTimeout); 232d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 233d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 234d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BrailleControllerImpl::ScheduleTryToConnect() { 235effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 236d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) TimeDelta delay(TimeDelta::FromMilliseconds(kConnectionDelayMs)); 237d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // Don't reschedule if there's already a connect scheduled or 238d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) // the next attempt would fall outside of the retry limit. 239d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (connect_scheduled_) 240d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return; 241d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (Time::Now() + delay > retry_connect_horizon_) { 2420f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) VLOG(1) << "Stopping to retry to connect to brlapi"; 243d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return; 244d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 2450f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) VLOG(1) << "Scheduling connection retry to brlapi"; 246d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) connect_scheduled_ = true; 247d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) BrowserThread::PostDelayedTask(BrowserThread::IO, FROM_HERE, 248d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Bind( 249d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) &BrailleControllerImpl::TryToConnect, 250d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) base::Unretained(this)), 251d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) delay); 252d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 253d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 254d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BrailleControllerImpl::Disconnect() { 255effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch DCHECK_CURRENTLY_ON(BrowserThread::IO); 256d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (!connection_ || !connection_->Connected()) 257d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return; 258d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) connection_->Disconnect(); 259d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) DispatchOnDisplayStateChanged(scoped_ptr<DisplayState>(new DisplayState())); 260d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 261d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 26258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)scoped_ptr<BrlapiConnection> BrailleControllerImpl::CreateBrlapiConnection() { 26358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(libbrlapi_loader_.loaded()); 26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return BrlapiConnection::Create(&libbrlapi_loader_); 26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 26658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 26758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrailleControllerImpl::DispatchKeys() { 26858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(connection_.get()); 26958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) brlapi_keyCode_t code; 27058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) while (true) { 27158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) int result = connection_->ReadKey(&code); 27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (result < 0) { // Error. 27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) brlapi_error_t* err = connection_->BrlapiError(); 27458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (err->brlerrno == BRLAPI_ERROR_LIBCERR && err->libcerrno == EINTR) 27558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) continue; 27658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // Disconnect on other errors. 2770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) VLOG(1) << "BrlAPI error: " << connection_->BrlapiStrError(); 278d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) Disconnect(); 27958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else if (result == 0) { // No more data. 28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 28258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 283cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) scoped_ptr<KeyEvent> event = BrlapiKeyCodeToEvent(code); 28458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (event) 28558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DispatchKeyEvent(event.Pass()); 28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 28758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 28858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 28958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void BrailleControllerImpl::DispatchKeyEvent(scoped_ptr<KeyEvent> event) { 29058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 29158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 29258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Bind( 29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) &BrailleControllerImpl::DispatchKeyEvent, 29458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Unretained(this), 29558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) base::Passed(&event))); 29658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return; 29758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) VLOG(1) << "Dispatching key event: " << *event->ToValue(); 299010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) FOR_EACH_OBSERVER(BrailleObserver, observers_, OnBrailleKeyEvent(*event)); 30058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 30158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 302d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void BrailleControllerImpl::DispatchOnDisplayStateChanged( 303d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) scoped_ptr<DisplayState> new_state) { 304d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { 3051e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if (!BrowserThread::PostTask( 3061e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) BrowserThread::UI, FROM_HERE, 3071e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::Bind(&BrailleControllerImpl::DispatchOnDisplayStateChanged, 3081e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::Unretained(this), 3091e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) base::Passed(&new_state)))) { 3101e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) NOTREACHED(); 3111e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) } 312d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return; 313d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 314d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) FOR_EACH_OBSERVER(BrailleObserver, observers_, 315010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles) OnBrailleDisplayStateChanged(*new_state)); 316d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)} 317d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 31858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} // namespace braille_display_private 31958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} // namespace api 32058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} // namespace extensions 321