Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion adapters/android/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
// the LICENSE-APACHE file) or the MIT license (found in
// the LICENSE-MIT file), at your option.

use jni::{JNIEnv, objects::JObject, sys::jint};
use jni::{
JNIEnv,
objects::JObject,
sys::{jfloat, jint},
};

use crate::util::*;

Expand All @@ -21,6 +25,9 @@ pub(crate) enum PlatformActionInner {
forward: bool,
extend_selection: bool,
},
SetProgress {
value: jfloat,
},
}

pub struct PlatformAction(pub(crate) PlatformActionInner);
Expand Down Expand Up @@ -63,6 +70,15 @@ impl PlatformAction {
extend_selection,
}))
}
ACTION_SET_PROGRESS => {
if arguments.is_null()
|| !bundle_contains_key(env, arguments, ACTION_ARGUMENT_PROGRESS_VALUE)
{
return None;
}
let value = bundle_get_float(env, arguments, ACTION_ARGUMENT_PROGRESS_VALUE);
Some(Self(PlatformActionInner::SetProgress { value }))
}
_ => Some(Self(PlatformActionInner::Simple { action })),
}
}
Expand Down
98 changes: 67 additions & 31 deletions adapters/android/src/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,42 +455,52 @@ impl Adapter {
target_node,
data: None,
},
ACTION_SCROLL_BACKWARD | ACTION_SCROLL_FORWARD => ActionRequest {
action: {
let node = tree_state.node_by_id(target).unwrap();
if let Some(orientation) = node.orientation() {
match orientation {
Orientation::Horizontal => {
if action == ACTION_SCROLL_BACKWARD {
Action::ScrollLeft
} else {
Action::ScrollRight
}
}
Orientation::Vertical => {
if action == ACTION_SCROLL_BACKWARD {
Action::ScrollUp
} else {
Action::ScrollDown
}
ACTION_SCROLL_BACKWARD | ACTION_SCROLL_FORWARD => {
let node = tree_state.node_by_id(target).unwrap();
let backward = action == ACTION_SCROLL_BACKWARD;
let is_range_control =
node.supports_increment(&filter) || node.supports_decrement(&filter);
let action = if is_range_control {
if backward {
Action::Decrement
} else {
Action::Increment
}
} else if let Some(orientation) = node.orientation() {
match orientation {
Orientation::Horizontal => {
if backward {
Action::ScrollLeft
} else {
Action::ScrollRight
}
}
} else if action == ACTION_SCROLL_BACKWARD {
if node.supports_action(Action::ScrollUp, &filter) {
Action::ScrollUp
} else {
Action::ScrollLeft
Orientation::Vertical => {
if backward {
Action::ScrollUp
} else {
Action::ScrollDown
}
}
} else if node.supports_action(Action::ScrollDown, &filter) {
Action::ScrollDown
}
} else if backward {
if node.supports_action(Action::ScrollUp, &filter) {
Action::ScrollUp
} else {
Action::ScrollRight
Action::ScrollLeft
}
},
target_tree,
target_node,
data: Some(ActionData::ScrollUnit(ScrollUnit::Page)),
},
} else if node.supports_action(Action::ScrollDown, &filter) {
Action::ScrollDown
} else {
Action::ScrollRight
};
ActionRequest {
action,
target_tree,
target_node,
data: (!is_range_control).then_some(ActionData::ScrollUnit(ScrollUnit::Page)),
}
}
ACTION_ACCESSIBILITY_FOCUS => {
self.accessibility_focus = Some(virtual_view_id);
events.push(QueuedEvent::InvalidateHost);
Expand Down Expand Up @@ -525,6 +535,29 @@ impl Adapter {
Some(QueuedEvents(events))
}

fn set_progress<H: ActionHandler + ?Sized>(
&mut self,
action_handler: &mut H,
virtual_view_id: jint,
value: jfloat,
) -> Option<QueuedEvents> {
let tree = self.state.get_full_tree()?;
let tree_state = tree.state();
let target = self.node_id_map.get_accesskit_id(virtual_view_id)?;
let (target_node, target_tree) = tree_state.locate_node(target)?;
let node = tree_state.node_by_id(target)?;
if !node.supports_action(Action::SetValue, &filter) || node.numeric_value().is_none() {
return None;
}
action_handler.do_action(ActionRequest {
action: Action::SetValue,
target_tree,
target_node,
data: Some(ActionData::NumericValue(value.into())),
});
Some(QueuedEvents(Vec::new()))
}

fn set_text_selection_common<H: ActionHandler + ?Sized, F, Extra>(
&mut self,
action_handler: &mut H,
Expand Down Expand Up @@ -795,6 +828,9 @@ impl Adapter {
forward,
extend_selection,
),
PlatformActionInner::SetProgress { value } => {
self.set_progress(action_handler, virtual_view_id, value)
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions adapters/android/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,9 @@ impl QueuedEvents {
/// any locks required by the host view's implementations of Android
/// framework callbacks.
pub fn raise(self, env: &mut JNIEnv, host: &JObject) {
if self.0.is_empty() {
return;
}
// The framework throws an exception if events are sent from the
// UI thread while accessibility is disabled.
if !is_accessibility_enabled(env, host) {
Expand Down
36 changes: 35 additions & 1 deletion adapters/android/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ impl NodeWrapper<'_> {
Range::from_node(self.0)
}

fn supports_set_progress(&self) -> bool {
self.range().is_some() && self.0.supports_action(Action::SetValue, &filter)
}

fn is_range_control(&self) -> bool {
self.0.supports_increment(&filter) || self.0.supports_decrement(&filter)
}

pub(crate) fn content_description(&self) -> Option<String> {
if self.0.label_comes_from_value() {
self.0.value()
Expand Down Expand Up @@ -358,7 +366,10 @@ impl NodeWrapper<'_> {
.unwrap();

let can_focus = self.is_focusable() && !self.0.is_focused();
if self.0.is_clickable(&filter) || can_focus {
// Without a click action, TalkBack handles a double-tap on a range
// control by tapping its center which can be useful to quickly
// set a slider value in the middle.
if self.0.is_clickable(&filter) || (can_focus && !self.is_range_control()) {
add_action(env, node_info, ACTION_CLICK);
}
if can_focus {
Expand All @@ -382,11 +393,13 @@ impl NodeWrapper<'_> {
}
if self.0.supports_action(Action::ScrollLeft, &filter)
|| self.0.supports_action(Action::ScrollUp, &filter)
|| self.0.supports_decrement(&filter)
{
add_action(env, node_info, ACTION_SCROLL_BACKWARD);
}
if self.0.supports_action(Action::ScrollRight, &filter)
|| self.0.supports_action(Action::ScrollDown, &filter)
|| self.0.supports_increment(&filter)
{
add_action(env, node_info, ACTION_SCROLL_FORWARD);
}
Expand All @@ -401,6 +414,27 @@ impl NodeWrapper<'_> {
)
.unwrap();
}
if self.supports_set_progress() {
let action_class = env
.find_class("android/view/accessibility/AccessibilityNodeInfo$AccessibilityAction")
.unwrap();
let action = env
.get_static_field(
&action_class,
"ACTION_SET_PROGRESS",
"Landroid/view/accessibility/AccessibilityNodeInfo$AccessibilityAction;",
)
.unwrap()
.l()
.unwrap();
env.call_method(
node_info,
"addAction",
"(Landroid/view/accessibility/AccessibilityNodeInfo$AccessibilityAction;)V",
&[(&action).into()],
)
.unwrap();
}

let live = match self.0.live() {
Live::Off => LIVE_REGION_NONE,
Expand Down
18 changes: 17 additions & 1 deletion adapters/android/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use accesskit_consumer::{FullNodeId, NodeRef};
use jni::{
JNIEnv,
objects::{GlobalRef, JObject},
sys::jint,
sys::{jfloat, jint},
};
use std::{collections::HashMap, sync::OnceLock};

Expand All @@ -20,13 +20,16 @@ pub(crate) const ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: jint = 1 << 9;
pub(crate) const ACTION_SCROLL_FORWARD: jint = 1 << 12;
pub(crate) const ACTION_SCROLL_BACKWARD: jint = 1 << 13;
pub(crate) const ACTION_SET_SELECTION: jint = 1 << 17;
pub(crate) const ACTION_SET_PROGRESS: jint = 0x0102003d;

pub(crate) const ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT: &str =
"ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
pub(crate) const ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN: &str =
"ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN";
pub(crate) const ACTION_ARGUMENT_SELECTION_START_INT: &str = "ACTION_ARGUMENT_SELECTION_START_INT";
pub(crate) const ACTION_ARGUMENT_SELECTION_END_INT: &str = "ACTION_ARGUMENT_SELECTION_END_INT";
pub(crate) const ACTION_ARGUMENT_PROGRESS_VALUE: &str =
"android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";

pub(crate) const CONTENT_CHANGE_TYPE_SUBTREE: jint = 1 << 0;

Expand Down Expand Up @@ -176,6 +179,19 @@ pub(crate) fn bundle_get_int(env: &mut JNIEnv, bundle: &JObject, key: &str) -> j
.unwrap()
}

pub(crate) fn bundle_get_float(env: &mut JNIEnv, bundle: &JObject, key: &str) -> jfloat {
let key = env.new_string(key).unwrap();
env.call_method(
bundle,
"getFloat",
"(Ljava/lang/String;)F",
&[(&key).into()],
)
.unwrap()
.f()
.unwrap()
}

pub(crate) fn bundle_get_bool(env: &mut JNIEnv, bundle: &JObject, key: &str) -> bool {
let key = env.new_string(key).unwrap();
env.call_method(
Expand Down
Loading