Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
plugins {
alias(libs.plugins.androidApplication)
alias(libs.plugins.ossLicenses)
alias(libs.plugins.googleServices)
alias(libs.plugins.firebaseCrashlytics)
alias(libs.plugins.aboutLibraries)
alias(libs.plugins.hiltAndroid)
}

Expand Down
6 changes: 5 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,11 @@
android:theme="@style/AppTheme" />

<activity
android:name="com.mikepenz.aboutlibraries.ui.LibsActivity"
android:name="com.google.android.gms.oss.licenses.OssLicensesMenuActivity"
android:exported="false"
android:theme="@style/AppTheme" />
<activity
android:name="com.google.android.gms.oss.licenses.OssLicensesActivity"
android:exported="false"
android:theme="@style/AppTheme" />

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.d4rk.androidtutorials.java.ui.screens.help;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
Expand All @@ -23,7 +22,6 @@
import com.d4rk.androidtutorials.java.utils.OpenSourceLicensesUtils;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.play.core.review.ReviewInfo;
import com.mikepenz.aboutlibraries.LibsBuilder;

import dagger.hilt.android.AndroidEntryPoint;

Expand Down Expand Up @@ -82,37 +80,13 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
openLink("https://mihaicristiancondrea.github.io/profile/#privacy-policy-end-user-software");
return true;
} else if (itemId == R.id.oss) {
OpenSourceLicensesUtils.loadHtmlData(this, (changelogHtml, eulaHtml) -> openLicensesScreen(this, eulaHtml, changelogHtml));
OpenSourceLicensesUtils.openLicensesScreen(this);
return true;
} else {
return super.onOptionsItemSelected(item);
}
}

private void openLicensesScreen(Context context, String eulaHtmlString, String changelogHtmlString) {
new LibsBuilder()
.withActivityTitle(context.getString(R.string.open_source_licenses))
.withEdgeToEdge(true)
.withShowLoadingProgress(true)
.withSearchEnabled(true)
.withAboutIconShown(true)
.withAboutAppName(context.getString(R.string.app_name))
.withVersionShown(true)
.withAboutVersionString(BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")")
.withLicenseShown(true)
.withAboutVersionShown(true)
.withAboutSpecial1(context.getString(R.string.eula_title))
.withAboutSpecial1Description(
eulaHtmlString != null ? eulaHtmlString : context.getString(R.string.loading_eula)
)
.withAboutSpecial2(context.getString(R.string.changelog))
.withAboutSpecial2Description(
changelogHtmlString != null ? changelogHtmlString : context.getString(R.string.loading_changelog)
)
.withAboutDescription(context.getString(R.string.app_short_description))
.start(context);
}

private void showVersionInfoDialog() {
DialogVersionInfoBinding binding = DialogVersionInfoBinding.inflate(getLayoutInflater());
AlertDialog.Builder builder = new AlertDialog.Builder(this);
Expand All @@ -131,7 +105,7 @@ private void openGooglePlayListing() {
final String appPackageName = getPackageName();
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + appPackageName)));
} catch (android.content.ActivityNotFoundException anfe) {
} catch (ActivityNotFoundException anfe) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + appPackageName)));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,9 @@
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.SwitchPreferenceCompat;

import com.d4rk.androidtutorials.java.BuildConfig;
import com.d4rk.androidtutorials.java.R;
import com.d4rk.androidtutorials.java.ui.components.dialogs.RequireRestartDialog;
import com.d4rk.androidtutorials.java.utils.OpenSourceLicensesUtils;
import com.mikepenz.aboutlibraries.LibsBuilder;

public class SettingsFragment extends PreferenceFragmentCompat {
@Override
Expand Down Expand Up @@ -57,7 +55,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
Preference ossPreference = findPreference(getString(R.string.key_open_source_licenses));
if (ossPreference != null) {
ossPreference.setOnPreferenceClickListener(preference -> {
OpenSourceLicensesUtils.loadHtmlData(requireContext(), (changelogHtml, eulaHtml) -> openLicensesScreen(requireContext(), eulaHtml, changelogHtml));
OpenSourceLicensesUtils.openLicensesScreen(requireContext());
return true;
});
}
Expand Down Expand Up @@ -98,28 +96,4 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
});
}
}

private void openLicensesScreen(Context context, String eulaHtmlString, String changelogHtmlString) {
new LibsBuilder()
.withActivityTitle(context.getString(R.string.open_source_licenses))
.withEdgeToEdge(true)
.withShowLoadingProgress(true)
.withSearchEnabled(true)
.withAboutIconShown(true)
.withAboutAppName(context.getString(R.string.app_name))
.withVersionShown(true)
.withAboutVersionString(BuildConfig.VERSION_NAME + " (" + BuildConfig.VERSION_CODE + ")")
.withLicenseShown(true)
.withAboutVersionShown(true)
.withAboutSpecial1(context.getString(R.string.eula_title))
.withAboutSpecial1Description(
eulaHtmlString != null ? eulaHtmlString : context.getString(R.string.loading_eula)
)
.withAboutSpecial2(context.getString(R.string.changelog))
.withAboutSpecial2Description(
changelogHtmlString != null ? changelogHtmlString : context.getString(R.string.loading_changelog)
)
.withAboutDescription(context.getString(R.string.app_short_description))
.start(context);
}
}
Original file line number Diff line number Diff line change
@@ -1,123 +1,32 @@
package com.d4rk.androidtutorials.java.utils;

import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.content.Intent;

import com.d4rk.androidtutorials.java.R;

import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class OpenSourceLicensesUtils {
private static final String TAG = "OpenSourceLicensesUtils";
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
private static final Handler mainHandler = new Handler(Looper.getMainLooper());

public static void loadHtmlData(final Context context, final HtmlDataCallback callback) {
executor.execute(() -> {
String packageName = context.getPackageName();
String currentVersion = getAppVersion(context);
String changelogUrl = "https://raw.githubusercontent.com/MihaiCristianCondrea/" + packageName + "/refs/heads/main/CHANGELOG.md";
String eulaUrl = "https://raw.githubusercontent.com/MihaiCristianCondrea/" + packageName + "/refs/heads/main/EULA.md";

String changelogMarkdown = loadMarkdown(context, changelogUrl, R.string.error_loading_changelog);
String extractedChangelog = extractLatestVersionChangelog(changelogMarkdown, currentVersion);
String changelogHtml = markdownToHtml(extractedChangelog);

String eulaMarkdown = loadMarkdown(context, eulaUrl, R.string.error_loading_eula);
String eulaHtml = markdownToHtml(eulaMarkdown);
import androidx.annotation.Nullable;

mainHandler.post(() -> callback.onHtmlDataLoaded(changelogHtml, eulaHtml));
});
}
import com.d4rk.androidtutorials.java.R;
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity;

private static String loadMarkdown(Context context, String urlString, int errorStringId) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try {
URL url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
public final class OpenSourceLicensesUtils {

int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder content = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append("\n");
}
return content.toString();
} else {
Log.e(TAG, "Failed to load URL: " + urlString + " with response code: " + responseCode);
return context.getString(errorStringId);
}
} catch (Exception e) {
Log.e(TAG, "Error loading markdown from URL: " + urlString, e);
return context.getString(errorStringId);
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
Log.e(TAG, "Error closing reader", e);
}
}
if (connection != null) {
connection.disconnect();
}
}
private OpenSourceLicensesUtils() {
// Utility class
}

private static String extractLatestVersionChangelog(String markdown, String currentVersion) {
// Define the regex pattern to match the latest version section
String regexPattern = "(?m)^#\\s+Version\\s+" + Pattern.quote(currentVersion) + ":\\s*(.*?)^(#\\s+Version\\s+|$)";
Pattern pattern = Pattern.compile(regexPattern, Pattern.DOTALL | Pattern.MULTILINE);
Matcher matcher = pattern.matcher(markdown);

if (matcher.find()) {
// Group 1 contains the changelog for the current version
return Objects.requireNonNull(matcher.group(1)).trim();
} else {
Log.e(TAG, "No changelog available for version " + currentVersion);
return "No changelog available for version " + currentVersion;
public static void openLicensesScreen(@Nullable Context context) {
if (context == null) {
return;
}
}

private static String markdownToHtml(String markdown) {
Parser parser = Parser.builder().build();
HtmlRenderer renderer = HtmlRenderer.builder().build();
Node document = parser.parse(markdown);
return renderer.render(document);
}
OssLicensesMenuActivity.setActivityTitle(context.getString(R.string.open_source_licenses));

private static String getAppVersion(Context context) {
try {
return context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0)
.versionName;
} catch (Exception e) {
Log.e(TAG, "Error getting app version", e);
return "1.0.0"; // Fallback version
Intent intent = new Intent(context, OssLicensesMenuActivity.class);
if (!(context instanceof Activity)) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
}

public interface HtmlDataCallback {
void onHtmlDataLoaded(String changelogHtml, String eulaHtml);
context.startActivity(intent);
}
}
14 changes: 13 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
// The oss-licenses Gradle plugin still relies on XmlSlurper from groovy-xml when
// running on recent Gradle versions, so we provide it explicitly on the classpath.
classpath 'org.codehaus.groovy:groovy-xml:3.0.19'
}
}

plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.googleServices) apply false
alias(libs.plugins.firebaseCrashlytics) apply false
alias(libs.plugins.aboutLibraries) apply true
alias(libs.plugins.ossLicenses) apply false
alias(libs.plugins.hiltAndroid) apply false
}
2 changes: 1 addition & 1 deletion docs/core/core-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Houses use case classes and other business logic that operate on repositories.
Contains Activities, Fragments and ViewModels such as `MainViewModel`.

### utils
Provides helpers like `OpenSourceLicensesUtils`, `ReviewHelper` and `EdgeToEdgeDelegate`.
Provides helpers like `OpenSourceLicensesUtils` for launching the open source license screen, `ReviewHelper` and `EdgeToEdgeDelegate`.

### di
Contains Hilt modules and qualifiers for dependency injection.
Expand Down
9 changes: 5 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
agp = "8.13.0"
firebaseCrashlyticsPlugin = "3.0.6"
googleServices = "4.4.3"
ossLicensesPlugin = "0.10.6"
appcompat = "1.7.1"
appUpdate = "2.1.0"
billing = "8.0.0"
constraintlayout = "2.2.1"
aboutlibraries = "11.3.0"
coreSplashscreen = "1.0.1"
core = "4.6.2"
coreTesting = "2.2.0"
Expand All @@ -27,6 +27,7 @@ coreKtx = "1.17.0"
material = "1.14.0-alpha04"
multidex = "2.0.1"
playServicesAds = "24.6.0"
playServicesOssLicenses = "17.3.0"
codeview = "1.3.9"
hilt = "2.57.1"
room = "2.8.0"
Expand Down Expand Up @@ -63,6 +64,7 @@ firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "fir
firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics" }
google-firebase-perf = { module = "com.google.firebase:firebase-perf" }
play-services-ads = { module = "com.google.android.gms:play-services-ads", version.ref = "playServicesAds" }
play-services-oss-licenses = { module = "com.google.android.gms:play-services-oss-licenses", version.ref = "playServicesOssLicenses" }

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

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

[bundles]
# Google Play services and related UI components
google-core = [
"material",
"play-services-ads",
"play-services-oss-licenses",
"review",
"app-update",
"billing",
Expand Down Expand Up @@ -138,7 +140,6 @@ androidx-lifecycle = [

# Shared UI tooling and visuals
ui-toolkit = [
"aboutlibraries",
"core",
"lottie",
"library",
Expand Down
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pluginManagement {
resolutionStrategy {
eachPlugin {
if (requested.id.id == 'com.google.android.gms.oss-licenses-plugin') {
useModule("com.google.android.gms:oss-licenses-plugin:${requested.version}")
useModule('com.google.android.gms:oss-licenses-plugin:0.10.6')
}
}
}
Expand Down