From 3952ae3617783345cc43e2ccb5d545d31611a840 Mon Sep 17 00:00:00 2001 From: Goooler Date: Sun, 16 Apr 2023 13:15:35 +0800 Subject: [PATCH 1/8] Licensee 1.7.0-SNAPSHOT --- build.gradle | 1 + settings.gradle | 1 + 2 files changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index 296acb6cf9f..0d48b31694a 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,7 @@ plugins { id "com.google.devtools.ksp" version "1.8.21-1.0.11" id 'com.google.protobuf' version "0.9.3" id 'com.google.android.gms.oss-licenses-plugin' version "0.10.6" + id 'app.cash.licensee' version "1.7.0-SNAPSHOT" id 'dev.rikka.tools.refine' version "4.3.0" } diff --git a/settings.gradle b/settings.gradle index 3468da07b81..70d35134b88 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,6 +2,7 @@ pluginManagement { repositories { google() gradlePluginPortal() + maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } } resolutionStrategy { eachPlugin { From a574535a1dd5db601afd424243c5e0b37d9c9aaf Mon Sep 17 00:00:00 2001 From: Goooler Date: Sun, 16 Apr 2023 13:24:38 +0800 Subject: [PATCH 2/8] Allow licenses --- build.gradle | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/build.gradle b/build.gradle index 0d48b31694a..28e13071402 100644 --- a/build.gradle +++ b/build.gradle @@ -390,3 +390,14 @@ protobuf { } } } + +licensee { + allow("Apache-2.0") + allow("BSD-3-Clause") + allowUrl("https://api.github.com/licenses/apache-2.0") + allowUrl("https://api.github.com/licenses/bsd-3-clause") + allowUrl("https://github.com/patrykmichalik/opto/blob/master/LICENSE") + allowUrl("https://github.com/RikkaApps/HiddenApiRefinePlugin/blob/main/LICENSE") + allowUrl("https://github.com/stleary/JSON-java/blob/master/LICENSE") + allowUrl("https://www.gnu.org/licenses/old-licenses/gpl-2.0.html") +} From da8938ada01216bc8e1c89bd7cf9a864dd530dd4 Mon Sep 17 00:00:00 2001 From: Goooler Date: Sat, 6 May 2023 16:56:44 +0800 Subject: [PATCH 3/8] 1.7.0 final --- build.gradle | 2 +- settings.gradle | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 28e13071402..feaf007ba8f 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ plugins { id "com.google.devtools.ksp" version "1.8.21-1.0.11" id 'com.google.protobuf' version "0.9.3" id 'com.google.android.gms.oss-licenses-plugin' version "0.10.6" - id 'app.cash.licensee' version "1.7.0-SNAPSHOT" + id 'app.cash.licensee' version "1.7.0" id 'dev.rikka.tools.refine' version "4.3.0" } diff --git a/settings.gradle b/settings.gradle index 70d35134b88..3468da07b81 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,6 @@ pluginManagement { repositories { google() gradlePluginPortal() - maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } } resolutionStrategy { eachPlugin { From 44248203bf42a06c20790b302b6fc3850015c89e Mon Sep 17 00:00:00 2001 From: Goooler Date: Wed, 31 May 2023 12:05:48 +0800 Subject: [PATCH 4/8] Copy artifacts.json into assets Ref https://www.jbamberger.de/development/2021/07/03/android-generating-asset-files.html --- build.gradle | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/build.gradle b/build.gradle index feaf007ba8f..31dfedad1cb 100644 --- a/build.gradle +++ b/build.gradle @@ -107,6 +107,15 @@ android { } applicationVariants.configureEach { variant -> + def copyArtifactList = tasks.register("copy${variant.name.capitalize()}ArtifactList", Copy) { + dependsOn "licensee${variant.name.capitalize()}" + from project.extensions.getByType(ReportingExtension).file("licensee/${variant.name}/artifacts.json") + into layout.buildDirectory.dir("generated/dependencyAssets/") + } + tasks.named("merge${variant.name.capitalize()}Assets").configure { + dependsOn copyArtifactList + } + variant.outputs.configureEach { outputFileName = "Lawnchair ${variant.versionName}.apk" } @@ -280,6 +289,7 @@ android { lawnWithQuickstep { manifest.srcFile "quickstep/AndroidManifest-launcher.xml" + assets.srcDir layout.buildDirectory.dir("generated/dependencyAssets/") } withoutQuickstep { From 462c29b212a88e14a1cba71b124262f93abe1aca Mon Sep 17 00:00:00 2001 From: Goooler Date: Wed, 31 May 2023 17:37:35 +0800 Subject: [PATCH 5/8] Re-model OssLibrary --- .../ui/preferences/PreferenceInteractor.kt | 2 +- .../ui/preferences/PreferenceViewModel.kt | 13 +++---- .../acknowledgements/Acknowledgements.kt | 18 +--------- .../about/acknowledgements/loadNotice.kt | 35 +++++++++++++++---- 4 files changed, 38 insertions(+), 30 deletions(-) diff --git a/lawnchair/src/app/lawnchair/ui/preferences/PreferenceInteractor.kt b/lawnchair/src/app/lawnchair/ui/preferences/PreferenceInteractor.kt index 2c3eb6e9e19..455c18faa02 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/PreferenceInteractor.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/PreferenceInteractor.kt @@ -16,7 +16,7 @@ package app.lawnchair.ui.preferences -import app.lawnchair.ossnotices.OssLibrary +import app.lawnchair.ui.preferences.about.acknowledgements.OssLibrary import kotlinx.coroutines.flow.StateFlow sealed interface PreferenceInteractor { diff --git a/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt b/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt index 824e646d440..562b111a9e1 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt @@ -22,8 +22,7 @@ import androidx.core.content.ContextCompat import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import app.lawnchair.icons.CustomAdaptiveIconDrawable -import app.lawnchair.ossnotices.OssLibrary -import app.lawnchair.ossnotices.getOssLibraries +import app.lawnchair.ui.preferences.about.acknowledgements.OssLibrary import com.android.launcher3.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted @@ -33,6 +32,7 @@ import kotlinx.coroutines.flow.stateIn import app.lawnchair.util.getPackageVersionCode import app.lawnchair.util.Constants.LAWNICONS_PACKAGE_NAME import kotlinx.coroutines.flow.StateFlow +import kotlinx.serialization.json.Json private val iconPackIntents = listOf( Intent("com.novalauncher.THEME"), @@ -109,10 +109,11 @@ class PreferenceViewModel(private val app: Application) : AndroidViewModel(app), .stateIn(viewModelScope, SharingStarted.Lazily, listOf()) override val ossLibraries: StateFlow> = flow { - val ossLibraries = app.getOssLibraries(R.raw.third_party_license_metadata) - .distinctBy { it.name } - emit(ossLibraries) + val jsonString = app.resources.assets.open("artifacts.json") + .bufferedReader().use { it.readText() } + val artifacts: List = Json.decodeFromString(jsonString) + emit(artifacts) } - .flowOn(Dispatchers.Default) + .flowOn(Dispatchers.IO) .stateIn(viewModelScope, SharingStarted.Lazily, emptyList()) } diff --git a/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/Acknowledgements.kt b/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/Acknowledgements.kt index d496e791ee0..6ce68b407eb 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/Acknowledgements.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/Acknowledgements.kt @@ -36,7 +36,6 @@ import androidx.compose.ui.unit.sp import androidx.navigation.NavGraphBuilder import androidx.navigation.NavType import androidx.navigation.navArgument -import app.lawnchair.ossnotices.OssLibrary import app.lawnchair.ui.preferences.LocalNavController import app.lawnchair.ui.preferences.LocalPreferenceInteractor import app.lawnchair.ui.preferences.components.* @@ -44,9 +43,6 @@ import app.lawnchair.ui.preferences.preferenceGraph import app.lawnchair.ui.preferences.subRoute import com.android.launcher3.R import com.google.accompanist.navigation.animation.composable -import com.google.accompanist.placeholder.PlaceholderHighlight -import com.google.accompanist.placeholder.material.fade -import com.google.accompanist.placeholder.material.placeholder @OptIn(ExperimentalAnimationApi::class) fun NavGraphBuilder.licensesGraph(route: String) { @@ -103,7 +99,7 @@ fun NoticePage(index: Int) { PreferenceLayout( label = ossLibrary?.name ?: stringResource(id = R.string.loading) ) { - Crossfade(targetState = data) { it -> + Crossfade(targetState = data, label = "") { it -> if (it != null) { val uriHandler = LocalUriHandler.current val layoutResult = remember { mutableStateOf(null) } @@ -132,18 +128,6 @@ fun NoticePage(index: Int) { layoutResult.value = it } ) - } else { - Text( - modifier = Modifier - .padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 16.dp) - .placeholder( - visible = true, - highlight = PlaceholderHighlight.fade(), - ), - text = "a".repeat(ossLibrary?.noticeLength ?: 20), - fontFamily = FontFamily.Monospace, - fontSize = 14.sp - ) } } } diff --git a/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/loadNotice.kt b/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/loadNotice.kt index 4b80d9e02af..d95f6aa7e47 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/loadNotice.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/loadNotice.kt @@ -20,22 +20,24 @@ import android.text.SpannableString import android.text.style.URLSpan import android.text.util.Linkify import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.* -import androidx.compose.ui.platform.LocalContext +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.style.TextDecoration -import app.lawnchair.ossnotices.OssLibrary -import com.android.launcher3.R +import kotlinx.serialization.Serializable @Composable fun loadNotice(ossLibrary: OssLibrary): State { - val context = LocalContext.current val noticeStringState = remember { mutableStateOf(null) } val accentColor = MaterialTheme.colorScheme.primary DisposableEffect(Unit) { - val string = ossLibrary.getNotice(context = context, thirdPartyLicensesId = R.raw.third_party_licenses) + val string = (ossLibrary.spdxLicenses ?: ossLibrary.unknownLicenses) + ?.firstOrNull()?.url.orEmpty() val spannable = SpannableString(string) Linkify.addLinks(spannable, Linkify.WEB_URLS) val spans = spannable.getSpans(0, string.length, URLSpan::class.java) @@ -66,6 +68,27 @@ fun loadNotice(ossLibrary: OssLibrary): State { return noticeStringState } +@Serializable +data class OssLibrary( + val groupId: String, + val artifactId: String, + val version: String, + val name: String, + val spdxLicenses: List? = null, + val unknownLicenses: List? = null, + val scm: Scm? = null, +) { + @Serializable + data class License( + val identifier: String? = null, + val name: String, + val url: String, + ) + + @Serializable + data class Scm(val url: String) +} + data class OssLibraryWithNotice( val ossLibrary: OssLibrary, val notice: AnnotatedString, From c88b0c9f7a450d650650a37478a8244c29537a26 Mon Sep 17 00:00:00 2001 From: Goooler Date: Wed, 31 May 2023 17:38:24 +0800 Subject: [PATCH 6/8] Remove oss-licenses-plugin & oss-notices --- build.gradle | 2 -- 1 file changed, 2 deletions(-) diff --git a/build.gradle b/build.gradle index 31dfedad1cb..32551262a4f 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,6 @@ plugins { id 'org.jetbrains.kotlin.plugin.serialization' version "1.8.21" id "com.google.devtools.ksp" version "1.8.21-1.0.11" id 'com.google.protobuf' version "0.9.3" - id 'com.google.android.gms.oss-licenses-plugin' version "0.10.6" id 'app.cash.licensee' version "1.7.0" id 'dev.rikka.tools.refine' version "4.3.0" } @@ -369,7 +368,6 @@ dependencies { implementation "com.github.topjohnwu.libsu:service:$libsu_version" implementation "com.google.protobuf:protobuf-javalite:$protocVersion" - implementation 'com.github.LawnchairLauncher:oss-notices:1.0.2' // Persian Date implementation 'com.github.samanzamani:PersianDate:1.6.1' From 1c43098828521bb1a73158062aacafd531bb868d Mon Sep 17 00:00:00 2001 From: Goooler Date: Wed, 31 May 2023 17:45:22 +0800 Subject: [PATCH 7/8] Resort OSS list --- .../ui/preferences/PreferenceViewModel.kt | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt b/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt index 562b111a9e1..81145f1c40c 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt @@ -23,15 +23,15 @@ import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.viewModelScope import app.lawnchair.icons.CustomAdaptiveIconDrawable import app.lawnchair.ui.preferences.about.acknowledgements.OssLibrary +import app.lawnchair.util.Constants.LAWNICONS_PACKAGE_NAME +import app.lawnchair.util.getPackageVersionCode import com.android.launcher3.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.stateIn -import app.lawnchair.util.getPackageVersionCode -import app.lawnchair.util.Constants.LAWNICONS_PACKAGE_NAME -import kotlinx.coroutines.flow.StateFlow import kotlinx.serialization.json.Json private val iconPackIntents = listOf( @@ -41,9 +41,11 @@ private val iconPackIntents = listOf( Intent("android.intent.action.MAIN").addCategory("com.anddoes.launcher.THEME") ) -class PreferenceViewModel(private val app: Application) : AndroidViewModel(app), PreferenceInteractor { +class PreferenceViewModel(private val app: Application) : AndroidViewModel(app), + PreferenceInteractor { - private val themedIconPackIntents = listOf(Intent(app.getString(R.string.icon_packs_intent_name))) + private val themedIconPackIntents = + listOf(Intent(app.getString(R.string.icon_packs_intent_name))) override val iconPacks = flow { val pm = app.packageManager val iconPacks = iconPackIntents @@ -111,7 +113,11 @@ class PreferenceViewModel(private val app: Application) : AndroidViewModel(app), override val ossLibraries: StateFlow> = flow { val jsonString = app.resources.assets.open("artifacts.json") .bufferedReader().use { it.readText() } - val artifacts: List = Json.decodeFromString(jsonString) + val artifacts = Json.decodeFromString>(jsonString) + .asSequence() + .distinctBy { "${it.groupId}:${it.artifactId}" } + .sortedBy { it.name } + .toList() emit(artifacts) } .flowOn(Dispatchers.IO) From ffcda9d3b7a47bc88d09390435b2efded149af37 Mon Sep 17 00:00:00 2001 From: Goooler Date: Wed, 31 May 2023 18:51:02 +0800 Subject: [PATCH 8/8] Cleanups --- build.gradle | 2 +- .../ui/preferences/PreferenceViewModel.kt | 10 ++-- .../acknowledgements/Acknowledgements.kt | 49 +++++++++---------- .../about/acknowledgements/loadNotice.kt | 2 +- 4 files changed, 30 insertions(+), 33 deletions(-) diff --git a/build.gradle b/build.gradle index 32551262a4f..6ab2af2cde4 100644 --- a/build.gradle +++ b/build.gradle @@ -107,7 +107,7 @@ android { applicationVariants.configureEach { variant -> def copyArtifactList = tasks.register("copy${variant.name.capitalize()}ArtifactList", Copy) { - dependsOn "licensee${variant.name.capitalize()}" + dependsOn tasks.named("licensee${variant.name.capitalize()}") from project.extensions.getByType(ReportingExtension).file("licensee/${variant.name}/artifacts.json") into layout.buildDirectory.dir("generated/dependencyAssets/") } diff --git a/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt b/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt index 81145f1c40c..831c2a8c425 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt @@ -41,11 +41,9 @@ private val iconPackIntents = listOf( Intent("android.intent.action.MAIN").addCategory("com.anddoes.launcher.THEME") ) -class PreferenceViewModel(private val app: Application) : AndroidViewModel(app), - PreferenceInteractor { +class PreferenceViewModel(private val app: Application) : AndroidViewModel(app), PreferenceInteractor { - private val themedIconPackIntents = - listOf(Intent(app.getString(R.string.icon_packs_intent_name))) + private val themedIconPackIntents = listOf(Intent(app.getString(R.string.icon_packs_intent_name))) override val iconPacks = flow { val pm = app.packageManager val iconPacks = iconPackIntents @@ -113,12 +111,12 @@ class PreferenceViewModel(private val app: Application) : AndroidViewModel(app), override val ossLibraries: StateFlow> = flow { val jsonString = app.resources.assets.open("artifacts.json") .bufferedReader().use { it.readText() } - val artifacts = Json.decodeFromString>(jsonString) + val ossLibraries = Json.decodeFromString>(jsonString) .asSequence() .distinctBy { "${it.groupId}:${it.artifactId}" } .sortedBy { it.name } .toList() - emit(artifacts) + emit(ossLibraries) } .flowOn(Dispatchers.IO) .stateIn(viewModelScope, SharingStarted.Lazily, emptyList()) diff --git a/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/Acknowledgements.kt b/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/Acknowledgements.kt index 6ce68b407eb..73e3485ad3b 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/Acknowledgements.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/Acknowledgements.kt @@ -100,35 +100,34 @@ fun NoticePage(index: Int) { label = ossLibrary?.name ?: stringResource(id = R.string.loading) ) { Crossfade(targetState = data, label = "") { it -> - if (it != null) { - val uriHandler = LocalUriHandler.current - val layoutResult = remember { mutableStateOf(null) } - val pressIndicator = Modifier.pointerInput(Unit) { - detectTapGestures { pos -> - layoutResult.value?.let { layoutResult -> - val position = layoutResult.getOffsetForPosition(pos) - val annotation = - it.notice.getStringAnnotations(position, position).firstOrNull() - if (annotation?.tag == "URL") { - uriHandler.openUri(annotation.item) - } + it ?: return@Crossfade + val uriHandler = LocalUriHandler.current + val layoutResult = remember { mutableStateOf(null) } + val pressIndicator = Modifier.pointerInput(Unit) { + detectTapGestures { pos -> + layoutResult.value?.let { layoutResult -> + val position = layoutResult.getOffsetForPosition(pos) + val annotation = + it.notice.getStringAnnotations(position, position).firstOrNull() + if (annotation?.tag == "URL") { + uriHandler.openUri(annotation.item) } } } - - Text( - modifier = Modifier - .fillMaxWidth() - .padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 16.dp) - .then(pressIndicator), - text = it.notice, - fontFamily = FontFamily.Monospace, - fontSize = 14.sp, - onTextLayout = { - layoutResult.value = it - } - ) } + + Text( + modifier = Modifier + .fillMaxWidth() + .padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 16.dp) + .then(pressIndicator), + text = it.notice, + fontFamily = FontFamily.Monospace, + fontSize = 14.sp, + onTextLayout = { + layoutResult.value = it + } + ) } } } diff --git a/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/loadNotice.kt b/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/loadNotice.kt index d95f6aa7e47..575b593a1db 100644 --- a/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/loadNotice.kt +++ b/lawnchair/src/app/lawnchair/ui/preferences/about/acknowledgements/loadNotice.kt @@ -74,9 +74,9 @@ data class OssLibrary( val artifactId: String, val version: String, val name: String, + val scm: Scm? = null, val spdxLicenses: List? = null, val unknownLicenses: List? = null, - val scm: Scm? = null, ) { @Serializable data class License(