--- a/core/build.gradle.kts Fri Apr 14 14:29:05 2023 -0400
+++ b/core/build.gradle.kts Thu Apr 13 16:09:27 2023 -0400
@@ -36,10 +36,9 @@
}
dependencies {
+ implementation(libs.okio)
+ implementation(libs.kotlinx.coroutines)
- implementation(libs.core.ktx)
- implementation(libs.appcompat)
- implementation(libs.material)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/main/java/com/geekorum/aboutoss/core/LicenseInfoRepository.kt Thu Apr 13 16:09:27 2023 -0400
@@ -0,0 +1,65 @@
+/*
+ * AboutOss is a utility library to retrieve and display
+ * opensource licenses in Android applications.
+ *
+ * Copyright (C) 2023 by Frederic-Charles Barthelery.
+ *
+ * This file is part of AboutOss.
+ *
+ * AboutOss is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AboutOss is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AboutOss. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.geekorum.aboutoss.core
+
+import android.content.Context
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.withContext
+
+class LicenseInfoRepository(
+ private val appContext: Context,
+ private val mainCoroutineDispatcher: CoroutineDispatcher,
+ private val ioCoroutineDispatcher: CoroutineDispatcher,
+) {
+
+ private var licensesInfo: Map<String, String>? = null
+
+ suspend fun getLicensesInfo(): Map<String, String> = withContext(mainCoroutineDispatcher) {
+ parseLicenses()
+ checkNotNull(licensesInfo)
+ }
+
+ suspend fun getLicenseFor(dependency: String): String = withContext(mainCoroutineDispatcher) {
+ parseLicenses()
+ checkNotNull(licensesInfo).let {
+ return@withContext it[dependency] ?: error("Dependency not found")
+ }
+ }
+
+ private suspend fun parseLicenses() = withContext(mainCoroutineDispatcher) {
+ if (licensesInfo == null) {
+ val licenses = withContext(ioCoroutineDispatcher) {
+ OssLicenseParser.openDefaultThirdPartyLicenses(appContext).use { licensesInput ->
+ OssLicenseParser.openDefaultThirdPartyLicensesMetadata(appContext)
+ .use { licensesMetadataInput ->
+ val parser = OssLicenseParser(
+ thirdPartyLicensesInput = licensesInput,
+ thirdPartyLicensesMetadataInput = licensesMetadataInput
+ )
+ parser.parseLicenses()
+ }
+ }
+ }
+ licensesInfo = licenses
+ }
+ }
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/main/java/com/geekorum/aboutoss/core/OssLicenseParser.kt Thu Apr 13 16:09:27 2023 -0400
@@ -0,0 +1,122 @@
+/*
+ * AboutOss is a utility library to retrieve and display
+ * opensource licenses in Android applications.
+ *
+ * Copyright (C) 2023 by Frederic-Charles Barthelery.
+ *
+ * This file is part of AboutOss.
+ *
+ * AboutOss is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AboutOss is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AboutOss. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.geekorum.aboutoss.core
+
+import android.annotation.SuppressLint
+import android.content.Context
+import okio.ByteString
+import okio.buffer
+import okio.source
+import java.io.InputStream
+
+/**
+ * Parse licences data generated by the "com.google.android.gms.oss-licenses-plugin" gradle plugin.
+ * [thirdPartyLicensesInput] is usually res/raw/third_party_licenses file
+ * [thirdPartyLicensesMetadataInput] is usually res/raw/third_party_license_metadata file
+ */
+class OssLicenseParser(
+ private val thirdPartyLicensesInput: InputStream,
+ private val thirdPartyLicensesMetadataInput: InputStream
+) {
+ fun parseLicenses(): Map<String, String> {
+ val licenses = readLicensesFile()
+ return buildLicenseInfo(licenses)
+ }
+
+ private fun readLicensesFile(): ByteString {
+ return thirdPartyLicensesInput.source().use { source ->
+ source.buffer().use {
+ it.readByteString()
+ }
+ }
+ }
+
+ private fun buildLicenseInfo(license: ByteString): Map<String, String> {
+ return thirdPartyLicensesMetadataInput.source().use { source ->
+ source.buffer().use {
+ buildMap {
+ while (true) {
+ val line = it.readUtf8Line() ?: break
+ if (line.isNotBlank()) {
+ with(line.toLineParser()) {
+ val start = readStartIdx()
+ val length = readLength()
+ val dependency = readName()
+ val licenseTxt = license.substring(
+ beginIndex = start,
+ endIndex = start + length + 1
+ ).string(Charsets.UTF_8)
+ put(dependency, licenseTxt)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ @SuppressLint("DiscouragedApi")
+ fun openDefaultThirdPartyLicenses(context: Context): InputStream {
+ val thirdPartyLicensesId = context.resources.getIdentifier("third_party_licenses", "raw", context.packageName)
+ check(thirdPartyLicensesId != 0) { "third_party_licenses was not found in resources raw of ${context.packageName}"}
+ return context.resources.openRawResource(thirdPartyLicensesId)
+ }
+
+ @SuppressLint("DiscouragedApi")
+ fun openDefaultThirdPartyLicensesMetadata(context: Context): InputStream {
+ val thirdPartyLicensesMetadataId = context.resources.getIdentifier("third_party_license_metadata", "raw", context.packageName)
+ check(thirdPartyLicensesMetadataId != 0) { "third_party_license_metadata was not found in resources raw of ${context.packageName}"}
+ return context.resources.openRawResource(thirdPartyLicensesMetadataId)
+ }
+ }
+}
+
+private class LicenseMetadataLineParser(
+ private val line: String
+) {
+
+ private var idx = 0
+
+ fun readStartIdx(): Int {
+ val end = line.indexOf(':', startIndex = idx)
+ val result = line.substring(idx, end).toInt()
+ idx = end + 1
+ return result
+ }
+
+ fun readLength(): Int {
+ val end = line.indexOf(' ', startIndex = idx)
+ val result = line.substring(idx, end).toInt()
+ idx = end + 1
+ return result
+ }
+
+ fun readName(): String {
+ val result = line.substring(idx)
+ idx = line.length + 1
+ return result
+ }
+
+}
+
+private fun String.toLineParser() = LicenseMetadataLineParser(this)
\ No newline at end of file
--- a/core/src/test/java/com/geekorum/aboutoss/ExampleUnitTest.kt Fri Apr 14 14:29:05 2023 -0400
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
-/*
- * AboutOss is a utility library to retrieve and display
- * opensource licenses in Android applications.
- *
- * Copyright (C) 2023 by Frederic-Charles Barthelery.
- *
- * This file is part of AboutOss.
- *
- * AboutOss is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * AboutOss is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with AboutOss. If not, see <http://www.gnu.org/licenses/>.
- */
-package com.geekorum.aboutoss
-
-import org.junit.Test
-
-import org.junit.Assert.*
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-class ExampleUnitTest {
- @Test
- fun addition_isCorrect() {
- assertEquals(4, 2 + 2)
- }
-}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/core/src/test/java/com/geekorum/aboutoss/core/ExampleUnitTest.kt Thu Apr 13 16:09:27 2023 -0400
@@ -0,0 +1,37 @@
+/*
+ * AboutOss is a utility library to retrieve and display
+ * opensource licenses in Android applications.
+ *
+ * Copyright (C) 2023 by Frederic-Charles Barthelery.
+ *
+ * This file is part of AboutOss.
+ *
+ * AboutOss is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AboutOss is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with AboutOss. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.geekorum.aboutoss.core
+
+import org.junit.Assert
+import org.junit.Test
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ Assert.assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
--- a/gradle/libs.versions.toml Fri Apr 14 14:29:05 2023 -0400
+++ b/gradle/libs.versions.toml Thu Apr 13 16:09:27 2023 -0400
@@ -8,6 +8,8 @@
espresso-core = "3.5.1"
appcompat = "1.6.1"
material = "1.8.0"
+okio = "3.3.0"
+kotlinx-coroutines = "1.6.4"
[libraries]
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
@@ -16,6 +18,9 @@
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+okio = { module = "com.squareup.okio:okio", version.ref = "okio"}
+kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines"}
+
[plugins]
com-android-application = { id = "com.android.application", version.ref = "com-android-application" }