Move highlight to next or prev if highlighted object goes out of screen.
This patch is using PropertyNotification only for highlighted object.
Change-Id: Idaea158fa9e9a1eb569ab619210d2aa916f28f22
using MethodType = TestDBusWrapper::MethodType;
using MessagePtr = DBusWrapper::MessagePtr;
+ static bool MoveOutedCalled = false;
+
void TestEnableSC(bool b) {
static bool firstTime = true;
if (b && firstTime) {
[wr](const MessagePtr &m) -> MessagePtr {
return wr->newReplyMessage(m);
};
+ wr->testMethods[std::tuple<std::string, std::string, std::string, MethodType>{"/org/a11y/atspi/accessible", "org.a11y.atspi.Event.Object", "MoveOuted", MethodType::Method}] =
+ [wr](const MessagePtr &m) -> MessagePtr {
+ MoveOutedCalled = true;
+ return wr->newReplyMessage(m);
+ };
}
auto wr = static_cast<TestDBusWrapper*>(DBusWrapper::Installed());
wr->fromTestChangeProperty("/org/a11y/bus", "org.a11y.Status", "ScreenReaderEnabled", b);
return std::move(std::get<0>(chs));
}
+ void TestResetMoveOutedCalled ()
+ {
+ MoveOutedCalled = false;
+ }
+
+ bool TestGetMoveOutedCalled ()
+ {
+ return MoveOutedCalled;
+ }
void printTree(const Address &root, size_t depth)
{
bool TestDoAction ( const Address &adr, const std::string& name );
std::string TestGetActionKeyBinding ( const Address &adr, size_t index );
std::string TestGetActionDescription ( const Address &adr, size_t index );
-
+ void TestResetMoveOutedCalled ();
+ bool TestGetMoveOutedCalled ();
}
}
Dali::Accessibility::TestEnableSC( false );
END_TEST;
}
+
+int UtcDaliAccessibilityCheckHighlight(void)
+{
+ ToolkitTestApplication application;
+ Dali::Accessibility::TestEnableSC( true );
+ Dali::Accessibility::TestResetMoveOutedCalled();
+
+ // Make precondition two children exist in parent area
+ PushButton parentButton = PushButton::New();
+ parentButton.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ parentButton.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ parentButton.SetProperty( Dali::Actor::Property::POSITION, Dali::Vector2(0.0f, 0.0f) );
+ parentButton.SetProperty( Dali::Actor::Property::SIZE, Dali::Vector2(100.0f, 200.0f) );
+ application.GetScene().Add( parentButton );
+
+ PushButton buttonA = PushButton::New();
+ buttonA.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ buttonA.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ buttonA.SetProperty( Dali::Actor::Property::POSITION, Dali::Vector2(0.0f, 0.0f) );
+ buttonA.SetProperty( Dali::Actor::Property::SIZE, Dali::Vector2(100.0f, 100.0f) );
+ parentButton.Add(buttonA);
+
+ PushButton buttonB = PushButton::New();
+ buttonB.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::TOP_LEFT);
+ buttonB.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ buttonB.SetProperty( Dali::Actor::Property::POSITION, Dali::Vector2(0.0f, 100.0f) );
+ buttonB.SetProperty( Dali::Actor::Property::SIZE, Dali::Vector2(100.0f, 100.0f) );
+ parentButton.Add(buttonB);
+ Wait(application);
+
+ // Move second child out of parent area
+ auto* accessible = dynamic_cast<DevelControl::AccessibleImpl*>(Dali::Accessibility::Accessible::Get(buttonA));
+ DALI_TEST_CHECK(accessible);
+ accessible->GrabHighlight();
+ Wait(application);
+
+ buttonA.SetProperty( Dali::Actor::Property::POSITION, Dali::Vector2(0.0f, -200.0f) );
+ Wait(application);
+ // Need one more seding notificaiton to get correct updated position
+ application.SendNotification();
+ DALI_TEST_EQUALS( true, Dali::Accessibility::TestGetMoveOutedCalled(), TEST_LOCATION );
+
+ // Reset verdict data
+ Dali::Accessibility::TestResetMoveOutedCalled();
+
+ // Move second child out of parent area
+ accessible = dynamic_cast<DevelControl::AccessibleImpl*>(Dali::Accessibility::Accessible::Get(buttonB));
+ DALI_TEST_CHECK(accessible);
+ accessible->GrabHighlight();
+ Wait(application);
+
+ buttonB.SetProperty( Dali::Actor::Property::POSITION, Dali::Vector2(300.0f, 100.0f) );
+ Wait(application);
+ // Need one more seding notificaiton to get correct updated position
+ application.SendNotification();
+ DALI_TEST_EQUALS( true, Dali::Accessibility::TestGetMoveOutedCalled(), TEST_LOCATION );
+
+ Dali::Accessibility::TestEnableSC( false );
+ END_TEST;
+}
}
}
+void AccessibleImpl::RegisterPositionPropertyNotification()
+{
+ auto control = Dali::Toolkit::Control::DownCast(Self());
+ Internal::Control& internalControl = Toolkit::Internal::GetImplementation(control);
+ Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get(internalControl);
+ controlImpl.RegisterAccessibilityPositionPropertyNotification();
+}
+
+void AccessibleImpl::UnregisterPositionPropertyNotification()
+{
+ auto control = Dali::Toolkit::Control::DownCast(Self());
+ Internal::Control& internalControl = Toolkit::Internal::GetImplementation(control);
+ Internal::Control::Impl& controlImpl = Internal::Control::Impl::Get(internalControl);
+ controlImpl.UnregisterAccessibilityPositionPropertyNotification();
+}
+
bool AccessibleImpl::GrabHighlight()
{
Dali::Actor self = Self();
SetHighlightActor(highlight);
}
- highlight.SetProperty(Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
- highlight.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
+ highlight.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
highlight.SetProperty(Actor::Property::POSITION_Z, 1.0f);
highlight.SetProperty(Actor::Property::POSITION, Vector2(0.0f, 0.0f));
+ // Need to set resize policy again, to update SIZE property which is set by
+ // AccessibleImpl_NUI. The highlight could move from AccessibleImpl_NUI to
+ // AccessibleImpl. In this case, highlight has incorrect size.
+ highlight.SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+
// Remember the highlight actor, so that when the default is changed with
// SetHighlightActor(), the currently displayed highlight can still be cleared.
mCurrentHighlightActor = highlight;
self.Add(highlight);
SetCurrentlyHighlightedActor(self);
EmitHighlighted(true);
+ RegisterPositionPropertyNotification();
return true;
}
if(GetCurrentlyHighlightedActor() == self)
{
+ UnregisterPositionPropertyNotification();
self.Remove(mCurrentHighlightActor.GetHandle());
mCurrentHighlightActor = {};
SetCurrentlyHighlightedActor({});
return Dali::Property::INVALID_INDEX;
}
+void AccessibleImpl::SetLastPosition(Vector2 position)
+{
+ mLastPosition = position;
+}
+
+Vector2 AccessibleImpl::GetLastPosition() const
+{
+ return mLastPosition;
+}
+
} // namespace Dali::Toolkit::DevelControl
public virtual Dali::Accessibility::Action
{
protected:
+ Vector2 mLastPosition{0.0f, 0.0f};
Dali::WeakHandle<Dali::Actor> mSelf;
Dali::WeakHandle<Dali::Actor> mCurrentHighlightActor;
bool mIsModal = false;
void ScrollToSelf();
+ /**
+ * @brief Register property notification to check highlighted object position
+ */
+ void RegisterPositionPropertyNotification();
+
+ /**
+ * @brief Remove property notification added by RegisterPropertyNotification
+ */
+ void UnregisterPositionPropertyNotification();
+
public:
AccessibleImpl(Dali::Actor self, Dali::Accessibility::Role role, bool modal = false);
* @brief Returns the index of the property that represents this actor's description
*/
virtual Dali::Property::Index GetDescriptionPropertyIndex();
+
+ /**
+ * @brief Sets last object position
+ * @param[in] position Last object position
+ */
+ void SetLastPosition(Vector2 position);
+
+ /**
+ * @brief Gets last object position
+ * @return The Last object position
+ */
+ Vector2 GetLastPosition() const;
};
} // namespace Dali::Toolkit::DevelControl
}
}
+Dali::Rect<> GetShowingGeometry(Dali::Rect<> rect, Dali::Toolkit::DevelControl::AccessibleImpl* accessibleImpl)
+{
+ Rect<> parentRect;
+ Vector2 currentPosition;
+ auto parent = dynamic_cast<Toolkit::DevelControl::AccessibleImpl*>(accessibleImpl->GetParent());
+
+ while(parent)
+ {
+ parentRect = parent->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
+
+ currentPosition.x = rect.x;
+ currentPosition.y = rect.y;
+
+ rect.x = rect.x > parentRect.x ? rect.x : parentRect.x;
+ rect.y = rect.y > parentRect.y ? rect.y : parentRect.y;
+ rect.width = currentPosition.x + rect.width < parentRect.x + parentRect.width ? currentPosition.x + rect.width - rect.x : parentRect.x + parentRect.width - rect.x;
+ rect.height = currentPosition.y + rect.height < parentRect.y + parentRect.height ? currentPosition.y + rect.height - rect.y : parentRect.y + parentRect.height - rect.y;
+
+ if(rect.width < 0 || rect.height < 0)
+ {
+ return rect;
+ }
+
+ parent = dynamic_cast<Toolkit::DevelControl::AccessibleImpl*>(parent->GetParent());
+ }
+
+ return rect;
+}
+
} // unnamed namespace
// clang-format off
return *internalControl.mImpl;
}
+void Control::Impl::CheckHighlightedObjectGeometry(PropertyNotification& propertyNotification)
+{
+ auto accessibleImpl = dynamic_cast<Dali::Toolkit::DevelControl::AccessibleImpl*>(mAccessibilityObject.get());
+ auto lastPosition = accessibleImpl->GetLastPosition();
+ auto accessibleRect = accessibleImpl->GetExtents(Dali::Accessibility::CoordinateType::WINDOW);
+
+ if(lastPosition.x == accessibleRect.x && lastPosition.y == accessibleRect.y)
+ {
+ return;
+ }
+
+ auto rect = GetShowingGeometry(accessibleRect, accessibleImpl);
+
+ // MoveOuted is sent already, no need to send it again
+ if(mAccessibilityMovedOutOfScreenDirection != Dali::Accessibility::MovedOutOfScreenType::NONE)
+ {
+ if(rect.width > 0 && rect.height > 0)
+ {
+ // flick next does not use MoveOuted - ScrollToSelf makes object show, so reset for sending MoveOuted next
+ mAccessibilityMovedOutOfScreenDirection = Dali::Accessibility::MovedOutOfScreenType::NONE;
+ }
+ return;
+ }
+
+ if(rect.width < 0)
+ {
+ mAccessibilityMovedOutOfScreenDirection = (accessibleRect.x < lastPosition.x) ? Dali::Accessibility::MovedOutOfScreenType::TOP_LEFT : Dali::Accessibility::MovedOutOfScreenType::BOTTOM_RIGHT;
+ }
+
+ if(rect.height < 0)
+ {
+ mAccessibilityMovedOutOfScreenDirection = (accessibleRect.y < lastPosition.y) ? Dali::Accessibility::MovedOutOfScreenType::TOP_LEFT : Dali::Accessibility::MovedOutOfScreenType::BOTTOM_RIGHT;
+ }
+
+ if(mAccessibilityMovedOutOfScreenDirection != Dali::Accessibility::MovedOutOfScreenType::NONE)
+ {
+ mAccessibilityObject.get()->EmitMovedOutOfScreen(mAccessibilityMovedOutOfScreenDirection);
+ accessibleImpl->SetLastPosition(Vector2(0.0f, 0.0f));
+ return;
+ }
+
+ accessibleImpl->SetLastPosition(Vector2(accessibleRect.x, accessibleRect.y));
+}
+
+void Control::Impl::RegisterAccessibilityPositionPropertyNotification()
+{
+ if(mIsAccessibilityPositionPropertyNotificationSet)
+ {
+ return;
+ }
+
+ mAccessibilityMovedOutOfScreenDirection = Dali::Accessibility::MovedOutOfScreenType::NONE;
+ mAccessibilityPositionNotification = mControlImpl.Self().AddPropertyNotification(Actor::Property::WORLD_POSITION, StepCondition(1.0f, 1.0f));
+ mAccessibilityPositionNotification.SetNotifyMode(PropertyNotification::NOTIFY_ON_CHANGED);
+ mAccessibilityPositionNotification.NotifySignal().Connect(this, &Control::Impl::CheckHighlightedObjectGeometry);
+ mIsAccessibilityPositionPropertyNotificationSet = true;
+}
+
+void Control::Impl::UnregisterAccessibilityPositionPropertyNotification()
+{
+ mControlImpl.Self().RemovePropertyNotification(mAccessibilityPositionNotification);
+ mIsAccessibilityPositionPropertyNotificationSet = false;
+}
+
// Gesture Detection Methods
void Control::Impl::PinchDetected(Actor actor, const PinchGesture& pinch)
{
*/
void OnIdleCallback();
+ /**
+ * @brief Checks highlighted object geometry if it is showing or not
+ * @param[in] propertyNotification PropertyNotification
+ */
+ void CheckHighlightedObjectGeometry(Dali::PropertyNotification& propertyNotification);
+
+ /**
+ * @brief Register property notification to check highlighted object position
+ */
+ void RegisterAccessibilityPositionPropertyNotification();
+
+ /**
+ * @brief Remove property notification added by RegisterPropertyNotification
+ */
+ void UnregisterAccessibilityPositionPropertyNotification();
+
public:
Control& mControlImpl;
DevelControl::State mState;
static const PropertyRegistration PROPERTY_20;
static const PropertyRegistration PROPERTY_21;
static const PropertyRegistration PROPERTY_22;
+
+private:
+ // Accessibility - notification for highlighted object to check if it is showing.
+ bool mIsAccessibilityPositionPropertyNotificationSet{false};
+ Dali::PropertyNotification mAccessibilityPositionNotification;
+ Dali::Accessibility::MovedOutOfScreenType mAccessibilityMovedOutOfScreenDirection;
};
} // namespace Internal