Commit 920422e0 authored by David Tseng's avatar David Tseng Committed by Commit Bot

Adds magnifier boiler plate

This change:
- adds the ability to swap between Autoclick and Magnifier in the same accessibility_common extension
- fixes the accessibility_common_manifest_guest.json path; accessibility_common was actually not being loaded when using guest manifests (e.g. login screen)
- adds starter class for magnifier

R=katie@chromium.org

AX-Relnotes: n/a
Test: toggle all states of autoclick and magnifier: 0, 0; 0, 1; 1,0; 1,1. Verify the correct accessibilityCommon.autoclick_ and accessibilityCommon.magnifier_ objects get nullified/set and that the extension gets unloaded with 0,0. Automated tests tbd.
Change-Id: I5bf2c25dd1a65403c07c5941c48129cd8ad86a1b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2325131
Commit-Queue: David Tseng <dtseng@chromium.org>
Reviewed-by: default avatarKatie Dektar <katie@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#792857}
parent 18d1b898
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/public/cpp/ash_pref_names.h"
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/extension_system.h"
#include "extensions/browser/notification_types.h"
namespace chromeos {
class AccessibilityCommonTest : public InProcessBrowserTest {
public:
bool DoesComponentExtensionExist(const std::string& id) {
return extensions::ExtensionSystem::Get(
AccessibilityManager::Get()->profile())
->extension_service()
->component_loader()
->Exists(id);
}
protected:
AccessibilityCommonTest() = default;
};
IN_PROC_BROWSER_TEST_F(AccessibilityCommonTest, ToggleFeatures) {
AccessibilityManager* manager = AccessibilityManager::Get();
const auto& enabled_features =
manager->GetAccessibilityCommonEnabledFeaturesForTest();
EXPECT_TRUE(enabled_features.empty());
EXPECT_FALSE(DoesComponentExtensionExist(
extension_misc::kAccessibilityCommonExtensionId));
PrefService* pref_service = manager->profile()->GetPrefs();
content::WindowedNotificationObserver
accessibility_common_extension_load_waiter(
extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD,
content::NotificationService::AllSources());
pref_service->SetBoolean(ash::prefs::kAccessibilityAutoclickEnabled, true);
accessibility_common_extension_load_waiter.Wait();
EXPECT_EQ(1U, enabled_features.size());
EXPECT_EQ(1U,
enabled_features.count(ash::prefs::kAccessibilityAutoclickEnabled));
EXPECT_TRUE(DoesComponentExtensionExist(
extension_misc::kAccessibilityCommonExtensionId));
pref_service->SetBoolean(ash::prefs::kAccessibilityScreenMagnifierEnabled,
true);
EXPECT_EQ(2U, enabled_features.size());
EXPECT_EQ(1U,
enabled_features.count(ash::prefs::kAccessibilityAutoclickEnabled));
EXPECT_EQ(1U, enabled_features.count(
ash::prefs::kAccessibilityScreenMagnifierEnabled));
EXPECT_TRUE(DoesComponentExtensionExist(
extension_misc::kAccessibilityCommonExtensionId));
pref_service->SetBoolean(ash::prefs::kAccessibilityAutoclickEnabled, false);
EXPECT_EQ(1U, enabled_features.size());
EXPECT_EQ(1U, enabled_features.count(
ash::prefs::kAccessibilityScreenMagnifierEnabled));
EXPECT_TRUE(DoesComponentExtensionExist(
extension_misc::kAccessibilityCommonExtensionId));
pref_service->SetBoolean(ash::prefs::kAccessibilityScreenMagnifierEnabled,
false);
EXPECT_TRUE(enabled_features.empty());
EXPECT_FALSE(DoesComponentExtensionExist(
extension_misc::kAccessibilityCommonExtensionId));
// Not an accessibility common feature.
content::WindowedNotificationObserver spoken_feedback_extension_load_waiter(
extensions::NOTIFICATION_EXTENSION_HOST_DID_STOP_FIRST_LOAD,
content::NotificationService::AllSources());
pref_service->SetBoolean(ash::prefs::kAccessibilitySpokenFeedbackEnabled,
true);
spoken_feedback_extension_load_waiter.Wait();
EXPECT_TRUE(enabled_features.empty());
EXPECT_FALSE(DoesComponentExtensionExist(
extension_misc::kAccessibilityCommonExtensionId));
EXPECT_TRUE(
DoesComponentExtensionExist(extension_misc::kChromeVoxExtensionId));
}
} // namespace chromeos
......@@ -38,8 +38,9 @@ void AccessibilityExtensionLoader::SetProfile(
if (!loaded_)
return;
// If the extension was loaded on the previous profile, unload it there.
if (prev_profile)
// If the extension was loaded on the previous profile (which isn't the
// current profile), unload it there.
if (prev_profile && prev_profile != profile)
UnloadExtensionFromProfile(prev_profile);
// If the extension was already enabled, but not for this profile, add it
......
......@@ -630,22 +630,23 @@ bool AccessibilityManager::IsAutoclickEnabled() const {
ash::prefs::kAccessibilityAutoclickEnabled);
}
void AccessibilityManager::OnAutoclickChanged() {
void AccessibilityManager::OnAccessibilityCommonChanged(
const std::string& pref_name) {
if (!profile_)
return;
const bool enabled = profile_->GetPrefs()->GetBoolean(
ash::prefs::kAccessibilityAutoclickEnabled);
if (enabled)
const bool enabled = profile_->GetPrefs()->GetBoolean(pref_name);
if (enabled) {
accessibility_common_extension_loader_->SetProfile(
profile_, base::Closure() /* done_callback */);
}
if (autoclick_enabled_ == enabled)
size_t pref_count = accessibility_common_enabled_features_.count(pref_name);
if ((pref_count != 0 && enabled) || (pref_count == 0 && !enabled))
return;
autoclick_enabled_ = enabled;
if (enabled) {
accessibility_common_enabled_features_.insert(pref_name);
if (!accessibility_common_extension_loader_->loaded()) {
accessibility_common_extension_loader_->Load(
profile_, base::BindRepeating(
......@@ -656,7 +657,11 @@ void AccessibilityManager::OnAutoclickChanged() {
PostLoadAccessibilityCommon();
}
} else {
accessibility_common_extension_loader_->Unload();
accessibility_common_enabled_features_.erase(pref_name);
if (accessibility_common_enabled_features_.empty()) {
accessibility_common_extension_loader_->Unload();
}
}
}
......@@ -1030,6 +1035,11 @@ void AccessibilityManager::SetProfile(Profile* profile) {
// Clear all dictation state on profile change.
dictation_.reset();
// All features supported by accessibility common.
static const char* kAccessibilityCommonFeatures[] = {
ash::prefs::kAccessibilityAutoclickEnabled,
ash::prefs::kAccessibilityScreenMagnifierEnabled};
if (profile) {
// TODO(yoshiki): Move following code to PrefHandler.
pref_change_registrar_.reset(new PrefChangeRegistrar);
......@@ -1086,10 +1096,13 @@ void AccessibilityManager::SetProfile(Profile* profile) {
ash::prefs::kAccessibilitySwitchAccessEnabled,
base::BindRepeating(&AccessibilityManager::OnSwitchAccessChanged,
base::Unretained(this)));
pref_change_registrar_->Add(
ash::prefs::kAccessibilityAutoclickEnabled,
base::BindRepeating(&AccessibilityManager::OnAutoclickChanged,
base::Unretained(this)));
for (const std::string& feature : kAccessibilityCommonFeatures) {
pref_change_registrar_->Add(
feature, base::BindRepeating(
&AccessibilityManager::OnAccessibilityCommonChanged,
base::Unretained(this)));
}
local_state_pref_change_registrar_.reset(new PrefChangeRegistrar);
local_state_pref_change_registrar_->Init(g_browser_process->local_state());
......@@ -1127,7 +1140,9 @@ void AccessibilityManager::SetProfile(Profile* profile) {
OnSpokenFeedbackChanged();
OnSwitchAccessChanged();
OnSelectToSpeakChanged();
OnAutoclickChanged();
for (const std::string& feature : kAccessibilityCommonFeatures)
OnAccessibilityCommonChanged(feature);
}
void AccessibilityManager::SetProfileByUser(const user_manager::User* user) {
......
......@@ -350,6 +350,10 @@ class AccessibilityManager
base::RepeatingCallback<void(const gfx::Rect&)> observer);
void SetSwitchAccessKeysForTest(const std::vector<int>& keys);
const std::set<std::string>& GetAccessibilityCommonEnabledFeaturesForTest() {
return accessibility_common_enabled_features_;
}
protected:
AccessibilityManager();
~AccessibilityManager() override;
......@@ -380,7 +384,7 @@ class AccessibilityManager
void OnFocusHighlightChanged();
void OnTapDraggingChanged();
void OnSelectToSpeakChanged();
void OnAutoclickChanged();
void OnAccessibilityCommonChanged(const std::string& pref_name);
void OnSwitchAccessChanged();
void CheckBrailleState();
......@@ -438,7 +442,10 @@ class AccessibilityManager
bool spoken_feedback_enabled_ = false;
bool select_to_speak_enabled_ = false;
bool switch_access_enabled_ = false;
bool autoclick_enabled_ = false;
// A set of pref names of enabled accessibility features using the
// accessibility common extension.
std::set<std::string> accessibility_common_enabled_features_;
AccessibilityStatusCallbackList callback_list_;
......
......@@ -70,7 +70,7 @@ manifest("accessibility_common_manifest") {
manifest("accessibility_common_guest_manifest") {
input_file = "accessibility_common_manifest.json.jinja2"
output_file =
"$accessibility_out_dir/accessibility_common_guest_manifest.json"
"$accessibility_out_dir/accessibility_common_manifest_guest.json"
key = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6SX/t6kDEi9UiG4fULwjbEW1uJmQoiJPtxvSZ/SDH14OjSzmfP6xfE97Hus3EY8uSIMxTHkGaZliGbFbIQXQn6/XwBpQRu2gPlrfz7TWR1Hw6SboBBMOpltM9A2nx+d3jLtz+YtKNYVcHyNil9hXfFeyFe6g5kLHapKb1UO0jo3q3kovo1a1z7ujzGwogfLmb58w1hkdFBnnqumRlT55dKLN8AQ6cSdB1sjDVoMgPYeWgkzXr9cR3A8UVJookSO0sDAmD+W8BtBijapt3UVkHiIL1NTPuXvGGUHL7TPFo5WcBXFMkTz74gJqqFdO5hQ2YWXAaCxQJwgJrQPrvPMSJAgMBAAECggEADDhEDww9wWbWzUz3BQEs2In1HrOgAFStN3zEkNFc9B78AJsvpXWczgPUqk9jrg1JzkUeghlK/mDWT8MNkkdQ4kmFMYCM9/jOI6+kU3js+arxlzU84VI5r4c4RhlSOtBEMOHjF0DORP3sopMXOxPAbYjXog3xhA0szYXdedwcIik7Xu3lt1Hl5FfVZbvVLdf4vw0jTfHcp8SmHy/BDVnSCrhC3pnPGi6o+lUaSK0ca3uvcJDZGLXJ/6LyFb6uLlS2XUoBMYsombioRKrerJJSOmMTLHvfu1cM6+iQ+J0wdBnJQpgmDoSVGjnksPU2SMpWgG2OzwuZYIUGI745s19wLQKBgQDvdHsMZ4ttBr9bjydzeZVATWTICHZgXdAYgfgrbGwppYDUjfKoAuJ6bHTvff4nj8aZrY+Y1SwuvqxgHHfiggUgqg+JyeaAdQG+CLdfl1M8An+6H0x/hx0nk0oOJQhu0y1R/SbtnDJ6JASszg/VrTwHIYbzUl6xKHbZ6X41apyLYwKBgQDHKJOeZdxuYj7AsAqFGreuPoAEh0S+2VHHi4rjNz5dC1z7o/8siixfkHg7ONM2hqCKo55XYj4UWtprEFZJ9ohbizHELNzpnTxjdS0cG/VfItml6CDJaUtrkShIx17yGjNi0u/7ywHQ3slJsUXu7CbEcESwEzdoSrsC048dyxBSIwKBgF0141wtxklXcg/LBtldf6q7NbrkCGh0vDd+CEOm/eesRBz5cHbUQKLVKyO60L9HqVBTDm24tW0wzdrP2h7y69oOOOQzEqX4Zgg6Tl9IgZ7/fgbOfjG6P7ATFqWw5rp1O9QJjii6P6/p62P1Bpbvy0kfVO/MpY2iqbkjufxDFtLvAoGBAMC5p4CVGedH82oL8WI1JKLdoIzBSelV7CmqA9E1WIg5wtVRMlIrtB0WdQL6ToppZVpEU6pES8bu1Ibe3GHezL2pyZMJxw3bNuEYN3sIIz7ZPr2qEHBYEMAbTFyBcoPejvOHJO0I2s0BitBhWEeJB0r5Sb8KGYg3KRnnGIvAQh75AoGBANEC/k1umGrnMO3rwHJF7R+aTHzeMnO6oi11pmSnT7eJcF+oi7OwHS3ickU6sGrIb5QmnwCY9ES1qY6mP7N++KQGsdQM2l13MpCn8cBZgrfpQg2slP1dz8LCDW/PB+6MF7qwEHN2afVA2muQaez+q0eXZjMXmGJ3VZIXz/cxBLD6"
is_guest_manifest = true
}
......
......@@ -25,6 +25,7 @@ run_jsbundler("accessibility_common_copied_files") {
sources = [
"accessibility_common_loader.js",
"autoclick/autoclick.js",
"magnifier/magnifier.js",
]
rewrite_rules = [
rebase_path(".", root_build_dir) + ":",
......@@ -80,7 +81,10 @@ js_type_check("closure_compile") {
js_library("accessibility_common") {
sources = [ "accessibility_common_loader.js" ]
deps = [ ":autoclick" ]
deps = [
":autoclick",
":magnifier",
]
externs_list = [
"$externs_path/chrome_extensions.js",
"$externs_path/accessibility_private.js",
......@@ -95,3 +99,7 @@ js_library("autoclick") {
"$externs_path/automation.js",
]
}
js_library("magnifier") {
sources = [ "magnifier/magnifier.js" ]
}
......@@ -8,10 +8,10 @@
*/
class AccessibilityCommon {
constructor() {
/**
* @private {Autoclick}
*/
/** @private {Autoclick} */
this.autoclick_ = null;
/** @private {Magnifier} */
this.magnifier_ = null;
this.init_();
}
......@@ -32,6 +32,11 @@ class AccessibilityCommon {
{}, this.onAutoclickUpdated_.bind(this));
chrome.accessibilityFeatures.autoclick.onChange.addListener(
this.onAutoclickUpdated_.bind(this));
chrome.accessibilityFeatures.screenMagnifier.get(
{}, this.onMagnifierUpdated_.bind(this));
chrome.accessibilityFeatures.screenMagnifier.onChange.addListener(
this.onMagnifierUpdated_.bind(this));
}
/**
......@@ -50,6 +55,18 @@ class AccessibilityCommon {
this.autoclick_ = null;
}
}
/**
* @param {*} details
* @private
*/
onMagnifierUpdated_(details) {
if (details.value && !this.magnifier_) {
this.magnifier_ = new Magnifier();
} else if (!details.value && this.magnifier_) {
this.magnifier_ = null;
}
}
}
// Initialize the AccessibilityCommon extension.
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Main class for the Chrome OS magnifier.
*/
class Magnifier {
constructor() {}
}
......@@ -12,6 +12,7 @@
"background": {
"scripts": [
"accessibility_common/autoclick/autoclick.js",
"accessibility_common/magnifier/magnifier.js",
"accessibility_common/accessibility_common_loader.js"
]
},
......
......@@ -2148,6 +2148,7 @@ if (!is_android) {
sources += [
"../browser/apps/platform_apps/app_window_interactive_uitest_base.cc",
"../browser/apps/platform_apps/app_window_interactive_uitest_base.h",
"../browser/chromeos/accessibility/accessibility_common_browsertest.cc",
"../browser/chromeos/accessibility/accessibility_manager_browsertest.cc",
"../browser/chromeos/accessibility/dictation_chromeos_browsertest.cc",
"../browser/chromeos/accessibility/magnification_controller_browsertest.cc",
......
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