From 3e66a6538ee4e43cbe03876c22d9b0810361adf6 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 27 Sep 2022 15:45:34 +0300 Subject: [PATCH] Implement use case to parse user agent. --- .../settings/devices/v2/DeviceUserAgent.kt | 20 +++-- .../devices/v2/ParseDeviceUserAgentUseCase.kt | 90 +++++++++++++++++++ 2 files changed, 104 insertions(+), 6 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/ParseDeviceUserAgentUseCase.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceUserAgent.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceUserAgent.kt index 14b02ce073..f307025d0b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceUserAgent.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceUserAgent.kt @@ -24,23 +24,31 @@ data class DeviceUserAgent( */ val deviceType: DeviceType, /** - * i.e. Google Pixel 6 + * i.e. Google */ - val deviceModel: String?, + val deviceManufacturer: String? = null, + /** + * i.e. Pixel 6 + */ + val deviceModel: String? = null, /** * i.e. Android */ - val deviceOperatingSystem: String?, + val deviceOperatingSystem: String? = null, /** * i.e. Android 11 */ - val deviceOperatingSystemVersion: String?, + val deviceOperatingSystemVersion: String? = null, /** * i.e. Element Nightly */ - val clientName: String?, + val clientName: String? = null, /** * i.e. 1.5.0 */ - val clientVersion: String?, + val clientVersion: String? = null, + /** + * i.e. Chrome + */ + val browser: String? = null, ) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/ParseDeviceUserAgentUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/ParseDeviceUserAgentUseCase.kt new file mode 100644 index 0000000000..1ea7dabbe4 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/ParseDeviceUserAgentUseCase.kt @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2 + +import im.vector.app.features.settings.devices.v2.list.DeviceType +import javax.inject.Inject + +class ParseDeviceUserAgentUseCase @Inject constructor() { + + fun execute(userAgent: String): DeviceUserAgent { + return when { + userAgent.contains(ANDROID_KEYWORD) -> parseAndroidUserAgent(userAgent) + userAgent.contains(IOS_KEYWORD) -> parseIosUserAgent(userAgent) + userAgent.contains(DESKTOP_KEYWORD) -> parseDesktopUserAgent(userAgent) + userAgent.contains(WEB_KEYWORD) -> parseWebUserAgent(userAgent) + else -> createUnknownUserAgent() + } + } + + private fun parseAndroidUserAgent(userAgent: String): DeviceUserAgent { + val appName = userAgent.substringBefore("/") + val appVersion = userAgent.substringAfter("/").substringBefore(" (") + val deviceInfoSegments = userAgent.substringAfter("(").substringBefore(")").split("; ") + val deviceManufacturer = deviceInfoSegments.getOrNull(0) + val deviceModel = deviceInfoSegments.getOrNull(1) + val deviceOsInfo = deviceInfoSegments.getOrNull(2)?.takeIf { it.startsWith("Android") } + val deviceOs = deviceOsInfo?.substringBefore(" ") + val deviceOsVersion = deviceOsInfo?.substringAfter(" ") + return DeviceUserAgent(DeviceType.MOBILE, deviceManufacturer, deviceModel, deviceOs, deviceOsVersion, appName, appVersion) + } + + private fun parseIosUserAgent(userAgent: String): DeviceUserAgent { + val appName = userAgent.substringBefore("/") + val appVersion = userAgent.substringAfter("/").substringBefore(" (") + val deviceInfoSegments = userAgent.substringAfter("(").substringBefore(")").split("; ") + val deviceManufacturer = "Apple" + val deviceModel = deviceInfoSegments.getOrNull(0) + val deviceOs = deviceInfoSegments.getOrNull(1)?.substringBefore(" ") + val deviceOsVersion = deviceInfoSegments.getOrNull(1)?.substringAfter(" ") + return DeviceUserAgent(DeviceType.MOBILE, deviceManufacturer, deviceModel, deviceOs, deviceOsVersion, appName, appVersion) + } + + private fun parseDesktopUserAgent(userAgent: String): DeviceUserAgent { + val appInfoSegments = userAgent.substringBeforeLast(" ").substringAfterLast(" ").split("/") + val appName = appInfoSegments.getOrNull(0) + val appVersion = appInfoSegments.getOrNull(1) + val deviceInfoSegments = userAgent.substringAfter("(").substringBefore(")").split("; ") + val deviceOs = deviceInfoSegments.getOrNull(1)?.substringBeforeLast(" ") + val deviceOsVersion = deviceInfoSegments.getOrNull(1)?.substringAfterLast(" ") + return DeviceUserAgent(DeviceType.DESKTOP, null, null, deviceOs, deviceOsVersion, appName, appVersion) + } + + private fun parseWebUserAgent(userAgent: String): DeviceUserAgent { + return parseDesktopUserAgent(userAgent).copy( + deviceType = DeviceType.WEB + ) + } + + private fun createUnknownUserAgent(): DeviceUserAgent { + return DeviceUserAgent(DeviceType.UNKNOWN) + } + + companion object { + // Element dbg/1.5.0-dev (Xiaomi; Mi 9T; Android 11; RKQ1.200826.002 test-keys; Flavour GooglePlay; MatrixAndroidSdk2 1.5.0) + private val ANDROID_KEYWORD = "; MatrixAndroidSdk2" + + // Element/1.8.21 (iPhone XS Max; iOS 15.2; Scale/3.00) + private val IOS_KEYWORD = "; iOS " + + // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) ElementNightly/2022091301 Chrome/104.0.5112.102 Electron/20.1.1 Safari/537.36 + private val DESKTOP_KEYWORD = " Electron/" + + // Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 + private val WEB_KEYWORD = "Mozilla/" + } +}