Skip to content

Commit f7da628

Browse files
Merge pull request #239 from MihaiCristianCondrea/codex/add-open-source-license-support
Integrate Play services OSS licenses screen
2 parents 2c216bd + 727e04e commit f7da628

File tree

9 files changed

+45
-171
lines changed

9 files changed

+45
-171
lines changed

app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
plugins {
22
alias(libs.plugins.androidApplication)
3+
alias(libs.plugins.ossLicenses)
34
alias(libs.plugins.googleServices)
45
alias(libs.plugins.firebaseCrashlytics)
5-
alias(libs.plugins.aboutLibraries)
66
alias(libs.plugins.hiltAndroid)
77
}
88

app/src/main/AndroidManifest.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@
6363
android:theme="@style/AppTheme" />
6464

6565
<activity
66-
android:name="com.mikepenz.aboutlibraries.ui.LibsActivity"
66+
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
67+
android:exported="false"
68+
android:theme="@style/AppTheme" />
69+
<activity
70+
android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
6771
android:exported="false"
6872
android:theme="@style/AppTheme" />
6973

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/help/HelpActivity.java

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.d4rk.androidtutorials.java.ui.screens.help;
22

33
import android.content.ActivityNotFoundException;
4-
import android.content.Context;
54
import android.content.Intent;
65
import android.net.Uri;
76
import android.os.Bundle;
@@ -23,7 +22,6 @@
2322
import com.d4rk.androidtutorials.java.utils.OpenSourceLicensesUtils;
2423
import com.google.android.material.snackbar.Snackbar;
2524
import com.google.android.play.core.review.ReviewInfo;
26-
import com.mikepenz.aboutlibraries.LibsBuilder;
2725

2826
import dagger.hilt.android.AndroidEntryPoint;
2927

@@ -82,37 +80,13 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
8280
openLink("https://mihaicristiancondrea.github.io/profile/#privacy-policy-end-user-software");
8381
return true;
8482
} else if (itemId == R.id.oss) {
85-
OpenSourceLicensesUtils.loadHtmlData(this, (changelogHtml, eulaHtml) -> openLicensesScreen(this, eulaHtml, changelogHtml));
83+
OpenSourceLicensesUtils.openLicensesScreen(this);
8684
return true;
8785
} else {
8886
return super.onOptionsItemSelected(item);
8987
}
9088
}
9189

92-
private void openLicensesScreen(Context context, String eulaHtmlString, String changelogHtmlString) {
93-
new LibsBuilder()
94-
.withActivityTitle(context.getString(R.string.open_source_licenses))
95-
.withEdgeToEdge(true)
96-
.withShowLoadingProgress(true)
97-
.withSearchEnabled(true)
98-
.withAboutIconShown(true)
99-
.withAboutAppName(context.getString(R.string.app_name))
100-
.withVersionShown(true)
101-
.withAboutVersionString(BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")")
102-
.withLicenseShown(true)
103-
.withAboutVersionShown(true)
104-
.withAboutSpecial1(context.getString(R.string.eula_title))
105-
.withAboutSpecial1Description(
106-
eulaHtmlString != null ? eulaHtmlString : context.getString(R.string.loading_eula)
107-
)
108-
.withAboutSpecial2(context.getString(R.string.changelog))
109-
.withAboutSpecial2Description(
110-
changelogHtmlString != null ? changelogHtmlString : context.getString(R.string.loading_changelog)
111-
)
112-
.withAboutDescription(context.getString(R.string.app_short_description))
113-
.start(context);
114-
}
115-
11690
private void showVersionInfoDialog() {
11791
DialogVersionInfoBinding binding = DialogVersionInfoBinding.inflate(getLayoutInflater());
11892
AlertDialog.Builder builder = new AlertDialog.Builder(this);
@@ -131,7 +105,7 @@ private void openGooglePlayListing() {
131105
final String appPackageName = getPackageName();
132106
try {
133107
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
134-
} catch (android.content.ActivityNotFoundException anfe) {
108+
} catch (ActivityNotFoundException anfe) {
135109
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName)));
136110
}
137111
}

app/src/main/java/com/d4rk/androidtutorials/java/ui/screens/settings/SettingsFragment.java

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616
import androidx.preference.PreferenceFragmentCompat;
1717
import androidx.preference.SwitchPreferenceCompat;
1818

19-
import com.d4rk.androidtutorials.java.BuildConfig;
2019
import com.d4rk.androidtutorials.java.R;
2120
import com.d4rk.androidtutorials.java.ui.components.dialogs.RequireRestartDialog;
2221
import com.d4rk.androidtutorials.java.utils.OpenSourceLicensesUtils;
23-
import com.mikepenz.aboutlibraries.LibsBuilder;
2422

2523
public class SettingsFragment extends PreferenceFragmentCompat {
2624
@Override
@@ -57,7 +55,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
5755
Preference ossPreference = findPreference(getString(R.string.key_open_source_licenses));
5856
if (ossPreference != null) {
5957
ossPreference.setOnPreferenceClickListener(preference -> {
60-
OpenSourceLicensesUtils.loadHtmlData(requireContext(), (changelogHtml, eulaHtml) -> openLicensesScreen(requireContext(), eulaHtml, changelogHtml));
58+
OpenSourceLicensesUtils.openLicensesScreen(requireContext());
6159
return true;
6260
});
6361
}
@@ -98,28 +96,4 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
9896
});
9997
}
10098
}
101-
102-
private void openLicensesScreen(Context context, String eulaHtmlString, String changelogHtmlString) {
103-
new LibsBuilder()
104-
.withActivityTitle(context.getString(R.string.open_source_licenses))
105-
.withEdgeToEdge(true)
106-
.withShowLoadingProgress(true)
107-
.withSearchEnabled(true)
108-
.withAboutIconShown(true)
109-
.withAboutAppName(context.getString(R.string.app_name))
110-
.withVersionShown(true)
111-
.withAboutVersionString(BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")")
112-
.withLicenseShown(true)
113-
.withAboutVersionShown(true)
114-
.withAboutSpecial1(context.getString(R.string.eula_title))
115-
.withAboutSpecial1Description(
116-
eulaHtmlString != null ? eulaHtmlString : context.getString(R.string.loading_eula)
117-
)
118-
.withAboutSpecial2(context.getString(R.string.changelog))
119-
.withAboutSpecial2Description(
120-
changelogHtmlString != null ? changelogHtmlString : context.getString(R.string.loading_changelog)
121-
)
122-
.withAboutDescription(context.getString(R.string.app_short_description))
123-
.start(context);
124-
}
12599
}
Lines changed: 16 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,123 +1,32 @@
11
package com.d4rk.androidtutorials.java.utils;
22

3+
import android.app.Activity;
34
import android.content.Context;
4-
import android.os.Handler;
5-
import android.os.Looper;
6-
import android.util.Log;
5+
import android.content.Intent;
76

8-
import com.d4rk.androidtutorials.java.R;
9-
10-
import org.commonmark.node.Node;
11-
import org.commonmark.parser.Parser;
12-
import org.commonmark.renderer.html.HtmlRenderer;
13-
14-
import java.io.BufferedReader;
15-
import java.io.InputStreamReader;
16-
import java.net.HttpURLConnection;
17-
import java.net.URL;
18-
import java.util.Objects;
19-
import java.util.concurrent.ExecutorService;
20-
import java.util.concurrent.Executors;
21-
import java.util.regex.Matcher;
22-
import java.util.regex.Pattern;
23-
24-
public class OpenSourceLicensesUtils {
25-
private static final String TAG = "OpenSourceLicensesUtils";
26-
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
27-
private static final Handler mainHandler = new Handler(Looper.getMainLooper());
28-
29-
public static void loadHtmlData(final Context context, final HtmlDataCallback callback) {
30-
executor.execute(() -> {
31-
String packageName = context.getPackageName();
32-
String currentVersion = getAppVersion(context);
33-
String changelogUrl = "https://raw.githubusercontent.com/MihaiCristianCondrea/" + packageName + "/refs/heads/main/CHANGELOG.md";
34-
String eulaUrl = "https://raw.githubusercontent.com/MihaiCristianCondrea/" + packageName + "/refs/heads/main/EULA.md";
35-
36-
String changelogMarkdown = loadMarkdown(context, changelogUrl, R.string.error_loading_changelog);
37-
String extractedChangelog = extractLatestVersionChangelog(changelogMarkdown, currentVersion);
38-
String changelogHtml = markdownToHtml(extractedChangelog);
39-
40-
String eulaMarkdown = loadMarkdown(context, eulaUrl, R.string.error_loading_eula);
41-
String eulaHtml = markdownToHtml(eulaMarkdown);
7+
import androidx.annotation.Nullable;
428

43-
mainHandler.post(() -> callback.onHtmlDataLoaded(changelogHtml, eulaHtml));
44-
});
45-
}
9+
import com.d4rk.androidtutorials.java.R;
10+
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity;
4611

47-
private static String loadMarkdown(Context context, String urlString, int errorStringId) {
48-
HttpURLConnection connection = null;
49-
BufferedReader reader = null;
50-
try {
51-
URL url = new URL(urlString);
52-
connection = (HttpURLConnection) url.openConnection();
53-
connection.setRequestMethod("GET");
54-
connection.setConnectTimeout(10000);
55-
connection.setReadTimeout(10000);
12+
public final class OpenSourceLicensesUtils {
5613

57-
int responseCode = connection.getResponseCode();
58-
if (responseCode == HttpURLConnection.HTTP_OK) {
59-
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
60-
StringBuilder content = new StringBuilder();
61-
String line;
62-
while ((line = reader.readLine()) != null) {
63-
content.append(line).append("\n");
64-
}
65-
return content.toString();
66-
} else {
67-
Log.e(TAG, "Failed to load URL: " + urlString + " with response code: " + responseCode);
68-
return context.getString(errorStringId);
69-
}
70-
} catch (Exception e) {
71-
Log.e(TAG, "Error loading markdown from URL: " + urlString, e);
72-
return context.getString(errorStringId);
73-
} finally {
74-
if (reader != null) {
75-
try {
76-
reader.close();
77-
} catch (Exception e) {
78-
Log.e(TAG, "Error closing reader", e);
79-
}
80-
}
81-
if (connection != null) {
82-
connection.disconnect();
83-
}
84-
}
14+
private OpenSourceLicensesUtils() {
15+
// Utility class
8516
}
8617

87-
private static String extractLatestVersionChangelog(String markdown, String currentVersion) {
88-
// Define the regex pattern to match the latest version section
89-
String regexPattern = "(?m)^#\\s+Version\\s+" + Pattern.quote(currentVersion) + ":\\s*(.*?)^(#\\s+Version\\s+|$)";
90-
Pattern pattern = Pattern.compile(regexPattern, Pattern.DOTALL | Pattern.MULTILINE);
91-
Matcher matcher = pattern.matcher(markdown);
92-
93-
if (matcher.find()) {
94-
// Group 1 contains the changelog for the current version
95-
return Objects.requireNonNull(matcher.group(1)).trim();
96-
} else {
97-
Log.e(TAG, "No changelog available for version " + currentVersion);
98-
return "No changelog available for version " + currentVersion;
18+
public static void openLicensesScreen(@Nullable Context context) {
19+
if (context == null) {
20+
return;
9921
}
100-
}
10122

102-
private static String markdownToHtml(String markdown) {
103-
Parser parser = Parser.builder().build();
104-
HtmlRenderer renderer = HtmlRenderer.builder().build();
105-
Node document = parser.parse(markdown);
106-
return renderer.render(document);
107-
}
23+
OssLicensesMenuActivity.setActivityTitle(context.getString(R.string.open_source_licenses));
10824

109-
private static String getAppVersion(Context context) {
110-
try {
111-
return context.getPackageManager()
112-
.getPackageInfo(context.getPackageName(), 0)
113-
.versionName;
114-
} catch (Exception e) {
115-
Log.e(TAG, "Error getting app version", e);
116-
return "1.0.0"; // Fallback version
25+
Intent intent = new Intent(context, OssLicensesMenuActivity.class);
26+
if (!(context instanceof Activity)) {
27+
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
11728
}
118-
}
11929

120-
public interface HtmlDataCallback {
121-
void onHtmlDataLoaded(String changelogHtml, String eulaHtml);
30+
context.startActivity(intent);
12231
}
12332
}

build.gradle

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
1+
buildscript {
2+
repositories {
3+
google()
4+
mavenCentral()
5+
}
6+
dependencies {
7+
// The oss-licenses Gradle plugin still relies on XmlSlurper from groovy-xml when
8+
// running on recent Gradle versions, so we provide it explicitly on the classpath.
9+
classpath 'org.codehaus.groovy:groovy-xml:3.0.19'
10+
}
11+
}
12+
113
plugins {
214
alias(libs.plugins.androidApplication) apply false
315
alias(libs.plugins.googleServices) apply false
416
alias(libs.plugins.firebaseCrashlytics) apply false
5-
alias(libs.plugins.aboutLibraries) apply true
17+
alias(libs.plugins.ossLicenses) apply false
618
alias(libs.plugins.hiltAndroid) apply false
719
}

docs/core/core-module.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Houses use case classes and other business logic that operate on repositories.
1111
Contains Activities, Fragments and ViewModels such as `MainViewModel`.
1212

1313
### utils
14-
Provides helpers like `OpenSourceLicensesUtils`, `ReviewHelper` and `EdgeToEdgeDelegate`.
14+
Provides helpers like `OpenSourceLicensesUtils` for launching the open source license screen, `ReviewHelper` and `EdgeToEdgeDelegate`.
1515

1616
### di
1717
Contains Hilt modules and qualifiers for dependency injection.

gradle/libs.versions.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
agp = "8.13.0"
33
firebaseCrashlyticsPlugin = "3.0.6"
44
googleServices = "4.4.3"
5+
ossLicensesPlugin = "0.10.6"
56
appcompat = "1.7.1"
67
appUpdate = "2.1.0"
78
billing = "8.0.0"
89
constraintlayout = "2.2.1"
9-
aboutlibraries = "11.3.0"
1010
coreSplashscreen = "1.0.1"
1111
core = "4.6.2"
1212
coreTesting = "2.2.0"
@@ -27,6 +27,7 @@ coreKtx = "1.17.0"
2727
material = "1.14.0-alpha04"
2828
multidex = "2.0.1"
2929
playServicesAds = "24.6.0"
30+
playServicesOssLicenses = "17.3.0"
3031
codeview = "1.3.9"
3132
hilt = "2.57.1"
3233
room = "2.8.0"
@@ -63,6 +64,7 @@ firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "fir
6364
firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics" }
6465
google-firebase-perf = { module = "com.google.firebase:firebase-perf" }
6566
play-services-ads = { module = "com.google.android.gms:play-services-ads", version.ref = "playServicesAds" }
67+
play-services-oss-licenses = { module = "com.google.android.gms:play-services-oss-licenses", version.ref = "playServicesOssLicenses" }
6668

6769
# Networking (Retrofit)
6870
retrofit2 = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
@@ -73,7 +75,6 @@ hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt"
7375
hilt-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" }
7476

7577
# Utility
76-
aboutlibraries = { module = "com.mikepenz:aboutlibraries", version.ref = "aboutlibraries" }
7778
app-update = { module = "com.google.android.play:app-update", version.ref = "appUpdate" }
7879
billing = { module = "com.android.billingclient:billing", version.ref = "billing" }
7980
core = { module = "io.noties.markwon:core", version.ref = "core" }
@@ -94,14 +95,15 @@ mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockito
9495
androidApplication = { id = "com.android.application", version.ref = "agp" }
9596
googleServices = { id = "com.google.gms.google-services", version.ref = "googleServices" }
9697
firebaseCrashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebaseCrashlyticsPlugin" }
97-
aboutLibraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "aboutlibraries" }
9898
hiltAndroid = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
99+
ossLicenses = { id = "com.google.android.gms.oss-licenses-plugin", version.ref = "ossLicensesPlugin" }
99100

100101
[bundles]
101102
# Google Play services and related UI components
102103
google-core = [
103104
"material",
104105
"play-services-ads",
106+
"play-services-oss-licenses",
105107
"review",
106108
"app-update",
107109
"billing",
@@ -138,7 +140,6 @@ androidx-lifecycle = [
138140

139141
# Shared UI tooling and visuals
140142
ui-toolkit = [
141-
"aboutlibraries",
142143
"core",
143144
"lottie",
144145
"library",

settings.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pluginManagement {
88
resolutionStrategy {
99
eachPlugin {
1010
if (requested.id.id == 'com.google.android.gms.oss-licenses-plugin') {
11-
useModule("com.google.android.gms:oss-licenses-plugin:${requested.version}")
11+
useModule('com.google.android.gms:oss-licenses-plugin:0.10.6')
1212
}
1313
}
1414
}

0 commit comments

Comments
 (0)