From 83bfa9a5d37958405b52c0a6a08f889f17e6ae9d Mon Sep 17 00:00:00 2001 From: yschermer Date: Fri, 28 Jul 2023 15:34:13 +0200 Subject: [PATCH 1/5] Add screen size --- README.md | 1 + .../collector/AccessibilityCollector.kt | 66 +++++++++++++++++-- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 26e6f7e..e7c2e95 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ versions of Android. If unsupported, the corresponding key is omitted. | Key | Value | Notes | |-|-|-| | `screenOrientation`| portrait, landscape, unknown | +| `screenSize` | String | Screen size in density-independent pixels and portrait mode. | ### System diff --git a/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt b/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt index 4c2e475..b9a56cf 100644 --- a/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt +++ b/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt @@ -6,9 +6,11 @@ import android.content.Context.ACCESSIBILITY_SERVICE import android.content.Context.CAPTIONING_SERVICE import android.content.res.Configuration.ORIENTATION_LANDSCAPE import android.content.res.Configuration.ORIENTATION_PORTRAIT +import android.graphics.Point import android.os.Build import android.provider.Settings import android.util.DisplayMetrics +import android.view.WindowManager import android.view.accessibility.AccessibilityManager import android.view.accessibility.CaptioningManager import androidx.annotation.RequiresApi @@ -82,7 +84,7 @@ internal object AccessibilityCollector { ) } } - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1){ + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { put( "isAnimationsDisabled", isAnimationsDisabled(context) @@ -101,6 +103,12 @@ internal object AccessibilityCollector { } }) + getScreenSize(context)?.let { + put( + "screenSize", + it + ) + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { getSystemIntAsBool( @@ -146,7 +154,7 @@ internal object AccessibilityCollector { */ @RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR1) private fun isMagnificationEnabled(context: Context, serviceNames: List): Boolean? = try { - val isMagnificationByTripleTapGesturesEnabled = getSystemIntAsBool(context,"accessibility_display_magnification_enabled") ?: false + val isMagnificationByTripleTapGesturesEnabled = getSystemIntAsBool(context, "accessibility_display_magnification_enabled") ?: false val isMagnificationByVolumeButtonsEnabled = serviceNames.map { s -> s.lowercase() }.contains("com.example.android.apis.accessibility.magnificationservice") if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { @@ -154,11 +162,11 @@ internal object AccessibilityCollector { Settings.Secure.getString(context.contentResolver, "accessibility_button_targets").lowercase().contains("com.android.server.accessibility.magnificationcontroller") isMagnificationByTripleTapGesturesEnabled || isMagnificationByVolumeButtonsEnabled || isMagnificationByNavigationButtonEnabled - }else{ + } else { isMagnificationByTripleTapGesturesEnabled || isMagnificationByVolumeButtonsEnabled } } catch (e: Throwable) { - Q42StatsLogger.e(TAG, "Could not read magnification. Returning null", e) + Q42StatsLogger.w(TAG, "Could not read magnification, user likely has never used magnification before. Returning null.") null } @@ -181,4 +189,54 @@ internal object AccessibilityCollector { Q42StatsLogger.e(TAG, "Could not read system int $name. Returning null", e) null } + + /** + * Gets the screen size in density independent pixels with portrait orientation. + * + * Note: calculates size given portrait mode. + */ + private fun getScreenSize(context: Context): Pair? { + return try { + val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + val resources = context.resources + + // get screen size in pixels + val pixelScreenSize = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val windowMetrics = windowManager.currentWindowMetrics + with(windowMetrics.bounds) { + Pair(right, bottom) + } + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + val point = Point() + @Suppress("DEPRECATION") + windowManager.defaultDisplay.getRealSize(point) + Pair(point.x, point.y) + } else { + with(resources.displayMetrics) { + Pair(widthPixels, heightPixels) + } + } + + // get screen size in portrait mode + val portraitScreenSize = with(pixelScreenSize) { + if (resources.configuration.orientation == ORIENTATION_LANDSCAPE) { + Pair(second, first) + } else { + Pair(first, second) + } + } + + val portraitDpScreenSize = with(portraitScreenSize) { + val density = resources.displayMetrics.density + Pair( + (first / density).toInt(), + (second / density).toInt() + ) + } + portraitDpScreenSize + } catch (e: Throwable) { + Q42StatsLogger.e(TAG, "Could not read screen size. Returning null", e) + null + } + } } From 3ea229f1aa0e2bfa7b81bffb857ad15adb26b531 Mon Sep 17 00:00:00 2001 From: yschermer Date: Fri, 8 Sep 2023 15:03:37 +0200 Subject: [PATCH 2/5] fix screen size to simply screen width --- README.md | 2 +- .../library/collector/AccessibilityCollector.kt | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e7c2e95..b5ab9aa 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ versions of Android. If unsupported, the corresponding key is omitted. | Key | Value | Notes | |-|-|-| | `screenOrientation`| portrait, landscape, unknown | -| `screenSize` | String | Screen size in density-independent pixels and portrait mode. | +| `screenWidth` | String | Screen width in density-independent pixels and portrait mode. | ### System diff --git a/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt b/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt index b9a56cf..4d58a31 100644 --- a/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt +++ b/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt @@ -105,7 +105,7 @@ internal object AccessibilityCollector { getScreenSize(context)?.let { put( - "screenSize", + "screenWidth", it ) } @@ -195,7 +195,7 @@ internal object AccessibilityCollector { * * Note: calculates size given portrait mode. */ - private fun getScreenSize(context: Context): Pair? { + private fun getScreenSize(context: Context): Int? { return try { val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager val resources = context.resources @@ -220,18 +220,15 @@ internal object AccessibilityCollector { // get screen size in portrait mode val portraitScreenSize = with(pixelScreenSize) { if (resources.configuration.orientation == ORIENTATION_LANDSCAPE) { - Pair(second, first) + second } else { - Pair(first, second) + first } } val portraitDpScreenSize = with(portraitScreenSize) { val density = resources.displayMetrics.density - Pair( - (first / density).toInt(), - (second / density).toInt() - ) + (this / density).toInt() } portraitDpScreenSize } catch (e: Throwable) { From 59765214f255cfc54ea196f6645db4903d633270 Mon Sep 17 00:00:00 2001 From: yschermer Date: Fri, 8 Sep 2023 15:10:48 +0200 Subject: [PATCH 3/5] Add screenheight as well, remove always portrait mode check --- README.md | 53 ++++++++++++------- .../collector/AccessibilityCollector.kt | 24 ++++----- 2 files changed, 46 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index b5ab9aa..71768a0 100644 --- a/README.md +++ b/README.md @@ -80,30 +80,40 @@ versions of Android. If unsupported, the corresponding key is omitted. ### Accessibliity | Key | Value | Notes | -|-|-|-| +|-|-|-| | `isClosedCaptioningEnabled` | bool | Live transcription of any spoken audio (minSdk >= 19) | -| `isTouchExplorationEnabled` | bool | Whether any assistive feature is enabled where the user navigates the interface by touch. Most probably TalkBack, or similar +| `isTouchExplorationEnabled` | bool | Whether any assistive feature is enabled where the user +navigates the interface by touch. Most probably TalkBack, or similar | `isTalkBackEnabled` | bool | iOS: VoiceOver -| `isSamsungTalkBackEnabled` | bool | Specifically checks whether com.samsung.android.app.talkback.talkbackservice is enabled +| `isSamsungTalkBackEnabled` | bool | Specifically checks whether +com.samsung.android.app.talkback.talkbackservice is enabled | `isSelectToSpeakEnabled` | bool | iOS: Speak Selection | `isSwitchAccessEnabled` | bool | Control the device by a switch such as a foot pedal | `isBrailleBackEnabled` | bool | Navigate the screen with an external Braille display | `isVoiceAccessEnabled` | bool | iOS: Voice Control -| `fontScale` | float | Default value depends on device model. Some devices have a default font scaling of 1.1, for example | -| `fontWeightAdjustment` | float | Default value is: 0. When bold text is enabled this value is greater than 0 (minSdk >= 31). Known issue: Always returns 0 on Samsung | -| `displayScale` | float | Overall interface scaling ie. display density scaling. Default value may depend on device model (minSdk >= 24)| -| `isMagnificationEnabled` | bool | Whether magnification is enabled (more specifically, whether magnification shortcuts are enabled) (minSdk >= 17). | +| `fontScale` | float | Default value depends on device model. Some devices have a default font +scaling of 1.1, for example | +| `fontWeightAdjustment` | float | Default value is: 0. When bold text is enabled this value is +greater than 0 (minSdk >= 31). Known issue: Always returns 0 on Samsung | +| `displayScale` | float | Overall interface scaling ie. display density scaling. Default value may +depend on device model (minSdk >= 24)| +| `isMagnificationEnabled` | bool | Whether magnification is enabled (more specifically, whether +magnification shortcuts are enabled) (minSdk >= 17). | | `isColorInversionEnabled` | bool | Available starting from Android 5.0 (>=21) | | `isColorBlindModeEnabled` | bool | | -| `isHighTextContrastEnabled` | bool | When enabled, all text has a thin outline. Available starting from Android 5.0 (>=21) | -| `isAnimationsDisabled` | bool | Can be disabled pre-Android 9 (<28) through Developer Options, starting from Android 9 possible to any user (minSdk >= 19). | -| `enabledAccessibilityServices` | Array\ | List of enabled accessibility package names, eg ['com.accessibility.service1', 'nl.accessibility.service2'] | +| `isHighTextContrastEnabled` | bool | When enabled, all text has a thin outline. Available starting +from Android 5.0 (>=21) | +| `isAnimationsDisabled` | bool | Can be disabled pre-Android 9 (<28) through Developer Options, +starting from Android 9 possible to any user (minSdk >= 19). | +| `enabledAccessibilityServices` | Array\ | List of enabled accessibility package names, +eg ['com.accessibility.service1', 'nl.accessibility.service2'] | ### Preferences | Key | Value | Notes | |-|-|-| -| `daytime`| day, twilight, night, unknown | Coarse estimation of time of day. unknown if user is not in Amsterdam TimeZone +| `daytime`| day, twilight, night, unknown | Coarse estimation of time of day. unknown if user is +not in Amsterdam TimeZone | `isNightModeEnabled` | bool | iOS: Dark Mode (minSdk: 29) ### Screen @@ -111,18 +121,24 @@ versions of Android. If unsupported, the corresponding key is omitted. | Key | Value | Notes | |-|-|-| | `screenOrientation`| portrait, landscape, unknown | -| `screenWidth` | String | Screen width in density-independent pixels and portrait mode. | +| `screenWidth` | String | Screen width in density-independent pixels. Beware: this value is +different when there is a different screen orientation. | +| `screenHeight` | String | Screen height in density-independent pixels. Beware: this value is +different when there is a different screen orientation. | ### System | Key | Value | Notes | |-|-|-| -| `applicationId` | String | identifier for the app for which data is collected, as set in the app's Manifest. iOS: bundleId | nl.hema.mobiel | -| `defaultLanguage`| en-GB, nl-BE, nl, ... | If the country part (-BE) is not available, the value is just the language part ("nl") -| `sdkVersion` | int | 29 for Android 10. [See this list](https://source.android.com/setup/start/build-numbers) +| `applicationId` | String | identifier for the app for which data is collected, as set in the app's +Manifest. iOS: bundleId | nl.hema.mobiel | +| `defaultLanguage`| en-GB, nl-BE, nl, ... | If the country part (-BE) is not available, the value +is just the language part ("nl") +| `sdkVersion` | int | 29 for Android +10. [See this list](https://source.android.com/setup/start/build-numbers) |`manufacturer`|String|eg. `samsung`| -|`modelName`|String| May be a marketing name, but more often an internal code name. eg. `SM-G980F` for a particular variant of a Samsung Galaxy S10| - +|`modelName`|String| May be a marketing name, but more often an internal code name. eg. `SM-G980F` +for a particular variant of a Samsung Galaxy S10| ## Development @@ -136,7 +152,8 @@ exceptions don't crash the implementing apps. Catch Throwable; not Exception. Since Throwabl is the superclass of Exception, this will make the lib more resilient to crashes. -For accessibility properties we want to track but could not find a property for, see [DOCUMENTATION.md](DOCUMENTATION.md) +For accessibility properties we want to track but could not find a property for, +see [DOCUMENTATION.md](DOCUMENTATION.md) ### Setup diff --git a/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt b/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt index 4d58a31..15fc6ef 100644 --- a/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt +++ b/q42stats/src/main/java/com/q42/q42stats/library/collector/AccessibilityCollector.kt @@ -106,7 +106,11 @@ internal object AccessibilityCollector { getScreenSize(context)?.let { put( "screenWidth", - it + it.first + ) + put( + "screenHeight", + it.second ) } @@ -195,7 +199,7 @@ internal object AccessibilityCollector { * * Note: calculates size given portrait mode. */ - private fun getScreenSize(context: Context): Int? { + private fun getScreenSize(context: Context): Pair? { return try { val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager val resources = context.resources @@ -217,18 +221,12 @@ internal object AccessibilityCollector { } } - // get screen size in portrait mode - val portraitScreenSize = with(pixelScreenSize) { - if (resources.configuration.orientation == ORIENTATION_LANDSCAPE) { - second - } else { - first - } - } - - val portraitDpScreenSize = with(portraitScreenSize) { + val portraitDpScreenSize = with(pixelScreenSize) { val density = resources.displayMetrics.density - (this / density).toInt() + Pair( + (first / density).toInt(), + (second / density).toInt() + ) } portraitDpScreenSize } catch (e: Throwable) { From 42e346b5296a73019112e0683d79412a7725e671 Mon Sep 17 00:00:00 2001 From: yschermer Date: Fri, 8 Sep 2023 15:11:48 +0200 Subject: [PATCH 4/5] update readme --- README.md | 54 +++++++++++++++++++----------------------------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 71768a0..cd02cc0 100644 --- a/README.md +++ b/README.md @@ -80,40 +80,30 @@ versions of Android. If unsupported, the corresponding key is omitted. ### Accessibliity | Key | Value | Notes | -|-|-|-| +|-|-|-| | `isClosedCaptioningEnabled` | bool | Live transcription of any spoken audio (minSdk >= 19) | -| `isTouchExplorationEnabled` | bool | Whether any assistive feature is enabled where the user -navigates the interface by touch. Most probably TalkBack, or similar +| `isTouchExplorationEnabled` | bool | Whether any assistive feature is enabled where the user navigates the interface by touch. Most probably TalkBack, or similar | `isTalkBackEnabled` | bool | iOS: VoiceOver -| `isSamsungTalkBackEnabled` | bool | Specifically checks whether -com.samsung.android.app.talkback.talkbackservice is enabled +| `isSamsungTalkBackEnabled` | bool | Specifically checks whether com.samsung.android.app.talkback.talkbackservice is enabled | `isSelectToSpeakEnabled` | bool | iOS: Speak Selection | `isSwitchAccessEnabled` | bool | Control the device by a switch such as a foot pedal | `isBrailleBackEnabled` | bool | Navigate the screen with an external Braille display | `isVoiceAccessEnabled` | bool | iOS: Voice Control -| `fontScale` | float | Default value depends on device model. Some devices have a default font -scaling of 1.1, for example | -| `fontWeightAdjustment` | float | Default value is: 0. When bold text is enabled this value is -greater than 0 (minSdk >= 31). Known issue: Always returns 0 on Samsung | -| `displayScale` | float | Overall interface scaling ie. display density scaling. Default value may -depend on device model (minSdk >= 24)| -| `isMagnificationEnabled` | bool | Whether magnification is enabled (more specifically, whether -magnification shortcuts are enabled) (minSdk >= 17). | +| `fontScale` | float | Default value depends on device model. Some devices have a default font scaling of 1.1, for example | +| `fontWeightAdjustment` | float | Default value is: 0. When bold text is enabled this value is greater than 0 (minSdk >= 31). Known issue: Always returns 0 on Samsung | +| `displayScale` | float | Overall interface scaling ie. display density scaling. Default value may depend on device model (minSdk >= 24)| +| `isMagnificationEnabled` | bool | Whether magnification is enabled (more specifically, whether magnification shortcuts are enabled) (minSdk >= 17). | | `isColorInversionEnabled` | bool | Available starting from Android 5.0 (>=21) | | `isColorBlindModeEnabled` | bool | | -| `isHighTextContrastEnabled` | bool | When enabled, all text has a thin outline. Available starting -from Android 5.0 (>=21) | -| `isAnimationsDisabled` | bool | Can be disabled pre-Android 9 (<28) through Developer Options, -starting from Android 9 possible to any user (minSdk >= 19). | -| `enabledAccessibilityServices` | Array\ | List of enabled accessibility package names, -eg ['com.accessibility.service1', 'nl.accessibility.service2'] | +| `isHighTextContrastEnabled` | bool | When enabled, all text has a thin outline. Available starting from Android 5.0 (>=21) | +| `isAnimationsDisabled` | bool | Can be disabled pre-Android 9 (<28) through Developer Options, starting from Android 9 possible to any user (minSdk >= 19). | +| `enabledAccessibilityServices` | Array\ | List of enabled accessibility package names, eg ['com.accessibility.service1', 'nl.accessibility.service2'] | ### Preferences | Key | Value | Notes | |-|-|-| -| `daytime`| day, twilight, night, unknown | Coarse estimation of time of day. unknown if user is -not in Amsterdam TimeZone +| `daytime`| day, twilight, night, unknown | Coarse estimation of time of day. unknown if user is not in Amsterdam TimeZone | `isNightModeEnabled` | bool | iOS: Dark Mode (minSdk: 29) ### Screen @@ -121,24 +111,19 @@ not in Amsterdam TimeZone | Key | Value | Notes | |-|-|-| | `screenOrientation`| portrait, landscape, unknown | -| `screenWidth` | String | Screen width in density-independent pixels. Beware: this value is -different when there is a different screen orientation. | -| `screenHeight` | String | Screen height in density-independent pixels. Beware: this value is -different when there is a different screen orientation. | +| `screenWidth` | String | Screen width in density-independent pixels. Beware: this value is different when there is a different screen orientation. | +| `screenHeight` | String | Screen height in density-independent pixels. Beware: this value is different when there is a different screen orientation. | ### System | Key | Value | Notes | |-|-|-| -| `applicationId` | String | identifier for the app for which data is collected, as set in the app's -Manifest. iOS: bundleId | nl.hema.mobiel | -| `defaultLanguage`| en-GB, nl-BE, nl, ... | If the country part (-BE) is not available, the value -is just the language part ("nl") -| `sdkVersion` | int | 29 for Android -10. [See this list](https://source.android.com/setup/start/build-numbers) +| `applicationId` | String | identifier for the app for which data is collected, as set in the app's Manifest. iOS: bundleId | nl.hema.mobiel | +| `defaultLanguage`| en-GB, nl-BE, nl, ... | If the country part (-BE) is not available, the value is just the language part ("nl") +| `sdkVersion` | int | 29 for Android 10. [See this list](https://source.android.com/setup/start/build-numbers) |`manufacturer`|String|eg. `samsung`| -|`modelName`|String| May be a marketing name, but more often an internal code name. eg. `SM-G980F` -for a particular variant of a Samsung Galaxy S10| +|`modelName`|String| May be a marketing name, but more often an internal code name. eg. `SM-G980F` for a particular variant of a Samsung Galaxy S10| + ## Development @@ -152,8 +137,7 @@ exceptions don't crash the implementing apps. Catch Throwable; not Exception. Since Throwabl is the superclass of Exception, this will make the lib more resilient to crashes. -For accessibility properties we want to track but could not find a property for, -see [DOCUMENTATION.md](DOCUMENTATION.md) +For accessibility properties we want to track but could not find a property for, see [DOCUMENTATION.md](DOCUMENTATION.md) ### Setup From febc55b881ded98fc6dc0292c2101adf96c103fb Mon Sep 17 00:00:00 2001 From: yschermer Date: Fri, 8 Sep 2023 15:32:48 +0200 Subject: [PATCH 5/5] bump version --- q42stats/src/main/java/com/q42/q42stats/library/Q42Stats.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/q42stats/src/main/java/com/q42/q42stats/library/Q42Stats.kt b/q42stats/src/main/java/com/q42/q42stats/library/Q42Stats.kt index ccbed37..1209191 100644 --- a/q42stats/src/main/java/com/q42/q42stats/library/Q42Stats.kt +++ b/q42stats/src/main/java/com/q42/q42stats/library/Q42Stats.kt @@ -19,7 +19,7 @@ internal const val TAG = "Q42Stats" * Version code for the data format that is sent to the server. Increment by 1 every time * you add / remove / change a field in any of the Collector classes */ -internal const val DATA_MODEL_VERSION = 4 +internal const val DATA_MODEL_VERSION = 5 class Q42Stats(private val config: Q42StatsConfig) {