Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
690d8d6
First phase of new Android adapter design
mwcampbell Jul 31, 2024
ee20c14
Base native support for touch exploration
mwcampbell Aug 2, 2024
4687971
Stop using unsafe method calls; work so far on injecting adapter
mwcampbell Aug 5, 2024
abdb5b7
Implement proper lazy initialization, partial support for updates
mwcampbell Aug 5, 2024
2a701f2
Add the necessary boilerplate to build the winit examples for Android
mwcampbell Aug 5, 2024
f4438b7
Partial adapter initialization in a winit example
mwcampbell Aug 7, 2024
932550c
Finish minimal proof-of-concept adapter
mwcampbell Aug 8, 2024
13570a0
Update to winit 0.30.5, since it has an API required by the accesskit…
mwcampbell Aug 29, 2024
4c5df21
Reformat; factor out a utility function to send events from native
mwcampbell Sep 3, 2024
1b2a379
Attempt to implement explore-by-touch
mwcampbell Sep 3, 2024
742a174
Try to add the missing pieces to let the framework draw the focus rec…
mwcampbell Sep 4, 2024
4fd6611
Resolve clippy warnings
mwcampbell Sep 4, 2024
fd94ce0
Fix copyright year
mwcampbell Sep 4, 2024
3615903
Map roles to Android classes
mwcampbell Sep 4, 2024
ef753e7
Better mapping of the AccessKit name property to the appropriate Andr…
mwcampbell Sep 5, 2024
9033088
Expose more properties
mwcampbell Sep 5, 2024
dd9b154
Support the focus action; drop a leftover bit of println debugging
mwcampbell Sep 23, 2024
87510d0
More complete event dispatching, including the input focus event
mwcampbell Sep 23, 2024
7f95939
Send text change events
mwcampbell Sep 24, 2024
cdfee0a
Expose the text selection and send text selection change events
mwcampbell Oct 1, 2024
c5edb2f
Implement ACTION_SET_SELECTION
mwcampbell Oct 2, 2024
5263e25
First attempt at traversing text by movement granularity
mwcampbell Oct 3, 2024
3729d8c
Implement ACTION_CLEAR_ACCESSIBILITY_FOCUS, in case it helps
mwcampbell Oct 23, 2024
c4c6443
Attempts to make TalkBack movement by granularity work reliably when …
mwcampbell Oct 23, 2024
f740f7a
Switch to assuming GameActivity in the winit Android backend
mwcampbell Nov 21, 2024
6ad5a1f
fixes after rebase
mwcampbell Dec 24, 2024
202d842
Clean up after some of the more desperate attempts to fix the TalkBac…
mwcampbell Dec 30, 2024
14aad89
Forgot to rebuild the dex
mwcampbell Dec 30, 2024
d310104
fmt
mwcampbell Dec 30, 2024
d7ca5a6
Add some documentation to the two adapter types; at least hint at the…
mwcampbell Dec 30, 2024
78c7d95
Bring back the better way of doing explore by touch, now that we're n…
mwcampbell Dec 30, 2024
f35fad7
Document that the Android adapter basically assumes GameActivity
mwcampbell Dec 30, 2024
ca2d6f4
Now that we no longer support NativeActivity in the winit adapter, do…
mwcampbell Dec 30, 2024
ce09983
The winit adapter's assumption of GameActivity in particular is stron…
mwcampbell Dec 30, 2024
e345d61
Reformat Java code using the Google Java formatter in AOSP mode
mwcampbell Dec 30, 2024
d7f1bf5
Fix the clippy warning
mwcampbell Dec 30, 2024
72a0ccc
Derive or implement `Debug` on public types
mwcampbell Feb 23, 2025
f68ff45
Fix struct doc comments
mwcampbell Feb 23, 2025
928d2b2
Fix copyright year
mwcampbell Feb 23, 2025
cbc60c7
Update READMEs
mwcampbell Feb 23, 2025
a5a9cfe
Try to add a CI job for verifying the committed .dex file
mwcampbell Feb 24, 2025
cb99b1c
try again
mwcampbell Feb 24, 2025
1ab205d
forgot quoting
mwcampbell Feb 24, 2025
adee2fb
Add CI step to check Java code formatting
mwcampbell Feb 24, 2025
cdb29d2
Fix action reference
mwcampbell Feb 24, 2025
8de91b0
Merge Java formatting check into the existing fmt job
mwcampbell Feb 24, 2025
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
20 changes: 20 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ jobs:
- name: cargo fmt
run: cargo fmt --all -- --check

- name: check Java formatting
uses: axel-op/googlejavaformat-action@v4
with:
args: "--aosp --set-exit-if-changed"

cargo-deny:
runs-on: ubuntu-22.04
steps:
Expand Down Expand Up @@ -81,3 +86,18 @@ jobs:
- name: cargo test -p accesskit_windows
if: matrix.os == 'windows-2019'
run: cargo test -p accesskit_windows

check-android-dex:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- uses: android-actions/setup-android@v2
- run: sdkmanager "platforms;android-30"
- run: sdkmanager "build-tools;33.0.2"
- run: cp platforms/android/classes.dex platforms/android/classes.dex.orig
- run: ./platforms/android/build-dex.sh
- run: cmp platforms/android/classes.dex.orig platforms/android/classes.dex
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ resolver = "2"
members = [
"common",
"consumer",
"platforms/android",
"platforms/atspi-common",
"platforms/macos",
"platforms/unix",
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ The current released platform adapters are all at rough feature parity. They don

The following platform adapters are currently available:

* [Android adapter](https://crates.io/crates/accesskit_android): This adapter implements the Java-based Android accessibility API.
* [macOS adapter](https://crates.io/crates/accesskit_macos): This adapter implements the NSAccessibility protocols in the AppKit framework.
* [Unix adapter](https://crates.io/crates/accesskit_unix): This adapter implements the AT-SPI D-Bus interfaces, using [zbus](https://github.com/dbus2/zbus), a pure-Rust implementation of D-Bus.
* [Windows adapter](https://crates.io/crates/accesskit_windows): This adapter implements UI Automation, the current Windows accessibility API.
Expand Down
1 change: 1 addition & 0 deletions common/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ To use AccessKit in your application or toolkit, you will also need a platform a
* [accesskit_windows](https://crates.io/crates/accesskit_windows): exposes an AccessKit tree on Windows using the UI Automation API
* [accesskit_macos](https://crates.io/crates/accesskit_macos): exposes an AccessKit tree on MacOS through the Cocoa `NSAccessibility` protocol
* [accesskit_unix](https://crates.io/crates/accesskit_unix): exposes an AccessKit tree on Linux and Unix systems through the AT-SPI protocol
* [accesskit_android](https://crates.io/crates/accesskit_android): exposes an AccessKit tree on Android through the Java-based Android accessibility API
* [accesskit_winit](https://crates.io/crates/accesskit_winit): wraps other platform adapters for use with the [winit](https://crates.io/crates/winit) windowing library

Some platform adapters include simple examples.
14 changes: 14 additions & 0 deletions common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,20 @@ impl From<Node> for FrozenNode {
}
}

impl From<&FrozenNode> for Node {
fn from(node: &FrozenNode) -> Self {
Self {
role: node.role,
actions: node.actions,
flags: node.flags,
properties: Properties {
indices: node.properties.indices,
values: node.properties.values.to_vec(),
},
}
}
}

impl FrozenNode {
#[inline]
pub fn role(&self) -> Role {
Expand Down
6 changes: 2 additions & 4 deletions consumer/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub struct Node<'a> {
}

impl<'a> Node<'a> {
pub(crate) fn data(&self) -> &NodeData {
pub fn data(&self) -> &NodeData {
&self.state.data
}

Expand Down Expand Up @@ -446,9 +446,7 @@ impl<'a> Node<'a> {
&& self.is_selected().is_none()
}

// The future of the `Action` enum is undecided, so keep the following
// function private for now.
fn supports_action(&self, action: Action) -> bool {
pub fn supports_action(&self, action: Action) -> bool {
self.data().supports_action(action)
}

Expand Down
36 changes: 36 additions & 0 deletions consumer/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ pub struct Position<'a> {
}

impl<'a> Position<'a> {
pub fn to_raw(self) -> WeakPosition {
self.inner.downgrade()
}

pub fn inner_node(&self) -> &Node {
&self.inner.node
}
Expand Down Expand Up @@ -223,6 +227,14 @@ impl<'a> Position<'a> {
self.is_document_end() || self.inner.is_paragraph_end()
}

pub fn is_paragraph_separator(&self) -> bool {
if self.is_document_end() {
return false;
}
let next = self.forward_to_character_end();
!next.is_document_end() && next.is_paragraph_end()
}

pub fn is_page_start(&self) -> bool {
self.is_document_start()
}
Expand Down Expand Up @@ -292,6 +304,20 @@ impl<'a> Position<'a> {
lines_before_current
}

pub fn biased_to_start(&self) -> Self {
Self {
root_node: self.root_node,
inner: self.inner.biased_to_start(&self.root_node),
}
}

pub fn biased_to_end(&self) -> Self {
Self {
root_node: self.root_node,
inner: self.inner.biased_to_end(&self.root_node),
}
}

pub fn forward_to_character_start(&self) -> Self {
let pos = self.inner.biased_to_start(&self.root_node);
Self {
Expand Down Expand Up @@ -905,6 +931,16 @@ impl<'a> Node<'a> {
})
}

pub fn text_selection_anchor(&self) -> Option<Position> {
self.data().text_selection().map(|selection| {
let anchor = InnerPosition::clamped_upgrade(self.tree_state, selection.anchor).unwrap();
Position {
root_node: *self,
inner: anchor,
}
})
}

pub fn text_selection_focus(&self) -> Option<Position> {
self.data().text_selection().map(|selection| {
let focus = InnerPosition::clamped_upgrade(self.tree_state, selection.focus).unwrap();
Expand Down
8 changes: 8 additions & 0 deletions consumer/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,14 @@ impl State {
self.is_host_focused
}

pub fn focus_id_in_tree(&self) -> NodeId {
self.focus
}

pub fn focus_in_tree(&self) -> Node<'_> {
self.node_by_id(self.focus_id_in_tree()).unwrap()
}

pub fn focus_id(&self) -> Option<NodeId> {
self.is_host_focused.then_some(self.focus)
}
Expand Down
1 change: 1 addition & 0 deletions platforms/android/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.class
23 changes: 23 additions & 0 deletions platforms/android/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "accesskit_android"
version = "0.1.0"
authors.workspace = true
license.workspace = true
description = "AccessKit UI accessibility infrastructure: Android adapter"
categories.workspace = true
keywords = ["gui", "ui", "accessibility"]
repository.workspace = true
readme = "README.md"
edition.workspace = true
rust-version.workspace = true

[features]
embedded-dex = []

[dependencies]
accesskit = { version = "0.17.1", path = "../../common" }
accesskit_consumer = { version = "0.26.0", path = "../../consumer" }
jni = "0.21.1"
log = "0.4.17"
once_cell = "1.17.1"
paste = "1.0.12"
10 changes: 10 additions & 0 deletions platforms/android/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# AccessKit Android adapter

This is the Android adapter for [AccessKit](https://accesskit.dev/).

This adapter is implemented in two layers:

* The `Adapter` struct is the core low-level adapter. It provides maximum flexibility in the application threading model, the interface between Java and native code, and the implementation of action callbacks, at the expense of requiring its caller to provide glue code.
* The `InjectingAdapter` struct injects accessibility into an arbitrary Android view without requiring the view class to be modified, at the expense of depending on a specific Java class and providing less flexibility in the aspects listed above.

The most convenient way to use `InjectingAdapter` is to embed a precompiled `.dex` file containing the associated Java class and its inner classes into the native code. This approach requires the `embedded-dex` Cargo feature.
7 changes: 7 additions & 0 deletions platforms/android/build-dex.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e -u -o pipefail
cd `dirname $0`
ANDROID_JAR=$ANDROID_HOME/platforms/android-30/android.jar
find java -name '*.class' -delete
javac --source 8 --target 8 --boot-class-path $ANDROID_JAR -Xlint:deprecation `find java -name '*.java'`
$ANDROID_HOME/build-tools/33.0.2/d8 --classpath $ANDROID_JAR --output . `find java -name '*.class'`
Binary file added platforms/android/classes.dex
Binary file not shown.
Loading