Commit 78dd4267 authored by David Tseng's avatar David Tseng Committed by Commit Bot

BtBrl: add necessary bindings to initialize bluetooth braille

- Adds an extension api, chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress, which will [re]start brltty with the given device.
- adds a pref to track the braille display desired by a given user
- adds logic to start and stop brltty on launch given a bluetooth braille display

TODO:
- the UI which will do the initial connection/pairing, and unpairing/forgetting of a device

Bug: 882261
Test: manually call all relevant api functions.
Change-Id: Ief0189a3f76ea6518bd8b644d3df816435feb019
- call chrome.brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress
- observe brltty is launched with the given address
- unload and reload chromevox and observe brltty is appropriately loaded/unloaded

Depends on:
https://chromium-review.googlesource.com/c/chromiumos/overlays/chromiumos-overlay/+/1308895

Change-Id: Ief0189a3f76ea6518bd8b644d3df816435feb019
Reviewed-on: https://chromium-review.googlesource.com/c/1308986
Commit-Queue: David Tseng <dtseng@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#605185}
parent 4e7c87b5
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/accessibility/accessibility_extension_api.h" #include "chrome/browser/accessibility/accessibility_extension_api.h"
...@@ -58,6 +59,7 @@ ...@@ -58,6 +59,7 @@
#include "chromeos/chromeos_switches.h" #include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/power_manager_client.h" #include "chromeos/dbus/power_manager_client.h"
#include "chromeos/dbus/upstart_client.h"
#include "components/language/core/browser/pref_names.h" #include "components/language/core/browser/pref_names.h"
#include "components/prefs/pref_member.h" #include "components/prefs/pref_member.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
...@@ -110,6 +112,13 @@ const char kUserSpokenFeedbackEnabled[] = "UserSpokenFeedbackEnabled"; ...@@ -110,6 +112,13 @@ const char kUserSpokenFeedbackEnabled[] = "UserSpokenFeedbackEnabled";
// A key for the startup sound enabled boolean state for a known user. // A key for the startup sound enabled boolean state for a known user.
const char kUserStartupSoundEnabled[] = "UserStartupSoundEnabled"; const char kUserStartupSoundEnabled[] = "UserStartupSoundEnabled";
// A key for the bluetooth braille display for a user.
const char kUserBluetoothBrailleDisplayAddress[] =
"UserBluetoothBrailleDisplayAddress";
// The name of the Brltty upstart job.
constexpr char kBrlttyUpstartJobName[] = "brltty";
static chromeos::AccessibilityManager* g_accessibility_manager = nullptr; static chromeos::AccessibilityManager* g_accessibility_manager = nullptr;
static BrailleController* g_braille_controller_for_test = nullptr; static BrailleController* g_braille_controller_for_test = nullptr;
...@@ -133,6 +142,24 @@ void EnableSwitchAccessAfterChromeVoxMetric(bool val) { ...@@ -133,6 +142,24 @@ void EnableSwitchAccessAfterChromeVoxMetric(bool val) {
UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSwitchAccessAfterChromeVox", val); UMA_HISTOGRAM_BOOLEAN("Accessibility.CrosSwitchAccessAfterChromeVox", val);
} }
// Restarts (stops, then starts brltty). If |address| is empty, only stops.
// In Upstart, sending an explicit restart command is a no-op if the job isn't
// already started. Without knowledge regarding brltty's current job status,
// stop followed by start ensures we both stop a started job, and also start
// brltty.
void RestartBrltty(const std::string& address) {
chromeos::UpstartClient* client =
chromeos::DBusThreadManager::Get()->GetUpstartClient();
client->StopJob(kBrlttyUpstartJobName, EmptyVoidDBusMethodCallback());
std::vector<std::string> args;
if (address.empty())
return;
args.push_back(base::StringPrintf("ADDRESS=%s", address.c_str()));
client->StartJob(kBrlttyUpstartJobName, args, EmptyVoidDBusMethodCallback());
}
} // namespace } // namespace
class AccessibilityPanelWidgetObserver : public views::WidgetObserver { class AccessibilityPanelWidgetObserver : public views::WidgetObserver {
...@@ -1260,6 +1287,11 @@ void AccessibilityManager::PostLoadChromeVox() { ...@@ -1260,6 +1287,11 @@ void AccessibilityManager::PostLoadChromeVox() {
return; return;
// Do any setup work needed immediately after ChromeVox actually loads. // Do any setup work needed immediately after ChromeVox actually loads.
// Maybe start brltty, if we have a bluetooth device stored for connection.
const std::string& address = GetBluetoothBrailleDisplayAddress();
if (!address.empty())
RestartBrltty(address);
PlayEarcon(SOUND_SPOKEN_FEEDBACK_ENABLED, PlaySoundOption::ALWAYS); PlayEarcon(SOUND_SPOKEN_FEEDBACK_ENABLED, PlaySoundOption::ALWAYS);
extensions::EventRouter* event_router = extensions::EventRouter* event_router =
...@@ -1291,6 +1323,10 @@ void AccessibilityManager::PostLoadChromeVox() { ...@@ -1291,6 +1323,10 @@ void AccessibilityManager::PostLoadChromeVox() {
void AccessibilityManager::PostUnloadChromeVox() { void AccessibilityManager::PostUnloadChromeVox() {
// Do any teardown work needed immediately after ChromeVox actually unloads. // Do any teardown work needed immediately after ChromeVox actually unloads.
// Stop brltty.
chromeos::DBusThreadManager::Get()->GetUpstartClient()->StopJob(
kBrlttyUpstartJobName, EmptyVoidDBusMethodCallback());
PlayEarcon(SOUND_SPOKEN_FEEDBACK_DISABLED, PlaySoundOption::ALWAYS); PlayEarcon(SOUND_SPOKEN_FEEDBACK_DISABLED, PlaySoundOption::ALWAYS);
// Clear the accessibility focus ring. // Clear the accessibility focus ring.
...@@ -1464,6 +1500,35 @@ void AccessibilityManager::SetStartupSoundEnabled(bool value) const { ...@@ -1464,6 +1500,35 @@ void AccessibilityManager::SetStartupSoundEnabled(bool value) const {
kUserStartupSoundEnabled, value); kUserStartupSoundEnabled, value);
} }
const std::string AccessibilityManager::GetBluetoothBrailleDisplayAddress()
const {
user_manager::UserManager* user_manager = user_manager::UserManager::Get();
const user_manager::UserList& user_list = user_manager->GetUsers();
if (user_list.empty())
return std::string();
// |user_list| is sorted by last log in date. Take the most recent user to log
// in.
std::string val;
return user_manager::known_user::GetStringPref(
user_list[0]->GetAccountId(), kUserBluetoothBrailleDisplayAddress,
&val)
? val
: std::string();
}
void AccessibilityManager::UpdateBluetoothBrailleDisplayAddress(
const std::string& address) {
CHECK(spoken_feedback_enabled_);
if (!profile_)
return;
user_manager::known_user::SetStringPref(
multi_user_util::GetAccountIdFromProfile(profile_),
kUserBluetoothBrailleDisplayAddress, address);
RestartBrltty(address);
}
void AccessibilityManager::SetProfileForTest(Profile* profile) { void AccessibilityManager::SetProfileForTest(Profile* profile) {
SetProfile(profile); SetProfile(profile);
} }
......
...@@ -313,6 +313,12 @@ class AccessibilityManager ...@@ -313,6 +313,12 @@ class AccessibilityManager
// Sets the startup sound user preference. // Sets the startup sound user preference.
void SetStartupSoundEnabled(bool value) const; void SetStartupSoundEnabled(bool value) const;
// Gets the bluetooth braille display device address for the current user.
const std::string GetBluetoothBrailleDisplayAddress() const;
// Sets the bluetooth braille display device address for the current user.
void UpdateBluetoothBrailleDisplayAddress(const std::string& address);
// Test helpers: // Test helpers:
void SetProfileForTest(Profile* profile); void SetProfileForTest(Profile* profile);
static void SetBrailleControllerForTest( static void SetBrailleControllerForTest(
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/browser/chromeos/login/lock/screen_locker.h" #include "chrome/browser/chromeos/login/lock/screen_locker.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
#endif #endif
...@@ -184,5 +185,20 @@ void BrailleDisplayPrivateWriteDotsFunction::Work() { ...@@ -184,5 +185,20 @@ void BrailleDisplayPrivateWriteDotsFunction::Work() {
bool BrailleDisplayPrivateWriteDotsFunction::Respond() { bool BrailleDisplayPrivateWriteDotsFunction::Respond() {
return true; return true;
} }
ExtensionFunction::ResponseAction
BrailleDisplayPrivateUpdateBluetoothBrailleDisplayAddressFunction::Run() {
#if !defined(OS_CHROMEOS)
NOTREACHED();
return RespondNow(Error("Unsupported on this platform."));
#else
std::string address;
EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &address));
chromeos::AccessibilityManager::Get()->UpdateBluetoothBrailleDisplayAddress(
address);
return RespondNow(NoArguments());
#endif
}
} // namespace api } // namespace api
} // namespace extensions } // namespace extensions
...@@ -106,6 +106,16 @@ class BrailleDisplayPrivateWriteDotsFunction : public AsyncApiFunction { ...@@ -106,6 +106,16 @@ class BrailleDisplayPrivateWriteDotsFunction : public AsyncApiFunction {
std::unique_ptr<braille_display_private::WriteDots::Params> params_; std::unique_ptr<braille_display_private::WriteDots::Params> params_;
}; };
class BrailleDisplayPrivateUpdateBluetoothBrailleDisplayAddressFunction
: public UIThreadExtensionFunction {
~BrailleDisplayPrivateUpdateBluetoothBrailleDisplayAddressFunction()
override {}
ResponseAction Run() override;
DECLARE_EXTENSION_FUNCTION(
"brailleDisplayPrivate.updateBluetoothBrailleDisplayAddress",
BRAILLEDISPLAYPRIVATE_UPDATEBLUETOOTHBRAILLEDISPLAYADDRESS)
};
} // namespace api } // namespace api
} // namespace extensions } // namespace extensions
......
...@@ -74,6 +74,10 @@ namespace brailleDisplayPrivate { ...@@ -74,6 +74,10 @@ namespace brailleDisplayPrivate {
// parameters give the original 2D dimensions of the buffer. To access // parameters give the original 2D dimensions of the buffer. To access
// an element cells[r][c], simply access cells[r * columns + c]. // an element cells[r][c], simply access cells[r * columns + c].
static void writeDots(ArrayBuffer cells, long columns, long rows); static void writeDots(ArrayBuffer cells, long columns, long rows);
// Updates the single user-preferred braille device with the given bluetooth
// device address and starts or restarts the Brltty daemon.
static void updateBluetoothBrailleDisplayAddress(DOMString address);
}; };
interface Events { interface Events {
......
...@@ -24,6 +24,12 @@ void FakeUpstartClient::StartJob(const std::string& job, ...@@ -24,6 +24,12 @@ void FakeUpstartClient::StartJob(const std::string& job,
FROM_HERE, base::BindOnce(std::move(callback), true)); FROM_HERE, base::BindOnce(std::move(callback), true));
} }
void FakeUpstartClient::StopJob(const std::string& job,
VoidDBusMethodCallback callback) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), true));
}
void FakeUpstartClient::StartAuthPolicyService() { void FakeUpstartClient::StartAuthPolicyService() {
static_cast<FakeAuthPolicyClient*>( static_cast<FakeAuthPolicyClient*>(
DBusThreadManager::Get()->GetAuthPolicyClient()) DBusThreadManager::Get()->GetAuthPolicyClient())
......
...@@ -19,10 +19,12 @@ class CHROMEOS_EXPORT FakeUpstartClient : public UpstartClient { ...@@ -19,10 +19,12 @@ class CHROMEOS_EXPORT FakeUpstartClient : public UpstartClient {
// DBusClient overrides. // DBusClient overrides.
void Init(dbus::Bus* bus) override; void Init(dbus::Bus* bus) override;
// UpstartClient overrides:
void StartJob(const std::string& job, void StartJob(const std::string& job,
const std::vector<std::string>& upstart_env, const std::vector<std::string>& upstart_env,
VoidDBusMethodCallback callback) override; VoidDBusMethodCallback callback) override;
// UpstartClient overrides. void StopJob(const std::string& job,
VoidDBusMethodCallback callback) override;
void StartAuthPolicyService() override; void StartAuthPolicyService() override;
void RestartAuthPolicyService() override; void RestartAuthPolicyService() override;
void StartMediaAnalytics(const std::vector<std::string>& upstart_env, void StartMediaAnalytics(const std::vector<std::string>& upstart_env,
......
...@@ -30,13 +30,18 @@ class UpstartClientImpl : public UpstartClient { ...@@ -30,13 +30,18 @@ class UpstartClientImpl : public UpstartClient {
~UpstartClientImpl() override = default; ~UpstartClientImpl() override = default;
// UpstartClient overrides:
void StartJob(const std::string& job, void StartJob(const std::string& job,
const std::vector<std::string>& upstart_env, const std::vector<std::string>& upstart_env,
VoidDBusMethodCallback callback) override { VoidDBusMethodCallback callback) override {
CallJobMethod(job, kStartMethod, upstart_env, std::move(callback)); CallJobMethod(job, kStartMethod, upstart_env, std::move(callback));
} }
// UpstartClient override. void StopJob(const std::string& job,
VoidDBusMethodCallback callback) override {
CallJobMethod(job, kStopMethod, {}, std::move(callback));
}
void StartAuthPolicyService() override { void StartAuthPolicyService() override {
StartJob(kAuthPolicyJob, {}, EmptyVoidDBusMethodCallback()); StartJob(kAuthPolicyJob, {}, EmptyVoidDBusMethodCallback());
} }
...@@ -56,12 +61,11 @@ class UpstartClientImpl : public UpstartClient { ...@@ -56,12 +61,11 @@ class UpstartClientImpl : public UpstartClient {
} }
void StopMediaAnalytics() override { void StopMediaAnalytics() override {
CallJobMethod(kMediaAnalyticsJob, kStopMethod, {}, StopJob(kMediaAnalyticsJob, EmptyVoidDBusMethodCallback());
EmptyVoidDBusMethodCallback());
} }
void StopMediaAnalytics(VoidDBusMethodCallback callback) override { void StopMediaAnalytics(VoidDBusMethodCallback callback) override {
CallJobMethod(kMediaAnalyticsJob, kStopMethod, {}, std::move(callback)); StopJob(kMediaAnalyticsJob, std::move(callback));
} }
protected: protected:
void Init(dbus::Bus* bus) override { void Init(dbus::Bus* bus) override {
......
...@@ -31,10 +31,17 @@ class CHROMEOS_EXPORT UpstartClient : public DBusClient { ...@@ -31,10 +31,17 @@ class CHROMEOS_EXPORT UpstartClient : public DBusClient {
// |job|: Name of Upstart job. // |job|: Name of Upstart job.
// |upstart_env|: List of upstart environment variables to be passed to the // |upstart_env|: List of upstart environment variables to be passed to the
// upstart service. // upstart service.
// |callback|: Called with a response.
virtual void StartJob(const std::string& job, virtual void StartJob(const std::string& job,
const std::vector<std::string>& upstart_env, const std::vector<std::string>& upstart_env,
VoidDBusMethodCallback callback) = 0; VoidDBusMethodCallback callback) = 0;
// Stops an Upstart job.
// |job|: Name of Upstart job.
// |callback|: Called with a response.
virtual void StopJob(const std::string& job,
VoidDBusMethodCallback callback) = 0;
// Starts authpolicyd. // Starts authpolicyd.
virtual void StartAuthPolicyService() = 0; virtual void StartAuthPolicyService() = 0;
......
...@@ -1351,6 +1351,7 @@ enum HistogramValue { ...@@ -1351,6 +1351,7 @@ enum HistogramValue {
FILEMANAGERPRIVATEINTERNAL_GETLINUXPACKAGEINFO = 1288, FILEMANAGERPRIVATEINTERNAL_GETLINUXPACKAGEINFO = 1288,
TABS_GOFORWARD = 1289, TABS_GOFORWARD = 1289,
TABS_GOBACK = 1290, TABS_GOBACK = 1290,
BRAILLEDISPLAYPRIVATE_UPDATEBLUETOOTHBRAILLEDISPLAYADDRESS = 1291,
// Last entry: Add new entries above, then run: // Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py // python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY ENUM_BOUNDARY
......
...@@ -15742,7 +15742,7 @@ Called by update_net_error_codes.py.--> ...@@ -15742,7 +15742,7 @@ Called by update_net_error_codes.py.-->
<int value="338" label="CAST_CHANNEL_ON_MESSAGE"/> <int value="338" label="CAST_CHANNEL_ON_MESSAGE"/>
<int value="339" label="CAST_CHANNEL_ON_ERROR"/> <int value="339" label="CAST_CHANNEL_ON_ERROR"/>
<int value="340" label="SCREENLOCK_PRIVATE_ON_CHANGED"/> <int value="340" label="SCREENLOCK_PRIVATE_ON_CHANGED"/>
<int value="341" label="SCREENLOCK_PRIVATE_ON_AUTH_ATTEMPTED"/> <int value="341" label="DELETED_SCREENLOCK_PRIVATE_ON_AUTH_ATTEMPTED"/>
<int value="342" label="TYPES_CHROME_SETTING_ON_CHANGE"/> <int value="342" label="TYPES_CHROME_SETTING_ON_CHANGE"/>
<int value="343" <int value="343"
label="DELETED_TYPES_PRIVATE_CHROME_DIRECT_SETTING_ON_CHANGE"/> label="DELETED_TYPES_PRIVATE_CHROME_DIRECT_SETTING_ON_CHANGE"/>
...@@ -17182,6 +17182,8 @@ Called by update_net_error_codes.py.--> ...@@ -17182,6 +17182,8 @@ Called by update_net_error_codes.py.-->
<int value="1288" label="FILEMANAGERPRIVATEINTERNAL_GETLINUXPACKAGEINFO"/> <int value="1288" label="FILEMANAGERPRIVATEINTERNAL_GETLINUXPACKAGEINFO"/>
<int value="1289" label="TABS_GOFORWARD"/> <int value="1289" label="TABS_GOFORWARD"/>
<int value="1290" label="TABS_GOBACK"/> <int value="1290" label="TABS_GOBACK"/>
<int value="1291"
label="BRAILLEDISPLAYPRIVATE_UPDATEBLUETOOTHBRAILLEDISPLAYADDRESS"/>
</enum> </enum>
<enum name="ExtensionIconState"> <enum name="ExtensionIconState">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment