Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to Licensee #3492

Merged
merged 8 commits into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 22 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ 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"
}

Expand Down Expand Up @@ -106,6 +106,15 @@ android {
}

applicationVariants.configureEach { variant ->
def copyArtifactList = tasks.register("copy${variant.name.capitalize()}ArtifactList", Copy) {
dependsOn tasks.named("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"
}
Expand Down Expand Up @@ -279,6 +288,7 @@ android {

lawnWithQuickstep {
manifest.srcFile "quickstep/AndroidManifest-launcher.xml"
assets.srcDir layout.buildDirectory.dir("generated/dependencyAssets/")
}

withoutQuickstep {
Expand Down Expand Up @@ -358,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'
Expand Down Expand Up @@ -389,3 +398,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")
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
21 changes: 13 additions & 8 deletions lawnchair/src/app/lawnchair/ui/preferences/PreferenceViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ 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 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(
Intent("com.novalauncher.THEME"),
Expand Down Expand Up @@ -109,10 +109,15 @@ class PreferenceViewModel(private val app: Application) : AndroidViewModel(app),
.stateIn(viewModelScope, SharingStarted.Lazily, listOf())

override val ossLibraries: StateFlow<List<OssLibrary>> = flow {
val ossLibraries = app.getOssLibraries(R.raw.third_party_license_metadata)
.distinctBy { it.name }
val jsonString = app.resources.assets.open("artifacts.json")
.bufferedReader().use { it.readText() }
val ossLibraries = Json.decodeFromString<List<OssLibrary>>(jsonString)
.asSequence()
.distinctBy { "${it.groupId}:${it.artifactId}" }
.sortedBy { it.name }
.toList()
emit(ossLibraries)
}
.flowOn(Dispatchers.Default)
.flowOn(Dispatchers.IO)
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,13 @@ 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.*
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) {
Expand Down Expand Up @@ -103,48 +99,35 @@ fun NoticePage(index: Int) {
PreferenceLayout(
label = ossLibrary?.name ?: stringResource(id = R.string.loading)
) {
Crossfade(targetState = data) { it ->
if (it != null) {
val uriHandler = LocalUriHandler.current
val layoutResult = remember { mutableStateOf<TextLayoutResult?>(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)
}
Crossfade(targetState = data, label = "") { it ->
it ?: return@Crossfade
val uriHandler = LocalUriHandler.current
val layoutResult = remember { mutableStateOf<TextLayoutResult?>(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
}
)
} 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
)
}

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
}
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<OssLibraryWithNotice?> {
val context = LocalContext.current
val noticeStringState = remember { mutableStateOf<OssLibraryWithNotice?>(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)
Expand Down Expand Up @@ -66,6 +68,27 @@ fun loadNotice(ossLibrary: OssLibrary): State<OssLibraryWithNotice?> {
return noticeStringState
}

@Serializable
data class OssLibrary(
val groupId: String,
val artifactId: String,
val version: String,
val name: String,
val scm: Scm? = null,
val spdxLicenses: List<License>? = null,
val unknownLicenses: List<License>? = 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,
Expand Down