From f4de4250a4916b6b2171910b04f0d027e3318fc8 Mon Sep 17 00:00:00 2001 From: Kagami Sascha Rosylight Date: Tue, 29 Oct 2024 19:16:35 +0000 Subject: [PATCH] Bug 1907575 - Part 1: Add telemetry for pointing device existence r=win-reviewers,rkraesig,geckoview-reviewers,m_kato For now this is Windows/Android only right now as we don't have the same set of detection used for IntID::AllPointerCapabilities on other platforms. That work can be done separately by e.g. bug 1874292. Differential Revision: https://phabricator.services.mozilla.com/D216455 --- .../java/org/mozilla/gecko/GeckoAppShell.java | 52 +++++++++++++++++++ toolkit/modules/Troubleshoot.sys.mjs | 16 ++++-- widget/LookAndFeel.h | 16 ++++++ widget/android/nsLookAndFeel.cpp | 4 ++ widget/metrics.yaml | 17 ++++++ widget/nsXPLookAndFeel.cpp | 15 ++++++ widget/windows/WinUtils.cpp | 39 ++------------ widget/windows/WinUtils.h | 8 +-- widget/windows/nsLookAndFeel.cpp | 15 ++++++ xpcom/base/nsSystemInfo.cpp | 21 +++++--- 10 files changed, 155 insertions(+), 48 deletions(-) diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java index 16ec6a79bc46..b0f5cf1d9fa7 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -1394,6 +1394,58 @@ public class GeckoAppShell { return result; } + /* + * Keep in sync with PointingDevices in LookAndFeel.h + */ + private static final int POINTING_DEVICE_NONE = 0x00000000; + private static final int POINTING_DEVICE_MOUSE = 0x00000001; + private static final int POINTING_DEVICE_TOUCH = 0x00000002; + private static final int POINTING_DEVICE_PEN = 0x00000004; + + private static int getPointingDeviceKinds(final InputDevice inputDevice) { + int result = POINTING_DEVICE_NONE; + final int sources = inputDevice.getSources(); + + // TODO(krosylight): For now this code is for telemetry purpose, but ultimately we want to + // replace the capabilities code above and move the capabilities computation into layout. We'll + // then have to add all the extra devices too that are not mouse/touch/pen. (Bug 1918207) + // We don't treat other devices properly for pointerType after all: + // https://searchfox.org/mozilla-central/rev/3b59c739df66574d94022a684596845cd05e7c65/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/PanZoomController.java#749-761 + + if (hasInputDeviceSource(sources, InputDevice.SOURCE_MOUSE)) { + result |= POINTING_DEVICE_MOUSE; + } + if (hasInputDeviceSource(sources, InputDevice.SOURCE_TOUCHSCREEN)) { + result |= POINTING_DEVICE_TOUCH; + } + if (hasInputDeviceSource(sources, InputDevice.SOURCE_STYLUS)) { + result |= POINTING_DEVICE_PEN; + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M + && hasInputDeviceSource(sources, InputDevice.SOURCE_BLUETOOTH_STYLUS)) { + result |= POINTING_DEVICE_PEN; + } + + return result; + } + + @WrapForJNI(calledFrom = "gecko") + // For pointing devices telemetry. + private static int getPointingDeviceKinds() { + int result = POINTING_DEVICE_NONE; + + for (final int deviceId : InputDevice.getDeviceIds()) { + final InputDevice inputDevice = InputDevice.getDevice(deviceId); + if (inputDevice == null || !InputDeviceUtils.isPointerTypeDevice(inputDevice)) { + continue; + } + + result |= getPointingDeviceKinds(inputDevice); + } + + return result; + } + private static boolean hasInputDeviceSource(final int sources, final int inputDeviceSource) { return (sources & inputDeviceSource) == inputDeviceSource; } diff --git a/toolkit/modules/Troubleshoot.sys.mjs b/toolkit/modules/Troubleshoot.sys.mjs index 2fa854b7b7c9..ae0d808de2f9 100644 --- a/toolkit/modules/Troubleshoot.sys.mjs +++ b/toolkit/modules/Troubleshoot.sys.mjs @@ -257,9 +257,19 @@ var dataProviders = { try { // Windows - Get info about attached pointing devices - data.pointingDevices = Services.sysinfo - .getProperty("pointingDevices") - .split(","); + data.pointingDevices = []; + if (Services.sysinfo.getProperty("hasMouse")) { + data.pointingDevices.push("pointing-device-mouse"); + } + if (Services.sysinfo.getProperty("hasTouch")) { + data.pointingDevices.push("pointing-device-touchscreen"); + } + if (Services.sysinfo.getProperty("hasPen")) { + data.pointingDevices.push("pointing-device-pen-digitizer"); + } + if (!data.pointingDevices.length) { + data.pointingDevices.push("pointing-device-none"); + } } catch (e) {} data.numTotalWindows = 0; diff --git a/widget/LookAndFeel.h b/widget/LookAndFeel.h index efc713d0f48d..95f1d701cc15 100644 --- a/widget/LookAndFeel.h +++ b/widget/LookAndFeel.h @@ -321,6 +321,13 @@ class LookAndFeel { /* Whether macOS' full keyboard access is enabled */ FullKeyboardAccess, + // TODO(krosylight): This should ultimately be able to replace + // IntID::AllPointerCapabilities. (Bug 1918207) + // + // Note that PrimaryPointerCapabilities may not be replaceable as it has a + // bit more system specific heuristic, e.g. IsTabletMode on Windows. + PointingDeviceKinds, + /* * Not an ID; used to define the range of valid IDs. Must be last. */ @@ -389,6 +396,13 @@ class LookAndFeel { using FontID = mozilla::StyleSystemFont; + enum class PointingDeviceKinds : uint8_t { + None = 0, + Mouse = 1 << 0, + Touch = 1 << 1, + Pen = 1 << 2, + }; + static ColorScheme SystemColorScheme() { return GetInt(IntID::SystemUsesDarkTheme) ? ColorScheme::Dark : ColorScheme::Light; @@ -574,6 +588,8 @@ class LookAndFeel { static bool sGlobalThemeChanged; }; +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(LookAndFeel::PointingDeviceKinds); + } // namespace mozilla // --------------------------------------------------------------------- diff --git a/widget/android/nsLookAndFeel.cpp b/widget/android/nsLookAndFeel.cpp index d13dbbdb8367..7aa6f09bcff1 100644 --- a/widget/android/nsLookAndFeel.cpp +++ b/widget/android/nsLookAndFeel.cpp @@ -384,6 +384,10 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) { aResult = 1; break; + case IntID::PointingDeviceKinds: + aResult = java::GeckoAppShell::GetPointingDeviceKinds(); + break; + default: aResult = 0; rv = NS_ERROR_FAILURE; diff --git a/widget/metrics.yaml b/widget/metrics.yaml index ff143ccc19c0..f30e05ab6397 100644 --- a/widget/metrics.yaml +++ b/widget/metrics.yaml @@ -26,3 +26,20 @@ widget: - cmccormack@mozilla.com expires: never telemetry_mirror: WIDGET_DARK_MODE + + pointing_devices: + type: labeled_boolean + labels: + - mouse + - touch + - pen + description: > + Whether the system has any matching pointing device for each label. + bugs: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1907575 + data_reviews: + - https://bugzilla.mozilla.org/show_bug.cgi?id=1907575 + notification_emails: + - krosylight@mozilla.com + - dom-core@mozilla.com + expires: never diff --git a/widget/nsXPLookAndFeel.cpp b/widget/nsXPLookAndFeel.cpp index c04aef164506..f4cd71008278 100644 --- a/widget/nsXPLookAndFeel.cpp +++ b/widget/nsXPLookAndFeel.cpp @@ -22,6 +22,7 @@ #include "SurfaceCacheUtils.h" #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentChild.h" +#include "mozilla/glean/GleanMetrics.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" #include "mozilla/ServoStyleSet.h" @@ -192,6 +193,7 @@ static const char sIntPrefs[][45] = { "ui.hideCursorWhileTyping", "ui.gtkThemeFamily", "ui.fullKeyboardAccess", + "ui.pointingDeviceKinds", }; static_assert(std::size(sIntPrefs) == size_t(LookAndFeel::IntID::End), @@ -1166,6 +1168,19 @@ void nsXPLookAndFeel::RecordTelemetry() { glean::widget::dark_mode.Set( NS_SUCCEEDED(GetIntValue(IntID::SystemUsesDarkTheme, i)) && i != 0); + auto devices = + static_cast(GetInt(IntID::PointingDeviceKinds, 0)); + + glean::widget::pointing_devices + .EnumGet(glean::widget::PointingDevicesLabel::eMouse) + .Set(!!(devices & PointingDeviceKinds::Mouse)); + glean::widget::pointing_devices + .EnumGet(glean::widget::PointingDevicesLabel::eTouch) + .Set(!!(devices & PointingDeviceKinds::Touch)); + glean::widget::pointing_devices + .EnumGet(glean::widget::PointingDevicesLabel::ePen) + .Set(!!(devices & PointingDeviceKinds::Pen)); + RecordLookAndFeelSpecificTelemetry(); } diff --git a/widget/windows/WinUtils.cpp b/widget/windows/WinUtils.cpp index 29a0bef64178..256f030536c5 100644 --- a/widget/windows/WinUtils.cpp +++ b/widget/windows/WinUtils.cpp @@ -1615,7 +1615,7 @@ static bool IsTabletDevice() { return false; } -static bool SystemHasMouse() { +bool WinUtils::SystemHasMouse() { // As per MSDN, this value is rarely false because of virtual mice, and // some machines report the existance of a mouse port as a mouse. // @@ -1642,13 +1642,13 @@ PointerCapabilities WinUtils::GetPrimaryPointerCapabilities() { return PointerCapabilities::None; } -static bool SystemHasTouchscreen() { +bool WinUtils::SystemHasTouch() { int digitizerMetrics = ::GetSystemMetrics(SM_DIGITIZER); return (digitizerMetrics & NID_INTEGRATED_TOUCH) || (digitizerMetrics & NID_EXTERNAL_TOUCH); } -static bool SystemHasPenDigitizer() { +bool WinUtils::SystemHasPen() { int digitizerMetrics = ::GetSystemMetrics(SM_DIGITIZER); return (digitizerMetrics & NID_INTEGRATED_PEN) || (digitizerMetrics & NID_EXTERNAL_PEN); @@ -1658,11 +1658,11 @@ static bool SystemHasPenDigitizer() { PointerCapabilities WinUtils::GetAllPointerCapabilities() { PointerCapabilities pointerCapabilities = PointerCapabilities::None; - if (SystemHasTouchscreen()) { + if (SystemHasTouch()) { pointerCapabilities |= PointerCapabilities::Coarse; } - if (SystemHasPenDigitizer() || SystemHasMouse()) { + if (SystemHasPen() || SystemHasMouse()) { pointerCapabilities |= PointerCapabilities::Fine | PointerCapabilities::Hover; } @@ -1670,35 +1670,6 @@ PointerCapabilities WinUtils::GetAllPointerCapabilities() { return pointerCapabilities; } -void WinUtils::GetPointerExplanation(nsAString* aExplanation) { - // To support localization, we will return a comma-separated list of - // Fluent IDs - *aExplanation = u"pointing-device-none"; - - bool first = true; - auto append = [&](const char16_t* str) { - if (first) { - aExplanation->Truncate(); - first = false; - } else { - aExplanation->Append(u","); - } - aExplanation->Append(str); - }; - - if (SystemHasTouchscreen()) { - append(u"pointing-device-touchscreen"); - } - - if (SystemHasPenDigitizer()) { - append(u"pointing-device-pen-digitizer"); - } - - if (SystemHasMouse()) { - append(u"pointing-device-mouse"); - } -} - /* static */ bool WinUtils::ResolveJunctionPointsAndSymLinks(std::wstring& aPath) { LOG_D("ResolveJunctionPointsAndSymLinks: Resolving path: %S", aPath.c_str()); diff --git a/widget/windows/WinUtils.h b/widget/windows/WinUtils.h index e6d0a2481004..43f2ad3407b8 100644 --- a/widget/windows/WinUtils.h +++ b/widget/windows/WinUtils.h @@ -463,9 +463,11 @@ class WinUtils { static PointerCapabilities GetPrimaryPointerCapabilities(); // For any-pointer and any-hover media queries features. static PointerCapabilities GetAllPointerCapabilities(); - // Returns a string containing a comma-separated list of Fluent IDs - // representing the currently active pointing devices - static void GetPointerExplanation(nsAString* aExplanation); + + // Returns whether the system has any active device for each pointer type. + static bool SystemHasMouse(); + static bool SystemHasTouch(); + static bool SystemHasPen(); /** * Fully resolves a path to its final path name. So if path contains diff --git a/widget/windows/nsLookAndFeel.cpp b/widget/windows/nsLookAndFeel.cpp index 58c5fc3b55da..7a5181a523b8 100644 --- a/widget/windows/nsLookAndFeel.cpp +++ b/widget/windows/nsLookAndFeel.cpp @@ -600,6 +600,21 @@ nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) { aResult = enable; break; } + case IntID::PointingDeviceKinds: { + LookAndFeel::PointingDeviceKinds result = + LookAndFeel::PointingDeviceKinds::None; + if (WinUtils::SystemHasMouse()) { + result |= LookAndFeel::PointingDeviceKinds::Mouse; + } + if (WinUtils::SystemHasTouch()) { + result |= LookAndFeel::PointingDeviceKinds::Touch; + } + if (WinUtils::SystemHasPen()) { + result |= LookAndFeel::PointingDeviceKinds::Pen; + } + aResult = static_cast(result); + break; + } default: aResult = 0; res = NS_ERROR_FAILURE; diff --git a/xpcom/base/nsSystemInfo.cpp b/xpcom/base/nsSystemInfo.cpp index 0f0569126342..84700ed853ff 100644 --- a/xpcom/base/nsSystemInfo.cpp +++ b/xpcom/base/nsSystemInfo.cpp @@ -1460,15 +1460,20 @@ nsresult nsSystemInfo::Init() { return rv; } - if (XRE_IsParentProcess()) { - nsString pointerExplanation; - widget::WinUtils::GetPointerExplanation(&pointerExplanation); - rv = SetPropertyAsAString(u"pointingDevices"_ns, pointerExplanation); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } +#endif +#if defined(XP_WIN) || defined(ANDROID) + // TODO(krosylight): Enable this on other platforms too when implemented + if (XRE_IsParentProcess()) { + auto kinds = static_cast( + LookAndFeel::GetInt(LookAndFeel::IntID::PointingDeviceKinds, 0)); + MOZ_TRY(SetPropertyAsBool( + u"hasMouse"_ns, !!(kinds & LookAndFeel::PointingDeviceKinds::Mouse))); + MOZ_TRY(SetPropertyAsBool( + u"hasTouch"_ns, !!(kinds & LookAndFeel::PointingDeviceKinds::Touch))); + MOZ_TRY(SetPropertyAsBool( + u"hasPen"_ns, !!(kinds & LookAndFeel::PointingDeviceKinds::Pen))); + } #endif #if defined(XP_MACOSX)