summaryrefslogtreecommitdiffstats
path: root/accessible/android/Platform.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'accessible/android/Platform.cpp')
-rw-r--r--accessible/android/Platform.cpp256
1 files changed, 256 insertions, 0 deletions
diff --git a/accessible/android/Platform.cpp b/accessible/android/Platform.cpp
new file mode 100644
index 0000000000..4d17d8be72
--- /dev/null
+++ b/accessible/android/Platform.cpp
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Platform.h"
+#include "ProxyAccessibleWrap.h"
+#include "DocAccessibleWrap.h"
+#include "SessionAccessibility.h"
+#include "mozilla/a11y/ProxyAccessible.h"
+#include "nsIAccessibleEvent.h"
+#include "nsIAccessiblePivot.h"
+#include "nsIStringBundle.h"
+
+#define ROLE_STRINGS_URL "chrome://global/locale/AccessFu.properties"
+
+using namespace mozilla;
+using namespace mozilla::a11y;
+
+static nsIStringBundle* sStringBundle;
+
+void a11y::PlatformInit() {}
+
+void a11y::PlatformShutdown() { NS_IF_RELEASE(sStringBundle); }
+
+void a11y::ProxyCreated(ProxyAccessible* aProxy, uint32_t aInterfaces) {
+ AccessibleWrap* wrapper = nullptr;
+ if (aProxy->IsDoc()) {
+ wrapper = new DocProxyAccessibleWrap(aProxy->AsDoc());
+ } else {
+ wrapper = new ProxyAccessibleWrap(aProxy);
+ }
+
+ wrapper->AddRef();
+ aProxy->SetWrapper(reinterpret_cast<uintptr_t>(wrapper));
+}
+
+void a11y::ProxyDestroyed(ProxyAccessible* aProxy) {
+ AccessibleWrap* wrapper =
+ reinterpret_cast<AccessibleWrap*>(aProxy->GetWrapper());
+
+ // If aProxy is a document that was created, but
+ // RecvPDocAccessibleConstructor failed then aProxy->GetWrapper() will be
+ // null.
+ if (!wrapper) {
+ return;
+ }
+
+ wrapper->Shutdown();
+ aProxy->SetWrapper(0);
+ wrapper->Release();
+}
+
+void a11y::ProxyEvent(ProxyAccessible* aTarget, uint32_t aEventType) {
+ RefPtr<SessionAccessibility> sessionAcc =
+ SessionAccessibility::GetInstanceFor(aTarget);
+ if (!sessionAcc) {
+ return;
+ }
+
+ switch (aEventType) {
+ case nsIAccessibleEvent::EVENT_FOCUS:
+ sessionAcc->SendFocusEvent(WrapperFor(aTarget));
+ break;
+ }
+}
+
+void a11y::ProxyStateChangeEvent(ProxyAccessible* aTarget, uint64_t aState,
+ bool aEnabled) {
+ RefPtr<SessionAccessibility> sessionAcc =
+ SessionAccessibility::GetInstanceFor(aTarget);
+
+ if (!sessionAcc) {
+ return;
+ }
+
+ if (aState & states::CHECKED) {
+ sessionAcc->SendClickedEvent(
+ WrapperFor(aTarget),
+ java::SessionAccessibility::FLAG_CHECKABLE |
+ (aEnabled ? java::SessionAccessibility::FLAG_CHECKED : 0));
+ }
+
+ if (aState & states::EXPANDED) {
+ sessionAcc->SendClickedEvent(
+ WrapperFor(aTarget),
+ java::SessionAccessibility::FLAG_EXPANDABLE |
+ (aEnabled ? java::SessionAccessibility::FLAG_EXPANDED : 0));
+ }
+
+ if (aState & states::SELECTED) {
+ sessionAcc->SendSelectedEvent(WrapperFor(aTarget), aEnabled);
+ }
+
+ if (aState & states::BUSY) {
+ sessionAcc->SendWindowStateChangedEvent(WrapperFor(aTarget));
+ }
+}
+
+void a11y::ProxyCaretMoveEvent(ProxyAccessible* aTarget, int32_t aOffset,
+ bool aIsSelectionCollapsed) {
+ RefPtr<SessionAccessibility> sessionAcc =
+ SessionAccessibility::GetInstanceFor(aTarget);
+
+ if (sessionAcc) {
+ sessionAcc->SendTextSelectionChangedEvent(WrapperFor(aTarget), aOffset);
+ }
+}
+
+void a11y::ProxyTextChangeEvent(ProxyAccessible* aTarget, const nsString& aStr,
+ int32_t aStart, uint32_t aLen, bool aIsInsert,
+ bool aFromUser) {
+ RefPtr<SessionAccessibility> sessionAcc =
+ SessionAccessibility::GetInstanceFor(aTarget);
+
+ if (sessionAcc) {
+ sessionAcc->SendTextChangedEvent(WrapperFor(aTarget), aStr, aStart, aLen,
+ aIsInsert, aFromUser);
+ }
+}
+
+void a11y::ProxyShowHideEvent(ProxyAccessible* aTarget,
+ ProxyAccessible* aParent, bool aInsert,
+ bool aFromUser) {
+ // We rely on the window content changed events to be dispatched
+ // after the viewport cache is refreshed.
+}
+
+void a11y::ProxySelectionEvent(ProxyAccessible*, ProxyAccessible*, uint32_t) {}
+
+void a11y::ProxyVirtualCursorChangeEvent(
+ ProxyAccessible* aTarget, ProxyAccessible* aOldPosition,
+ int32_t aOldStartOffset, int32_t aOldEndOffset,
+ ProxyAccessible* aNewPosition, int32_t aNewStartOffset,
+ int32_t aNewEndOffset, int16_t aReason, int16_t aBoundaryType,
+ bool aFromUser) {
+ if (!aNewPosition || !aFromUser) {
+ return;
+ }
+
+ RefPtr<SessionAccessibility> sessionAcc =
+ SessionAccessibility::GetInstanceFor(aTarget);
+
+ if (!sessionAcc) {
+ return;
+ }
+
+ if (aReason == nsIAccessiblePivot::REASON_POINT) {
+ sessionAcc->SendHoverEnterEvent(WrapperFor(aNewPosition));
+ } else if (aBoundaryType == nsIAccessiblePivot::NO_BOUNDARY) {
+ RefPtr<AccessibleWrap> wrapperForNewPosition = WrapperFor(aNewPosition);
+ sessionAcc->SendAccessibilityFocusedEvent(wrapperForNewPosition);
+ }
+
+ if (aBoundaryType != nsIAccessiblePivot::NO_BOUNDARY) {
+ sessionAcc->SendTextTraversedEvent(WrapperFor(aNewPosition),
+ aNewStartOffset, aNewEndOffset);
+ }
+}
+
+void a11y::ProxyScrollingEvent(ProxyAccessible* aTarget, uint32_t aEventType,
+ uint32_t aScrollX, uint32_t aScrollY,
+ uint32_t aMaxScrollX, uint32_t aMaxScrollY) {
+ if (aEventType == nsIAccessibleEvent::EVENT_SCROLLING) {
+ RefPtr<SessionAccessibility> sessionAcc =
+ SessionAccessibility::GetInstanceFor(aTarget);
+
+ if (sessionAcc) {
+ sessionAcc->SendScrollingEvent(WrapperFor(aTarget), aScrollX, aScrollY,
+ aMaxScrollX, aMaxScrollY);
+ }
+ }
+}
+
+void a11y::ProxyAnnouncementEvent(ProxyAccessible* aTarget,
+ const nsString& aAnnouncement,
+ uint16_t aPriority) {
+ RefPtr<SessionAccessibility> sessionAcc =
+ SessionAccessibility::GetInstanceFor(aTarget);
+
+ if (sessionAcc) {
+ sessionAcc->SendAnnouncementEvent(WrapperFor(aTarget), aAnnouncement,
+ aPriority);
+ }
+}
+
+void a11y::ProxyBatch(ProxyAccessible* aDocument, const uint64_t aBatchType,
+ const nsTArray<ProxyAccessible*>& aAccessibles,
+ const nsTArray<BatchData>& aData) {
+ RefPtr<SessionAccessibility> sessionAcc =
+ SessionAccessibility::GetInstanceFor(aDocument);
+ if (!sessionAcc) {
+ return;
+ }
+
+ nsTArray<AccessibleWrap*> accWraps(aAccessibles.Length());
+ for (size_t i = 0; i < aAccessibles.Length(); i++) {
+ accWraps.AppendElement(WrapperFor(aAccessibles.ElementAt(i)));
+ }
+
+ switch (aBatchType) {
+ case DocAccessibleWrap::eBatch_Viewport:
+ sessionAcc->ReplaceViewportCache(accWraps, aData);
+ break;
+ case DocAccessibleWrap::eBatch_FocusPath:
+ sessionAcc->ReplaceFocusPathCache(accWraps, aData);
+ break;
+ case DocAccessibleWrap::eBatch_BoundsUpdate:
+ sessionAcc->UpdateCachedBounds(accWraps, aData);
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unknown batch type.");
+ break;
+ }
+}
+
+bool a11y::LocalizeString(const char* aToken, nsAString& aLocalized,
+ const nsTArray<nsString>& aFormatString) {
+ MOZ_ASSERT(XRE_IsParentProcess());
+ nsresult rv = NS_OK;
+ if (!sStringBundle) {
+ nsCOMPtr<nsIStringBundleService> sbs = services::GetStringBundleService();
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Failed to get string bundle service");
+ return false;
+ }
+
+ nsCOMPtr<nsIStringBundle> sb;
+ rv = sbs->CreateBundle(ROLE_STRINGS_URL, getter_AddRefs(sb));
+ if (NS_FAILED(rv)) {
+ NS_WARNING("Failed to get string bundle");
+ return false;
+ }
+
+ sb.forget(&sStringBundle);
+ }
+
+ MOZ_ASSERT(sStringBundle);
+
+ if (aFormatString.Length()) {
+ rv = sStringBundle->FormatStringFromName(aToken, aFormatString, aLocalized);
+ if (NS_SUCCEEDED(rv)) {
+ return true;
+ }
+ } else {
+ rv = sStringBundle->GetStringFromName(aToken, aLocalized);
+ if (NS_SUCCEEDED(rv)) {
+ return true;
+ }
+ }
+
+ NS_WARNING("Failed to localize string");
+ aLocalized.AssignLiteral("");
+ return false;
+}