Commit 46fca134 authored by dmazzoni's avatar dmazzoni Committed by Commit bot

Improve Android accessible hit testing.

Take advantage of a new function we defined already for what nodes are
"interesting" on Android.

When we get a hit test result back and it's not interesting, first see if
there's a single child that's interesting. If so, return that. If not,
walk up to the first interesting ancestor.

That will avoid returning something like a wrapper <div>.

BUG=656146

Review-Url: https://chromiumcodereview.appspot.com/2422773002
Cr-Commit-Position: refs/heads/master@{#426938}
parent cbfc4c03
...@@ -277,6 +277,42 @@ bool BrowserAccessibilityAndroid::IsVisibleToUser() const { ...@@ -277,6 +277,42 @@ bool BrowserAccessibilityAndroid::IsVisibleToUser() const {
return !HasState(ui::AX_STATE_INVISIBLE); return !HasState(ui::AX_STATE_INVISIBLE);
} }
bool BrowserAccessibilityAndroid::IsInterestingOnAndroid() const {
// Focusable nodes are always interesting. Note that IsFocusable()
// already skips over things like iframes and child frames that are
// technically focusable but shouldn't be exposed as focusable on Android.
if (IsFocusable())
return true;
// If it's not focusable but has a control role, then it's interesting.
if (IsControl())
return true;
// Otherwise, the interesting nodes are leaf nodes with text.
return PlatformIsLeaf() && !GetText().empty();
}
const BrowserAccessibilityAndroid*
BrowserAccessibilityAndroid::GetSoleInterestingNodeFromSubtree() const {
if (IsInterestingOnAndroid())
return this;
const BrowserAccessibilityAndroid* sole_interesting_node = nullptr;
for (uint32_t i = 0; i < PlatformChildCount(); ++i) {
const BrowserAccessibilityAndroid* interesting_node =
static_cast<const BrowserAccessibilityAndroid*>(PlatformGetChild(i))->
GetSoleInterestingNodeFromSubtree();
if (interesting_node && sole_interesting_node) {
// If there are two interesting nodes, return nullptr.
return nullptr;
} else if (interesting_node) {
sole_interesting_node = interesting_node;
}
}
return sole_interesting_node;
}
bool BrowserAccessibilityAndroid::CanOpenPopup() const { bool BrowserAccessibilityAndroid::CanOpenPopup() const {
return HasState(ui::AX_STATE_HASPOPUP); return HasState(ui::AX_STATE_HASPOPUP);
} }
......
...@@ -48,6 +48,18 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility { ...@@ -48,6 +48,18 @@ class CONTENT_EXPORT BrowserAccessibilityAndroid : public BrowserAccessibility {
bool IsSlider() const; bool IsSlider() const;
bool IsVisibleToUser() const; bool IsVisibleToUser() const;
// This returns true for all nodes that we should navigate to.
// Nodes that have a generic role, no accessible name, and aren't
// focusable or clickable aren't interesting.
bool IsInterestingOnAndroid() const;
// If this node is interesting (IsInterestingOnAndroid() returns true),
// returns |this|. If not, it recursively checks all of the
// platform children of this node, and if just a single one is
// interesting, returns that one. If no descendants are interesting, or
// if more than one is interesting, returns nullptr.
const BrowserAccessibilityAndroid* GetSoleInterestingNodeFromSubtree() const;
bool CanOpenPopup() const; bool CanOpenPopup() const;
bool HasFocusableChild() const; bool HasFocusableChild() const;
......
...@@ -56,20 +56,9 @@ bool SectionPredicate( ...@@ -56,20 +56,9 @@ bool SectionPredicate(
bool AllInterestingNodesPredicate( bool AllInterestingNodesPredicate(
BrowserAccessibility* start, BrowserAccessibility* node) { BrowserAccessibility* start, BrowserAccessibility* node) {
// Focusable nodes should never be skipped. Note that IsFocusable()
// already skips over things like iframes and child frames that are
// technically focusable but shouldn't be exposed as focusable on Android.
BrowserAccessibilityAndroid* android_node = BrowserAccessibilityAndroid* android_node =
static_cast<BrowserAccessibilityAndroid*>(node); static_cast<BrowserAccessibilityAndroid*>(node);
if (android_node->IsFocusable()) return android_node->IsInterestingOnAndroid();
return true;
// If it's not focusable but has a control role, then it's interesting.
if (android_node->IsControl())
return true;
// Otherwise, the interesting nodes are leaf nodes with text.
return node->PlatformIsLeaf() && !node->GetText().empty();
} }
void AddToPredicateMap(const char* search_key_ascii, void AddToPredicateMap(const char* search_key_ascii,
...@@ -709,19 +698,30 @@ void BrowserAccessibilityManagerAndroid::HandleHoverEvent( ...@@ -709,19 +698,30 @@ void BrowserAccessibilityManagerAndroid::HandleHoverEvent(
if (obj.is_null()) if (obj.is_null())
return; return;
BrowserAccessibilityAndroid* ancestor = // First walk up to the nearest platform node, in case this node isn't
static_cast<BrowserAccessibilityAndroid*>(node->GetParent()); // even exposed on the platform.
while (ancestor && ancestor != GetRoot()) { node = node->GetClosestPlatformObject();
if (ancestor->PlatformIsLeaf() ||
(ancestor->IsFocusable() && !ancestor->HasFocusableChild())) { // If this node is uninteresting and just a wrapper around a sole
node = ancestor; // interesting descendant, prefer that descendant instead.
// Don't break - we want the highest ancestor that's focusable or a const BrowserAccessibilityAndroid* android_node =
// leaf node. static_cast<BrowserAccessibilityAndroid*>(node);
} const BrowserAccessibilityAndroid* sole_interesting_node =
ancestor = static_cast<BrowserAccessibilityAndroid*>(ancestor->GetParent()); android_node->GetSoleInterestingNodeFromSubtree();
if (sole_interesting_node)
android_node = sole_interesting_node;
// Finally, if this node is still uninteresting, try to walk up to
// find an interesting parent.
while (android_node && !android_node->IsInterestingOnAndroid()) {
android_node = static_cast<BrowserAccessibilityAndroid*>(
android_node->GetParent());
} }
Java_BrowserAccessibilityManager_handleHover(env, obj, node->unique_id()); if (android_node) {
Java_BrowserAccessibilityManager_handleHover(
env, obj, android_node->unique_id());
}
} }
jint BrowserAccessibilityManagerAndroid::FindElementType( jint BrowserAccessibilityManagerAndroid::FindElementType(
......
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